Jump to content
Nologic

Recursive Batch Create Roku BIF Files

Recommended Posts

Nologic

What this solves:

1. On demand creating Roku Bif files recursively through sub folders, using Emby Servers naming scheme. (Simple Dialog Interface, Command Line and SendTo {must be compiled}).

2. Scheduled Bif file creation,

3. Allow networked computers to work on shared folders to speed things along. Only limiting factors are the speed of your network & the number of systems connected.

 

Notes:

The Folders this script is to run against must be on ether a local or network mapped drive, as the script isn't setup to handle UNC paths.

Also checkout the concurrent version further down in the thread.

 

Requirements:

AutoIt

FFMpeg

Roku SDK

 

Instructions:

Install AutoIt and set it to execute scripts when double clicked.

 

Create a folder somewhere...lets call it "Creat BIF" just to be unimaginative.

 

Now inside "Create BIF" create a sub folder called "Bin".

 

Now extract the contents of FFMpeg's "Bin" folder into your new "Bin" sub folder.

 

Now extract "biftool.exe" from the Roku SDK into your new "Bin" sub folder.

 

Now going back into "Create  BIF" folder Right Click on it's background and select "New\AutoIt v3 Script" from the context menu, and Rename it "Create BIF.au3"

 

Now Right Click "Create BIF.au3" & select "Edit Script" from the context menu.

 

Now paste the following code into:

 

 

#Include <Array.au3>
#Include <File.au3>
#Include <String.au3>

Global $iVideoWidthSize = 320
Global $sErrorLog

Global $aWeekLong  = StringSplit( 'Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday' , '|' )
Global $aWeekShort = StringSplit( 'Sun|Mon|Tue|Wed|Thu|Fri|Sat' , '|' )
Global $iSchedule  = 0
Global $sExtension = '*.mkv;*.mp4;*.mov;*.m4v'

; Create Basic Settings If Required
$sSavedSettings = @ScriptDir & '\Create Bif.ini'
If NOT FileExists( $sSavedSettings ) Then _Settings( $sSavedSettings )

