VideoHelp Forum




+ Reply to Thread
Page 3 of 3
FirstFirst 1 2 3
Results 61 to 77 of 77
  1. Member
    Join Date
    May 2008
    Location
    France
    Search Comp PM
    Thanks for the merge python script, I'll try that.

    You can also merge with SE: tools -> join subtitles

    Just add the 2 subs and click "join".

    Then: tools > Sort > By start time

    Looking at your subs I see what happens: the missing subs come from the merge, but that has a penalty: there are parts where you have both subs generated by whisper and those merged for the same dialog.

    Example starting at 47:42:507 for E02 (timestamp with my version):

    One sub with 2 lines:

    Code:
    I always believed that I
    had a future in this country.
    And then 2 subs with 2 lines and one line:

    Code:
    I always believed
    we had a future
    Code:
    in this country.
    That's a bit of a mess!

    About syncing subs.

    Most US shows are designed to have ads. These ads are generally inserted at scene changes, when the video goes dark briefly.

    2 different versions of a same show (web-dl and FOX edited to remove ads for example) will show a timing discrepancy at the scene changes.

    My process is:

    1) Use comskip, a tool to find ads, to detect scene changes to produce a VideoRedo .vprj file.

    I use:

    comskip82_010_donators\comskip.exe --threads=20 --videoredo --detectmethod=95 --verbose=0 "Bones S01-E01.mkv"

    Even if the adds have already been removed, comskip usually finds where

    2) Open the VideoRedo project. VideoRedo will clearly show where the ads where. It will show many false positions, but using F6 to navigate from one to the next shows the image, and when it's dark, it's likely where the adds were.

    Example with an old FOX show where the adds were already removed:

    Image
    [Attachment 89434 - Click to enlarge]


    Use SE to adjust at the beginning using "Set start and offset the rest". Then navigate to the next scene change that you see with VideoRedo. Check before the timestamp if it's in sync (usually it is) and there after. If it's not, sync it at this location with ""Set start and offset the rest"".

    That does not work with all the shows (not with Kabul for example that never had embedded ads anyway), but in my experience with many of them.

    Not sure if the donator version of comskip is still available. Or if it's actually needed.

    VideoRedo is no longer sold, it's hard to activate it now but I read somewhere that somebody has the rights to it now and can provide a legal way. You would need to do a search for that.

    If I get more information, I'll send you a PM.
    Quote Quote  
  2. Example starting at 47:42:507 for E02 (timestamp with my version):

    One sub with 2 lines:

    Code:
    I always believed that I
    had a future in this country.
    And then 2 subs with 2 lines and one line:

    Code:
    I always believed
    we had a future
    Code:
    in this country.
    SE engine is the culprit. No problems with CMD>CLI

    Image
    [Attachment 89439 - Click to enlarge]


    Doing the transcription again.Will update you with new subs soon.

    Meanwhile, read my PM
    Quote Quote  
  3. Member
    Join Date
    May 2008
    Location
    France
    Search Comp PM
    Originally Posted by sam12345 View Post
    Uploaded complete clean subs of Kabul (Mini TV Series) 2025


    https://www.opensubtitles.org
    Great, that will save me the trouble doing all the subs myself.

    I actually tried to upload the Assembly ones, they were rejected because it's too obvious that they are AI generated.

    Edit:

    But there are still subs that overlap:

    Image
    [Attachment 89446 - Click to enlarge]
    Last edited by robena; 29th Oct 2025 at 12:53.
    Quote Quote  
  4. Will update the code of assembly tommorow.
    Quote Quote  
  5. Member
    Join Date
    May 2008
    Location
    France
    Search Comp PM
    Hi,

    So, here is a perfect way for this Kabul series.

    This uses my way to number episodes: "Kabul S01-E01.mkv"

    This will likely fail if using another convention such as " "Kabul S01E01.mkv"

    1) Use Faster-Whisper-XXL_r245.1_windows with this model (based on a REXX script, easy to transcribe for something else):


    Code:
                                                                                                                   
    /* Just in case you want something else than English */
    if lang = 'en' then do
        task = ' --task translate'
        prompt = ' --initial_prompt "Translate everything to English."'
    end
    else do
        task = ' --task transcribe'
        prompt = ' --initial_prompt "Transcribe in 'lang'."'
    end
                                                                                                                   
    '--model large-v3' ,
    task ,
    ' --language 'lang ,
    prompt ,
    ' --device cuda' ,
    ' --compute_type float16' ,
    ' --batch_size 8' ,
    ' --vad_method pyannote_onnx_v3' ,
    ' --vad_device cuda' ,
    ' --beep_off',
    ' --vad_threshold 0.1' ,                 /* ULTRA LOW */
    ' --vad_min_speech_duration_ms 50' ,     /* 50ms = catch whispers */
    ' --vad_min_silence_duration_ms 100' ,   /* tighter gaps */
    ' --hallucination_silence_threshold 0.6' ,
    ' --no_speech_threshold 0.1' ,           /* catch ANY speech */
    ' --logprob_threshold -2.0' ,            /* keep low-conf */
    ' --compression_ratio_threshold 2.4' ,
    ' --beam_size 5' ,
    ' --best_of 5' ,
    ' --temperature 0' ,
    ' --repetition_penalty 1.1' ,
    ' --no_repeat_ngram_size 3' ,
    ' --condition_on_previous_text False' ,
    ' --word_timestamps True' ,
    ' --output_format all' ,                 /* JSON + SRT */
    ' --output_dir "'fdd(file)'"'
    That outputs a file such as "Kabul S01-E01.srt" that my REXX script renames to "Kabul S01-E01-en.srt"

    *** Having a filename ending with "-something" is necessary.

    Then, store in the same directory: "Kabul S01-E01-F.srt"

    These are the forced subs for the foreign dialogs.

    *** Having '-F' is necessary.

    Whisper has translated these foreign dialogs, but we want those that are already in "Kabul S01-E01-F.srt".

    To get that, merge with this python script:

    Code:
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    """
    merge_subtitles.py -
    - -F.srt loaded FIRST
    - Every forced sub PRESERVED exactly
    - Whisper fills gaps OR is replaced on overlap
    - No duplicates, no loss
    """
     
    import sys
    from pathlib import Path
    from typing import List, Tuple
     
    def time_to_seconds(t: str) -> float:
        h, m, s_ms = t.split(":")
        s, ms = s_ms.replace(",", ".").split(".")
        return int(h) * 3600 + int(m) * 60 + float(s) + float(ms) / 1000
     
    def seconds_to_srt(sec: float) -> str:
        h = int(sec // 3600)
        m = int((sec % 3600) // 60)
        s = sec % 60
        return f"{h:02}:{m:02}:{s:06.3f}".replace(".", ",")[:12]
     
    def parse_srt_robust(content: str, filename: str) -> List[Tuple[float, float, List[str], str]]:
        entries = []
        lines = content.splitlines()
        i = 0
        while i < len(lines):
            if lines[i].strip().isdigit():
                i += 1
                if i >= len(lines): break
                time_line = lines[i].strip()
                if "-->" not in time_line:
                    i += 1
                    continue
                try:
                    start_str, end_str = time_line.split("-->", 1)
                    start = time_to_seconds(start_str.strip())
                    end = time_to_seconds(end_str.strip())
                except:
                    i += 1
                    continue
                i += 1
                text_lines = []
                while i < len(lines) and lines[i].strip() and not lines[i].strip().isdigit():
                    text_lines.append(lines[i].strip())
                    i += 1
                if text_lines:
                    entries.append((start, end, text_lines, filename))
            else:
                i += 1
        return entries
     
    def is_forced(filename: str) -> bool:
        return any(k in filename.lower() for k in ("-f.", "-forced", ".f.", "forced"))
     
    def main(mkv_path: str) -> None:
        mkv = Path(mkv_path)
        if not mkv.exists():
            print(f"[ERROR] File not found: {mkv}")
            sys.exit(1)
     
        folder = mkv.parent
        base_name = mkv.stem
        output_srt = folder / f"{base_name}.srt"
     
        if output_srt.exists():
            print("Skipping merge, file exists")
            return
     
        srt_files = list(folder.glob(f"{base_name}*.srt"))
        if not srt_files:
            print(f"[INFO] No SRT files")
            return
     
        forced_file = next((f for f in srt_files if is_forced(f.name)), None)
        whisper_file = next((f for f in srt_files if not is_forced(f.name)), None)
     
        if not forced_file:
            print("[ERROR] No -F.srt found!")
            return
     
        print(f"[INFO] Forced: {forced_file.name}")
        print(f"[INFO] Whisper: {whisper_file.name if whisper_file else 'None'}")
     
        # Parse forced
        try:
            forced_text = forced_file.read_text(encoding="utf-8", errors="replace")
            forced_subs = parse_srt_robust(forced_text, forced_file.name)
            print(f"    ? {len(forced_subs)} forced lines")
        except Exception as e:
            print(f"[ERROR] Failed to read forced: {e}")
            return
     
        # Parse whisper
        whisper_subs = []
        if whisper_file:
            try:
                whisper_text = whisper_file.read_text(encoding="utf-8", errors="replace")
                whisper_subs = parse_srt_robust(whisper_text, whisper_file.name)
                print(f"    ? {len(whisper_subs)} whisper lines")
            except Exception as e:
                print(f"[WARNING] Whisper failed: {e}")
     
        forced_subs.sort(key=lambda x: x[0])
        whisper_subs.sort(key=lambda x: x[0])
     
        final_subs = []
        w_idx = 0
        W = len(whisper_subs)
     
        for f_start, f_end, f_lines, _ in forced_subs:
            # Add all Whisper subs that END before this forced sub starts
            while w_idx < W:
                w_start, w_end, _, _ = whisper_subs[w_idx]
                if w_end <= f_start:  # No overlap
                    final_subs.append(whisper_subs[w_idx][:3])
                    w_idx += 1
                else:
                    break
     
            # Now: skip all Whisper subs that overlap this forced sub
            while w_idx < W:
                w_start, w_end, _, _ = whisper_subs[w_idx]
                if w_start < f_end:  # Overlaps
                    w_idx += 1
                else:
                    break
     
            # Add forced sub
            final_subs.append((f_start, f_end, f_lines))
     
        # Add remaining non-overlapping whisper subs
        while w_idx < W:
            final_subs.append(whisper_subs[w_idx][:3])
            w_idx += 1
     
        # Write output
        with open(output_srt, "w", encoding="utf-8") as f:
            for idx, (start, end, lines) in enumerate(final_subs, 1):
                f.write(f"{idx}\n")
                f.write(f"{seconds_to_srt(start)} --> {seconds_to_srt(end)}\n")
                for line in lines:
                    f.write(f"{line}\n")
                f.write("\n")
     
        print(f"\n[OK] Merged {len(final_subs)} blocks ? {output_srt.name}")
        print(f"    ? {len(forced_subs)} forced subs preserved (100%)")
     
    if __name__ == "__main__":
        if len(sys.argv) != 2:
            print("Usage: merge_subtitles.py <mkv_path>")
            sys.exit(1)
        main(sys.argv[1])
    that will produce "Kabul S01-E01.srt"

    It will contain:

    - English dialogs transcribed in English
    - Foreign dialogs that are already in the '-F' forced subs "as is".
    - Foreign dialogs missing in the '-F' forced subs translated by whisper.

    I did all that with a mix of ChatGPT, Grok and Deepseek.

    Here are all the episode batch processed:

    https://limewire.com/d/9JGEX#qH5IhI1Y1x


    Keep in mind that my SE settings are different than yours, so formating might not be 100% to your liking.

    Also, it seems that you don't have exactly the same version, you will likely need to sync the start of the subs.
    Last edited by robena; 29th Oct 2025 at 20:47.
    Quote Quote  
  6. No.The lines are too big to read. Update the code with

    --max_line_count 2 ^
    --max_line_width 36 ^
    Image Attached Thumbnails Click image for larger version

Name:	Screenshot_25.png
Views:	4
Size:	1.60 MB
ID:	89454  

    Click image for larger version

Name:	Screenshot_26.png
Views:	6
Size:	1.84 MB
ID:	89455  

    Click image for larger version

Name:	Screenshot_27.png
Views:	4
Size:	1.76 MB
ID:	89456  

    Quote Quote  
  7. Member
    Join Date
    May 2008
    Location
    France
    Search Comp PM
    Not too many lines like that, but I'll try and compare the results, that's easy!

    The way I did it with a REXX script, it's just a right click to do everything.
    Quote Quote  
  8. Updated Assembly Code [Assembly.c]
    Perfect Two lines break. No need for SE batch for touchup.
    Image Attached Files
    Quote Quote  
  9. Member
    Join Date
    May 2008
    Location
    France
    Search Comp PM
    I did not test Assembly yet, but for whisper, I am surprised to see the difference it makes between --max_line_width 36 and --max_line_width 40, it's not only 4 characters.

    I asked why, and got:

    --max_line_width does not mean “no line may be longer than N characters”.
    It tells Faster-Whisper the target width that the line-breaker tries to stay under while it is splitting a segment into subtitle lines.
    Because the breaker also respects sentence boundaries, words that are already > N, and minimum-line-length rules, you will still see lines that are much longer than the value you passed – especially when you raise it from 36 to 40.

    Thanks for pointing it out, I would never had thought by myself that it would make the subs that better.

    Here they are:

    https://limewire.com/d/ZpjSg#tNvqHhY3Gl

    Whisper gives much more natural looking subs than Assembly. opensubtitles.org rejects Assembly ones.

    Edit: I'll reserve judgment until I test your version!

    Edit edit: I get "Failed to upload file." with your version. Firewall was open. Don't waste time on it for me, I'll use whisper from now on.

    Edit edit edit: stupid, I forgot to update the API key!!!
    Last edited by robena; 30th Oct 2025 at 03:50.
    Quote Quote  
  10. Member
    Join Date
    May 2008
    Location
    France
    Search Comp PM
    Sam,

    I remux my subs using a routine that detects the aspect ratio and creates PGS files that are located inside the active video region, just a few pixels above the black bar:

    Image
    [Attachment 89467 - Click to enlarge]


    Interested?
    Quote Quote  
  11. Ofcource YES.


    The way I did it with a REXX script, it's just a right click to do everything.
    Kindly PM your code for Faster-Whisper-XXL that you used
    Quote Quote  
  12. Tehran [Season 03] KAN (Color-Yellow) ENG-NON Hi

    subs uploaded > opensubtitles.org [uploader-SamGer]
    Last edited by sam12345; 30th Oct 2025 at 06:48.
    Quote Quote  
  13. Member
    Join Date
    May 2008
    Location
    France
    Search Comp PM
    Originally Posted by sam12345 View Post
    Tehran [Season 03] KAN (Color-Yellow) ENG-NON Hi

    subs uploaded > opensubtitles.org [uploader-SamGer]
    Waiting for the UHD version...
    Quote Quote  
  14. @robena

    I remux my subs using a routine that detects the aspect ratio and creates PGS files that are located inside the active video region, just a few pixels above the black bar:
    Can you PM me the batch (.bat) files for above. Not familiar with REXX.
    Last edited by sam12345; 1st Nov 2025 at 02:26.
    Quote Quote  
  15. Member
    Join Date
    May 2008
    Location
    France
    Search Comp PM
    Originally Posted by sam12345 View Post
    @robena

    I remux my subs using a routine that detects the aspect ratio and creates PGS files that are located inside the active video region, just a few pixels above the black bar:
    Can you PM me the batch (.bat) files for above. Not familiar with REXX.
    I don't have them!

    I don't use .bat scripts, I never learned how to do it. REXX is so much powerful and easy to use that I have no reason to.

    You could show the REXX routines I sent you to ChatGPT, ask it to analyze them and re-write in python or power shell.**

    Basically, my routines use tools like tsmuxer, mkvtoolnix and ffmpeg to do all that.

    Here are some examples, this is the he script I sent you for getting the AR:

    Code:
    #! d:\m1\sedit\obj\xed\srexx.exe
                                                                                                                   
    /*
    ** AspectRatio: returns AR      
    **
    ** Called by edseries
    **/
    signal on novalue
    option setenv mixed
    address exec
    procedure
    if 0 = index($PATH, $HOME'/rcmd') then $PATH = $PATH';'$HOME'/rcmd;'$HOME'/cmd'
                                                                                                                   
    file = arg(1)
    if ft(file) = '' then file = file'.mkv'
    if ($AspectRatio_file = fn(file)||ft(file)) & $AspectRatio_found ~= '' then
      return $AspectRatio_found
                                                                                                                   
    cmd = ffmpeg()
    say
    say '*** Finding Aspect Ratio for: 'file
    say
    say 'Running: 'cmd' -hwaccel cuda -ss 00:03:00 -i "'file'" -map 0:v:0 -copyts -vf cropdetect -frames:v 500 -f null -'
                                                                                                                   
    /* Run cropdetect with hardware acceleration and tuned parameters */
    crop_cmd = '"'cmd'" -hwaccel cuda -ss 00:03:00 -i "'file'" -map 0:v:0 -copyts -vf cropdetect -frames:v 500 -f null -'
    call windows crop_cmd, tab
                                                                                                                   
    /* Log cropdetect output for debugging */
    /* do i = 1 to tab.0
      if pos('crop=', tab.i) > 0 then
        say 'Cropdetect: 'tab.i
    end */
                                                                                                                   
    do i = tab.0 to 1 by -1
      parse value tab.i with 'crop='hh':'ww':'
      if hh ~= '' & ww ~= '' & ww ~= 0 & hh ~= 0 then
        { ar = hh/ww
          say 'Initial AR: 'ar
          if ar <= 1.90 then ar = '1.85'
          else if ar > 1.90 & ar <= 2.1 then ar = '2'
          else if ar > 2.10 & ar <= 2.25 then ar = '2.2'
          else if ar > 2.25 & ar < 2.60 then ar = '2.39'
          else if ar >= 2.60 then ar = '2.60'
          say 'Final AR: 'ar
          $AspectRatio_found = ar
          $AspectRatio_file = fn(file)||ft(file)
          return ar
        }
    end
                                                                                                                   
    say 'Unable to determine aspect ratio'
    return ''
    That runs ffmpeg and captures its output in variables tab.1, tab.2, etc...

    It parses the output and returns 1.85, 2, 2.2, 2.39 or 2.60.

    Give that to Chat, if will do the same with another language.

    This is the routine that produces 2 PGS files, one pure white and one darker in case HDR makes that too bright:

    Code:
    #! d:\m1\sedit\obj\xed\srexx.exe
                                                                                                                   
    /*
    ** MakeSup: Makes a sup from an srt
    **
    **  TSMuxer with
                                                                                                                   
    MUXOPT --no-pcr-on-video-pid --new-audio-pes --demux --vbr  --vbv-len=500
    S_TEXT/UTF8, "B:\prob\test.srt",font-name="Arial Unicode MS",font-size=48,font-color=0xffffffff,bottom-offset=158,font-border=5,text-align=center,video-width=1920,video-height=1080,fps=23.976
                                                                                                                   
    **   06/06/24:  Arial Unicode MS
    **
    **    MakeSup ar fn1 fn2 ....
    **
    **    Can read offset from offset.txt and size from SizeFont.size
    **
    **    if $DoSupGey == 1, does grey subs too
    **    if $?LevelSup, uses $LevelSup
    **    if $?offset  , uses $offset
    **    if $SizeFont , uses $SizeFont
    **
    **   Size for PJ:  font-size=48
    **   Size for TV:  font-size=50       WebFont =  60 IF VIDEO HEIGHT == 1600 (WEBRips)
    **
    **         offset.25 of.25 SizeFont.55  sf.55   anamorphic   2.0      handbrake recode
    **         offset.25 of.25 SizeFont.50          anamorphic   2.35     handbrake recode
    **
    **         greyUHD.145
    **         greyHD.174
    **
    **         // ntweb.txt   prevents testing WEB-DL for positioning  -- Obsolete
    **
    **/
    signal on novalue
    option setenv mixed
    address exec
    if 0 = index($PATH, $HOME'/rcmd') then  $PATH = $PATH';'$HOME'/rcmd;'$HOME'/cmd'
    procedure
                                                                                                                   
    UseWebFont = 0
    WebFont = WebFont() /* returns 56 but not used anymore */
    /* trace x */
    SizeFont = SizeFont()
    FontBorder = 5
    FontBorderWeb = 3
    /* FontName = 'Arial' */
    FontName = 'Arial Unicode MS'
                                                                                                                   
    if ~ $?LG_UHD then $LG_UHD = 0
    movie = arg(2, 'x')
    movie = fdd(movie)'\'||fn(movie)||'.mkv'
    white = fdd(movie)'\'||fn(movie)||'.sup'
    grey  = fdd(movie)'\'||fn(movie)'-grey'||'.sup'
    if state(white) & state(grey) then
    *{ say 'MakeSup: subs exist, skipping'
       return 0
    *}
    if ft(arg(2, 'x')) * '.srt' then call GetStreams movie
                                                                                                                   
    stv = value("stream.video.1.Display_aspect_ratio")
    if (UseWebFont & ~$?offset & stv ~= 'stream.video.1.Display_aspect_ratio' & stv ~= "16:9") then
      $offset = 20
    nn = ReadNumExt('offset')
    call edseries fn(movie)||'.srt'
    if nn = '' then nn = ReadNumExt('of')
                                                                                                                   
    if $?offset & nn = '' then
      { offset = $offset
        ar = arg(1, 'x')
        CustomOffset = 1
        say 'Using read custom 'offset' offset'
      }
    else
    *{  if nn ~= '' then
         { offset = nn
           ar = 'Custom 'offset
           CustomOffset = 1
           say 'Using read custom 'offset' offset'
           $IsRatio = 0    /* of.NN overides all */
           $IsOf = 1
         }
        else
         { ar = arg(1, 'x')
           CustomOffset = 0
             select
              when ar = '2.60'                             then offset = 190
              when ar = '2.35' | ar = '2.39' | ar = '2.40' then offset = 158
              when ar = '2.20'                             then offset = 118
              when ar = '2'                                then offset = 85
              when ar = '1.85' | ar = '1.77'               then offset = 50
              otherwise
               offset = ar
             end
             $IsRatio = 1    /* of.NN overides all */
             $IsOf = 0
         }
      }
    ForceBR = arg(2, 'x')
                                                                                                                   
    meta = cwd()'\srt2sub.meta'
                                                                                                                   
    if 0 ~= pos("-DV", fn(movie), 1) then
       greyHD = '0xff919191'    /* 145 145 145 */
    else
       greyHD = '0xffAEAEAE'  /* 174 174 174 */
       /* greyHD = '0xff919191'    \* 145 145 145 *\ */
    /* greyHD  = '0xff787878' \* 120 120 120 *\   \* LG *\ */
    /* greyHD  = '0xff3C3C3C' \* 60 60 60    *\   \* Envy too dark *\ */
    /* greyHD  = '0xff646464'  \* 100 100 100 *\   \* LG *\ */
    greyUHD = greyHD  /* With Envy */
    SizeWEB = 57
    /* SizeWEB = 70 */
                                                                                                                   
    nn = ReadNumExt('greyUHD')
    if nn ~= ''then
    *{ gg = d2x(nn)
       if ½gg = 1 then gg = '0'gg
       gg = gg[1:2]
       greyUHD = '0xff'||gg||gg||gg
    *}
                                                                                                                   
    nn = ReadNumExt('greyHD')
    if nn ~= '' then
    *{ gg = d2x(nn)
       if ½gg = 1 then gg = '0'gg
       gg = gg[1:2]
       greyHD = '0xff'||gg||gg||gg
    *}
                                                                                                                   
    whitecolor = '0xffEBEBEB'     /* 235 */
    if $?LevelSup then
    *{ gg = d2x($LevelSup)
       greyHD = '0xff'||gg||gg||gg
       greyUHD = '0xff'||gg||gg||gg
       whitecolor = greyUHD
    *}
                                                                                                                   
    if $LG_UHD then
      greycolor = greyUHD
    else
      greycolor = greyHD
                                                                                                                   
    nn = ReadNumExt('SizeFont')
    if nn = '' then nn = ReadNumExt('sf')
    if nn ~= '' then
    *{ SizeFont = nn
       CustomSizeFont = 1
       say 'Using read custom 'SizeFont' font size'
    *}
    else CustomSizeFont = 0
                                                                                                                   
                                                                                                                   
    if $?SizeFont then
    *{ SizeFont = $SizeFont
       CustomSizeFont = 1
    *}
                                                                                                                   
    /* UseWebFont = ~state('ntweb.txt') */
    das = value('stream.video.1.Display_aspect_ratio')
    if das * '16:9' then UseWebFont = 0
                                                                                                                   
    if UseWebFont then
    {  if value('stream.video.1.Width') * '3 840 pixels' then
         { /*
            * WebRIPS with stream.video.1.Height = 1 600 need a 60 font, and a 40 ofset for 2.35 ratio
            */
            if ar > 1.85 | das = '2.40:1' | das = '2.000:1' | das = '2.35:1' then
            { vv = value('stream.video.1.Height')
              vv = change(vv, ' ', '')  /* 1 600 pixels */
              vv = change(vv, 'pixels', '')
              if datatype(vv, 'num') & vv < 1650 then
               {  if CustomSizeFont = 0 then SizeFont = WebFont
                  /* trace x */
                  if CustomOffset = 0 /* & ~$IsRatio */ then offset = 20
                  FontBorder = FontBorderWeb
                  /* offset = 30 */
                  /* offset = 25 */
                  /* offset = 20 */
                  /* if ~ $?GONG then call gong */
                  say
                  say '************** WebRIP: switching to 'SizeFont' font size and 'offset' offset'
                  say
               }
               else if datatype(vv, 'num') & vv < 1800 then    /* 2.0  1714 pixels */
               {  if CustomSizeFont = 0 then SizeFont = SizeWEB
                  if CustomOffset = 0 /* & ~$IsRatio */ then offset = 15
                  FontBorder = FontBorderWeb
                  /* offset = 30 */
                  /* offset = 25 */
                  /* offset = 20 */
                  /* if ~ $?GONG then call gong */
                  say
                  say '************** WebRIP: switching to 'SizeFont' font size and 'offset' offset'
                  say
               }
           }
         }
       else if value('stream.video.1.Width') = '1 280 pixels' & value('stream.video.1.Height') < 540 then
         {
           /*
            * 720p WebRIPS with 2.35 AR
            */
            if CustomSizeFont = 0 then SizeFont = WebFont
            if CustomOffset = 0 then offset = 13
            FontBorder = FontBorderWeb
            /* offset = 30 */
            /* offset = 25 */
            /* offset = 20 */
            /* if ~ $?GONG then call gong */
            say
            say '************** 720p WebRIP: switching to 'SizeFont' font size and 'offset' offset'
            say
         }
       else
         {
           /*
            * WebRIPS with stream.video.1.Height = 816 need a 60 font, and a 40 ofset for 2.35 ratio
            */
                                                                                                                   
            if ar > 1.85 | das = '2.40:1' | das = '2.000:1' | das = '2.35:1' | (CustomOffset = 1 & offset > 100)  then
            { vv = value('stream.video.1.Height')
              vv = change(vv, ' ', '')  /* 816 pixels */
              vv = change(vv, 'pixels', '')
              if vv < 850 then
               {  if CustomSizeFont = 0 then SizeFont = WebFont
                  if CustomOffset = 0 then offset = 20
                  FontBorder = FontBorderWeb
                  /* offset = 30 */
                  /* offset = 25 */
                  /* offset = 20 */
                  /* if ~ $?GONG then call gong */
                  say
                  say '************** WebRIP: switching to 'SizeFont' font size and 'offset' offset'
                  say
               }
              else if vv < 970 then       /* 2.0  872 -> 960 pixels */
               {  if CustomSizeFont = 0 then SizeFont = SizeWEB
                  if CustomOffset = 0 then
                   { stv = value('stream.video.1.Display_aspect_ratio')
                     parse value stv with ar':'xxx
                      { if ar >= '2' then offset = 15
                        else offset = 60
                      }
                   }
                  /* offset = 30 */
                  /* offset = 25 */
                  /* offset = 20 */
                  FontBorder = FontBorderWeb
                  /* if ~ $?GONG then call gong */
                   say
                   say '************** WebRIP: switching to 'SizeFont' font size and 'offset' offset'
                   say
               }
            }
         }
    }
    /* trace x */
    Say '.... Using 'greycolor' grey color, 'offset' offset and 'SizeFont' font size.'
    $MakeSupOffsetSizeFont = offset' offset/'SizeFont' font size'
    $MakeSupOffsetSizeFontGrey = offset' offset/'SizeFont' font size/'greycolor 'greycolor'
    /* greycolor = '0xff919191' */         /* 145 145 145 */
    /* greycolor = '0xff646464'  */  /* 100 100 100 */
    /* greycolor = '0xff878787' */   /* 135 135 135 */
                                                                                                                   
    i = 2
    file = arg(i, 'x')
                                                                                                                   
    if ~$?IsCCEX & ~CustomOffset then
    *{ call edseries file
       if $?offset then
       offset = $offset
       CustomOffset = 1
    *}
    rcode = 0
                                                                                                                   
    do while file ~= ''
    *call rm '"'meta'"'
    *if $DoSupGey = 1 then
       fontcolor = greycolor
    *else
       fontcolor = whitecolor
    *call lineout meta, 'MUXOPT --no-pcr-on-video-pid --new-audio-pes --demux --vbr  --vbv-len=500'
    *call lineout meta, 'S_TEXT/UTF8, "'follow(file)'",font-name="'FontName'",font-size='SizeFont',font-color='fontcolor',bottom-offset='offset',font-border='FontBorder',text-align=center,video-width=1920,video-height=1080,fps=23.976'
    *call lineout meta
    *say '.... Using 'SizeFont' font size'
    *say 'D:/m1/soft/T/TSMuxer/tsMuxeR_2.6.12/tsMuxeR.exe "'meta'" "'cwd()'"'
    */* trace x */
    *call tee 'D:/m1/soft/T/TSMuxer/tsMuxeR_2.6.12/tsMuxeR.exe "'meta'" "'cwd()'"', tab
    *rcode = rcode + rc
    */* Blank lines make TSMuxer stop before ending */
    *amount = 0
    *do k = 1 to tab.0
       if 'flushing' * (tab.k)[1:8] then
        { l = k-1
          parse var tab.l amount '%' foo
        }
    *end
    *if amount < 99 then rcode = -1
                                                                                                                   
    */*
      * With "G.I. Jane-s.srt", TSMuxer outputs "G.sup"
      */
    *fn = fn(file)
    *len = ½fn
    *do k = 2 to len
       if fn[k] = '.' then
        {  saved = fn[1:k-1]'.sup'
           needed = fn'.sup'
           call mv saved, needed
           leave k
        }
    *end
                                                                                                                   
    */*
      * Make grey if called standalone
      */
    *if ~$?MakeSupNotStand then
      { fontcolor = greycolor
        call rm '"'meta'"'
        file_grey = fdd(file)'\'fn(file)'-grey'||ft(file)
        call cp '"'file'" "'file_grey'"'
        call lineout meta, 'MUXOPT --no-pcr-on-video-pid --new-audio-pes --demux --vbr  --vbv-len=500'
        call lineout meta, 'S_TEXT/UTF8, "'file_grey'",font-name="'FontName'",font-size=48,font-color='fontcolor',bottom-offset='offset',font-border='FontBorder',text-align=center,video-width=1920,video-height=1080,fps=23.976'
        call lineout meta
        say 'D:/m1/soft/T/TSMuxer/tsMuxeR_2.6.12/tsMuxeR.exe "'meta'" "'cwd()'"'
        call tee 'D:/m1/soft/T/TSMuxer/tsMuxeR_2.6.12/tsMuxeR.exe "'meta'" "'cwd()'"', tab
        call rm '"'file_grey'"'
      }
                                                                                                                   
    *i = i+1
    *file = arg(i, 'x')
    end
    call rm '"'meta'"'
                                                                                                                   
    return rcode
    It makes a command file to be used by the command line version of tsmuxer.

    It uses this function to get "media info" information"

    Code:
    #! d:\m1\sedit\obj\xed\srexx.exe
                                                                                                                   
    /*
    ** GetStreams  file  (quotes not needed)          TGetStreams
    **
    **    $TestMediaInfo uses new version of mediainfo
    **
    **
    **    Creates         stream.video == NNN
    **                    stream.video.1.xxxxx
    **                     derived from content with "/" -> "."
    **                                               " " -> "_"
    **                                               "," -> "_"
    **                                               "(" -> "_"
    **                                               ")" -> "_"
    **                                               "*" -> "_"
    **                    stream.audio == NNN
    **                    stream.audio.1.xxxxx
    **                    stream.audio.2.xxxxx
    **
    **                    stream.text == NNN
    **                    stream.text.1.xxxxx
    **                    stream.text.2.xxxxx
                                                                                                                   
    *Example:
                                                                                                                   
                    call GetStreams 'b:\prob\WithAAC.mkv'
                                                                                                                   
                    do a in cvtails('stream.audio.1')
                       interpret 'zz = stream.audio.1.'a
                       say 'stream.audio.1.'a' = 'zz
                    end
                    say '---'
                    do a in cvtails('stream.audio.2')
                       interpret 'zz = stream.audio.2.'a
                       say 'stream.audio.2.'a' = 'zz
                    end
                    say '---'
                                                                                                                   
                    say 'Video: 'stream.video
                    do a in cvtails('stream.video.1')
                       interpret 'zz = stream.video.1.'a
                       say 'stream.video.1.'a' = 'zz
                    end
                    say '---'
                                                                                                                   
                    say 'Text: 'stream.text
                    do a in cvtails('stream.text.1')
                       interpret 'zz = stream.text.1.'a
                       say 'stream.text.1.'a' = 'zz
                    end
                                                                                                                   
    Donne:
                                                                                                                   
                    Audio: 2
                    stream.audio.1.Channel_positions = Front: L R
                    stream.audio.1.Channel_s_ = 2 channels
                    stream.audio.1.Format_profile = LC
                    stream.audio.1.Format = AAC
                    stream.audio.1.ID = 1
                    stream.audio.1.Duration = 42mn 51s
                    stream.audio.1.Compression_mode = Lossy
                    stream.audio.1.Sampling_rate = 48.0 KHz
                    stream.audio.1.Default = Yes
                    stream.audio.1.Language = English
                    stream.audio.1.Forced = No
                    stream.audio.1.Format.Info = Advanced Audio Codec
                    stream.audio.1.Codec_ID = A_AAC
                    stream.audio.1.Rank = 0
                    ---
                    stream.audio.2.Bit_rate = 384 Kbps
                    stream.audio.2.Stream_size = 118 MiB (7%)
                    stream.audio.2.Language = English
                    stream.audio.2.Bit_depth = 16 bits
                    stream.audio.2.Sampling_rate = 48.0 KHz
                    stream.audio.2.ID = 3
                    stream.audio.2.Channel_positions = Front: L C R, Side: L R, LFE
                    stream.audio.2.Format.Info = Audio Coding 3
                    stream.audio.2.Compression_mode = Lossy
                    stream.audio.2.Default = No
                    stream.audio.2.Format = AC-3
                    stream.audio.2.Forced = No
                    stream.audio.2.Channel_s_ = 6 channels
                    stream.audio.2.Codec_ID = A_AC3
                    stream.audio.2.Bit_rate_mode = Constant
                    stream.audio.2.Duration = 42mn 51s
                    stream.audio.2.Mode_extension = CM (complete main)
                    stream.audio.2.Format_settings__Endianness = Big
                    stream.audio.2.Rank = 1
                    ---
                    Video: 1
                    stream.video.1.ID = 2
                    stream.video.1.Format.Info = Advanced Video Codec
                    stream.video.1.Width = 1 920 pixels
                    stream.video.1.Frame_rate = 23.976 fps
                    stream.video.1.Format_settings__CABAC = Yes
                    stream.video.1.Format = AVC
                    stream.video.1.Forced = No
                    stream.video.1.Format_profile = High@L4.0
                    stream.video.1.Display_aspect_ratio = 16:9
                    stream.video.1.Chroma_subsampling = 4:2:0
                    stream.video.1.Format_settings__ReFrames = 4 frames
                    stream.video.1.Height = 1 080 pixels
                    stream.video.1.Default = Yes
                    stream.video.1.Matrix_coefficients = BT.709
                    stream.video.1.Scan_type = Progressive
                    stream.video.1.Frame_rate_mode = Constant
                    stream.video.1.Bit_depth = 8 bits
                    stream.video.1.Codec_ID = V_MPEG4/ISO/AVC
                    stream.video.1.Color_space = YUV
                    stream.video.1.Duration = 42mn 51s
                    stream.video.1.Transfer_characteristics = BT.709
                    stream.video.1.Color_primaries = BT.709
                    stream.video.1.Language = English
                    stream.video.1.Rank = 3
                    ---
                    Text: 1
                    stream.text.1.Codec_ID.Info = UTF-8 Plain Text
                    stream.text.1.Format = UTF-8
                    stream.text.1.Codec_ID = S_TEXT/UTF8
                    stream.text.1.Default = Yes
                    stream.text.1.Forced = No
                    stream.text.1.ID = 4
                    stream.text.1.Rank = 4
                    ---
                    Menu: 9
                    stream.menu.1 = 00:00:00.000                             : Chapter 1
                    stream.menu.2 = 00:09:27.525                             : Chapter 2
                    stream.menu.3 = 00:26:15.782                             : Chapter 3
                    stream.menu.4 = 00:38:16.127                             : Chapter 4
                    stream.menu.5 = 00:54:36.898                             : Chapter 5
                    stream.menu.6 = 01:18:51.100                             : Chapter 6
                    stream.menu.7 = 01:28:02.443                             : Chapter 7
                    stream.menu.8 = 01:36:42.379                             : Chapter 8
                    stream.menu.9 = 01:49:07.374                             : Chapter 9
                                                                                                                   
       24/04/23 Change  stream.text.text_i.RANK = text_i+1
                                                                                                                   
    **/
    procedure expose stream.
    signal on novalue
    option setenv mixed
    address exec
                                                                                                                   
    $debug_GetStream = 0
                                                                                                                   
    file = arg(1, 'x')
    if file[1] = '"' then file = file[2:(½file)-1]
                                                                                                                   
    video_i = 0
    audio_i = 0
    text_i  = 0
    menu_i  = 0
    rank_i  = 0
                                                                                                                   
    drop stream.
                                                                                                                   
    media = MediaInfo()
    call windows(media '--Inform=Text "'file'"', tab)
                                                                                                                   
    /* do i = 1 to tab.0
       say tab.i
    end i
    exit */
                                                                                                                   
    do i = 1 to tab.0
       if tab.i = "General" then
        { do k = i+1 to tab.0
             if tab.k = '' then
              { i = k
                leave k
              }
             call do_stem tab.k, 'general'
          end k
          i = k
        }
                                                                                                                   
       if (tab.i)[1:5] = "Video" then
        { video_i = video_i+1
          do k = i+1 to tab.0
             if tab.k = '' then
              { i = k
                leave k
              }
             call do_stem tab.k, 'video.'video_i
          end k
          call do_stem3 'video', video_i
          i = k
        }
                                                                                                                   
       if (tab.i)[1:5] = "Audio" then
        { audio_i = audio_i+1
          do k = i+1 to tab.0
             if tab.k = '' then
              { i = k
                leave k
              }
             call do_stem tab.k, 'audio.'audio_i
         end k
         call do_stem3 'audio', audio_i
         i = k
        }
                                                                                                                   
       if (tab.i)[1:4] = "Text" then
        { /* trace x */
          text_i = text_i+1
          do k = i+1 to tab.0
             if tab.k = '' then
              { i = k
                leave k
              }
             call do_stem tab.k, 'text.'text_i
         end k
         call do_stem3 'text', text_i
         stream.text.text_i.RANK = text_i+1
         i = k
        }
                                                                                                                   
       if (tab.i)[1:4] * "Menu" then
        { /* trace x */
          do k = i+1 to tab.0
             if tab.k = '' then
              { i = k
                leave k
              }
             menu_i = menu_i+1
             call do_stem2 tab.k, 'menu.'menu_i
         end k
         call do_stem3 'menu', menu_i
         i = k
        }
    end
                                                                                                                   
    stream.video = video_i
    stream.audio = audio_i
    stream.text  = text_i
    stream.menu  = menu_i
    /* trace x
    say value('stream.text.1.Language')
    procedure expose stream. */
                                                                                                                   
    return
                                                                                                                   
    do_stem: procedure expose stream.
       parse value arg(1) with left ':' right
       stem = 'stream.'arg(2)'.'clean(strip(left))
       if 0 = pos('"', right) then sep = '"'
       else
        { sep = "'"
          right = change(right, "'", "''")
        }
       stem = change(stem, '-', '_')
       interpret stem'='sep||strip(right)sep
       if $debug_GetStream then
        { sayn 'Stem <'stem'> = "'
          interpret 'sayn 'stem
          say '"'
        }
    return
                                                                                                                   
    do_stem2: procedure expose stream.
       stem = 'stream.'arg(2)
       interpret stem'=arg(1)'
       if $debug_GetStream then
        { sayn 'Stem <'stem'> = "'
          interpret 'sayn 'stem
          say '"'
        }
    return
                                                                                                                   
    do_stem3: procedure expose stream. rank_i
                                                                                                                   
      stem = 'stream.'arg(1)'.'arg(2)'.Rank'
      interpret stem'=rank_i'
      rank_i = rank_i + 1
       if $debug_GetStream then
        { sayn 'Stem <'stem'> = "'
          interpret 'sayn 'stem
          say '"'
        }
    return
                                                                                                                   
    clean:procedure
    *a = change(arg(1), "/", ".")
    *a = change(a     , " ", "_")
    *a = change(a     , ",", "_")
    *a = change(a     , "(", "_")
    *a = change(a     , ")", "_")
    *a = change(a     , "*", "_")
    return a
                                                                                                                   
    /*
    General
    Unique ID                                : 200995056992673479727480854705761339975 (0x97363D69AAC25B858AF6248DD0D6CA47)
    Complete name                            : WithAAC.mkv
    Format                                   : Matroska
    Format version                           : Version 4 / Version 2
    File size                                : 1.69 GiB
    Duration                                 : 42mn 51s
    Overall bit rate                         : 5 629 Kbps
    Encoded date                             : UTC 2014-12-03 08:53:34
    Writing application                      : mkvmerge v7.2.0 ('On Every Street') 32bit built on Sep 13 2014 15:42:11
    Writing library                          : libebml v1.3.0 + libmatroska v1.4.1
    DURATION                                 : 00:41:58.815000000
    NUMBER_OF_FRAMES                         : 758
    NUMBER_OF_BYTES      h                    : 32250
    _STATISTICS_WRITING_APP                  : mkvmerge v7.2.0 ('On Every Street') 32bit built on Sep 13 2014 15:42:11
    _STATISTICS_WRITING_DATE_UTC             : 2014-12-03 08:53:34
    _STATISTICS_TAGS                         : BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
                                                                                                                   
    Video
    ID                                       : 2
    Format                                   : AVC
    Format/Info                              : Advanced Video Codec
    Format profile                           : High@L4.0
    Format settings, CABAC                   : Yes
    Format settings, ReFrames                : 4 frames
    Codec ID                                 : V_MPEG4/ISO/AVC
    Duration                                 : 42mn 51s
    Width                                    : 1 920 pixels
    Height                                   : 1 080 pixels
    Display aspect ratio                     : 16:9
    Frame rate mode                          : Constant
    Frame rate                               : 23.976 fps
    Color space                              : YUV
    Chroma subsampling                       : 4:2:0
    Bit depth                                : 8 bits
    Scan type                                : Progressive
    Language                                 : English
    Default                                  : Yes
    Forced                                   : No
    Color primaries                          : BT.709
    Transfer characteristics                 : BT.709
    Matrix coefficients                      : BT.709
                                                                                                                   
    Audio #1
    ID                                       : 1
    Format                                   : AAC
    Format/Info                              : Advanced Audio Codec
    Format profile                           : LC
    Codec ID                                 : A_AAC
    Duration                                 : 42mn 51s
    Channel(s)                               : 2 channels
    Channel positions                        : Front: L R
    Sampling rate                            : 48.0 KHz
    Compression mode                         : Lossy
    Language                                 : English
    Default                                  : Yes
    Forced                                   : No
                                                                                                                   
    Audio #2
    ID                                       : 3
    Format                                   : AC-3
    Format/Info                              : Audio Coding 3
    Mode extension                           : CM (complete main)
    Format settings, Endianness              : Big
    Codec ID                                 : A_AC3
    Duration                                 : 42mn 51s
    Bit rate mode                            : Constant
    Bit rate                                 : 384 Kbps
    Channel(s)                               : 6 channels
    Channel positions                        : Front: L C R, Side: L R, LFE
    Sampling rate                            : 48.0 KHz
    Bit depth                                : 16 bits
    Compression mode                         : Lossy
    Stream size                              : 118 MiB (7%)
    Language                                 : English
    Default                                  : No
    Forced                                   : No
                                                                                                                   
    Text
    ID                                       : 4
    Format                                   : UTF-8
    Codec ID                                 : S_TEXT/UTF8
    Codec ID/Info                            : UTF-8 Plain Text
    Default                                  : Yes
    Forced                                   : No
    */
    Really not easy to do that in BAT format!

    Again, send it to Chat (or Grok, very good too) to analyze it and prompt it to make what you want using it as a template.

    You'll be surprised how easy and fast it will be.

    Then you can use MKVtoolnix (https://mkvtoolnix.download/downloads.html) to remux, either with the gui or with a script in command line mode.

    My REXX routines to do all in one right click that are thousand of lines, all I can do is give you general guidelines.

    They depend of a lot of tools like the one above, downloaded on a precise location on my D: drive, making a portable package would be a huge undertaking.

    If you're stuck with some particular task, ask, I'll help.

    Edit: for some reason, this forum alters what I try to post and adds in some places unwanted "*' characters, in the code also. I don't know how to avoid that.
    If you know how, let me know and I'll edit this post.

    It prints "*i = i+1" instead of "i = i+1"

    Note also that this S/REXX version has features, like using {} or calling external routines as easily as using "nn = ReadNumExt('greyUHD')" when the*ReadNumExt file is in the path, that do not exist with the usual REXX implementation.
    ---
    Robert
    Last edited by robena; 1st Nov 2025 at 05:20.
    Quote Quote  
  16. Member
    Join Date
    May 2008
    Location
    France
    Search Comp PM
    Sam,

    I realize this might be a bit daunting, so I'm going to see if working on a virtual machine, I can cobble together something portable.

    No promises, I'm just evaluating how much work it will require for now.
    Quote Quote  



Similar Threads

Visit our sponsor! Try DVDFab and backup Blu-rays!