0

I'm generating html with a batch file for personal use, and one of my sections I'm getting the width and height of all mp4 files in a folder. This "mp4 library" can have files swapped out, renamed, added to, or extracted, etc...so I don't want to manually enter in the width and height every time its gets updated.

This code below works, but it is very slow...is there any way to make it faster using a batch file?

for /f %%g in ('dir /B /S *.mp4') do (

    set "g=%%g"
    set "g=!g:\=/!"
    
    for /f "tokens=1 delims=x" %%a in ('ffprobe -v error -select_streams v:0 -show_entries stream^=width^,height -of csv^=s^=x:p^=0 %%g') do set sW=%%a
    for /f "tokens=2 delims=x" %%b in ('ffprobe -v error -select_streams v:0 -show_entries stream^=width^,height -of csv^=s^=x:p^=0 %%g') do set sH=%%b
    
    echo %TAB% %TAB% ^<span^>^ ^<a style="text-decoration:none" class="image" href="file:///!g!" target="_blank"^>^ ^<video width="!sW!" height="!sH!" poster="file:///S:/_Stuff/_Data/_o/6.gif" poster="file:///S:/_Stuff/_Data/_o/6.gif" preload="auto" muted autoplay loop^>^ ^<source src="file:///!g!" type="video/mp4"^>^ ^</video^>^ ^</a^>^ ^</span^>^ >> _01.html 2>nul  
)

**UPDATE: I tried this and it works, took 4 seconds vs 11seconds, but I just noticed a new answer so I will now try that suggestion out!

@echo off
setlocal EnableDelayedExpansion

>_output_test.txt (for /f %%g in ('dir /B /S *.mp4') do (

    set "g=%%g"
    set "g=!g:\=/!"
    REM @echo !g!

    for /f "tokens=1,2 delims=x" %%a in ('ffprobe -v error -select_streams v:0 -show_entries stream^=width^,height -of csv^=s^=x:p^=0 %%g') do (
        set sW=%%a 
        set sH=%%b
    )
    REM @echo !sW!
    REM @echo !sH!
    @echo %TAB% %TAB% ^<span^>^ ^<a style="text-decoration:none" class="image" href="file:///!g!" target="_blank"^>^ ^<video width="!sW!" height="!sH!" poster="file:///S:/_DaveStuff/_Data/_o/6.gif" preload="auto" muted autoplay loop^>^ ^<source src="file:///!g!" type="video/mp4"^>^ ^</video^>^ ^</a^>^ ^</span^>^  
    )
)

endlocal
pause
exit
  • 2
    1. `FOR /R` 2. Combine the two `FOR` loops 3. Parenthesize the entire `FOR` loop and redirect it, that only opens the file once – ScriptKidd Jun 20 '20 at 23:04
  • Please note, that requests for speed improvements, with no shown attempts at doing so yourself, are essentially off topic code requests. Therefore I'd suggest you try to implement the advice given thus far, we're not here to do it all for you. – Compo Jun 20 '20 at 23:29
  • Thanks for replying. I think I understand the "combining" part, but what do you mean redirect it? – General Knox Jun 20 '20 at 23:41
  • @Compo Sorry, I tried many options searching here, Ill continue to try on my own.I can post what I already tried? – General Knox Jun 20 '20 at 23:43
  • Currently, for each iteration of your outer `for /f` loop, you're redirecting output to `_01.html`. The advice was to redirect only once. When you redirect output to a file it opens the file, writes to it, and closes it again. Doing that for each and every `.mp4` file is a lot more work that just redirecting the entire `for /f` output. Please do, update your question with your updated code, if what you've now created needs further assistance. But please include with that exactly which part of the code requires it, your question should really be limited to just one specific one, not everything. – Compo Jun 20 '20 at 23:55
  • Ok Im trying the suggestions now + googling/research, will edit+reply once I get more results (good or bad). Thanks! – General Knox Jun 21 '20 at 01:25
  • Ok so I tried the above code in my "update" edited post, and I went from 11 seconds to 4 seconds to execute...and it works! But just as I logged on to write this response, I just noticed someone else answered below so I will now try their suggestion. – General Knox Jun 21 '20 at 01:54

1 Answers1

1

You are executing the same ffprobe command line twice within separate for /F loops, which is of course inefficient. Furthermore, you are writing every line separately into the output file, so many individual file I/O operations happen. Moreover, for /F together with dir /B /S (which should have been dir /B /S /A:-D-H-S) first build the complete list of items before beginning to iterate, which is not needed here, because the iterated items are not altered; so a for /R loop would be faster here, because it caches some items and begins to iterate then.

So here is a possible improvement:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Redirect to the output files once only (`>` to overwrite, `>>` to append):
>> "_01.html" 2> nul (
    rem /* `for /F` + `dir /B /S` first retrieves the whole list of items before iterating,
    rem    but `for /R` begins to iterate earlier: */
    for /R %%F in (*.mp4) do (
        rem // Store currently iterated file path:
        set "FILE=%%F"
        rem // Get values from `ffprobe` program:
        for /F "tokens=1,2 delims=x" %%a in ('ffprobe -v error -select_streams v:0 -show_entries stream^=width^,height -of csv^=s^=x:p^=0 "%%F"') do set "sW=%%a" & set "sH=%%b"
        rem // Toggle delayed expansion to avoid troubles with `!`:
        setlocal EnableDelayedExpansion
        rem // Replace `\` by `/` in file path:
        set "FILE=!FILE:\=/!"
        rem // Return HTML string (with unnecessary escaping avoided):
        echo %TAB% %TAB% ^<span^> ^<a style="text-decoration:none" class="image" href="file:///!FILE!" target="_blank"^> ^<video width="!sW!" height="!sH!" poster="file:///S:/_Stuff/_Data/_o/6.gif" poster="file:///S:/_Stuff/_Data/_o/6.gif" preload="auto" muted autoplay loop^> ^<source src="file:///!FILE!" type="video/mp4"^> ^</video^> ^</a^> ^</span^> 
        endlocal
    )
)
endlocal

If none of the iterated file paths contains exclamatio marks, you may remove the setlocal/endlocal pair inside of the for /R loop and change DisableDelayedExpansion to EnableDelayedExpansion at the beginning, which may slightly further improve performance although hardly noticeable.

aschipfl
  • 33,626
  • 12
  • 54
  • 99