#NoTrayIcon #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Outfile_type=a3x #AutoIt3Wrapper_Icon=..\Icones\YaST.ico #AutoIt3Wrapper_Outfile=D:\Users\celeri\Documents\AutoIT3\CCTools\CCTools2.0.2.0.a3x #AutoIt3Wrapper_Compression=4 #AutoIt3Wrapper_UseUpx=y #AutoIt3Wrapper_Compile_Both=y #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_Res_Comment=CCTools. Numerous tools to enhance CapCut's usability. #AutoIt3Wrapper_Res_Description=CapCut tools for PC #AutoIt3Wrapper_Res_Fileversion=2.0.2.0 #AutoIt3Wrapper_Res_CompanyName=DrLouis #AutoIt3Wrapper_Res_LegalCopyright=2024 (c) #AutoIt3Wrapper_Res_Language=3084 #AutoIt3Wrapper_Res_File_Add=D:\Users\celeri\Documents\HelpNDoc\Output\Build chm documentation\CCTools 20.chm, RT_RCDATA, BIN_1, 0 #Tidy_Parameters=/gd #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** ; CCtools 2.0.2.0 ; PROGRAM MATURE, READY FOR DISTRIBUTION ; Program to do different tasks related to CapCut : backup, restore, export subs, export YT auto chapters ; Built upon AutoSRT & CCBackup ; ComboBox code pilfered from GaryFrost --> https://www.autoitscript.com/forum/topic/47709-combobox-onchange-event-not-triggered-after-typing/ #cs DONE [2.0.2.0] - Large enough changes for a version change. --> Reprogramming of _Show_Resources(), integrating help in most GUI - _Show_Resources() : Indicate "[NOT FOUND]" at the beginning of filename and tip, esthetic changes to label h-positionning. Tried centering text vertically within label and failed. Lightened background a little bit. - Alternate label background color in _Show_Resources(). Include not found too. - $aRes wrong size after second use. Forcing ReDim when fetching resources - Test ListView for _Show_Resources() ... WORKS GREAT! - Have help page open with the proper context page --> https://help-info.de/en/htmlhelp/htmlhelp-command-line --> hh.exe D:\_temp\CHM-example.chm::/Garden/tree.htm - Get Install Manager to use ListView too (and then no use for GUIScrollBars_Ex anymore!) - Simplified $aGUI_Ver[999]. Now only 1 dimension. - Remove all traces of GUIScrollBars_Ex. ListView is the king. - NO : Find a way to merge _Backup_Project() and _Backup_Project2() --> Issue with passing parameters with a function called from _GuiCtrlSetOnEvent(). Perhaps no solution ... not strapped for space anyways and little gain. - Go through comments and add some when they are missing, correcting when there's an error and making it more precise when possible - NO : SETTINGS : Show ALL CapCut resources (created / imported by CapCut). But will not backup the files --> Always show all CapCut resources but still don't back them up - _Show_Resources() : Make background blue and indicate [Internal] for all internal (downloaded from inside CapCut) resources - _Export_Resources() : Filter file list and exclude missing and internal files - Group functions and make a banner for each group to facilitate "spotting" LOL --> Not perfect but will help a lot - Deleted _Project_Name_7z() that was not used anywhere. - Deleted _List_7z() that was only used by _Project_Name_7z(). - Edit Help file to convey the changes - _Backup_Project() and _Backup_Project2() should filter files before exporting - Regression? _Export_chapters() last chapter time 0, reads font name (!) on older .JSON files ... rewrite required. Note : same error going back to v. 2.0.0.0 --> Changed '"mark_items":' to '"mark_items":[{' - _Export_chapters() should test to see if there's chapters before offering to export file ... - Document all error codes in help file - _Export_Chapters() : use Number() instead of Eval() - Write error # in MsgBox [2.0.1.2] - Preparing way for help file being opened on the proper page when called --> _Open_Help() & _Load_Ver() - Open the "About" screen if "hh.exe" is not found in the Windows directory - Added $SS_LEFTNOWORDWRAP to GuiCtrlLabel in _Load_Ver() --> takes care of pixels below some lines - SHOW RESOURCES : Find a way to flag resources that cannot be found (deleted) --> red background --> MUST ROLL MY OWN GUI - Fixed help and hooked it up with all GUIs where pressing F1 makes sense. [2.0.1.1] - Add "Install manager" that enable user to delete old versions of CapCut - Modify GUI to enable Install manager - AutoIT icon is now hidden - program is mature and shouldn't hang in weird places LOL - NO : Concatenate all GUI into a same array? $aGUI[n][x] --> X : 1 = main GUI, 2 = settings, 3 = about, etc. --> Will make program almost impossible to decipher and lead to wasted RAN - Integrate "GUIScrollbars_Ex" so no include necessary (required to share CCTools2 source with one single file) - # Include cleanup - Move global variables in "GUIScrollbars_Ex" to the top of program - Add link to "GUIScrollbars_Ex" in the "About" screen. Do BEFORE publishing the code. - "Loading" cursor while processing folders in _Load_Ver() - Tell user backup during _Load_Ver() might be huge and take a long time. - Make "Manage Install" without selecting a project but unavailable if no output folder selected - Crashes if you want to see project resources and all resources are missing. --> _Load_Resources --> $iMatrice starts at 1 but program was expecting 0 to say no valid resources found. - DUH. Wrong hyperlink for CCTools2 page on Reddit - Settings greyed out with default parameters. Should always be available (didn't I fix this before?) - GEEEZUS. Selecting the root folder is possible while selecting output folder. Check for "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and just ignore the selection - Checking for valid output folder and valid project at startup, blanking if required. Not required for project : always starts blank - Find out where the combo box hack is from : GaryFrost --> https://www.autoitscript.com/forum/topic/47709-combobox-onchange-event-not-triggered-after-typing/ - Add .CHM help file during compile --> Through FileInstall() - Show resources should not skip files if they don't exist on the drive. --> 7-Zip is the one to deal with the missing pictures and will tell user about it. - Missing dash when exporting chapters (chapters wouldn't appear on YouTube - Create a help file. This could be an online web page --> Naah it's a .CHM file created with HelpNDoc --> CCTools2.chm - NO : Output Folder : prefer home instead of root? --> No valid option found, tried many CSLIDs ... - Better historic in documentation by going through old saved versions --> Will start with 2.0.1.1 - Keyboard shortcuts for Install manager (at least Ctrl-N and Ctrl-A) - Possible regression : [Dracomora] subs come out as "start --> length" instead of "start --> end" --> Mixup during the creation of the .SRT file. Probably induced when optimizing code? - Backup button was on if no project was selected. --> _Unselected() modified (again!) - NO : Try to meld both _Compress_7z() and _Extract_7z() if it's worthwhile --> Too many differences and savings are not sufficiently significant. - Open "About" if .CHM file is not found [2.0.0.1] - Wrong month coming out --> Index for @Mon starting at 1, array was starting at 0 TO DO - JOURNAL : Make a journal? And switch to disable journal $bNo_Journal. Could be useful. - JOURNAL : Where to put the journal if program is compiled? Next to the EXE? That is the issue - Move with resources : Create a new project and put all ressources into a specific folder. Harder because there will be a lot of filepath replacement. Useful when all resources are spread all over the place - _Export_Chapters() : Presently exports ALL markers. Eventually have user choose : all, cyan, red, orange, green, purple and on specific types of media. Note : internal pointer is color in hex format - Try to merge _Select_Save_Filename() and _Select_Load_Filename() - SETTINGS : Overwrite always during restore - Free space checking : add 5GB PLUS 100% of the current file size - Investigate skipping for missing files in the _Load_Resources() module. Apparently there are some genuine reasons to skip a file - Cancel during sub extraction? (currently have to wait for it to finish) - Popup $iErr and $iLast_Err during exit, for 30 seconds? EXIT ERROR CODES NON-FATAL 3 - CapCut currently running 7 - User opted to exit program while selecting output folder 8 - Cannot load 'draft_meta_info.json' due to a read error. 9 - Cannot load 'draft_content.json' due to a read error. 10 - No subtitles found during extraction 11 - Cannot write settings to the registry 12 - User opted to exit program while selecting save filename 13 - Cannot write subtitles to file 14 - Unexpected internal error writing subtitles to file 15 - No chapters found in this project 16 - Cannot write chapters to output folder 18 - Project contains no resources 19 - Cannot write file list to disk 20 - Cannot load project files 21 - Not enough space 22 - Cannot find project name in 7z archive 23 - No version folders to parse in CapCut install directory 24 - Cannot extract chapters from project made with version < 3.6 25 - Incompatible .JSON file 26 - No resources to export FATAL 1 - CapCut isn't installed 2 - CapCut executable cannot be found 4 - Can only run CCTools once 5 - Cannot load project list 6 - No projects found 17 - 7-Zip not installed #ce Opt("MustDeclareVars", 1) ; All variables must be created before they are used. Opt("GUIOnEventMode", 1) ; Buttons call functions independantly Opt("TrayIconHide", 1) ; Hide AutoIt tray icon #include #include #include #include #include #include #include #include #include #include #include #include FileInstall(".\CCTools2.chm", @TempDir&"\CCTools2.chm", 1) ; Join help file and copy to temp folder when running, wherever that is. Overwrite the existing file ; ==== VARIABLES ============= Global $sVer = "CCTools 2.0.2.0" ; Software version Global $s7z = RegRead("HKEY_CURRENT_USER\Software\7-Zip", "Path") & "7zg.exe" ; Full path to 7-zip compression (gui mode). If non-existent then string will be "" and will trigger error during pre-flight Global $s7z2 = RegRead("HKEY_CURRENT_USER\Software\7-Zip", "Path") & "7z.exe" ; Full path to 7-zip (command line) Global $i7z_Code ; Code returned by 7-zip. Anything over 0 is an error Global $sDraft = RegRead("HKEY_CURRENT_USER\Software\Bytedance\CapCut\GlobalSettings\History", "currentCustomDraftPath") ; Gives the path to CapCut's project folder. If CapCut not installed will be "" and trigger error later. Global $iErr ; Contains value of @error. Required since @error changes as soon as another command is run Global $iLast_Err = 0 ; Document latest error and return this value when program exits normally Global $iPROJ_QTY ; How many projects are there? For stat lovers LOL Global $sOut_Folder ; Contains full path to output folder (the resulting archive, chapters and subtitles will be put there) Global $sOut_File ; Contains full path to output file when exporting subs or chapters. Suggest filename anyways but user will have to choose. Global $iMsgBoxAnswer ; Variable used by CodeWizard. Global $bGreyOut = False ; Boolean. Determines if everything in the GUI is greyed out or not Global $bExit_Backup_all = False ; User clicked on Cancel during the backup of all projects Global $bWarning = True ; If true then CCtools displays a warning screen (this program is experimental, etc.) Global $bExport_nag = True ; Tell user the perils of extracting files from a CCTOOLs.7z archive. Shown once per program run Global $sCCDir = RegRead("HKEY_CURRENT_USER\Software\Bytedance\CapCut", "installDir") ; Find where the install directories are Global $aVer[999][2] ; 999 versions of Capcut, two possible data for each folder. Global since it must be available outside of _Load_Ver() Global $aRES[999] ; Resource array containing filenames with full path. Made global because you can't pass parameters using accelerators Global $sHelp = "hh.exe mk:@MSITStore:" & @TempDir&"\CCTools2.chm::/" ; If running the compiled version of this program, this file should appear in the computer's temp files Global $iCC_Count ; Tells program how many versions of CapCut can be deleted. Global because it is used outside of _Load_Ver() ; GUIs Global $aGUI[34] ; Array containing main interface Global $aGUI_About[14] ; Array containing About screen Global $aGUI_Set[13] ; Array containing Settings screen Global $aGUI_ALL[5] ; Array containing Backup Project All screen Global $aGUI_Ver[999] ; Array containing interface to manage CC versions. Global so array can be used in different functions related to CC versions. Global $aGUI_Res[999] ; Array used to create the GUI in _Show_resources(). Global so array can be used in _Copy_res() ; SETTINGS SCREEN Global $bSkip_Disabled = True ; Part of settings : will skip subtitles if .JSON says they are not active. Global $bSpace_nag = True ; Part of settings : tells user how much space a backup requires before proceeding Global $bBackup_Internal = False ; Does CCTools backup internal media downloaded through CapCut? ; ==== PRE-FLIGHT TESTING ============= _One_Instance() ; CCTools can only run once _Check_Capcut() ; Make sure CapCut exists and is NOT running _Check_7z() ; Make sure 7-Zip is installed ; ==== LOAD SETTINGS ================== _Load_Settings() ; Load all settings BEFORE creating the GUI ; ==== WARNING SCREEN ================= If $bWarning Then MsgBox(48, "Warning : not 100% bullet-proof", "Before you start using CCTools, be warned that this program is not 100% bullet-proof. Also CapCut specifications might change at any moment and the resulting files and extraction might be erroneous. If you should encounter a bug please post your version and bug description on zzz. That being said, as of version 3.6.0 everything is working fine." & @CRLF & "Have fun!") $bWarning = False ; Seen it once, that's enough _Save_Settings() ; Now remember it. EndIf ; ==== MAIN PROGRAM =================== _GUI() ; Create GUI and display it _Unselected() ; Grey out what needs to be greyed out While 1 Sleep(50) ; Since we're in "GuiOnEvent" mode, program will sit idle for most of the time. Waiting for a button to be pressed. WEnd Exit ; Not required but a good idea nevertheless. ; ==== FUNCTIONS ====================== ; ***************************************************************************** ; MAIN GUI ; ***************************************************************************** Func _GUI() ; Create main GUI $aGUI[0] = GUICreate($sVer, 609, 125, -1, -1, BitXOR($GUI_SS_DEFAULT_GUI, $WS_MINIMIZEBOX)) ; Create the main GUI GUISetOnEvent($GUI_EVENT_CLOSE, "_Xit") ; If someone presses "Esc" or "X" the pogram calls Func _Xit() ; MENU AND SUBMENU ITEMS ; Handles to work on [8,9,10,11,12,13,14,15,16,17,18,19] (total 12) $aGUI[1] = GUICtrlCreateMenu("&File") ; Program menu, item names are self-explanatory $aGUI[2] = GUICtrlCreateMenu("&Tools") ; Tools menu $aGUI[3] = GUICtrlCreateMenu("?") ; Typical help menu ; FILE $aGUI[4] = GUICtrlCreateMenuItem("&Output Folder (Ctrl+O)", $aGUI[1]) ; Select an output folder GUICtrlSetOnEvent(-1, "_Output_Folder") ; Call the appropriate function $aGUI[5] = GUICtrlCreateMenuItem("&Settings (F2)", $aGUI[1]) ; Change settings GUICtrlSetOnEvent(-1, "_Settings") ; Open the settings GUI $aGUI[6] = GUICtrlCreateMenuItem("E&xit (Esc, Alt+F4)", $aGUI[1]) ; Exit program GUICtrlSetOnEvent(-1, "_Xit") ; If pressed, call Func _Xit() : Note this function is required since we are using GuiOnEvent mode ; ? $aGUI[17] = GUICtrlCreateMenuItem("&Help (F1)", $aGUI[3]) ; About screen GUICtrlSetOnEvent(-1, "_Open_Help") ; Open the about GUI $aGUI[7] = GUICtrlCreateMenuItem("&About (F3)", $aGUI[3]) ; About screen GUICtrlSetOnEvent(-1, "_About") ; Open the about GUI ; TOOLS $aGUI[8] = GUICtrlCreateMenuItem("&Backup", $aGUI[2]) ; Backup on top GUICtrlSetOnEvent(-1, "_Backup_Project") ; Call the appropriate function $aGUI[9] = GUICtrlCreateMenuItem("B&ackup ALL", $aGUI[2]) ; Backup all GUICtrlSetOnEvent(-1, "_Backup_Project_ALL") ; Call the appropriate function GUICtrlCreateMenuItem("", $aGUI[2]) ; Horizontal line $aGUI[10] = GUICtrlCreateMenuItem("&Restore", $aGUI[2]) ; Restore GUICtrlSetOnEvent(-1, "_Restore_Project") ; Call the appropriate function GUICtrlCreateMenuItem("", $aGUI[2]) ; Horizontal line $aGUI[11] = GUICtrlCreateMenuItem("&Show resources", $aGUI[2]) ; Show resources GUICtrlSetOnEvent(-1, "_Show_Resources") ; Call the appropriate function $aGUI[12] = GUICtrlCreateMenuItem("&Show subs", $aGUI[2]) ; Show subs GUICtrlSetOnEvent(-1, "_Show_Subs") ; Call the appropriate function GUICtrlCreateMenuItem("", $aGUI[2]) ; Horizontal line $aGUI[13] = GUICtrlCreateMenuItem("&Export subs", $aGUI[2]) ; Export subs GUICtrlSetOnEvent(-1, "_Export_Subs") ; Call the appropriate function $aGUI[14] = GUICtrlCreateMenuItem("Export &chapters", $aGUI[2]) ; Export chapters GUICtrlSetOnEvent(-1, "_Export_Chapters") ; Call the appropriate function $aGUI[15] = GUICtrlCreateMenuItem("Export &resources", $aGUI[2]) ; Export resources from selected project to the selected folder GUICtrlSetOnEvent(-1, "_Export_Resources") ; Call the appropriate function GUICtrlCreateMenuItem("", $aGUI[2]) ; Horizontal line $aGUI[16] = GUICtrlCreateMenuItem("Install &manager", $aGUI[2]) ; Manage installed versions of CapCut on this computer GUICtrlSetOnEvent(-1, "_Load_Ver") ; Call the appropriate function ; DUMMY / PADDING $aGUI[18] = GUICtrlCreateDummy() ; Dummy control so that a for-next loop in _Unselected() will be quick and easy $aGUI[19] = GUICtrlCreateDummy() ; '' ; COMBO BOX ; Handles to work on [22,23,24,25,26,27,28,29,30,31] (total 12) $aGUI[20] = GUICtrlCreateCombo("", 8, 4, 569, 25, BitOR($CBS_DROPDOWNLIST, $WS_VSCROLL)) ; This combo box contains all the projects GUICtrlSetData(-1, _Get_PROJ(), "Please select project from this dropdown list") ; This fills the combo selector. GUICtrlSetTip(-1, "Project required for almost all commands" & @CRLF & "Please select a project", "Select project", $TIP_INFOICON) ; Give a tip ; OUTPUT FOLDER $aGUI[21] = GUICtrlCreateLabel($sOut_Folder, 12, 37, 569, 25) ; This shows the output folder If $sOut_Folder = "" Or Not FileExists($sOut_Folder) Then ; The output folder is not set or doesn't exit GUICtrlSetData(-1, "Click here to choose an output folder to backup to, save subs and chapters") ; Set warning should $sOut_Folder be blank GUICtrlSetColor(-1, 0xFF0000) ; Make it red so user knows it's a boo-boo. $sOut_Folder = "" ; Blankity blank $sOut_Folder _Save_Settings() ; Write the change to the registry EndIf GUICtrlSetCursor(-1, 3) ; Change cursor to a cross so it stands out GUICtrlSetOnEvent(-1, "_Output_Folder") ; Call the appropriate function if button pushed ; OPEN FOLDER ICONS $aGUI[22] = GUICtrlCreateIcon("shell32.dll", 46, 578, 4, 24, 24) ; Put an icon at the right of the combo box GUICtrlSetOnEvent(-1, "_Open_Project") ; If pressed, will open the project folder in the explorer GUICtrlSetTip(-1, "Opens up the selected project folder") ; A tip to tell user what this button serves for. $aGUI[23] = GUICtrlCreateIcon("shell32.dll", 46, 578, 37, 24, 24) ; Create an icon at the right of the output folder label GUICtrlSetOnEvent(-1, "_Open_Output_Folder") ; If pressed, will open the output folder in the explorer GUICtrlSetTip(-1, "Opens up the output folder") ; A tip to tell user what this button serves for. ; BUTTONS $aGUI[24] = GUICtrlCreateButton("Backup", 16, 64, 56, 25) ; First on top : backup GUICtrlSetOnEvent(-1, "_Backup_Project") ; Call the appropriate function if button pushed $aGUI[25] = GUICtrlCreateButton("Restore", 76, 64, 56, 25) ; next, restore GUICtrlSetOnEvent(-1, "_Restore_Project") ; Call the appropriate function if button pushed $aGUI[26] = GUICtrlCreateButton("Show resources", 136, 64, 92, 25) ; show resources in selected project GUICtrlSetOnEvent(-1, "_Show_Resources") ; Call the appropriate function if button pushed $aGUI[27] = GUICtrlCreateButton("Show subs", 232, 64, 64, 25) ; show subtitles in selected project GUICtrlSetOnEvent(-1, "_Show_Subs") ; Call the appropriate function if button pushed $aGUI[28] = GUICtrlCreateButton("Export subs", 300, 64, 72, 25) ; export subs to file GUICtrlSetOnEvent(-1, "_Export_Subs") ; Call the appropriate function if button pushed $aGUI[29] = GUICtrlCreateButton("Export chapters", 376, 64, 92, 25) ; export chapters to a YouTube friendly text file GUICtrlSetOnEvent(-1, "_Export_Chapters") ; Call the appropriate function if button pushed $aGUI[30] = GUICtrlCreateButton("Settings", 472, 64, 56, 25) ; Open the settings GUI GUICtrlSetOnEvent(-1, "_Settings") ; Call the appropriate function if button pushed $aGUI[31] = GUICtrlCreateButton("About", 532, 64, 56, 25) ; Open the about GUI GUICtrlSetOnEvent(-1, "_About") ; Call the appropriate function if button pushed ; DUMMY / PADDING $aGUI[32] = GUICtrlCreateDummy() ; Dummy control so that a for-next loop in _Unselected() will be quick and easy $aGUI[33] = GUICtrlCreateDummy() ; '' Local $aAccelKeys = [["{F1}", $aGUI[17]], ["{F3}", $aGUI[7]], ["{F2}", $aGUI[5]], ["^o", $aGUI[4]]] ; Array containing the list of keys and their corresponding action GUISetAccelerators($aAccelKeys) ; Bind F1-F3, Control + o keys to this GUI GUISetState(@SW_SHOW) ; Show the main GUI! GUIRegisterMsg($WM_COMMAND, "_Combo_Drop") ; Get around bug with Combo not notifying when changed. EndFunc ;==>_GUI Func _GreyOut() ; Grey out GUI or make it normal again If $bGreyOut Then ; Currently locked and grey. Go back to "normal" WinSetTrans($aGUI[0], "", 255) ; Full solid For $i = 16 To 24 ; Go through most of the elements in the GUI If $i = 16 And $sOut_Folder = "" Then ContinueLoop ; Skip the red "please select folder" if folder isn't set GUICtrlSetColor($aGUI[$i], 0x000000) ; Text in black Next GUISetState(@SW_ENABLE, $aGUI[0]) ; Show the interface once more WinActivate($aGUI[0]) ; Just in case it isn't brought to the foreground Else ; The main GUI has to be disabled and greyed out WinSetTrans($aGUI[0], "", 160) ; Half-transparent For $i = 16 To 24 ; Go through most of the elements in the GUI If $i = 15 And $sOut_Folder = "" Then ContinueLoop ; Skip the red "please select folder" if folder isn't set GUICtrlSetColor($aGUI[$i], 0x808080) ; Text in grey Next GUISetState(@SW_DISABLE, $aGUI[0]) ; Interface is now disabled. No pointy-clicky EndIf $bGreyOut = Not $bGreyOut ; Whatever happened, invert $bGreyOut. False becomes True and True becomes False EndFunc ;==>_GreyOut Func _Unselected() ; Grey out or enable items depending on value selected in ComboBox ; Grey out if project and outfolder not set : 6,7,8,9,10,11,12 & 17,18,19,20,21,22,23,24 ; Grey ou if project set and outfolder not set : 6,7,8,11,12 & 17,18,21,22,23,24 Local $bNo_Proj = GUICtrlRead($aGUI[20]) = "Please select project from this dropdown list" ; True when no project is selected Local $bNo_Outf = $sOut_Folder = "" ; True when no Out Folder is selected If $bNo_Proj Or $bNo_Outf Then ; Nothing selected. Grey out GUI items For $i = 8 To 19 ; Go through all related items GUICtrlSetState($aGUI[$i], $GUI_DISABLE) ; Disable items in the menu GUICtrlSetState($aGUI[$i + 14], $GUI_DISABLE) ; Disable itemps in the GUI Next Else ; Activate them items in the GUI! If Not $sOut_Folder = "" Then ; Output folder is set. Enable some stuff! For $i = 8 To 19 ; Go through all related items GUICtrlSetState($aGUI[$i], $GUI_ENABLE) ; Enable items in the menu GUICtrlSetState($aGUI[$i + 14], $GUI_ENABLE) ; Enable items in the GUI Next EndIf EndIf If Not $bNo_Proj Then ; Special case : As soon as a project is selected, all the following become enabled, even if there's no output folder GUICtrlSetState($aGUI[10], $GUI_ENABLE) ; Show resources in menu, enable GUICtrlSetState($aGUI[11], $GUI_ENABLE) ; Show subs in menu, enable GUICtrlSetState($aGUI[22], $GUI_ENABLE) ; Open project folder is now available (in the GUI) GUICtrlSetState($aGUI[25], $GUI_ENABLE) ; Show resources in GUI, enable GUICtrlSetState($aGUI[26], $GUI_ENABLE) ; Show subs in GUI, enable EndIf If Not $bNo_Outf Then ; Items that are available once $sOut_Folder is set GUICtrlSetState($aGUI[9], $GUI_ENABLE) ; Backup All is now available (in the menu) GUICtrlSetState($aGUI[10], $GUI_ENABLE) ; Restore is now available (in the menu) GUICtrlSetState($aGUI[16], $GUI_ENABLE) ; Manage Install is now available (in the menu) GUICtrlSetState($aGUI[23], $GUI_ENABLE) ; Open output folder icon is available (in the GUI) If Not $bNo_Proj Then ; Also if the project is set GUICtrlSetState($aGUI[24], $GUI_ENABLE) ; Backup is now available (in the GUI) EndIf GUICtrlSetState($aGUI[25], $GUI_ENABLE) ; Restore is now available (in the GUI) EndIf GUICtrlSetState($aGUI[17], $GUI_ENABLE) ; SPECIAL CASE Help menu item always available GUICtrlSetState($aGUI[30], $GUI_ENABLE) ; SPECIAL CASE Settings button always available GUICtrlSetState($aGUI[31], $GUI_ENABLE) ; SPECIAL CASE About button always available EndFunc ;==>_Unselected Func _Open_Draft_Folder() ; Calls explorer and shows CapCut's draft folder ShellExecute($sDraft) ; Go forth and explore EndFunc ;==>_Open_Draft_Folder Func _Open_Output_Folder() ; Calls explorer and shows the selected output folder ShellExecute($sOut_Folder) ; Calls explorer and shows the selected output folder EndFunc ;==>_Open_Output_Folder Func _Open_Project() ; Open the selected project's folder If GUICtrlRead($aGUI[20]) = "Please select project from this dropdown list" Then Return ; No project selected yet! ShellExecute($sDraft & "\" & GUICtrlRead($aGUI[20])) ; Open the draft folder for the selected project EndFunc ;==>_Open_Project ; ***************************************************************************** ; PRE-FLIGHT CHECKING ; ***************************************************************************** Func _Check_7z() ; Is 7-zip installed? Is 7zG.exe installed? It's needed for this program. If Not FileExists($s7z) Then ; 7-Zip is not installed (or not installed properly or version too old) MsgBox(20, "7-zip not installed [17]", "7-zip not installed or outdated. Program required in order to create archive. Do you want to visit https://www.7-zip.org?") Select Case $iMsgBoxAnswer = 6 ;Yes ShellExecute("https://www.7-zip.org") EndSelect Exit 17 ; Fatal. Exit with error code 17 EndIf EndFunc ;==>_Check_7z Func _Check_Capcut() ; Let's check and see if CapCut is installed RegRead("HKEY_CURRENT_USER\Software\Bytedance\CapCut", "ver") ; We don't need the actual install time. If this value exists then CapCut is installed. $iErr = @error ; Take note of the error code If $iErr Then ; Cannot read the registry key : CapCut isn't installed $iMsgBoxAnswer = MsgBox(20, "CapCut not installed [1]", "CapCut is not installed on this computer. Do you want to visit https://www.capcut.com?") Select Case $iMsgBoxAnswer = 6 ;Yes ShellExecute("https://www.capcut.com") EndSelect Exit 1 ; Fatal. Exit with error code 1 EndIf If Not FileExists(RegRead("HKEY_CURRENT_USER\Software\Bytedance\CapCut", "installDir") & "CapCut.exe") Then ; Searching for the actual executable $iMsgBoxAnswer = MsgBox(20, "CapCut executable cannot be found [2]", "CapCut executable cannot be found. Please install CapCut. Do you want to Visit https://www.capcut.com?") Select Case $iMsgBoxAnswer = 6 ;Yes ShellExecute("https://www.capcut.com") EndSelect Exit 2 ; Fatal. Exit with error code 2 EndIf If ProcessExists("CapCut.exe") Then ; If CapCut running? $iMsgBoxAnswer = MsgBox(52, "CapCut currently running [3]", "CapCut is currently running. This might interfere with program operation. Would you like for CCTools to shut down CapCut?") Select Case $iMsgBoxAnswer = 6 ;Yes ProcessClose("CapCut.exe") ; Just kill it $iLast_Err = 0 ; Pretend nothing happened Return ; But return "clean" EndSelect $iLast_Err = 3 ; Load $iLast_Err. Not fatal but compression / extraction will not proceed. Return 3 ; Return to program with error 3 and back to main GUI EndIf EndFunc ;==>_Check_Capcut Func _One_Instance() ; Check if script is already running ; Source: https://www.autoitscript.com/forum/topic/32301-start-script-check-if-script-is-running-if-it-is-kill-it-and-continue/ Local $g_szVersion = $sVer ; Give this program a name If WinExists($g_szVersion) Then Exit 4 ; FATAL. If a window has this name, close this program. Return code 4. AutoItWinSetTitle($g_szVersion) ; Set windows title accordingly EndFunc ;==>_One_Instance ; ***************************************************************************** ; FILENAME MANAGEMENT ; ***************************************************************************** Func _Backup_Filename($sPrefix = "CCBackup", $sTYPE = ".7z", $sPRJCT = "") ; Picks a proper filename for the backup file ; $sPrefix : text at beginning of a filename. Per example "Subtitles" or "Chapters" ; $sType : type of file this will be (put at the end of the filename) ; $sPRJCT : This is the name of the CapCut project. If not give, function reads project name from GUI Local $aMonth = ["","JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"] ; Set all months in an array, AutoIT doesn't have a macro for the months in text format If $sPRJCT Then Return $sPrefix & " " & $sPRJCT & " [" & @MDAY & $aMonth[@MON] & @YEAR & "_" & @HOUR & "h" & @MIN & "]" & $sTYPE ; We have enough info to build the filename and send it back Else Return $sPrefix & " " & GUICtrlRead($aGUI[20]) & " [" & @MDAY & $aMonth[@MON] & @YEAR & "_" & @HOUR & "h" & @MIN & "]" & $sTYPE ; We have enough info to build the filename and send it back EndIf EndFunc ;==>_Backup_Filename Func _Output_Folder() ; Choose another output folder _GreyOut() ; Disable GUI and grey out controls while selecting folder _Select_Folder() ; Go and select a folder If Not $iLast_Err = 7 Then ; No error from _Select_Folder() so it's a valid path GUICtrlSetData($aGUI[21], $sOut_Folder) ; Change the GUI to write the output folder GUICtrlSetColor($aGUI[21], 0x000000) ; Set text to black, it's a valid folder ElseIf $sOut_Folder = "" Then GUICtrlSetData($aGUI[21], "Click here to choose an output folder to backup to, save subs and chapters") ; Change the GUI to write the output folder GUICtrlSetColor($aGUI[21], 0xFF0000) ; Set text to red, user will have to set a new output folder GUICtrlSetData($aGUI_Set[2], "Click 'change' to choose an output folder") ; Now change the path in the settings GUI GUICtrlSetColor($aGUI_Set[2], 0xFF0000) ; Set text to red, user will have to set a new output folder EndIf _Unselected() ; Activate menu & buttons _GreyOut() ; Control back to the main GUI _Save_Settings() ; Write that folder to the registry EndFunc ;==>_Output_Folder Func _Select_Load_Filename($sTitle, $sFilter = "All (*.*)") ; Show a file selector and change $sOut_Filename. While 1 ; Infinite loop $sOut_File = FileOpenDialog($sTitle, $sOut_Folder, $sFilter, BitOR($FD_PATHMUSTEXIST, $FD_FILEMUSTEXIST)) ; Select project archive to restore If $sOut_File = "" Then ; No file selected $iLast_Err = 12 ; Set $iLast_Err to 12 Return 12 Else ExitLoop ; Exiting the infinite loop. EndIf WEnd ; Filename not selected so open the file selector again. EndFunc ;==>_Select_Load_Filename Func _Select_Save_Filename($sTitle, $sSuggest = "", $sFilter = "All (*.*)") ; Show a file selector and change $sOut_Filename. While 1 ; Infinite loop $sOut_File = FileSaveDialog($sTitle, $sOut_Folder, $sFilter, BitOR($FD_PATHMUSTEXIST, $FD_PROMPTOVERWRITE), $sSuggest) ; What file will we save? Suggest a filename but user will have to choose. If $sOut_File = "" Then ; No file selected $iLast_Err = 12 ; Set $iLast_Err to 12 Return 12 Else ExitLoop ; Exiting the infinite loop. EndIf WEnd ; Filename not selected so open the file selector again. EndFunc ;==>_Select_Save_Filename Func _Select_Folder() ; Select folder Local $sPrevious_Folder = $sOut_Folder ; Remeber what it was before file selector While 1 ; Infinite loop If $sOut_Folder = "" Then ; No current $sOut_Folder $sOut_Folder = FileSelectFolder("Select your output folder", "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}") ; Select the folder (by default it's "My Computer") Else ; $sOut_Folder is already set! $sOut_Folder = FileSelectFolder("Select your output folder", $sOut_Folder) ; Open in the previous $sOut_Folder EndIf ; NOW THAT FOLDER HAS BEEN SELECTED (OR NOT!) If $sOut_Folder = "" Or $sOut_Folder = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" Then ; None selected $sOut_Folder = $sPrevious_Folder ; Just put it back to what it was before. $iLast_Err = 7 ; Set non-fatal error Return 7 ; Simply return to regular operation EndIf GUICtrlSetData($aGUI[21], $sOut_Folder) ; Display new folder name ExitLoop ; Exiting the infinite loop. WEnd ; Filename not selected so open the file selector again. EndFunc ;==>_Select_Folder ; ***************************************************************************** ; INSTALL MANAGER ; ***************************************************************************** Func _Load_Ver() ; Main process for Install Manager. Actually a contraption of "Load Versions" Local $aCCDir = _FileListToArray($sCCDir, "*", $FLTA_FOLDERS, True) ; Load it up! Full folder path also Local $iLine ; Integer. Vertical coordinate of items in the GUI Local $j ; Generic variable Local $aCCDir2[999] ; Transfer array. Will copy proper array values to this array Local $iBSlash ; Points to last slash in pathname Local $iAsc ; Ascii value of first character Local $iCount = 1 ; Counter to follow the transfer array ; RETURN ERROR CODE 23 IF $aCCDIR[] IS EMPTY --> SHOULD HAVE AT LEAST ONE ENTRY If UBound($aCCDir) = 0 Then ; Non-fatal error : there were no folders in the install directory $iLast_Err = 23 ; 23 - No version folders to parse in CapCut install directory Return 23 EndIf ; REMOVE LAST VERSION OF CAPCUT _ArrayDelete($aCCDir,$aCCDir[0]) ; Remove the last item since it would mean removing the current version of CapCut!!! $aCCDir[0] = $aCCDir[0] -1 ; Adjust size since _ArrayDelete doesn't (dammit!) $iCC_Count = $aCCDir[0] ; Set global variable so that functions out of _Load_Ver() know how many versions of CapCut can be deleted _GreyOut() ; Lock GUI and fade text GUISetCursor(15, 1, $aGUI[0]) ; Every cursor within that window turns into an hourglass icon --> Main GUI ; PROMPT USER MsgBox(48, "Experimental process", "Deleting older versions of CapCut is still experimental. " & _ "Although all the tests I've done indicate it is completely safe I have not tested with versions below 3.3 and future versions might break. Please use ''Backup ALL'' in the subsequent ''Tool'' menu." & _ @CRLF & "Note : backing up previous versions might take some time and is likely to create a very large file") ; CLEANUP FOLDER LIST ; If first char is not a number then chuck the folder path, decrement count For $i = 1 To $aCCDir[0] ; Go through all the paths $iBSlash = StringInStr($aCCDir[$i], "\", 0, -1) + 1 ; Find position of last slash, add 1 --> we want the filename after the last slash $iAsc = Asc(StringMid($aCCDir[$i], $iBSlash, 1)) ; Get the ASCII value of the character If $iAsc > 47 And $iAsc < 57 Then ; ASCII value is higher than "0" AND lower than "9" --> it's a number --> IsNumber() is useless here BTW $aCCDir2[$iCount] = $aCCDir[$i] ; Copy array cell into transfer array $aCCDir2[0] = $iCount ; Put amount of array cells in cell 0 $iCount += 1 ; Increment counter EndIf Next $aCCDir = $aCCDir2 ; Now that the cleanup is done, the old array is the new array ; CREATE GUI $aGUI_Ver[0] = GUICreate("Manage CapCut versions", 480, 788, -1, 100, BitOR($GUI_SS_DEFAULT_GUI, $WS_MINIMIZEBOX)) ; Create the GUI. Height is important, if not set properly white gap appears at the bottom GUISetOnEvent($GUI_EVENT_CLOSE, "_Manage_Cancel") ; If someone presses "Esc" or "X" the pogram calls _Manage_Cancel() GUISetOnEvent($GUI_EVENT_PRIMARYDOWN,"_Select_line") ; Selecting a line toggles the checkmark $aGUI_Ver[1] = GUICtrlCreateListView("",0,0,480,768) ; Create that ListView _GUICtrlListView_SetExtendedListViewStyle(-1, BitOR($LVS_EX_INFOTIP, $LVS_EX_CHECKBOXES)) ; Add style : Shorter than space creates a tooltip, every line has a checkbox $aGUI_Ver[2] = _GUICtrlListView_AddColumn($aGUI_Ver[1], "Filename", 425) ; First column $aGUI_Ver[3] = _GUICtrlListView_AddColumn($aGUI_Ver[1], "Size", 51) ; Second column ; POPULATE THE LIST Local $iCount = 4 ; Used to identify each item of the ListView. Reset count at 4 to skip the previous items in the array For $i = 1 To $aCCDir[0] ; Go through all the valid folders $aGUI_Ver[$iCount] = _GUICtrlListView_AddItem($aGUI_Ver[1], $aCCDir[$i]) ; Add filename with full path. Because of $LVS_EX_CHECKBOXES, it all starts with a checkbox. $aGUI_Ver[$iCount + 1] = _GUICtrlListView_AddSubItem($aGUI_Ver[1], $i-1,_ByteSuffix(DirGetSize($aCCDir[$i])),1) ; Add size (as a sub-item). Index is 1 since filename has index 0 $iCount += 2 ; Increment by two Next ; MENU $i = $iCount ; Used for menu : skip all the currently used spots in the array $aGUI_Ver[$i + 1] = GUICtrlCreateMenu("&Tools") ; Tools menu, item names are self-explanatory $aGUI_Ver[$i + 2] = GUICtrlCreateMenuItem("Select &All (Ctrl+A)", $aGUI_Ver[$i + 1]) ; Select all items (but not the current one) GUICtrlSetOnEvent(-1, "_Select_All") ; Call the appropriate function $aGUI_Ver[$i + 3] = GUICtrlCreateMenuItem("Select &None (Ctrl+N)", $aGUI_Ver[$i + 1]) ; Select no items GUICtrlSetOnEvent(-1, "_Select_None") ; Call the appropriate function $aGUI_Ver[$i + 4] = GUICtrlCreateMenuItem("&Delete selected", $aGUI_Ver[$i + 1]) ; Delete all selected folders GUICtrlSetOnEvent(-1, "_Delete_Selected") ; Call the appropriate function $aGUI_Ver[$i + 5] = GUICtrlCreateMenuItem("&Backup ALL", $aGUI_Ver[$i + 1]) ; Backup all selected folders GUICtrlSetOnEvent(-1, "_Backup_Install_ALL") ; Call the appropriate function $aGUI_Ver[$i + 6] = GUICtrlCreateMenuItem("&Cancel", $aGUI_Ver[$i + 1]) ; Close window and return GUICtrlSetOnEvent(-1, "_Manage_Cancel") ; Call the appropriate function $aGUI_Ver[$i + 7] = GUICtrlCreateMenuItem("&Help (F1)", $aGUI_Ver[$i + 1]) ; Close window and return GUICtrlSetOnEvent(-1, "_Open_Help") ; Call the appropriate function ReDim $aGUI_Ver[$i + 8] ; Waste not. Trim all the unused items GUISetState(@SW_SHOW) ; Show the GUI GUISetCursor(-1, 1, $aGUI[0]) ; Reset main GUI cursor Local $aAccelKeys = [["^a", $aGUI_Ver[$i + 2]], ["^n", $aGUI_Ver[$i + 3]], ["{F1}", $aGUI_Ver[$i + 7]]] ; Array containing the list of keys and their corresponding action GUISetAccelerators($aAccelKeys,$aGUI_Ver[0]) ; Setting accelerator keys for select all and select none EndFunc ;==>_Load_Ver Func _Manage_Cancel() GUIDelete($aGUI_Ver[0]) _GreyOut() ; Return to main program EndFunc ;==>_Manage_Cancel Func _Delete_Selected() ; Delete all selected folders Local $iCount ; Counter to determine how many folders are deleted Local $iCount_Del ; Reverse counter in last part of this function Local $iBytes ; Counter to determine the number of bytes deleted Local $iErr ; Picks up error if it exists Local $iErr2 ; Picks up error if it exists ; FIRST PASS : DETERMINE COUNT AND STORAGE USED For $i = 0 To $iCC_Count -1 ; Go through all the items If _GUICtrlListView_GetItemChecked($aGUI_Ver[1],$i) = True Then ; Is the item checked? Note : since we're outside of _Load_Ver() we have to read the GUI $iCount += 1 ; Increment counter so we know how many folders we have to delete $iBytes += DirGetSize(_GUICtrlListView_GetItemText($aGUI_Ver[1],$i)) ; Get size. Note : since we're outside of _Load_Ver() we have to read the GUI here too EndIf Next If $iCount = 0 Then Return ; Nothing selected! Return. ; LAST CHANCE TO QUIT OR ELSE FOLDERS ARE DELETED $iMsgBoxAnswer = MsgBox(292, $iCount & " folders to delete", $iCount & " versions of CapCut to delete. Do you want to proceed?") ; Prompt to choose Select Case $iMsgBoxAnswer = 6 ; Yes Case $iMsgBoxAnswer = 7 ; No, default Return ; Do nothing and return. EndSelect ; SECOND PASS : NOW DELETE THE FOLDERS $iCount_Del = $iCC_Count -1 While $iCount_Del ; Reverse counter : going forwards does not work with ListView's delete function as the index changes as items are deleted If _GUICtrlListView_GetItemChecked($aGUI_Ver[1],$iCount_Del) Then ; Is the item checked? FileSetAttrib(_GUICtrlListView_GetItemText($aGUI_Ver[1],$iCount_Del),"-R-A-S-H",1) ; Remove all attributes that can affect deletion. Not sure if -RASH works the same? FileRecycle(_GUICtrlListView_GetItemText($aGUI_Ver[1],$iCount_Del)) ; Put that file in the recycle bin _GUICtrlListView_DeleteItem($aGUI_Ver[1],$iCount_Del) ; Delete it from the GUI too EndIf $iCount_Del -= 1 ; Decrement counter WEnd MsgBox(64, $iCount & " folders deleted", $iCount & " versions of CapCut deleted for a total of " & _ByteSuffix($iBytes)) EndFunc ;==>_Delete_Selected Func _Backup_Install_ALL() ; $sOut_Folder Local $iCCRUN = _Check_Capcut() ; Check CapCut status again Local $iSel_Err ; Return from _Select_Save_Filename() Local $iComp_Err ; Return from _Compress_7z() Local $iTime = TimerInit() ; Start timer ; INITIAL VERIFICATION If $iCCRUN Then ; Capcut is currently running Return $iCCRUN ; Back to main GUI. EndIf _GreyOut() ; Lock GUI and fade text ; SELECT FILENAME $sOut_File = _Backup_Filename("CCTools", ".CCTOOLs.7z", "Backup Install") ; Select an appropriate output filename ; CHECK FOR VALIDITY OF $Out_Folder ; THE ACTUAL BACKING UP $iComp_Err = _Compress_7z($sOut_Folder & $sOut_File, $sCCDir & "*", "a -mx9 -spf -ssw -mqs") ; This is where the compression starts If $iComp_Err Then ; Something went wrong _GreyOut() ; Load back main GUI Return $iComp_Err EndIf MsgBox(64, "Backup completed", "Install folder(s) succesfully backed up to :" & @CRLF & $sOut_File & @CRLF & "Compression time: " & _How_Long(TimerDiff($iTime))) ; Tell user the backup is completed. _GreyOut() ; Unlock GUI and make text black again EndFunc ;==>_Backup_Install_ALL Func _Select_All() ; Check all folders for deletion _GUICtrlListView_SetItemChecked($aGUI_Ver[1],-1,True) ; -1 = all items checked. A one-liner. WOW EndFunc ;==>_Select_All Func _Select_None() ; Uncheck all the folders _GUICtrlListView_SetItemChecked($aGUI_Ver[1],-1,False) ; -1 = all items unchecked. A one-liner. WOW EndFunc ;==>_Select_None Func _Select_line() ; Toggle checkmark on selected line (with left mouse button) Local $iLine = _GUICtrlListView_GetSelectedIndices($aGUI_Ver[1]) ; Something got clicked. Check out if it has a line number. 0 = NO ConsoleWrite(_GUICtrlListView_GetItemCount($aGUI_Ver[1]) & @TAB & "|" & $iLine & "|" &@CRLF) If $iLine = "" Then Return ; No line selected or error with _GUICtrlListView_GetSelectedIndices() If $iLine Then ; Was there something else than 0 returned? If so there's a line to checkmark. Local $iState = Not _GUICtrlListView_GetItemChecked($aGUI_Ver[1],$iLine) ; Find the value and then negate it _GUICtrlListView_SetItemChecked($aGUI_Ver[1],$iLine,$iState) EndIf EndFunc ; ***************************************************************************** ; SHOW RESOURCES ; ***************************************************************************** Func _Show_Resources() ; Show resources for currently selected project Local $iLine ; Integer. Vertical coordinate of items in the GUI Local $aRES = _Load_Resources() If $aRES Then ; There was an issue extracting resources Return $aRES ; Back to main GUI EndIf If $aRes[0] = 0 Then ; Array is empty, nothing to show Return EndIf _GreyOut() ; Lock GUI and fade text ; GUI $aGUI_Res[0] = GUICreate("Show resources", 480, 788, -1, 100, BitOR($GUI_SS_DEFAULT_GUI, $WS_MINIMIZEBOX)) ; Create the GUI. Height is important, if not set properly white gap appears at the bottom GUISetOnEvent($GUI_EVENT_CLOSE, "_Show_res_Cancel") ; If someone presses "Esc" or "X" the pogram calls _Show_res_Cancel() GUISetOnEvent($GUI_EVENT_SECONDARYDOWN, "_Copy_res") ; Right button copies line to clipboard $aGUI_Res[1] = GUICtrlCreateListView("#|Filename",0,0,480,768,-1,BitOR($LVS_EX_INFOTIP,$LVS_EX_FULLROWSELECT)) ; Create listview, lines longer than screen have a tooltip and full row selected _GUICtrlListView_SetColumnWidth($aGUI_Res[1],0, 26) ; Minimum width for numbers from 0 to 999 _GUICtrlListView_SetColumnWidth($aGUI_Res[1],1, 437) ; Using the rest of the space WITHOUT the horizontal scroll bar For $i = 1 to $aRes[0] -1 ; Go through all items If Not FileExists($aRES[$i]) Then ; File cannot be found! $aGUI_Res[$i + 1] = GUICtrlCreateListViewItem($i & "|" & "[NOT FOUND] " & $aRes[$i], $aGUI_Res[1]) ; Create listview item with line number GUICtrlSetBkColor(-1,_IsEven($i) ? 0xFFDDDD : 0xFFEEEE) ; Set it light red (will alternate) ElseIf StringInStr($aRes[$i],"\AppData\Local\CapCut\User Data\Cache") Then ; It's an internal resource $aGUI_Res[$i + 1] = GUICtrlCreateListViewItem($i & "|" & "[Internal] " & $aRes[$i], $aGUI_Res[1]) ; Create listview item with line number GUICtrlSetBkColor(-1,_IsEven($i) ? 0x99DDFF : 0x99EEFF) ; Set it light blue (will alternate) Else $aGUI_Res[$i + 1] = GUICtrlCreateListViewItem($i & "|" & $aRes[$i], $aGUI_Res[1]) ; Create listview item with line number GUICtrlSetBkColor(-1,_IsEven($i) ? 0xEEEEEE : 0xFFFFFF) ; Set it light gray (will alternate) EndIf Next ; MENU $aGUI_Res[$i + 1] = GUICtrlCreateMenu("&Tools") ; Tools menu, item names are self-explanatory $aGUI_Res[$i + 2] = GUICtrlCreateMenuItem("Copy line (Ctrl+C) or Right click", $aGUI_Res[$i + 1]) ; MENU Copy current selected line to clipboard GUICtrlSetOnEvent(-1, "_Copy_res") ; Call the appropriate function $aGUI_Res[$i + 3] = GUICtrlCreateMenuItem("Copy &all items(Ctrl+A)", $aGUI_Res[$i + 1]) ; MENU Copy all lines to clipboard GUICtrlSetOnEvent(-1, "_Copy_all_res") ; Call the appropriate function $aGUI_Res[$i + 4] = GUICtrlCreateMenuItem("Help (F1)", $aGUI_Res[$i + 1]) ; MENU Call for help GUICtrlSetOnEvent(-1, "_Open_Help") ; Call the appropriate function $aGUI_Res[$i + 5] = GUICtrlCreateMenuItem("Cancel (Esc)", $aGUI_Res[$i + 1]) ; MENU Exit current GUI GUICtrlSetOnEvent(-1, "_Show_res_Cancel") ; Call the appropriate function GUISetState(@SW_SHOW) ; Show the GUI Local $aAccelKeys = [["{F1}", $aGUI_Res[$i + 4]], ["^a", $aGUI_Res[$i + 3]], ["^c", $aGUI_Res[$i + 2]]] ; Array containing the list of keys and their corresponding action GUISetAccelerators($aAccelKeys,$aGUI_Res[0]) ; Setting accelerator keys for copy EndFunc ;==>_Show_Resources Func _Show_Res_Cancel() ; User elected to exit _Show_Resources() GUIDelete($aGUI_Res[0]) ; It's over. Delete the GUI _GreyOut() ; Put the colors back to the main menu and return focus to it EndFunc Func _Copy_res() ; Copy selected resource (one line) to clipboard ;~ ConsoleWrite(GUICtrlRead($aGUI_Res[1])) If GUICtrlRead($aGUI_Res[1]) Then ClipPut($aRES[GUICtrlRead($aGUI_Res[1])-40]) ; Convert $aRes to a string and put that in the clipboard MsgBox(64,"Copied to clipboard","Selected line has been copied to the clipboard") ; Announce it so user knows it happened. Endif EndFunc Func _Copy_all_res() ; Copy all resources to clipboard (with enter at end of line) ClipPut(_ArrayToString($aRes,@CRLF,1)) ; Convert $aRes to a string and put that in the clipboard MsgBox(64,"Copied to clipboard","List of resources has been copied to the clipboard") ; Announce it so user knows it happened. EndFunc ; ***************************************************************************** ; SETTINGS ; ***************************************************************************** Func _Settings() ; This is where all the settings ... are set LOL If WinGetState("Settings : " & $sVer) = 15 Then Return ; Open only once! Goes back if already there. 15 = values 1-8 inclusive : exists, visible, enabled and active all at once :) _GreyOut() ; Grey out main GUI $aGUI_Set[0] = GUICreate("Settings : " & $sVer, 417, 159, -1, -1, BitXOR($GUI_SS_DEFAULT_GUI, $WS_MINIMIZEBOX)) ; Create the actual settings GUI GUISetOnEvent($GUI_EVENT_CLOSE, "_Settings_Close") ; If someone presses "Esc" or "X" the pogram calls _Settings_Close() $aGUI_Set[1] = GUICtrlCreateLabel("Ouput path:", 8, 8, 60, 17) ; Descriptor for output path $aGUI_Set[2] = GUICtrlCreateLabel($sOut_Folder, 72, 8, 262, 17) ; The actual output path GUICtrlSetTip(-1, "Click to open folder" & @CRLF & $sOut_Folder) ; Give it a tip GUICtrlSetOnEvent(-1, "_Open_Output_Folder") ; If clicked, open output fold in explorer If $sOut_Folder = "" Then ; Whoops, no output folder! GUICtrlSetData(-1, "Click 'change' to choose an output folder") ; Set warning should $sOut_Folder be blank GUICtrlSetColor(-1, 0xFF0000) ; Make it red so user knows it's a boo-boo. EndIf $aGUI_Set[3] = GUICtrlCreateLabel("Draft path : ", 8, 32, 60, 17) ; Descriptor for draft path $aGUI_Set[4] = GUICtrlCreateLabel($sDraft, 72, 32, 336, 34) ; The actual draft path GUICtrlSetTip(-1, "Click to open folder" & @CRLF & $sDraft) ; Give a tip GUICtrlSetOnEvent(-1, "_Open_Draft_Folder") ; If clicked, this opens the draft folder in explorer $aGUI_Set[5] = GUICtrlCreateButton("Change", 344, 5, 65, 24) ; Button to change output folder GUICtrlSetTip(-1, "Click change output path") GUICtrlSetOnEvent(-1, "_Settings_Change") ; Do the changin' $aGUI_Set[6] = GUICtrlCreateCheckbox("", 8, 73, 15, 17) ; Create a checkbox for $bSpace_nag If $bSpace_nag Then ; It's True GUICtrlSetState(-1, $Gui_Checked) ; Yeah, don't nag me I don't want to be disturbed. Else ; It's False GUICtrlSetState(-1, $Gui_Unchecked) ; Logic : False = give me a heads up and ask me to confirm. So therefore unchecked because this is to DISABLE nagging (DEFAULT) EndIf $aGUI_Set[7] = GUICtrlCreateLabel("Don't nag during backup but still warn about low space", 26, 75, 260, 17) ; There you go, that's the question $aGUI_Set[8] = GUICtrlCreateCheckbox("", 8, 97, 15, 17) ; Create a checkbox for $bSkip_Disabled If $bSkip_Disabled Then ; True GUICtrlSetState(-1, $Gui_Checked) ; Logic : I want to skip disabled subs so therefore it's checked Else GUICtrlSetState(-1, $Gui_Unchecked) ; Unchecked : get all the subtitles you can. EndIf $aGUI_Set[9] = GUICtrlCreateLabel("Skip disabled subtitles", 26, 99, 260, 17) ; The label says it all. $aGUI_Set[10] = GUICtrlCreateButton("Reset default", 232, 123, 81, 24) ; This button to reset all values to their default state GUICtrlSetOnEvent(-1, "_Settings_Reset") ; DO IT! $aGUI_Set[11] = GUICtrlCreateButton("&OK", 326, 123, 81, 24) ; OK button to exit the settings GUICtrlSetOnEvent(-1, "_Settings_Close") ; Close and exit GUICtrlSetState(-1, $GUI_FOCUS) ; Make this button the focus $aGUI_Set[12] = GUICtrlCreateDummy() ; There's no "Help" button but this is the next best thing GUICtrlSetOnEvent(-1, "_Open_Help") ; Close and exit GUISetState(@SW_SHOW, $aGUI_Set[0]) ; Show the settings to the world! Local $aAccelKeys = [["{F1}", $aGUI_Set[12]]] ; Array containing the list of keys and their corresponding action GUISetAccelerators($aAccelKeys,$aGUI_Set[0]) ; Setting accelerator keys for copy EndFunc ;==>_Settings Func _Settings_Change() ; Change output folder GUISetState(@SW_DISABLE, $aGUI_Set[0]) ; Temporarily disable the settings GUI Local $iSel_Err = _Select_Folder() ; Go and select a folder If $sOut_Folder = "" Then ; There's no selected path. Make sure user sees comment in red. GUICtrlSetData($aGUI[21], "Click here to choose an output folder to backup to, save subs and chapters") ; Change the GUI to write the output folder GUICtrlSetColor($aGUI[21], 0xFF0000) ; Set text to red, user will have to set a new output folder GUICtrlSetData($aGUI_Set[2], "Click 'change' to choose an output folder") ; Now change the path in the settings GUI GUICtrlSetColor($aGUI_Set[2], 0xFF0000) ; Set text to red, user will have to set a new output folder Else GUICtrlSetData($aGUI[21], $sOut_Folder) ; Change the GUI to write the output folder GUICtrlSetColor($aGUI[21], 0x000000) ; Set text to black, it's a valid folder GUICtrlSetData($aGUI_Set[2], $sOut_Folder) ; Now change the path in the settings GUI GUICtrlSetColor($aGUI_Set[2], 0x000000) ; Set text to black, it's a valid folder EndIf _Save_Settings() ; Save those settings to the registry GUISetState(@SW_ENABLE, $aGUI_Set[0]) ; Enable main GUI again. WinActivate($aGUI_Set[0]) ; Just in case EndFunc ;==>_Settings_Change Func _Settings_Close() ; Close settings GUI ; CHECK STATUS OF $bSPACE_NAG CHECKBOX If GUICtrlRead($aGUI_Set[6]) = $GUI_CHECKED Then $bSpace_nag = True Else $bSpace_nag = False EndIf ; CHECK STATUS OF $bSKIP_DISABLED CHECKBOX If GUICtrlRead($aGUI_Set[9]) = $GUI_CHECKED Then $bSkip_Disabled = True Else $bSkip_Disabled = False EndIf GUIDelete($aGUI_Set[0]) ; Delete the Settings window _Save_Settings() ; Save all that data to the registry _GreyOut() ; Give control back to main GUI EndFunc ;==>_Settings_Close Func _Settings_Reset() GUISetState(@SW_DISABLE, $aGUI_Set[0]) ; Temporarily disable the settings GUI $iMsgBoxAnswer = MsgBox(308, "Reset settings", "Do you want to reset all variables to their default values, including the output path?") ; Ask user if he still wants a reset If $iMsgBoxAnswer = 6 Then ; User said YES $sOut_Folder = "" ; Blank $sOut_Folder $bSpace_nag = False ; Back to nagging you about creating a large archive $bSkip_Disabled = True ; Skip subtitles if they are deactivated or track is hidden $bWarning = True ; Next start will tell user about the dangers of using this program LOL GUICtrlSetData($aGUI[21], "Click here to choose an output folder to backup to, save subs and chapters") ; Change the GUI to write the output folder GUICtrlSetColor($aGUI[21], 0xFF0000) ; Set text to red, user will have to set a new output folder GUICtrlSetData($aGUI_Set[2], "Click 'change' to choose an output folder") ; Now change the path in the settings GUI GUICtrlSetColor($aGUI_Set[2], 0xFF0000) ; Set text to red, user will have to set a new output folder GUICtrlSetState($aGUI_Set[6], $Gui_Unchecked) ; Uncheck checkbox for $sSpace_nag in the settings screen. GUICtrlSetState($aGUI_Set[8], $Gui_Checked) ; Check checkbox for $bSkip_Disabled in the settings screen. _Save_Settings() ; Save those variables to the registry EndIf GUISetState(@SW_ENABLE, $aGUI_Set[0]) ; Enable settings GUI again. WinActivate($aGUI_Set[0]) ; Just in case EndFunc ;==>_Settings_Reset Func _Save_Settings() ; Save settings to registry whenever a change has occured. Local $sBase = "HKEY_CURRENT_USER\Software\DrLouis\CCTools", $iErr2 RegWrite($sBase, "$sOut_Folder", "REG_SZ", $sOut_Folder) ; Write the Output folder to registry $iErr = @error ; Note : increment error number. 0 means no error so anything that hits a snag means it's not good. $iErr2 += $iErr ; Add errors up. RegWrite($sBase, "$bSkip_Disabled", "REG_SZ", $bSkip_Disabled) ; Write the skip disabled flag to registry $iErr = @error ; Note : increment error number. 0 means no error so anything that hits a snag means it's not good. $iErr2 += $iErr ; Add errors up. RegWrite($sBase, "$bSpace_nag", "REG_SZ", $bSpace_nag) ; Write the space nag flag to registry $iErr = @error ; Note : increment error number. 0 means no error so anything that hits a snag means it's not good. $iErr2 += $iErr ; Add errors up. RegWrite($sBase, "$bWarning", "REG_SZ", $bWarning) ; Write the warning flag to registry $iErr = @error ; Note : increment error number. 0 means no error so anything that hits a snag means it's not good. $iErr2 += $iErr ; Add errors up. If $iErr2 Then ; Something went wrong somewhere MsgBox(48, "Cannot write to registry [11]", "Cannot write settings to Windows Registry. Non-fatal but not good.") $iLast_Err = 11 ; Set last error Return ; Return normally to program EndIf EndFunc ;==>_Save_Settings Func _Load_Settings() ; Load settings at program startup Local $sBase = "HKEY_CURRENT_USER\Software\DrLouis\CCTools", $sReg ; Points to the base registry for this program $sReg = RegRead($sBase, "$sOut_Folder") ; Read the output directory $iErr = @error ; 0 means no error so anything that hits a snag means it's not good. If Not $iErr Then ; It's all great, transfer value, If error, value doesn't change $sOut_Folder = $sReg EndIf $sReg = RegRead($sBase, "$bSkip_Disabled") ; Read the Skip Disabled flag, should be in the "Settings" screen. $iErr = @error If Not $iErr Then ; It's all great, transfer value, If error, default value is True If $sReg = "True" Then ; True means "Skip any caption that is hidden or has track hidden" $bSkip_Disabled = True Else $bSkip_Disabled = False EndIf Else $bSkip_Disabled = True EndIf $sReg = RegRead($sBase, "$bSpace_nag") ; Read the Space nag flag, should be in the "Settings" screen. $iErr = @error If Not $iErr Then ; It's all great, transfer value, If error, default value is True If $sReg = "True" Then ; True means $bSpace_nag = True Else $bSpace_nag = False EndIf Else $bSpace_nag = True EndIf $sReg = RegRead($sBase, "$bWarning") ; Read the warning flag, is set on first run. $iErr = @error If Not $iErr Then ; It's all great, transfer value, If error, default value is True If $sReg = "True" Then $bWarning = True Else $bWarning = False EndIf Else $bWarning = True EndIf EndFunc ;==>_Load_Settings ; ***************************************************************************** ; ABOUT ; ***************************************************************************** Func _About() ; Create the _About() GUI If WinGetState("About : " & $sVer) = 15 Then Return ; Open only once! Goes back if already there. 15 = values 1-8 inclusive : exists, visible, enabled and active all at once :) _GreyOut() ; Grey out main GUI $aGUI_About[0] = GUICreate("About : " & $sVer, 314, 299, -1, -1, BitXOR($GUI_SS_DEFAULT_GUI, $WS_MINIMIZEBOX)) ; Make the About GUI, center of screen, no reduce window or full screen GUISetOnEvent($GUI_EVENT_CLOSE, "_About_Close") ; If someone presses "Esc" or "X" the pogram calls Func _About_Close() $aGUI_About[1] = GUICtrlCreateGroup("", 8, 1, 297, 253) ; Create a group. For esthetics only $aGUI_About[2] = GUICtrlCreateLabel($sVer & @CRLF & "Current versions of CapCut are a moving target. Some bugs, some changes. CCTools aims to complement and alleviate", 16, 16, 279, 51) ; Short description $aGUI_About[3] = GUICtrlCreateLabel("Useful stats: " & $iPROJ_QTY & " CapCut projects" & @CRLF & @CRLF & "CapCut draft folder: " & $sDraft, 16, 74, 279, 76) ; Useful stats $aGUI_About[4] = GUICtrlCreateLabel("Links to stuff :", 16, 151, 70, 17) ; Advertise links $aGUI_About[5] = GUICtrlCreateLabel("CCTools2 on Reddit", 16, 167, 93, 17) ; First link GUICtrlSetCursor(-1, 0) ; Typical "this is a hyperlink" cursor GUICtrlSetFont(-1, Default, Default, 4) ; slightly smaller text, underlined GUICtrlSetColor(-1, 0x0000FF) ; Make it blue GUICtrlSetOnEvent(-1, "_HL_Reddit1") ; Clicked? Go to associated function GUICtrlSetTip(-1, "https://www.reddit.com/r/CapCut/comments/1c8b7kx/cctools_20_ready_for_testing/") $aGUI_About[6] = GUICtrlCreateLabel("AutoSRT on Reddit", 16, 183, 97, 17) GUICtrlSetCursor(-1, 0) ; Typical "this is a hyperlink" cursor GUICtrlSetFont(-1, Default, Default, 4) ; slightly smaller text, underlined GUICtrlSetColor(-1, 0x0000FF) ; Make it blue GUICtrlSetOnEvent(-1, "_HL_Reddit2") ; Clicked? Go to associated function $aGUI_About[7] = GUICtrlCreateLabel("CCBackup on Reddit", 16, 199, 104, 17) GUICtrlSetCursor(-1, 0) ; Typical "this is a hyperlink" cursor GUICtrlSetFont(-1, Default, Default, 4) ; slightly smaller text, underlined GUICtrlSetColor(-1, 0x0000FF) ; Make it blue GUICtrlSetOnEvent(-1, "_HL_Reddit3") ; Clicked? Go to associated function $aGUI_About[8] = GUICtrlCreateLabel("Many thanks to Igor Pavlov for ", 16, 215, 150, 17) $aGUI_About[9] = GUICtrlCreateLabel("7-zip", 166, 215, 100, 17) GUICtrlSetCursor(-1, 0) ; Typical "this is a hyperlink" cursor GUICtrlSetFont(-1, Default, Default, 4) ; slightly smaller text, underlined GUICtrlSetColor(-1, 0x0000FF) ; Make it blue GUICtrlSetOnEvent(-1, "_HL_7Zip") ; Clicked? Go to associated function GUICtrlCreateGroup("", -99, -99, 1, 1) ; This closes the group. $aGUI_About[12] = GUICtrlCreateButton("&OK", 119, 263, 75, 25) ; OK button. Alt-O will activate button also --> because of the ampersand GUICtrlSetOnEvent(-1, "_About_Close") ; Clicked? Exit "about" GUI GUICtrlSetState(-1, $GUI_FOCUS) ; Make this button the focus GUISetState(@SW_SHOW, $aGUI_About[0]) ; Show your wares :) $aGUI_About[13] = GUICtrlCreateDummy() ; Dummy control to handle the F1 key GUICtrlSetOnEvent(-1, "_Open_Help") ; Clicked? Open help Local $aAccelKeys = [["{F1}", $aGUI_About[13]]] ; Array containing the list of keys and their corresponding action GUISetAccelerators($aAccelKeys,$aGUI_About[0]) ; Setting accelerator keys for copy EndFunc ;==>_About Func _About_Close() ; It's "About" time to go GUIDelete($aGUI_About[0]) ; Delete the About window _GreyOut() ; Bring back the main GUI EndFunc ;==>_About_Close Func _HL_Melba23() ; Credits where credits due! ShellExecute("https://www.autoitscript.com/forum/topic/113723-scrollbars-made-easy-new-version-27-jan-22/") EndFunc ;==>_HL_7Zip Func _HL_7Zip() ; Visit 7-Zip and show some numeric love ShellExecute("https://7-zip.org") EndFunc ;==>_HL_7Zip Func _HL_Reddit1() ; First hyperlink. ShellExecute("https://www.reddit.com/r/CapCut/comments/1c8b7kx/cctools_20_ready_for_testing/") EndFunc ;==>_HL_Reddit1 Func _HL_Reddit2() ; Second hyperlink. ShellExecute("https://www.reddit.com/r/CapCut/comments/1bx0gwo/thinking_of_creating_a_ressource_assembler_to/") EndFunc ;==>_HL_Reddit2 Func _HL_Reddit3() ; Third hyperlink. ShellExecute("https://www.reddit.com/r/CapCut/comments/1bp0d77/cannot_export_subs_captions_since_360b4/") EndFunc ;==>_HL_Reddit3 ; ***************************************************************************** ; BACKUP PROJECT ; ***************************************************************************** Func _Backup_Project() ; This is where we backup the selected project Local $aRES = _Load_Resources() ; Load all resources into this array Local $iByte_Count ; Byte count to figure out how much data will need to be compressed Local $sAT_File ; String containing all the filenames to backup, spaced by a carriage return and a line feed Local $aRES_PROJ ; Array containing the list of all the files in the selected project folder Local $sList = @TempDir & "\" & "CCTOOLS.RES" ; Temporary filename in order to save the list file Local $sPROJ = $sDraft & "\" & GUICtrlRead($aGUI[20]) ; Create the path to the project files Local $iCCRUN = _Check_Capcut() ; Check CapCut status again Local $iTime = TimerInit() ; Start timer Local $iSel_Err ; Return from _Select_Save_Filename() Local $iExp_Err ; Return from _Export_List() Local $iComp_Err ; Return from _Compress_7z() Local $iCount ; Used to filter out $aRes array ; INITIAL VERIFICATION If $iCCRUN Then ; Capcut is currently running Return $iCCRUN ; Back to main GUI. EndIf If $aRES Then ; There was an issue extracting resources Return $aRES ; Back to main GUI EndIf _GreyOut() ; Lock GUI and fade text ; FILTER OUT UNNEEDED FILES $iCount = $aRes[0] -1 ; Set backward counter to max value While $iCount > 0 ; Filter until $iCount = 0. Must use "While" since For-Next cannot accept negative steps ConsoleWrite($iCount & @TAB & $aRes[$iCount] & @CRLF) If StringInStr($aRes[$iCount],"\AppData\Local\CapCut\User Data\Cache") Or Not FileExists($aRes[$iCount]) Then ; Is an internal resource file OR file does not exist _ArrayDelete($aRes,$iCount) ; Delete the cell $aRes[0] = $aRes[0] -1 ; Decrement value EndIf $iCount -= 1 ; Decrement counter Wend ; CHECK TOTAL FILE SIZE If $aRES[0] Then ; Array is not empty - it's a possibility For $i = 1 To $aRES[0] - 1 ; Go through all the files $iByte_Count += FileGetSize($aRES[$i]) ; Get the file size, increment $iByte_Count Next EndIf $iByte_Count += DirGetSize($sDraft & "\" & $aGUI[20]) ; Get the size of the folder containing the project ; WARN USER If $bSpace_nag Then ; There was no project passed on and $bSpace_nag is true then ... nag! Ask user if he wants to proceed ; And $bAll_Nag $iMsgBoxAnswer = MsgBox(52, "Proceed with backup?", "You are about to backup " & _ByteSuffix($iByte_Count) & " using 7-zip." & @CRLF & "Compression usually yields low compression." & @CRLF & _ "Current free space on selected drive : " & _ByteSuffix(DriveSpaceFree($sOut_Folder) * 1048576) & @CRLF & "Output directory : " & $sOut_Folder & @CRLF & "Draft folder : " & $sDraft) Select Case $iMsgBoxAnswer = 7 ;No _GreyOut() ; Give back control to the main GUI Return EndSelect EndIf ; CHECK FREE SPACE ON DRIVE CONTAINING OUT_FOLDER If (DriveSpaceFree($sOut_Folder) * 1048576) < ($iByte_Count + 5368709120) Then ; If free space on output drive is smaller that projected archive size + 5 GB for confort MsgBox(16, "Not enough space [21]", "Not enough space in the output drive to store the current archive." & @CRLF & "Remaining space : " & _ByteSuffix(DriveSpaceFree($sOut_Folder)) & @CRLF & _ "Projected archive size + 5GB confort zone : " & _ByteSuffix($iByte_Count) & @CRLF & "Please select another output drive") _GreyOut() ; Give back control to main GUI $iLast_Err = 21 Return 21 ; and return EndIf ; ASK USER FOR A FILENAME $iSel_Err = _Select_Save_Filename("Select a filename for the archive containing this backup", _Backup_Filename("Backup", ".CCTOOLs.7z"), "CCtools archive (*.CCTOOLs.7z)") If $iSel_Err Then ; There was an issue selecting a filename _GreyOut() ; Give back control to the main Gui Return $iSel_Err ; and return ... EndIf ; CREATE @FILE FOR 7-ZIP (LIST ALL FILES TO COMPRESS) For $i = 1 To $aRES[0] - 1 ; Go through all cells of $aRES $sAT_File &= $aRES[$i] & @CRLF ; Add filename and Carriage Return + Line Feed Next ; ADD PROJECT FILES (not pictures and audio but files created by CapCut) $aRES_PROJ = _FileListToArrayRec($sPROJ, "*", $FLTAR_FILESFOLDERS, $FLTAR_RECUR, $FLTAR_NOSORT, $FLTAR_FULLPATH) ; Load all files in the selected project If $aRES_PROJ = "" Then ; Something went wrong! MsgBox(16, "Cannot load project files [20]", "Cannot load project file list. Cannot proceed with backup.") $iLast_Err = 20 _GreyOut() ; Load back main GUI Return 20 EndIf ; LOAD STRING CONTAIN ALL PROJECT FILES For $i = 1 To $aRES_PROJ[0] - 1 ; Go through all of them $sAT_File &= $aRES_PROJ[$i] & @CRLF ; Add filename and Carriage Return + Line Feed in string Next ; WRITE FILE LIST TO TEMPORARY FOLDER $iExp_Err = _Export_List($sList, $sAT_File) If $iExp_Err Then ; Writing the file didn't work _GreyOut() ; Load back main GUI Return $iExp_Err ; Go back EndIf ; THE ACTUAL BACKING UP $iComp_Err = _Compress_7z($sOut_File, $sList) ; This is where the compression starts If $iComp_Err Then ; Something went wrong _GreyOut() ; Load back main GUI Return $iComp_Err EndIf MsgBox(64, "Backup completed", "Project succesfully backed up to :" & @CRLF & $sOut_File & @CRLF & "Compression time: " & _How_Long(TimerDiff($iTime))) ; Tell user the backup is completed. FileDelete($sList) ; That list is not needed anymore _GreyOut() ; Unlock GUI and make text black again EndFunc ;==>_Backup_Project Func _Backup_Project2($sPRJCT) ; Temporary copy of _Backup_Project --> Apparently calling a function with an integrated parameter via GuiOnEvent causes an error. ; $sPROJECT : Name of the project to backup when passed on from _Backup_Project_all() Local $aRES = _Load_Resources($sPRJCT) ; Load all resources into this array Local $iByte_Count ; Byte count to figure out how much data will need to be compressed Local $sAT_File ; String containing all the filenames to backup, spaced by a carriage return and a line feed Local $aRES_PROJ ; Array containing the list of all the files in the selected project folder Local $sList = @TempDir & "\" & "CCTOOLS.RES" ; Temporary filename in order to save the list file Local $sPROJ = $sDraft & "\" & $sPRJCT ; Create the path to the project files Local $iCCRUN = _Check_Capcut() ; Check CapCut status again Local $iTime = TimerInit() ; Start timer Local $iExp_Err ; Return from _Export_List() Local $iComp_Err ; Return from _Compress_7z() Local $iCount ; Used to filter out $aRes array ; INITIAL VERIFICATION If $iCCRUN Then ; Capcut is currently running Return $iCCRUN ; Back to main GUI. EndIf If $aRES Then ; There was an issue extracting resources Return $aRES ; Back to main GUI EndIf ; FILTER OUT UNNEEDED FILES $iCount = $aRes[0] -1 ; Set backward counter to max value While $iCount > 0 ; Filter until $iCount = 0. Must use "While" since For-Next cannot accept negative steps ConsoleWrite($iCount & @TAB & $aRes[$iCount] & @CRLF) If StringInStr($aRes[$iCount],"\AppData\Local\CapCut\User Data\Cache") Or Not FileExists($aRes[$iCount]) Then ; Is an internal resource file OR file does not exist _ArrayDelete($aRes,$iCount) ; Delete the cell $aRes[0] = $aRes[0] -1 ; Decrement value EndIf $iCount -= 1 ; Decrement counter Wend ; CHECK TOTAL FILE SIZE If $aRES[0] Then ; Array is not empty - it's a possibility For $i = 1 To $aRES[0] - 1 ; Go through all the files $iByte_Count += FileGetSize($aRES[$i]) ; Get the file size, increment $iByte_Count Next EndIf $iByte_Count += DirGetSize($sDraft & "\" & $sPRJCT) ; Get the size of the folder containing the project ; CHECK FREE SPACE ON DRIVE CONTAINING OUT_FOLDER If (DriveSpaceFree($sOut_Folder) * 1048576) < ($iByte_Count + 5368709120) Then ; If free space on output drive is smaller that projected archive size + 5 GB for confort MsgBox(16, "Not enough space [21]", "Not enough space in the output drive to store the current archive." & @CRLF & "Remaining space : " & _ByteSuffix(DriveSpaceFree($sOut_Folder)) & @CRLF & _ "Projected archive size + 5GB confort zone : " & _ByteSuffix($iByte_Count) & @CRLF & "Please select another output drive") $iLast_Err = 21 Return 21 ; and return EndIf ; SELECT FILENAME $sOut_File = _Backup_Filename("Backup", ".CCTOOLs.7z", $sPRJCT) ; Select an appropriate output filename ; ADD PROJECT RESOURCES (LIST ALL FILES TO COMPRESS) For $i = 1 To $aRES[0] - 1 ; Go through all cells of $aRES $sAT_File &= $aRES[$i] & @CRLF ; Add filename and Carriage Return + Line Feed Next ; ADD PROJECT FILES (not pictures and audio but files created by CapCut) $aRES_PROJ = _FileListToArrayRec($sPROJ, "*", $FLTAR_FILESFOLDERS, $FLTAR_RECUR, $FLTAR_NOSORT, $FLTAR_FULLPATH) ; Load all files in the selected project If $aRES_PROJ = "" Then ; Something went wrong! MsgBox(16, "Cannot load project files [20]", "Cannot load project file list. Cannot proceed with backup.") $iLast_Err = 20 Return 20 EndIf ; LOAD STRING CONTAIN ALL PROJECT FILES For $i = 1 To $aRES_PROJ[0] - 1 ; Go through all of them $sAT_File &= $aRES_PROJ[$i] & @CRLF ; Add filename and Carriage Return + Line Feed in string Next ; WRITE FILE LIST TO TEMPORARY FOLDER $iExp_Err = _Export_List($sList, $sAT_File) If $iExp_Err Then ; Writing the file didn't work Return $iExp_Err ; Go back to main GUI EndIf ; THE ACTUAL BACKING UP $iComp_Err = _Compress_7z($sOut_File, $sList) ; This is where the compression starts If $iComp_Err Then ; Something went wrong Return $iComp_Err EndIf FileDelete($sList) ; That list is not needed anymore EndFunc ;==>_Backup_Project2 Func _Backup_Project_ALL() Local $aPROJ_list = _Get_PROJ(1) ; Get all the projects. Function does not return any error message Local $iBack_err ; Error return from _Backup_Project2() Local $iTime = TimerInit() ; Start timer _GreyOut() ; Don't touch the main GUI until it's done! ; CREATE BACKUP ALL GUI $aGUI_ALL[0] = GUICreate("", 512, 122, -1, -1, $WS_POPUP) ; Small window with no controls GUISetCursor(15, 1) ; Every cursor within that window turns into an hourglass icon $aGUI_ALL[1] = GUICtrlCreateLabel("Currently backing up :", 0, 16, 512, 17, $SS_CENTER) ; Title line $aGUI_ALL[2] = GUICtrlCreateLabel("", 0, 40, 512, 17, $SS_CENTER) ; Name of the project currently being backed up GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif") ; bold font $aGUI_ALL[3] = GUICtrlCreateLabel("Label3", 0, 62, 512, 17, $SS_CENTER) ; Enumeration : n out of x items $aGUI_ALL[4] = GUICtrlCreateButton("Cancel", 224, 88, 64, 25) ; Click this button to exit GUICtrlSetOnEvent(-1, "_Cancel_Backup_all") ; Go here if Cancel button is clicked GUISetState(@SW_SHOW, $aGUI_ALL[0]) ; Show the window! ; THIS IS WHERE THE BACKUPS ARE ACTUALLY DONE ; All error checking and space requirements are calculated within _Backup_Project2() For $i = 1 To $aPROJ_list[0] ; Go through all projects If $aPROJ_list[$i] = ".recycle_bin" Then ContinueLoop GUICtrlSetData($aGUI_ALL[2], $aPROJ_list[$i]) ; Show what project is being backed up GUICtrlSetData($aGUI_ALL[3], $i & " of " & $aPROJ_list[0]) ; Show where the backups are at $iBack_err = _Backup_Project2($aPROJ_list[$i]) ; Call _Backup_Project2 with the project name If $iBack_err Or $bExit_Backup_all Then ; Something went wrong. Let's stop backing up the projects MsgBox(48, "Backup not complete", "Backup of all projects incomplete. " & $i & " out of " & $aPROJ_list[0] & " projects completed. Time to complete " & _How_Long(TimerDiff($iTime))) GUIDelete($aGUI_ALL[0]) ; Not needed anymore $bExit_Backup_all = False ; Reset $bExit_Backup_all variable for next backup all. _GreyOut() Return $iBack_err EndIf Next ; ALL DONE HERE WE GRACEFULLY TELL USER HOW IT WENT GUIDelete($aGUI_ALL[0]) ; Not needed anymore MsgBox(48, "All backups completed", "Backup of " & $i & " out of " & $aPROJ_list[0] & " projects completed. Time to complete " & _How_Long(TimerDiff($iTime))) ; Exit telling user how many archives have been created. _GreyOut() ; Control back to main GUI EndFunc ;==>_Backup_Project_ALL Func _Cancel_Backup_all() ; User has pressed Cancel during _Backup_Project_All $bExit_Backup_all = True ; Yes to stop backing up GUICtrlSetData($aGUI_ALL[3], "Wait...") ; Tell user cancel will happen very soon EndFunc ;==>_Cancel_Backup_all ; ***************************************************************************** ; RESTORE PROJECT ; ***************************************************************************** Func _Restore_Project() ; Restore archive to it's original drive and folder ; 7z x archive.7z -spf ; 1. Select archive to restore ; 2. Check to see if CapCut is running (again!) ; 3. Warn user that restore requires (n) bytes / megs / gigs ; 3a Extract list with 7z.exe l archive.7z ; Last line sample : ------------------- ----- ------------ ------------ ------------------------ ; 2024-04-10 04:51:36 2774077535 2767818189 55 files ; 3b Load list and keep only last line ; 3c from chr # 28 to chr #38 is the uncompressed archive size Local $iSel_Err ; Return fomr _Select_Load_Filename() Local $iCCRUN = _Check_Capcut() ; Check CapCut status again Local $iByte_Count ; Amount of required bytes to extract project archive Local $iExtrct_Err ; Contains error code sent back _ _GreyOut() ; Grey out main GUI, we're entering the restore zone ; LET'S EXPLAIN THE SITUATION If $bExport_nag Then ; Tell user the perils of extracting files from a CCTOOLs.7z archive MsgBox(48, "Extraction : important information", "When CCTOOLs.7z archives are created, they contain the EXACT PATH AND DRIVE where the files came from. Restoring the content of this archive will put the files back" _ & "to the same drive and path. Unless you say 'Yes to all', you will be prompted each time a file already exists. Check out options in the settings screen (F2)" & @CRLF _ & "You can also use the the 7-Zip file manager to extract files individually") $bExport_nag = False ; Dont's show until program is restarted EndIf ; ASK USER FOR A FILENAME $iSel_Err = _Select_Load_Filename("Select a filename for the archive containing this backup", "CCtools archive (*.CCTOOLs.7z)") If $iSel_Err Then ; There was an issue selecting a filename _GreyOut() ; Give back control to the main Gui Return $iSel_Err ; and return ... EndIf ; INITIAL VERIFICATION If $iCCRUN Then ; Capcut is currently running _GreyOut() ; Give back control to the main Gui Return $iCCRUN ; Back to main GUI. EndIf ; HOW BIG IS THE UNCOMPRESSED ARCHIVE? $iByte_Count = _Size_7z($sOut_File) ; Get the file size, uncompressed ; CHECK FREE SPACE ON DRIVE CONTAINING OUT_FOLDER If (DriveSpaceFree($sOut_Folder) * 1048576) < ($iByte_Count + 5368709120) Then ; If free space on output drive is smaller that projected archive size + 5 GB for confort MsgBox(16, "Not enough space [21]", "Not enough space in the output drive to store the current archive." & @CRLF & "Remaining space : " & _ByteSuffix(DriveSpaceFree($sOut_Folder)) & @CRLF & "Projected archive size + 5GB confort zone : " & _ByteSuffix($iByte_Count) & @CRLF & "Please select another output drive") $iLast_Err = 21 Return 21 ; and return EndIf ; DO THE ACTUAL EXTRACTION $iExtrct_Err = _Extract_7z($sOut_File) ; EXTRACT THOSE FILES! If Not $iExtrct_Err Then ; No error so extraction was successful! MsgBox(64, "Extraction successful!", "Project archive extraction successful. You can now acces your restored project in CapCut.") EndIf ; Else, program already told user there was an issue so there's nothing else to do. _GreyOut() ; Give back control to the main Gui EndFunc ;==>_Restore_Project ; ***************************************************************************** ; SHOW DATA ; ***************************************************************************** Func _Show_Subs() ; Same as extract subs but we show it first Local $aSubs ; Array containg subs $aSubs = _Extract_Subs() ; Load the array with the subtitles found in the selected project If $aSubs Then ; An error occured Return ; Just return to the main Gui EndIf _GreyOut() ; Temporarily put main GUI in the background _DebugArrayDisplay($aSubs) ; Show the subtitles _GreyOut() ; Out of the background and back to fore EndFunc ;==>_Show_Subs ; ***************************************************************************** ; EXTRACT AND EXPORT ; ***************************************************************************** Func _Extract_Subs() ; Extract the subtitles from draft_content.json, return an array Local $aGui_Subs[3] ; Array containing the GUI showing the progress while extracting subs Local $aCAP[9999][4] ; This array will contain each caption and information about each caption Local $aSRT[9999] ; This array will contain all the lines in the .SRT file Local $sPath = $sDraft & "\" & GUICtrlRead($aGUI[20]) & "\draft_content.json" ; "draft_meta_info.json" is where all the resources are noted Local $iStart, $iEnd, $iPoint1, $iPoint2, $iPoint3, $iPoint4, $iPoint5, $iPoint6, $iPoint7, $iPoint8 ; Generic variables Local $iCount = 1 ; Generic counter that points where to search in the .JSON file --> character-wise Local $iMatrice = 1 ; Keeps counts of each sub in the sub array Local $sID ; Unique string for each text string, used to point to the second section containing extra information _GreyOut() ; The main GUI must be dimmed first; focus is on the extraction windo. ; READ THE .JSON FILE Local $sJSON = FileRead($sPath) ; First step : load the .JSON file in a string variable. $iErr = @error ; Note the error number If $iErr Then ; Whoops! MsgBox(16, "Read error [9]", "Cannot load 'draft_content.json' due to a read error.") $iLast_Err = 9 ; Set last error _GreyOut() ; Main GUI back to normal Return 9 ; Return normally to program. Not good but not fatal. EndIf ; CREATE THE GUI (EXTRACTION) $aGui_Subs[0] = GUICreate("Extracting subtitles from " & GUICtrlRead($aGUI[20]), 640, 45, 219, 136) ; Create the window $aGui_Subs[1] = GUICtrlCreateProgress(0, 0, 640, 17) ; A progress bar $aGui_Subs[2] = GUICtrlCreateLabel("", 5, 24, 630, 20) ; A line to show the line being processed GUICtrlSetFont(-1, 10, 400, 0, "MS Sans Serif") ; A slightly larger font GUISetState(@SW_SHOW) ; Show it to the world ; SUBTITLE EXTRACTION While 1 ; Infinite loop. Extracting subtitles GUICtrlSetData($aGui_Subs[1], ($iCount * 1.5 / StringLen($sJSON)) * 100) ; Calculate the percentage and tell the progress bar. Since most subs don't usually pas the half of the .JSON file, *2 for it to be more realistic. ; FIND THE NEXT TEXT SECTION + DETERMINE IF THIS TEXT IS A SUBTITLE OR NOT. $iStart = StringInStr($sJSON, '"add_type":', 0, 1, $iCount) + 11 ; Start of next text section. Also place where we find out it it's a subtitle. 11 = length of '"add_type":' If $iStart = 11 Then ExitLoop ; We're at the end of the file. Exit the extraction loop $iEnd = StringInStr($sJSON, ',"', 0, 1, $iStart) ; What type of text is this? $iCount = $iEnd + 2 ; Increment the counter by 2 --> ',"' is two characters long If StringMid($sJSON, $iStart, $iEnd - $iStart) = "0" Then ContinueLoop ; add_type = 0. This is not a subtitle. Go back to the first line of this loop ; HERE WE FIND WHERE THE TEXT OF THE SUBTITLE IS $iStart = StringInStr($sJSON, '\"text\":\"', 0, 1, $iCount) + 11 ; Find the start of the next text section. 11 = length of '\"text\":\"' $iEnd = StringInStr($sJSON, '\"', 0, 1, $iStart) ; Find the end of the text section. + 11 = skip over the search string also $iCount = $iEnd ; No need to increment any further : second section is near the end of the .JSON file and would not create a pleasant progress bar ; NOW WE SAVE IT $aCAP[$iMatrice][0] = StringMid($sJSON, $iStart, $iEnd - $iStart) ; Put that text in the array for future use GUICtrlSetData($aGui_Subs[2], $aCAP[$iMatrice][0]) ; Display it ; FIND THE ID KEY $iStart = StringInStr($sJSON, '"id":', 0, 1, $iEnd) + 6 ; The ID key starts here. 6 = Offset to actual ID key. We save a step by not searching for the opening quotes. $iEnd = StringInStr($sJSON, '",', 0, 1, $iStart) ; And it ends here $sID = StringMid($sJSON, $iStart, $iEnd - $iStart) ; Extract the value ; NOW JUMP TO THE ID SECTION TO FIND "DURATION", "START", "TRACK_ATTRIBUTE" AND "VISIBLE" $iPoint1 = StringInStr($sJSON, '{"duration":', 0, 1, StringInStr($sJSON, $sID, 0, 2)) + 12 ; Start of the "duration" section. 12 = length of '{"duration":' $iPoint2 = StringInStr($sJSON, ',', 0, 1, $iPoint1) ; End of the "duration" section $iPoint3 = StringInStr($sJSON, '"start":', 0, 1, $iPoint2) + 8 ; Start of the "start" section. 8 = length of '"start":' $iPoint4 = StringInStr($sJSON, '},', 0, 1, $iPoint3) ; End of the "start" section $iPoint5 = StringInStr($sJSON, '"track_attribute":', 0, 1, $iPoint4) + 18 ; Start of "Track attribute". 18 = length of '"track_attribute":' $iPoint6 = StringInStr($sJSON, ',"', 0, 1, $iPoint5) ; end of "Track attribute" $iPoint7 = StringInStr($sJSON, '"visible":', 0, 1, $iPoint6) + 10 ; Start of "Track attribute". 10 = length of '"visible":' $iPoint8 = StringInStr($sJSON, ',"', 0, 1, $iPoint7) ; end of "Visible" ; LOGIC TO DETERMINE IF A SUB IS VISIBLE OR NOT If $bSkip_Disabled Then ; You want to know if it's visible in order to skip it If Number(StringMid($sJSON, $iPoint5, $iPoint6 - $iPoint5)) = 2 Or _ StringMid($sJSON, $iPoint7, $iPoint8 - $iPoint7) = "False" Then ContinueLoop EndIf ; Anything else and all subtitles are added to array ; NOW STORE ALL THE INFORMATION INTO THE $aCAP ARRAY Local $sDur = StringMid($sJSON, $iPoint1, $iPoint2 - $iPoint1) ; Duration of subtitle Local $sStart = StringMid($sJSON, $iPoint3, $iPoint4 - $iPoint3) ; Starting point of subtitle $aCAP[$iMatrice][1] = _MStoSMPTE($sDur) ; Put duration in #1 $aCAP[$iMatrice][2] = _MStoSMPTE($sStart) ; Put start in #2 $aCAP[$iMatrice][3] = _MStoSMPTE($sDur + $sStart) ; Added together should be end of subtitle, in #3 $iMatrice += 1 ; Increment. Next line in the array $aCAP[0][0] = $iMatrice ; Put that value in the first cell of the array WEnd GUIDelete($aGui_Subs[0]) ; Delete the GUI now that we've extracted what we can from the .JSON file. If $iMatrice = 1 Then ; No subs were found! MsgBox(16, "No subtitles found [10]", "'draft_content.json' did not contain any recognized subtitle. Consider searching for disable subtitles (in setting screen).") $iLast_Err = 10 _GreyOut() ; Main GUI back to normal Return 10 ; to program ... EndIf ; .SRT FILE RECONSTITUTION $iCount = 0 ; Set to 0 in order to create the .SRT file For $i = 1 To $iMatrice - 1 ; Go through all the lines $aSRT[$iCount] = $i ; First line : ... is the line number $aSRT[$iCount + 1] = $aCAP[$i][2] & " --> " & $aCAP[$i][3] ; Write the timing. $aSRT[$iCount + 2] = $aCAP[$i][0] ; Next line is the actual subtitle $iCount += 4 ; Increment the counter : three text lines and an empty one Next ReDim $aSRT[$iCount] ; Remove any extraneous information _GreyOut() ; Control back to main GUI Return $aSRT ; Send back the subtitles EndFunc ;==>_Extract_Subs Func _Export_Chapters() ; This will extract chapters (if they exist) and ask to export them to a file in a YouTube friendly way. Local $aChap[999][2] ; Array containing detailed information about each chapter Local $sChap ; String containing the YouTube friendly file created from the array Local $iCount = 1 ; Generic variable, counts progression in characters Local $iIndex = 1 ; Counts progression in found chapters Local $iPoint1, $iPoint2, $iPoint3, $iPoint4, $iPoint5 ; Generic variables Local $sPath = $sDraft & "\" & GUICtrlRead($aGUI[20]) & "\draft_content.json" ; "draft_content.json" is where all the resources are noted Local $iSel_Err ; Contains the error return from _Select_Save_Filename() Local $sJSON = FileRead($sPath) ; First step : load the .JSON file in a string variable. $iErr = @error ; Note the error number If $iErr Then ; Whoops! MsgBox(16, "Read error [9]", "Cannot load 'draft_content.json' due to a read error.") $iLast_Err = 9 ; Set error code. Return 9 ; to normal program operation EndIf ; CHECK FOR VERSION NUMBER $iPoint1 = StringInStr($sJSON,"app_version") ; Find the first occurence of "app_version" Switch Number(StringMid($sJSON,$iPoint1 + 14,3)) ; Extract the version number and evaluate it (else it's just a string) Case 0 ; Not a number, incompatible .JSON file MsgBox(0,"incompatible .JSON file [25]","Something's wrong with this project's .JSON file. Version pointer not found. Back to main menu.") $iLast_Err = 25 ; Set error code Return 25 ; to normal program operation Case 1.0 to 3.5 ; Version too low to have chapters MsgBox(48,"Cannot extract chapters [24]","Cannot extract chapters from project made with version < 3.6 Returning to main menu.") ; Tell user wrong version number $iLast_Err = 24 ; Set error code Return 24 ; to normal program operation EndSwitch _GreyOut() ; Temporarily put main GUI in the background ; START SEARCHING! $iPoint1 = StringInStr($sJSON, '"mark_items":[{') + 13 ; Find first and only instance of "mark items" If $iPoint1 = 0 Then ; There are no chapters here! MsgBox(48, "No chapters found! [15]", "No chapters found in this project. ") $iLast_Err = 15 _GreyOut() ; Give back control to the main GUI Return 15 ; Return to GUI and set $iLast_Err EndIf $iCount = $iPoint1 ; Skip over "mark items" While 1 ; Infinite loop $iPoint2 = StringInStr($sJSON, '"start":', 0, 1, $iCount) + 8 ; Then find the start of this marker, number in CapCut notation If $iPoint2 = 8 Then ExitLoop ; Start of next chapter not found. Nothing else to search for. Note 8 = number added to the previous point ... 0 (not found) + 8 $iPoint3 = StringInStr($sJSON, '},', 0, 1, $iPoint2) + 2 ; Then find the end of that number. 2 = length of '},' $iPoint4 = StringInStr($sJSON, '"title":', 0, 1, $iPoint3) + 9 ; Onto the title. 8 = length of '"title":' + 1 because of .JSON delimiter character If $iPoint4 = 9 Then ExitLoop ; No more titles found, might as well exit loop. Note 9 = number added to the previous point ... 0 (not found) + 9 $iPoint5 = StringInStr($sJSON, '"}', 0, 1, $iPoint4) ; And the last. 2 = length of '"}' $iCount = $iPoint5 ; Skip ahead to next chapter $aChap[$iIndex][0] = StringMid($sJSON, $iPoint4, $iPoint5 - $iPoint4) ; Here you have the name of the chapter $aChap[$iIndex][1] = _MStoSMPTE(StringMid($sJSON, $iPoint2, $iPoint3 - $iPoint2), True) ; Convert the time to readable format for YouTube (that's what "True" means) $iIndex += 1 ; Increment to next chapter $aChap[0][0] = $iIndex ; As per usual, cell [0][0] contains number of items in array WEnd If $iIndex = 0 Then ; There are no chapters here! MsgBox(48, "No chapters found! [15]", "No chapters found in this project. ") $iLast_Err = 15 _GreyOut() ; Give back control to the main GUI Return 15 ; Return to GUI and set $iLast_Err EndIf ReDim $aChap[$iIndex][2] ; Cut any exceeding cells and rows. ; CONVERTING ARRAY TO A YOUTUBE FRIENDLY STRING $sChap = "00:00:00" & @CRLF ; Required by YouTube For $i = $aChap[0][0] - 1 To 1 Step -1 ; Read backwards ... apparently CapCut has put the markers in the reverse order. $sChap &= $aChap[$i][1] & " - " & $aChap[$i][0] & @CRLF ; Append to string with both marker timing and title Next ; ASKING USER FOR A FILENAME $iSel_Err = _Select_Save_Filename("Chapters : Select output filename", _Backup_Filename("Chapters", ".TXT"), "Text (*.TXT)") ; Ask for a filename and suggest one If $iSel_Err Then ; User pressed ESC or cancel so there's not output filename _GreyOut() ; Give back control to the main GUI Return $iSel_Err EndIf ; WRITE CHAPTERS TO THE OUTPUT FOLDER FileWrite($sOut_File, $sChap) ; Write the file itself! $iErr = @error ; Save the error number If $iErr Then ; 0 = no error. Anything else is an error. MsgBox(48, "Error writing chapters [16]", "Cannot write chapters to output folder.") $iLast_Err = 16 _GreyOut() ; Give back control to the main GUI Return 16 ; Return to GUI and set $iLast_Err EndIf MsgBox(64, "Export chapters successful", "Export chapters successful. Open " & $sOut_File & ", copy text and append to your YouTube description.") _GreyOut() ; Bring main GUI back to the fore! EndFunc ;==>_Export_Chapters Func _Export_List($sFile, $sListFile) ; Export file list to temporary folder ; $sFile = path to filename to write, $sListFile = string to write to file ; WRITE FILE LIST TO TEMPORARY FOLDER Local $iFile_Err ; Contains flag following writing to disk If FileExists($sFile) Then FileDelete($sFile) ; Is there a list file already there? Delete it. $iFile_Err = FileWrite($sFile, $sListFile) ; Write that list to the temp folder If Not $iFile_Err Then ; Error code = 0 MsgBox(48, "Cannot write file list to disk [19]", "Program was unable to write file list to temp folder. Compression impossible.") $iLast_Err = 19 ; Note that error number Return 19 ; Return to whatever called _Export_Resources() EndIf EndFunc ;==>_Export_List Func _Export_Resources() ; Grab all the pictures, video and audio from a project and compress them into a .7z file. Put that file in the $sOut_Folder folder. Local $aRES = _Load_Resources() ; Get the list of all the resources Local $iByte_Count = 0 ; Count bytes to make sure the archive will not exceed available space Local $sList = @TempDir & "\" & "CCTOOLS.RES" ; Path to file that will contain all the files to add to archive Local $sAT_File ; Will contain a text file containing all files to backup followed by a linefeed and a carriage return --> @CRLF Local $iFile_Err ; Contains the return code for FileWrite() Local $iSel_Err ; Contains the return code for _Select_Save_Filename() Local $iExp_Err ; Contains the return code for _Export_List() Local $iComp_Err ; Contains the return code for _Compress_7z() Local $iTime = TimerInit() ; Start timer Local $iCount ; Counter to walk through backwards while $aRes[] is being filtered out ; IS THERE SOMETHING IN $aRES? ; Error 8 or 18 means _Load_Resources() failed. If $aRES Then Return $aRES ; Return the error number if there was one. When it's an array "If $aRES" does not trigger the return _GreyOut() ; Lock GUI and fade text ; FILTER OUT UNNEEDED FILES $iCount = $aRes[0] -1 ; Set backward counter to max value While $iCount > 0 ; Filter until $iCount = 0. Must use "While" since For-Next cannot accept negative steps ConsoleWrite($iCount & @TAB & $aRes[$iCount] & @CRLF) If StringInStr($aRes[$iCount],"\AppData\Local\CapCut\User Data\Cache") Or Not FileExists($aRes[$iCount]) Then ; Is an internal resource file OR file does not exist _ArrayDelete($aRes,$iCount) ; Delete the cell $aRes[0] = $aRes[0] -1 ; Decrement value EndIf $iCount -= 1 ; Decrement counter Wend If $aRes[0] = 1 Then ; No resources to export! MsgBox(48,"No resources to export [26]","Either all resources are missing or all resources are internal. Returning to main GUI.") ; Return EndIf ; CHECK TOTAL FILE SIZE For $i = 1 To $aRES[0] -1 ; Go through all the files $iByte_Count += FileGetSize($aRES[$i]) ; Get the file size, increment $iByte_Count Next $iByte_Count += DirGetSize($sDraft & "\" & $aGUI[20]) ; Get the size of the resource files ; WARN USER If $bSpace_nag Then $iMsgBoxAnswer = MsgBox(52, "Proceed with backup?", "You are about to backup " & _ByteSuffix($iByte_Count) & " using 7-zip." & @CRLF & "Compression usually yields low compression." & @CRLF & _ "Current free space on selected drive : " & _ByteSuffix(DriveSpaceFree($sOut_Folder) * 1048576) & @CRLF & "Output directory : " & $sOut_Folder) Select Case $iMsgBoxAnswer = 7 ;No _GreyOut() ; Give back control to the main GUI Return EndSelect EndIf ; ASK USER FOR A FILENAME $iSel_Err = _Select_Save_Filename("Select a filename for the archive containing the resource files", _Backup_Filename("Resources", ".7z"), "7-zip (*.7z)") If $iSel_Err Then ; There was an issue selecting a filename _GreyOut() ; Give back control to the main Gui Return $iSel_Err ; and return ... EndIf ; CREATE @FILE FOR 7-ZIP (LIST ALL FILES TO COMPRESS) For $i = 1 To $aRES[0] - 1 ; Go through all cells of $aRES $sAT_File &= $aRES[$i] & @CRLF ; Append filename with full path and Carriage Return + Line Feed Next ; WRITE FILE LIST TO TEMPORARY FOLDER $iExp_Err = _Export_List($sList, $sAT_File) If $iExp_Err Then ; Couild not export the list required to do the backup --> Error 19 _GreyOut() ; Load back main GUI Return $iExp_Err ; Go back EndIf ; THE ACTUAL BACKING UP $iComp_Err = _Compress_7z($sOut_File, $sList, "a -mx9 -ssw") ; This is where the compression starts. Note "a mx9 -ssw" : compress max, should make a flat file with no subdirectories If $iComp_Err Then ; Error occured during compression _GreyOut() ; Load back main GUI Return $iComp_Err EndIf MsgBox(64, "Resources exported", "Resources succesfully backed up to :" & @CRLF & $sOut_File & @CRLF & "Compression time: " & _How_Long(TimerDiff($iTime))) ; Tell user the backup is completed. FileDelete($sList) ; That list is not needed anymore _GreyOut() ; Unlock GUI and make text black again EndFunc ;==>_Export_Resources Func _Export_Subs() ; Extract then export the subtitle file Local $aSRT ; Array containing the subtitles as extracted Local $iSel_Err ; Error returning from _Select_Save_Filename() _GreyOut() ; Temporarily put main GUI in the background $aSRT = _Extract_Subs() ; Go get'em! If $aSRT Then ; Whoops, error during extraction --> 9 = Cannot open .JSON file, 10 = No subtitles found _GreyOut() ; Return GUI to normal Return ; Return to program without doing anything EndIf $iSel_Err = _Select_Save_Filename("Subtitles : Select output filename", _Backup_Filename("Subtitles", ".SRT"), "Subtitles (*.SRT)") ; Ask user for a filename, propose a filename and search for .SRT files in the meantime ; Note : filename is in "$sOut_File" and it's a global variable If $iSel_Err Then ; User pressed ESC or cancel so there's not output filename _GreyOut() ; Give back control to the main GUI Return $iSel_Err ; Go back with the error code EndIf ; WRITE THE SUBS TO THE OUTPUT FOLDER _FileWriteFromArray($sOut_File, $aSRT) ; Write the file itself! $iErr = @error ; Save the error number If $iErr Then ; 0 = no error. Anything else is an error. ;~ 1 - Error opening specified file ;~ 2 - $aArray is not an array ;~ 3 - Error writing to file ;~ 4 - $aArray is not a 1D or 2D array ;~ 5 - Start index is greater than the $iUbound parameter Select Case $iErr = 1 Or $iErr = 3 ; Cannot write to file MsgBox(16, "Cannot write to file [13]", "Error writing to file" & @CRLF & "$sSortie" & @CRLF & "Program exit.") $iLast_Err = 13 ; Set $iLast_Err _GreyOut() ; Give back control to the main GUI Return 3 ; Return back to program Case $iErr = 2 Or $iErr > 3 ; Internal error, very unlikely MsgBox(16, "Internal error [14]", "Unexpected internal error. No data to write to file." & @CRLF & "Program exit") $iLast_Err = 14 ; Set $iLast_Err _GreyOut() ; Give back control to the main GUI Return 14 ; Return back to program EndSelect EndIf _GreyOut() ; Restore main GUI EndFunc ;==>_Export_Subs ; ***************************************************************************** ; 7-ZIP ; ***************************************************************************** Func _Compress_7z($sArchive, $sFiles, $sParam = "a -mx9 -spf -ssw") ; Flexible function to compress files to 7z format ; $sArchive = valid archive name with full path ; $sFiles = @list (with full path) or a full path followed by \* ; Check parameters here : https://axelstudios.github.io/7z/#!/ Local $s7z_FINAL = Chr(34) & $s7z & Chr(34) & " " & $sParam & " " & Chr(34) & $sArchive & Chr(34) & " " ; Setup the final command line. Notice quotation marks : Chr(34) If StringRight($sFiles, 11) = "CCTOOLS.RES" Then ; If $sFiles ends with "CCTOOLS.RES" then it's a @list fer sure. $s7z_FINAL &= "@" & Chr(34) & $sFiles & Chr(34) ; Put "@" and then $sFile between quotation marks and add it to the final command line Else $s7z_FINAL &= Chr(34) & $sFiles & Chr(34) ; Else just put $sFile between quotation marks EndIf $i7z_Code = RunWait($s7z_FINAL) ; This is where the compression occus. #cs | | | 0 No error | | | 1 Warning (Non fatal error(s)). For example, one or more files were locked by some other application, so they were not compressed. | | | 2 Fatal error | | | 7 Command line error | | | 8 Not enough memory for operation | | | 255 User stopped the process #ce Select Case $i7z_Code = 1 MsgBox(16, "Backup completed with errors", "Backup completed but some files couldn't be opened :" & @CRLF & $sArchive) ; Tell user it's not a complete success. Case $i7z_Code = 2 MsgBox(16, "Fatal error during compression", "7-Zip has encountered a fatal error during compression. Debugging required.") ; This is BAD. Possible RAM issue Case $i7z_Code = 8 MsgBox(16, "Not enough memory for operation", "7-Zip has ran out of memory. Close programs or buy more memory!") ; 16 Gigs of RAM ideal Case $i7z_Code = 255 $iMsgBoxAnswer = MsgBox(260, "User stopped the process", "User stopped the process. Do you also want to exit CCBackup?") ; Select Case $iMsgBoxAnswer = 6 ;Yes _Xit() ; Then do so ... EndSelect EndSelect Return $i7z_Code ; Return 7-zip's error code so whoever called _Compress_7z() can do some logical stuff. EndFunc ;==>_Compress_7z Func _Extract_7z($sArchive, $sParam = "x -spf") ; Extract all those files. Note : filename should end with .CCTOOLs.7z to ensure the original archive was created with switch -spf Local $s7z_FINAL = Chr(34) & $s7z & Chr(34) & " " & $sParam & " " & Chr(34) & $sArchive & Chr(34) ; Setup the final command line. Notice quotation marks : Chr(34) $i7z_Code = RunWait($s7z_FINAL) ; This is where the extraction occurs. Select Case $i7z_Code = 1 MsgBox(16, "Restore completed with errors", "Restore completed but some files couldn't be opened :" & @CRLF & $sArchive) ; Tell user it's not a complete success. Case $i7z_Code = 2 MsgBox(16, "Fatal error during extraction", "7-Zip has encountered one or more fatal error during extraction. Debugging required.") ; This is BAD. Possible RAM issue Case $i7z_Code = 8 MsgBox(16, "Not enough memory for operation", "7-Zip has ran out of memory. Close programs or buy more memory!") ; 16 Gigs of RAM ideal Case $i7z_Code = 255 $iMsgBoxAnswer = MsgBox(260, "User stopped the process", "User stopped the process. Do you also want to exit CCBackup?") ; Select Case $iMsgBoxAnswer = 6 ; Exit = Yes _Xit() ; Then do so ... EndSelect EndSelect Return $i7z_Code ; Return 7-zip's error code so whoever called _Compress_7z() can do some logical stuff. EndFunc ;==>_Extract_7z Func _Size_7z($sArchive) ; Return the (uncompressed) size of an archive. Local $sOutput = "" ; This string will contain the output from that 7-zip console Local $aLine ; We only need the last line of the output Local $iProcessId = Run(Chr(34) & $s7z2 & Chr(34) & " l -r " & Chr(34) & $sArchive & Chr(34), "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) ; Run 7-zip as a command line While 1 ; Infinite loop $sOutput &= StdoutRead($iProcessId) ; and extract all the text you can If @error Then ExitLoop ; When the programs end, it will generate an error : we got all the text. WEnd $aLine = StringRight($sOutput, StringLen($sOutput) - StringInStr($sOutput, @CRLF, 0, -2)) ; We just need the last line (string length minus position of second to last carriage return) Return StringMid($aLine, 28, 11) ; Let's return that snip that shows the amounts of bytes of uncompressed data in the archive, in bytes. EndFunc ;==>_Size_7z ; ***************************************************************************** ; MAIN SUPPORT FUCTIONS ; ***************************************************************************** Func _Get_PROJ($iArray = 0) ; Return a string containing all the CapCut projects, separated by a pipe character : | --> For the combobox in the main GUI Local $aPROJ_list[9999] ; Create an array to contain all the folders Local $sPROJ_list = "Please select project from this dropdown list|" ; a string to contain the formated result $aPROJ_list = _FileListToArray($sDraft, "*", $FLTA_FOLDERS) ; Load it up! $iErr = @error ; Load the error code If $iErr Then ; There was an issue loading the folders, FATAL ERROR MsgBox(16, "Cannot load project list [5]", "The program is not able to enumerate the project folders or there was an error accessing CapCut's draft folder. Program exit.") Exit 5 ; FATAL. Exit program with error code 5 EndIf If $aPROJ_list[0] = 0 Then ; Whoops, no projects found! FATAL ERROR MsgBox(16, "No projects found [6]", "There were no projects found in CapCut's Draft folder. Cannot continue. Program exit. ") Exit 6 ; FATAL. Exit program with error code 3 EndIf If $iArray Then Return $aPROJ_list ; Called from ZZZ, return array with project list instead. For $i = 1 To $aPROJ_list[0] ; Cycle through all the project folders If $aPROJ_list[$i] = ".recycle_bin" Then ContinueLoop ; If it's the recycle bin we don't want it. $sPROJ_list &= $aPROJ_list[$i] & "|" ; Put a pipe after each project name, required by GUICtrlCreateCombo() $iPROJ_QTY += 1 ; We want to know how many projects there are in total but only the first time this list is read Next Return $sPROJ_list ; There you go EndFunc ;==>_Get_PROJ Func _Load_Resources($sPRJCT = "") ; Dig in draft_meta_info.json to find all the media items in the selected project If $sPRJCT Then ; A parameter has been passed to this function Local $sPath = $sDraft & "\" & $sPRJCT & "\draft_meta_info.json" ; "draft_meta_info.json" is where all the resources are noted, filename from $sPRJCT Else Local $sPath = $sDraft & "\" & GUICtrlRead($aGUI[20]) & "\draft_meta_info.json" ; "draft_meta_info.json" is where all the resources are noted, filename from GUI EndIf Local $iCount = 1 ; Counter that keeps track where the search is at in the .JSON file Local $iPoint1 ; This points to the start of the path Local $iPoint2 ; And this points to the end Local $iMatrice = 1 ; This counter keeps track of all the individual resources found Local $sRes ; Path to resource. Used to get rid of entry starting with ".\" ReDim $aRES[9999] ; Back to max size Local $sJSON = FileRead($sPath) ; First step : load the .JSON file in a string variable. $iErr = @error ; Note the error number If $iErr Then ; Whoops! MsgBox(16, "Read error [8]", "Cannot load 'draft_meta_info.json' due to a read error.") $iLast_Err = 8 ; Set last error code Return 8 ; to program normally EndIf ; EXTRACTING RESSOURCES PATHS FROM "DRAFT_META_INFO.JSON" While 1 ; Infinite loop ; FIND THE PATHS IN THIS FILE $iPoint1 = StringInStr($sJSON, '"file_Path":"', 0, 1, $iCount) + 13 ; Find the next path. 13 = search string length If $iPoint1 = 13 Then ExitLoop ; None left. Only happens right off the bat or after one full pass through the file $iPoint2 = StringInStr($sJSON, '",', 0, 1, $iPoint1) ; Where does it end? $sRes = StringMid($sJSON, $iPoint1, $iPoint2 - $iPoint1) ; Extract the string $iCount = $iPoint2 + 2 ; Increment the counter. 2 = length of '",' ; CHECK FOR STUFF $sRes = StringReplace($sRes, "/", "\") ; For some reason, CapCut stores it's filenames with a backslash instead of a slash. Reverse them $aRES[$iMatrice] = $sRes ; Put the result into the $aRES array $iMatrice += 1 ; Increment the array counter WEnd $aRES[0] = $iMatrice ; All extracted. Put the amount of cells in $aRES into cell #0 ; NO RESOURCES If $aRES[0] < 2 Then ; No resources found If $sPRJCT Then MsgBox(16, "No resources found [18]", Chr(34) & $sPRJCT & Chr(34) & " does not contain any valid resources.") ; Tell user there's no resources in this project $iLast_Err = 18 ; load $iLast_Err Return 18 ; No drama. Just return with nothing. Else MsgBox(16, "No resources found [18]", Chr(34) & GUICtrlRead($aGUI[20]) & Chr(34) & " does not contain any resources.") ; Tell user there's no resources in this project $iLast_Err = 18 ; load $iLast_Err Return 18 ; No drama. Just return with nothing.. EndIf EndIf ReDim $aRES[$aRES[0]] ; Cut off all extraneous data _ArrayUnique($aRES, 0, 1) ; Keep only unique entries, start at cell #1. Not absolutely required but you never know ... Return $aRES EndFunc ;==>_Load_Resources ; ***************************************************************************** ; MISC ; ***************************************************************************** Func _ByteSuffix($iBytes) Local $iIndex = 0, $aArray = [' bytes', ' KB', ' MB', ' GB', ' TB', ' PB', ' EB', ' ZB', ' YB'] ; Array contains all text values from bytes to yottabytes LOL. Note each value is 1024 * bigger than the previous While $iBytes > 1023 ; so long as there's more than 1023 bytes $iIndex += 1 ; increment $iIndex $iBytes /= 1024 ; Divide by 1024 WEnd Return Round($iBytes, 2) & $aArray[$iIndex] ; Return rounded value to two decimals and text tag EndFunc ;==>_ByteSuffix Func _Combo_Drop($hWnd, $msg, $wParam, $lParam) ; Determine if ComboBox has been dropped. For some reason, OnEvent doesn't seem to work with this type of object ; Inspired by _Combo_Changed() by GaryFrost https://www.autoitscript.com/forum/topic/47709-combobox-onchange-event-not-triggered-after-typing/ Local $nNotifyCode = BitShift($wParam, 16), $nID = BitAND($wParam, 0xFFFF), $hCtrl = $lParam If $nID = $aGUI[20] And $nNotifyCode = $CBN_SELCHANGE Then _Unselected() ; If per chance, someone touched to the ComboBox, rebuild the GUI selected / unselected state Return $GUI_RUNDEFMSG EndFunc ;==>_Combo_Drop Func _How_Long($iTicks) ; Tells us how long it's been since the timer started. Input must be TimerDiff(handle) Local $iHour, $iMin, $iSec, $sTime _TicksToTime($iTicks, $iHour, $iMin, $iSec) ; Convert to time but there's still work to do If $iHour Then $sTime = $iHour & "h" ; If it's passed an hour, put it in $sTime $sTime &= StringFormat("%02um", $iMin) ; Format the minutes to fit. Ends with small m $sTime &= StringFormat("%02us", $iSec) ; Format the seconds to fit. Ends with small s Return $sTime ; Return the readable time string EndFunc ;==>_How_Long Func _IsEven($iVal) ; Checks to see if a specific value is odd or even. Used to make alternate backgrounds in GUI If Mod($iVal,2) Then Return 1 ; Is there anything left when you divide by 2? If yes then return 1 Return 0 ; Value is odd. EndFunc Func _MStoSMPTE($ms, $bYT = False) ; Convert the internal value given by CapCut and send back the SMPTE notation Local $iHeure, $iMin, $iSec, $iFrm, $iSecTOT ; IMPORTANT : This assumes 30 frames per second. I'm not checking for that so the result might be off. $iSecTOT = Floor($ms / 1000000) ; Let's get the TOTAL amount of seconds $iHeure = Round($iSecTOT / 3600) ; Let's get the TOTAL amount of hours $iMin = Floor($iSecTOT / 60) ; Let's get the TOTAL amount of minutes $iSec = $iSecTOT - ($iMin * 60) ; Total amount of seconds minus the total amount of minutes $iFrm = ($ms - ($iSecTOT * 1000000)) / 1000 ; What is left is the number of frames. Precision is very high so let's divide by an extra 1000. If $bYT = True Then ; User asked for a YouTube friendly output Return StringFormat("%02u:%02u:%02u", $iHeure, $iMin, $iSec) ; Return a YouTube-friendly string Else ; Adapted to an .SRT file Return StringFormat("%02u:%02u:%02u,%03u", $iHeure, $iMin, $iSec, $iFrm) ; Return a formated string that can be output to the .SRT file EndIf EndFunc ;==>_MStoSMPTE Func _Open_Help() ; Open help and use the window title in order to figure out what page to display (better than setting a global variable which was my first idea) If (Not FileExists(@TempDir&"\CCTools2.chm")) Or (Not FileExists(@WindowsDir & "\hh.exe")) Then ; Does the file exist in the temporary folder? Does the tool to display the help file exist? _About() ; NO so just pop open the "About" screen where user can find a link and perhaps download the latest version EndIf If WinActive("Manage CapCut versions") Then ; We're in the "Manage install" window Run($sHelp & "Installmanager.htm") ; Open up the help file with the window pointing to the instructions for the install manager. ElseIf WinActive("Settings : " & $sVer) Then ; We're in the "Settings" window Run($sHelp & "SettingsF2.htm") ; Open up the help file with the window pointing to the instructions for the settings. ElseIf WinActive("Show resources") Then ; We're in the "Show resources" window Run($sHelp & "Showresources.htm") ; Open up the help file with the window pointing to the instructions for Show Resources. ElseIf WinActive("About : " & $sVer) Then ; We're in the "About" window Run($sHelp & "CCTools21.htm") ; Open up the help file with the window pointing to the instructions for Show Resources. Else ; Not sure where user is so let's just open the main help file Run($sHelp & "CCTools21.htm") ; Open up the help file with the main page EndIf EndFunc Func _Xit() Exit $iLast_Err ; If there was ever a non-fatal error, send back the code. EndFunc ;==>_Xit