; Create SendTo Shortcut
If StringRight( @ScriptName , 4 ) = '.exe' Then
	$sSendTo = StringReplace( RegRead( 'HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders' , 'SendTo' ) , '%USERPROFILE%' , @UserProfileDir )
	If StringRight( $sSendTo , 1 ) <> '\' Then $sSendTo &= '\'
	; Actual SendTo Shortcut Creation
	If NOT FileExists( $sSendTo & StringTrimRight( @ScriptName , 4 ) & '.lnk' ) Then
		FileCreateShortcut( @ScriptDir & '\' & @ScriptName , $sSendTo & StringTrimRight( @ScriptName , 4 ) & '.lnk' , '' , '' , '' , @ScriptDir & '\' & @ScriptName  , '' , 0 )
	EndIf
EndIf

; Remove Temp Files & Folders
$aTemps = _FileListToArrayRec( @TempDir , 'Create Biff-*' , 14 , 0 , 1 , 2 )
If IsArray( $aTemps ) Then
	For $ii = 1 To $aTemps[0]
		DirRemove( $aTemps[$ii] & '\' , 1 )
	Next
EndIf

; Select Video Folder
If $CmdLine[0] = 0 Then
	While 1
		$sSourceFolder = FileSelectFolder( 'Select Video Folder.' , '' , 6 )
		If @[member="ERROR"] = 1 AND $sSourceFolder = '' Then
			MsgBox( 4096 , 'Exit:' , 'Ending Application' )
			Exit
		ElseIf $sSourceFolder = '' Then
			MsgBox( 4096 , 'Error:' , 'Unable To Open Folder.' )
		ElseIf NOT FileExists ( $sSourceFolder ) Then
			MsgBox( 4096 , 'Error:' , 'Invalid Folder.' )
		Else
			If StringRight( $sSourceFolder , 1 ) <> '\' Then $sSourceFolder &= '\'
			$aAllFiles = _FileListToArrayRec( $sSourceFolder , $sExtension , 1 , 1 , 0 , 2 )
			If NOT IsArray( $aAllFiles ) Then
				MsgBox( 4096 , 'Error:' , 'No Videos Found.' )
			Else
				_ArraySort( $aAllFiles , 0 , 1 )
				ExitLoop
			EndIf
		EndIf
	WEnd
	; One Instance at a Time
	$RunningScripts = ProcessList( @ScriptName )
	For $aa = 1 To $RunningScripts[0][0]
		If $RunningScripts[$aa][1] <> @AutoItPID Then ProcessWaitClose( $RunningScripts[$aa][1] )
	Next
	_Main( $aAllFiles )
Else
	Switch $CmdLine[1]
		; Run All Bif Tasks
		Case 'Schedule'
			$iSchedule = 1
			$aEndTime = _ScheduleTaskRead( $sSavedSettings )
			$aFolders = IniReadSection( $sSavedSettings , 'Folders' )
			For $ii = 1 To $aFolders[0][0]
				If FileExists( $aFolders[$ii][1] ) Then
					If StringRight( $aFolders[$ii][1] , 1 ) <> '\' Then $aFolders[$ii][1] &= '\'
					$aAllFiles = _FileListToArrayRec( $aFolders[$ii][1] , $sExtension , 1 , 1 , 0 , 2 )
					If NOT IsArray( $aAllFiles ) Then ContinueLoop
					_ArraySort( $aAllFiles , 0 , 1 )
					_Main( $aAllFiles )
				EndIf
			Next
		; Create New Bif Tasks
		Case 'ScheduleNew'
			_ScheduleTaskCreate( $sSavedSettings )
			Exit
		; Delete All Bif Tasks
		Case 'ScheduleDelete'
			_ScheduleTaskDelete()
			Exit
		; Process Command Line Files & Folders
		Case Else
			For $ii = 1 To $CmdLine[0]
				; One Instance at a Time
				$RunningScripts = ProcessList( @ScriptName )
				For $aa = 1 To $RunningScripts[0][0]
					If $RunningScripts[$aa][1] <> @AutoItPID Then ProcessWaitClose( $RunningScripts[$aa][1] )
				Next
				; Test if Folder
				If StringInStr( FileGetAttrib( $CmdLine[$ii] ) , 'D' ) <> 0 Then
					$sSourceFolder = $CmdLine[$ii]
					If StringRight( $sSourceFolder , 1 ) <> '\' Then $sSourceFolder &= '\'
					$aAllFiles = _FileListToArrayRec( $sSourceFolder , $sExtension , 1 , 1 , 0 , 2 )
					If NOT IsArray( $aAllFiles ) Then ContinueLoop
					_ArraySort( $aAllFiles , 0 , 1 )
					_Main( $aAllFiles )
				Else
					; Test if Supported File Type
					If StringInStr( $sExtension , StringTrimLeft( $CmdLine[$ii] , StringInStr( $CmdLine[$ii] , '.' , 0 , -1 ) - 1 )) <> 0 Then
						Dim $aAllFiles[2] = [1 , $CmdLine[$ii]]
						_Main( $aAllFiles )
					EndIf
				EndIf
			Next
	EndSwitch
EndIf
; Create Error Log
If StringLen( $sErrorLog ) > 1 Then
	If NOT FileExists( @ScriptDir & '\Error Logs\' ) Then DirCreate( @ScriptDir & '\Error Logs\' )
	$sErrorLogFile = @ScriptDir & '\Error Logs\[' & @YEAR & '-' & @[member="Mon"] & '-' & @MDAY & '] ' & @HOUR & '-' & @MIN & '.txt'
	FileWrite( $sErrorLogFile , $sErrorLog )
	ShellExecute( $sErrorLogFile )
EndIf
MsgBox( 0 , 'Finished:' , 'Batch BIF File Creation Is Complete.' )

Func _Main( ByRef $aArray )
	For $ii = 1 To $aArray[0]
		; Early Out
		If $iSchedule = 1 Then
			If $aEndTime[1] > @HOUR Then Exit
			If $aEndTime[1] = @HOUR AND $aEndTime[2] >= @MIN Then Exit
		EndIf

		; Create Base Name
		_FileMacros( $aArray[$ii] )
		$sTempName = $sShortName & '-' & $iVideoWidthSize

		; Early Out
		If FileExists( $aArray[$ii] ) = 0 Then ContinueLoop
		If FileExists( $sFileDir & $sTempName & '.bif' ) Then ContinueLoop

		; Create Temp Folder
		$sTempFolder = @TempDir & '\Create Biff-' & _RandomString() & '\' & $sTempName
		If NOT FileExists( $sTempFolder ) Then DirCreate( $sTempFolder )

		; Create Images
		If StringInStr( $sTempFolder , '%' ) <> 0 Then
			$sTempFolderNew = StringReplace( $sTempFolder , '%' , '%%' )
		Else
			$sTempFolderNew = $sTempFolder
		EndIf
		RunWait( @ComSpec & ' /c ffmpeg -i "' & $aArray[$ii] & '" -r .1 -vf "scale=min(iw\,' & $iVideoWidthSize & '):trunc(ow/dar/2)*2:flags=lanczos" -f image2 "' & $sTempFolderNew & '\%08d.jpg"' , @ScriptDir & '\BIN\' , @SW_HIDE )

		; Re Number Images (0 Base Index)
		$aAllImages = _FileListToArrayRec( $sTempFolder , '*.jpg' , 1 , 1 , 0 , 2 )
		If IsArray( $aAllImages ) Then
		   _ArraySort( $aAllImages , 0 , 1 )
		   For $jj = 1 To $aAllImages[0]
		   	FileMove( $aAllImages[$jj] , $sTempFolder & '\' & _StringRepeat( '0' , 8 - StringLen( $jj - 1 )) & $jj - 1 & '.jpg' )
		   Next
		Else
			DirRemove( $sTempFolder , 1 )
			$sErrorLog &= 'Could Not Process File:' & @CRLF & $aArray[$ii] & @CRLF & @CRLF
			ContinueLoop
		EndIf

		; Create Actual BIF File
		RunWait( @ComSpec & ' /c biftool -t 10000 "' & $sTempFolder & '"' , @ScriptDir & '\BIN\' , @SW_HIDE )

		; Move BIF To Correct Folder
		FileMove( @ScriptDir & '\BIN\' & $sTempName & '.bif' , $sFileDir , 1 )

		; Delete Temp Folder
		DirRemove( $sTempFolder , 1 )
	Next
EndFunc

Func _FileMacros( $sInFile )
	Global $sFileDir    = StringLeft     ( $sInFile   , StringInStr( $sInFile   , '\' , 0 , -1 ) )
	Global $sFileExt    = StringTrimLeft ( $sInFile   , StringInStr( $sInFile   , '.' , 0 , -1 ) - 1 )
	Global $sFileName   = StringTrimLeft ( $sInFile   , StringInStr( $sInFile   , '\' , 0 , -1 ) )
	Global $sShortName  = StringLeft     ( $sFileName , StringInStr( $sFileName , '.' , 0 , -1 ) - 1 )
	Global $sParent     = StringTrimLeft ( $sFileDir  , StringInStr( $sFileDir  , '\' , 0 , -2 ) )
	Global $sFolderName = StringTrimRight( StringTrimLeft( $sFileDir , StringInStr( $sFileDir , '\' , 0 , -2 ) ) , 1 )
EndFunc

Func _RandomString()
	Local $sString , $aSpace[3]

	For $i = 1 To 15
		$aSpace[0] = Chr( Random( 65 ,  90 , 1 )) ; A-Z
		$aSpace[1] = Chr( Random( 97 , 122 , 1 )) ; a-z
		$aSpace[2] = Chr( Random( 48 ,  57 , 1 )) ; 0-9
		$sString &= $aSpace[Random( 0 , 2 , 1 )]
	Next

	Return $sString
EndFunc

Func _Settings( $sSettingsFile )
	$sString = ''
	For $ii = 1 To $aWeekLong[0]
		$sString &= '[' & $aWeekLong[$ii] & ']' & @CRLF
		$sString &= 'Start=03:00' & @CRLF
		$sString &= 'End=06:00'   & @CRLF
		$sString &= @CRLF
	Next
	$sString &= '[Folders]'  & @CRLF
	$sString &= 'Folder_01=' & @CRLF & @CRLF
	FileWrite( $sSettingsFile , $sString )
EndFunc

Func _ScheduleTaskRead( $sSettingsFile )
	Return StringSplit( IniRead( $sSettingsFile , $aWeekLong[@WDAY] , 'End' , '06:00' ) , ':' )
EndFunc

Func _ScheduleTaskDelete()
	For $ii = 1 To $aWeekLong[0]
		; Remove Old Tasks If Exists
		RunWait( @ComSpec & ' /c SchTasks /DELETE /TN "Create Bif - ' & $aWeekLong[$ii] & '" /F' , '' , @SW_HIDE )
	Next
EndFunc

Func _ScheduleTaskCreate( $sSettingsFile )
	$aFolders = IniReadSection( $sSettingsFile , 'Folders' )
	If IsArray( $aFolders ) = 0 Then
		MsgBox( 48 , 'Error:' , 'Folders in INI Invalid or Missing.' )
		Exit
	EndIf
	For $ii = 1 To $aFolders[0][0]
		If FileExists( $aFolders[$ii][1] ) = 0 Then
			MsgBox( 48 , 'Error:' , 'Folder Invalid.' & @LF & $aFolders[$ii][1] )
			Exit
		EndIf
	Next

	For $ii = 1 To $aWeekLong[0]
		; Remove Old Task If Exists
		RunWait( @ComSpec & ' /c SchTasks /DELETE /TN "Create Bif - ' & $aWeekLong[$ii] & '" /F' , '' , @SW_HIDE )

		$aTaskStart = StringSplit( IniRead( $sSettingsFile , $aWeekLong[$ii] , 'Start' , '03:00' ) , ':' )
		$aTaskEnd   = StringSplit( IniRead( $sSettingsFile , $aWeekLong[$ii] , 'End'   , '06:00' ) , ':' )
		Select
			Case $aTaskStart[1] < 0
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Hour Less Than 0.'   & @LF & $aTaskStart[1] & ':' & $aTaskStart[2] )
				Exit
			Case $aTaskStart[2] < 0
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Minute Less Than 0.' & @LF & $aTaskStart[1] & ':' & $aTaskStart[2] )
				Exit
			Case $aTaskEnd[1] < 0
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Hour Less Than 0.'   & @LF & $aTaskEnd[1]   & ':' & $aTaskEnd[2] )
				Exit
			Case $aTaskEnd[2] < 0
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Minute Less Than 0.' & @LF & $aTaskEnd[1]   & ':' & $aTaskEnd[2] )
				Exit
			Case $aTaskStart[1] > 24
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Hour Greater Than 24.'   & @LF & $aTaskStart[1] & ':' & $aTaskStart[2] )
				Exit
			Case $aTaskStart[2] > 59
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Minute Greater Than 59.' & @LF & $aTaskStart[1] & ':' & $aTaskStart[2] )
				Exit
			Case $aTaskEnd[1] > 24
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Hour Greater Than 24.'   & @LF & $aTaskEnd[1]   & ':' & $aTaskEnd[2] )
				Exit
			Case $aTaskEnd[2] > 59
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Minute Greater Than 59.' & @LF & $aTaskEnd[1]   & ':' & $aTaskEnd[2] )
				Exit
			Case $aTaskStart[1] > $aTaskEnd[1]
				MsgBox( 48 , 'Error:' , 'Start Time Hour Greater Than End Time Hour.'       & @LF & 'Start: ' & $aTaskStart[1] & ':' & $aTaskStart[2] & @LF & 'End: ' & $aTaskEnd[1] & ':' & $aTaskEnd[2] )
				Exit
			Case $aTaskStart[1] = $aTaskEnd[1] AND $aTaskStart[2] > $aTaskEnd[2]
				MsgBox( 48 , 'Error:' , 'Start Time Minutes Greater Than End Time Minutes.' & @LF & 'Start: ' & $aTaskStart[1] & ':' & $aTaskStart[2] & @LF & 'End: ' & $aTaskEnd[1] & ':' & $aTaskEnd[2] )
				Exit
			Case $aTaskStart[1] = $aTaskEnd[1] AND $aTaskStart[2] = $aTaskEnd[2]
				ContinueLoop
		EndSelect

		; Create New Task
		RunWait( @ComSpec & ' /c SchTasks /Create /SC WEEKLY /D ' & $aWeekShort[$ii] & ' /TN "Create Bif - ' & $aWeekLong[$ii] & '" /TR "\"' & @ScriptFullPath & '\" Schedule" /ST ' & $aTaskStart[1] & ':' & $aTaskStart[2] & ' /F' , '' , @SW_HIDE )
	Next
EndFunc

 

 

 

Now save the script & execute it by double clicking it and then select the folder holding your videos that you wish to process.

 

Now go do something else, this will take a while...maybe a great while depending on the number of videos you have.

 

The script will notify you when it's done...and if you're currious as to if it's still running there should be a icon in your system tray that looks like a blue "A". Past that you can start your Task Manager and you should more than likely see FFMpeg running in the background.

 

By default this will create 320px aspect correct BIF files, if you wish to create 240px or any other size you'll need to edit line 7.

 

Example:

from

$iVideoWidthSize = 320

to

$iVideoWidthSize = 240

 

Update 1:

I decided to let FFMpeg do all the calculations for resize...which result in a massive code reduction.

 

Update 2:

Added passing folders via command line. This is mostly aimed at adding SendTo context menu support.

1. Right Click on "Create BIF.au3" and select "Compile Script (x86)" from the context menu

2. ALT + Left Click on "Create BIF.exe" and Drag to create a shortcut...rename to remove ".exe" from the file name

3. Cut & Paste shortcut to your SendTo folder: %APPDATA%\Microsoft\Windows\SendTo\

Now you don't even need to hunt down the script when you need it.

 

Update 3:

Added very simplistic scheduling based on a 24 hour clock.

Currently you can not start on one day and end on the following.

Only one time block allowed per day.

The script now produces an INI that can be edited "Create Bif.ini"

If you choose to use the scheduling the script needs to be compiled.

Once compiled & the INI edited to your liking, open up a console in the script folder.

Then enter:

"Create Bif.exe" ScheduleNew

Now new tasks have been created in the Windows Task Scheduler.

To remove tasks enter:

"Create Bif.exe" ScheduleDelete

To not have a task scheduled for a day, set the start time and end time to be the same.

 

Update 4:

Command Line now supports both Folders & Files...thus making a SendTo shortcut more useful.

 

Update 5:

Added auto SendTo shortcut creation...only happens if script is compiled.

To trigger this...simply use the executable once...you don't even have to actually process a file.

If you don't want this feature simply delete the code on and between lines 17 & 25 (currently)

 

Update 6:

Now allows only one instance to run at a time, to prevent bogging down your system.

This applies to Command Line and GUI, but not Task Scheduler...as the Task Scheduler should only have one instance anyways.

This allows you to cue up several folders\files to be processed, even though they are in very different locations.

 

Update 7:

Made it easier for the script to clean up after it's self.

Edited by Nologic
  • Like 2

Share this post


Link to post
Share on other sites
Luke

Well done!

Share this post


Link to post
Share on other sites
Nologic

Thanks :)

Share this post


Link to post
Share on other sites
Nologic

Why thank you. :)

Share this post


Link to post
Share on other sites
Spaceboy

But the plugin does create bif files for existing videos if you run the scheduled task. I've just spent the last 2 weeks with it running. Or am I missing something?

  • Like 1

Share this post


Link to post
Share on other sites
Nologic

Well if the plugin did it for you...then I'd say I missed something or something was screwy with my config...as I certainly didn't write the script for giggles. :)

 

If that's the case, as it sounds like it is...then the only reason to run my script would be spread the work around, between multiple systems.

Share this post


Link to post
Share on other sites
Nologic

Updated the script, now has an error log file, for video's it's unable to process for whatever reason.

Share this post


Link to post
Share on other sites
Nologic

Minor update to correct creating images for files that already have a percent sign in them "%" which was causing the script to fail on some files.

Share this post


Link to post
Share on other sites
hoxtonia

Thanks for this tool Nologic - has really sped up my processing for BIFs spread around various pcs - essential if you have a roku  :)

Share this post


Link to post
Share on other sites
Nologic

You are very welcome, and glad to hear it's helpful.

 

I'm thinking of making a modified version that can be used as a scheduled task. Where one just has to edit an INI file for when to start, and end processing, and what folders to do.

 

Granted generally after the bulk of the BIF files are created, the Roku Plug-in should handle things fine unless one is always adding video's in mass...then a scheduled networked BIF setup like I'm suggesting might be useful.

  • Like 1

Share this post


Link to post
Share on other sites
hoxtonia

I think that's a great idea - would be really useful to be able to run as a scheduled task  :)

Share this post


Link to post
Share on other sites
Nologic

I updated the code...so give it a try and let me know how it works out.

  • Like 1

Share this post


Link to post
Share on other sites
Nologic

Okay took another wack at this, this time looking to run concurrent BIF file creations...to help speed things along.

 

The recommended setting is 1 less the number of physical cores your CPU has...in my case since my Ivy has 4...I set it to 3, to keep the system usable...anything above would hose the system.

 

For me this speeds things up to about 2.5X what is normally done with the original script.

 

This takes two scripts to make this work, I call this "Create Bif Master.au3" & "Create Bif Slave.au3" both need to be compiled, and used the same way as the original.

 

Here is the master script:

 

 

#Include <Array.au3>
#Include <File.au3>
#Include <String.au3>

;================================================================================
;== User Vars
;================================================================================

Global $iImage_Width = 320
Global $iConcurrent  = 3

;================================================================================
;================================================================================

Global $aWeekLong  = StringSplit( 'Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday' , '|' )
Global $aWeekShort = StringSplit( 'Sun|Mon|Tue|Wed|Thu|Fri|Sat' , '|' )
Global $iSchedule  = 0
Global $sExtension = '*.mkv;*.mp4;*.mov;*.m4v'
Global $bExitLoop  = False

; Create Basic Settings If Required
$sSavedSettings = @ScriptDir & '\Create Bif.ini'
If NOT FileExists( $sSavedSettings ) Then _Settings( $sSavedSettings )

; Create SendTo Shortcut
If StringRight( @ScriptName , 4 ) = '.exe' Then
	$sSendTo = StringReplace( RegRead( 'HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders' , 'SendTo' ) , '%USERPROFILE%' , @UserProfileDir )
	If StringRight( $sSendTo , 1 ) <> '\' Then $sSendTo &= '\'
	; Actual SendTo Shortcut Creation
	If NOT FileExists( $sSendTo & StringTrimRight( @ScriptName , 4 ) & '.lnk' ) Then
		FileCreateShortcut( @ScriptDir & '\' & @ScriptName , $sSendTo & StringTrimRight( @ScriptName , 4 ) & '.lnk' , '' , '' , '' , @ScriptDir & '\' & @ScriptName  , '' , 0 )
	EndIf
EndIf

; Remove Temp Files & Folders
$aTemps = _FileListToArrayRec( @TempDir , 'Create Biff-*' , 14 , 0 , 1 , 2 )
If IsArray( $aTemps ) Then
	For $ii = 1 To $aTemps[0]
		DirRemove( $aTemps[$ii] & '\' , 1 )
	Next
EndIf

; Select Video Folder
If $CmdLine[0] = 0 Then
	While 1
		$sSourceFolder = FileSelectFolder( 'Select Video Folder.' , '' , 6 )
		If @[member="ERROR"] = 1 AND $sSourceFolder = '' Then
			MsgBox( 4096 , 'Exit:' , 'Ending Application' )
			Exit
		ElseIf $sSourceFolder = '' Then
			MsgBox( 4096 , 'Error:' , 'Unable To Open Folder.' )
		ElseIf NOT FileExists ( $sSourceFolder ) Then
			MsgBox( 4096 , 'Error:' , 'Invalid Folder.' )
		Else
			If StringRight( $sSourceFolder , 1 ) <> '\' Then $sSourceFolder &= '\'
			Global $aAllFiles = _FileListToArrayRec( $sSourceFolder , $sExtension , 1 , 1 , 0 , 2 )
			If NOT IsArray( $aAllFiles ) Then
				MsgBox( 4096 , 'Error:' , 'No Videos Found.' )
			Else
				_ArraySort( $aAllFiles , 0 , 1 )
				ExitLoop
			EndIf
		EndIf
	WEnd
	; One Instance at a Time
	$RunningScripts = ProcessList( @ScriptName )
	For $aa = 1 To $RunningScripts[0][0]
		If $RunningScripts[$aa][1] <> @AutoItPID Then ProcessWaitClose( $RunningScripts[$aa][1] )
	Next
	_Main()
Else
	Switch $CmdLine[1]
		; Run All Bif Tasks
		Case 'Schedule'
			$iSchedule = 1
			$aEndTime = _ScheduleTaskRead( $sSavedSettings )
			$aFolders = IniReadSection( $sSavedSettings , 'Folders' )
			For $ii = 1 To $aFolders[0][0]
				If FileExists( $aFolders[$ii][1] ) Then
					If StringRight( $aFolders[$ii][1] , 1 ) <> '\' Then $aFolders[$ii][1] &= '\'
					Global $aAllFiles = _FileListToArrayRec( $aFolders[$ii][1] , $sExtension , 1 , 1 , 0 , 2 )
					If NOT IsArray( $aAllFiles ) Then ContinueLoop
					_ArraySort( $aAllFiles , 0 , 1 )
					_Main()
				EndIf
			Next
		; Create New Bif Tasks
		Case 'ScheduleNew'
			_ScheduleTaskCreate( $sSavedSettings )
			Exit
		; Delete All Bif Tasks
		Case 'ScheduleDelete'
			_ScheduleTaskDelete()
			Exit
		; Process Command Line Files & Folders
		Case Else
			For $ii = 1 To $CmdLine[0]
				; One Instance at a Time
				$RunningScripts = ProcessList( @ScriptName )
				For $aa = 1 To $RunningScripts[0][0]
					If $RunningScripts[$aa][1] <> @AutoItPID Then ProcessWaitClose( $RunningScripts[$aa][1] )
				Next
				; Test if Folder
				If StringInStr( FileGetAttrib( $CmdLine[$ii] ) , 'D' ) <> 0 Then
					$sSourceFolder = $CmdLine[$ii]
					If StringRight( $sSourceFolder , 1 ) <> '\' Then $sSourceFolder &= '\'
					Global $aAllFiles = _FileListToArrayRec( $sSourceFolder , $sExtension , 1 , 1 , 0 , 2 )
					If NOT IsArray( $aAllFiles ) Then ContinueLoop
					_ArraySort( $aAllFiles , 0 , 1 )
					_Main()
				Else
					; Test if Supported File Type
					If StringInStr( $sExtension , StringTrimLeft( $CmdLine[$ii] , StringInStr( $CmdLine[$ii] , '.' , 0 , -1 ) - 1 )) <> 0 Then
						Global $aAllFiles[2] = [1 , $CmdLine[$ii]]
						_Main()
					EndIf
				EndIf
			Next
	EndSwitch
EndIf
MsgBox( 0 , 'Finished:' , 'Batch BIF File Creation Is Complete.' )


Func _Main()
	_ArrayDelete( $aAllFiles , 0 )
	AdlibRegister( '_Concurrent' , 250 )
	
	While $bExitLoop = False
		Sleep( 100 )
	WEnd

	$bExitLoop = False
	AdlibUnRegister( '_Concurrent' )
EndFunc

Func _Concurrent()
	; Early Out
	If $iSchedule = 1 Then
		If $aEndTime[1] > @HOUR Then Exit
		If $aEndTime[1] = @HOUR AND $aEndTime[2] >= @MIN Then Exit
	EndIf

	$aProcesslist = ProcessList( 'Create Bif Slave.exe' )
	If $aProcesslist[0][0] < $iConcurrent Then
		If UBound( $aAllFiles ) <> 0 Then
			$sCurrentFile = _ArrayPop( $aAllFiles )
			If $sCurrentFile <> '' Then
				; Create Base Name
				_FileMacros( $sCurrentFile )
				$sTempName = $sShortName & '-' & $iImage_Width

				; Early Out
				If FileExists( $sCurrentFile ) = 0 Then Return
				If FileExists( $sFileDir & $sTempName & '.bif' ) Then Return

				Run( '"' & @ScriptDir & '\Create Bif Slave.exe" "' & $sCurrentFile & '" "' & $iImage_Width & '"' )
			EndIf
		Else
			If ProcessExists( 'Create Bif Slave.exe' ) = 0 Then
				$bExitLoop = True
			EndIf
		EndIf
	EndIf
EndFunc

Func _FileMacros( $sInFile )
	Global $sFileDir    = StringLeft     ( $sInFile   , StringInStr( $sInFile   , '\' , 0 , -1 ) )
	Global $sFileExt    = StringTrimLeft ( $sInFile   , StringInStr( $sInFile   , '.' , 0 , -1 ) - 1 )
	Global $sFileName   = StringTrimLeft ( $sInFile   , StringInStr( $sInFile   , '\' , 0 , -1 ) )
	Global $sShortName  = StringLeft     ( $sFileName , StringInStr( $sFileName , '.' , 0 , -1 ) - 1 )
	Global $sParent     = StringTrimLeft ( $sFileDir  , StringInStr( $sFileDir  , '\' , 0 , -2 ) )
	Global $sFolderName = StringTrimRight( StringTrimLeft( $sFileDir , StringInStr( $sFileDir , '\' , 0 , -2 ) ) , 1 )
EndFunc

Func _Settings( $sSettingsFile )
	$sString = ''
	For $ii = 1 To $aWeekLong[0]
		$sString &= '[' & $aWeekLong[$ii] & ']' & @CRLF
		$sString &= 'Start=03:00' & @CRLF
		$sString &= 'End=06:00'   & @CRLF
		$sString &= @CRLF
	Next
	$sString &= '[Folders]'  & @CRLF
	$sString &= 'Folder_01=' & @CRLF & @CRLF
	FileWrite( $sSettingsFile , $sString )
EndFunc

Func _ScheduleTaskRead( $sSettingsFile )
	Return StringSplit( IniRead( $sSettingsFile , $aWeekLong[@WDAY] , 'End' , '06:00' ) , ':' )
EndFunc

Func _ScheduleTaskDelete()
	For $ii = 1 To $aWeekLong[0]
		; Remove Old Tasks If Exists
		RunWait( @ComSpec & ' /c SchTasks /DELETE /TN "Create Bif - ' & $aWeekLong[$ii] & '" /F' , '' , @SW_HIDE )
	Next
EndFunc

Func _ScheduleTaskCreate( $sSettingsFile )
	$aFolders = IniReadSection( $sSettingsFile , 'Folders' )
	If IsArray( $aFolders ) = 0 Then
		MsgBox( 48 , 'Error:' , 'Folders in INI Invalid or Missing.' )
		Exit
	EndIf
	For $ii = 1 To $aFolders[0][0]
		If FileExists( $aFolders[$ii][1] ) = 0 Then
			MsgBox( 48 , 'Error:' , 'Folder Invalid.' & @LF & $aFolders[$ii][1] )
			Exit
		EndIf
	Next

	For $ii = 1 To $aWeekLong[0]
		; Remove Old Task If Exists
		RunWait( @ComSpec & ' /c SchTasks /DELETE /TN "Create Bif - ' & $aWeekLong[$ii] & '" /F' , '' , @SW_HIDE )

		$aTaskStart = StringSplit( IniRead( $sSettingsFile , $aWeekLong[$ii] , 'Start' , '03:00' ) , ':' )
		$aTaskEnd   = StringSplit( IniRead( $sSettingsFile , $aWeekLong[$ii] , 'End'   , '06:00' ) , ':' )
		Select
			Case $aTaskStart[1] < 0
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Hour Less Than 0.'   & @LF & $aTaskStart[1] & ':' & $aTaskStart[2] )
				Exit
			Case $aTaskStart[2] < 0
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Minute Less Than 0.' & @LF & $aTaskStart[1] & ':' & $aTaskStart[2] )
				Exit
			Case $aTaskEnd[1] < 0
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Hour Less Than 0.'   & @LF & $aTaskEnd[1]   & ':' & $aTaskEnd[2] )
				Exit
			Case $aTaskEnd[2] < 0
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Minute Less Than 0.' & @LF & $aTaskEnd[1]   & ':' & $aTaskEnd[2] )
				Exit
			Case $aTaskStart[1] > 24
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Hour Greater Than 24.'   & @LF & $aTaskStart[1] & ':' & $aTaskStart[2] )
				Exit
			Case $aTaskStart[2] > 59
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Minute Greater Than 59.' & @LF & $aTaskStart[1] & ':' & $aTaskStart[2] )
				Exit
			Case $aTaskEnd[1] > 24
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Hour Greater Than 24.'   & @LF & $aTaskEnd[1]   & ':' & $aTaskEnd[2] )
				Exit
			Case $aTaskEnd[2] > 59
				MsgBox( 48 , 'Error:' , $aWeekLong[$ii] ' Minute Greater Than 59.' & @LF & $aTaskEnd[1]   & ':' & $aTaskEnd[2] )
				Exit
			Case $aTaskStart[1] > $aTaskEnd[1]
				MsgBox( 48 , 'Error:' , 'Start Time Hour Greater Than End Time Hour.'       & @LF & 'Start: ' & $aTaskStart[1] & ':' & $aTaskStart[2] & @LF & 'End: ' & $aTaskEnd[1] & ':' & $aTaskEnd[2] )
				Exit
			Case $aTaskStart[1] = $aTaskEnd[1] AND $aTaskStart[2] > $aTaskEnd[2]
				MsgBox( 48 , 'Error:' , 'Start Time Minutes Greater Than End Time Minutes.' & @LF & 'Start: ' & $aTaskStart[1] & ':' & $aTaskStart[2] & @LF & 'End: ' & $aTaskEnd[1] & ':' & $aTaskEnd[2] )
				Exit
			Case $aTaskStart[1] = $aTaskEnd[1] AND $aTaskStart[2] = $aTaskEnd[2]
				ContinueLoop
		EndSelect

		; Create New Task
		RunWait( @ComSpec & ' /c SchTasks /Create /SC WEEKLY /D ' & $aWeekShort[$ii] & ' /TN "Create Bif - ' & $aWeekLong[$ii] & '" /TR "\"' & @ScriptFullPath & '\" Schedule" /ST ' & $aTaskStart[1] & ':' & $aTaskStart[2] & ' /F' , '' , @SW_HIDE )
	Next
EndFunc

 

 

 

Now the Slave:

 

 

#Include <Array.au3>
#Include <File.au3>
#Include <String.au3>

If $CmdLine[0] = 0 OR $CmdLine[0] < 2 Then Exit

; Create Base Name
_FileMacros( $CmdLine[1] )
$sTempName = $sShortName & '-' & $CmdLine[2]

; Create Temp Folder
$sTempFolder = @TempDir & '\Create Biff-' & _RandomString() & '\' & $sTempName
If NOT FileExists( $sTempFolder ) Then DirCreate( $sTempFolder )

; Create Images
If StringInStr( $sTempFolder , '%' ) <> 0 Then
	$sTempFolderNew = StringReplace( $sTempFolder , '%' , '%%' )
Else
	$sTempFolderNew = $sTempFolder
EndIf
RunWait( @ComSpec & ' /c ffmpeg -i "' & $CmdLine[1] & '" -r .1 -vf "scale=min(iw\,' & $CmdLine[2] & '):trunc(ow/dar/2)*2:flags=lanczos" -f image2 "' & $sTempFolderNew & '\%08d.jpg"' , @ScriptDir & '\BIN\' , @SW_HIDE )

; Re Number Images (0 Base Index)
$aAllImages = _FileListToArrayRec( $sTempFolder , '*.jpg' , 1 , 1 , 0 , 2 )
If IsArray( $aAllImages ) Then
   _ArraySort( $aAllImages , 0 , 1 )
   For $ii = 1 To $aAllImages[0]
   	FileMove( $aAllImages[$ii] , $sTempFolder & '\' & _StringRepeat( '0' , 8 - StringLen( $ii - 1 )) & $ii - 1 & '.jpg' )
   Next
Else
	DirRemove( $sTempFolder , 1 )
	Exit
EndIf

; Create Actual BIF File
RunWait( @ComSpec & ' /c biftool -t 10000 "' & $sTempFolder & '"' , @ScriptDir & '\BIN\' , @SW_HIDE )

; Move BIF To Correct Folder
FileMove( @ScriptDir & '\BIN\' & $sTempName & '.bif' , $sFileDir & $sTempName & '.bif' , 1 )

; Delete Temp Folder
DirRemove( $sTempFolder , 1 )



Func _FileMacros( $sInFile )
	Global $sFileDir    = StringLeft     ( $sInFile   , StringInStr( $sInFile   , '\' , 0 , -1 ) )
	Global $sFileExt    = StringTrimLeft ( $sInFile   , StringInStr( $sInFile   , '.' , 0 , -1 ) - 1 )
	Global $sFileName   = StringTrimLeft ( $sInFile   , StringInStr( $sInFile   , '\' , 0 , -1 ) )
	Global $sShortName  = StringLeft     ( $sFileName , StringInStr( $sFileName , '.' , 0 , -1 ) - 1 )
	Global $sParent     = StringTrimLeft ( $sFileDir  , StringInStr( $sFileDir  , '\' , 0 , -2 ) )
	Global $sFolderName = StringTrimRight( StringTrimLeft( $sFileDir , StringInStr( $sFileDir , '\' , 0 , -2 ) ) , 1 )
EndFunc

Func _RandomString()
	Local $sString , $aSpace[3]

	For $i = 1 To 15
		$aSpace[0] = Chr( Random( 65 ,  90 , 1 )) ; A-Z
		$aSpace[1] = Chr( Random( 97 , 122 , 1 )) ; a-z
		$aSpace[2] = Chr( Random( 48 ,  57 , 1 )) ; 0-9
		$sString &= $aSpace[Random( 0 , 2 , 1 )]
	Next

	Return $sString
EndFunc

 

 

 

Enjoy!

Edited by Nologic

Share this post


Link to post
Share on other sites
cf23

Nologic, thank you very much for creating these scripts.  They'll potentially save me a ton of time.  However, can someone post a link to biftool.exe.  I'm not able to find it on the Roku SDK site anywhere, and they haven't responded to my emails asking about it.

 

Thanks.

Share this post


Link to post
Share on other sites
Happy2Play

Nologic, thank you very much for creating these scripts.  They'll potentially save me a ton of time.  However, can someone post a link to biftool.exe.  I'm not able to find it on the Roku SDK site anywhere, and they haven't responded to my emails asking about it.

 

Thanks.

Just googled it.  :)  Here you go.

Edited by Happy2Play

Share this post


Link to post
Share on other sites
cf23

Clearly your Google-Fu is better than mine.  Thanks!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...