Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
fflogs-backlog-uploader.ahk
; This script will go through and upload every log in your ACT folder to fflogs,
; and then remove or archive those log files according to your configuration.
; Just update the configuration below, run the script, click your fflogs uploader
; (not companion) window, and press <Delete> to start it up!
; Fortunately, the fflogs uploader program has a minimum width and height, so
; just reduce the window width and height all the way.
; <Delete> inside of the fflogs window will start the script
; <Home> will pause and un-pause the script
; <F1> will end the script
; Made February 2022 by Ethan Henderson (zbee), version 4
; Check update: https://gist.github.com/zbee/a2b2afe40bbe9642f060c8da988331ab
; Tested on Windows 10 with FF Logs Uploader v5.8.4
; Notes:
; This version only supports personal logs uploading.
; You will not be able to access your clipboard until the script finishes,
; even if you pause the script.
; You mustn't move your mouse while running the script. Pause it if you need
; your mouse.
; Configuration
; Whether or not you have ads in FFLogs
; Required: Yes
; Options: True, False
; Default: True
_have_ads := True
; Directory of your ACT logs
; Required: Yes
; Options: any path inside of your %appdata% folder (or relative to it)
; Default: "\Advanced Combat Tracker\FFXIVLogs"
_location := "\Advanced Combat Tracker\FFXIVLogs"
; Which region to upload to - only applicable for personal target
; Required: Yes
; Options: "na", "eu", "jp", "oc"
; Default: "na"
_region := "na"
; The privacy setting for the upload
; Required: Yes
; Options: "public", "private", "unlisted"
; Default: "public"
_privacy := "public"
; What you want done with the log files after they're uploaded
; Required: Yes
; Options: "delete", "archive"
; Default: "archive"
_action := "delete"
; A description for all of the uploads
; Required: No
; Options: Any text
; Default: ""
_description := ""
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Setting up data
; How much to shift coordinates if ads are on
_ad_y_shift = 50
; Sleep between clicks
_click_time = 800
; Positions for pixel checks and clicks
_login_button_check := [660, 385]
_split_log_click := [280, 140]
_upload_log_click := [170, 140]
_specific_raids_check := [75 , 525]
_specific_raids_click := [75 , 525]
_choose_file_click := [50 , 315]
_target_click := [55 , 415]
_personal_logs_click := [55 , 445] ; you could set this to click your guild..
_region_click := [235, 415] ; if you do, update _region* and _privacy*
_region_na_click := [235, 445]
_region_eu_click := [235, 475]
_region_jp_click := [235, 505]
_region_oc_click := [235, 535]
_privacy_click := [315, 415]
_privacy_public_click := [315, 445]
_privacy_private_click := [315, 475]
_privacy_unlisted_click := [315, 505]
_description_click := [335, 470]
_go_button_click := [680, 525]
_cancel_gone_check := [360, 480]
_error_present_check := [19 , 594]
_action_delete_click := [165, 435]
_action_archive_click := [475, 435]
_yes_button_click := [220, 425]
_done_button_click := [390, 495]
; Colors for pixel checks
_login_button_check_color = 0x5588BB ; not logged in
_specific_button_check_color = 0xFAFAFA ; select specific on
_error_check_color = 0xFF0000 ; there is an error
_cancel_check_color = 0x050506 ; there is not a cancel button
; Config option definitions
_region_options := { "na": _region_na_click
, "eu": _region_eu_click
, "jp": _region_jp_click
, "oc": _region_oc_click }
_privacy_options := { "public": _privacy_public_click
, "private": _privacy_private_click
, "unlisted": _privacy_unlisted_click }
_action_options := { "delete": _action_delete_click
, "archive": _action_archive_click }
; Handle config values
; Verify the _location value exists
_full_location := A_AppData _location
if !InStr(FileExist(_full_location), "D")
throw % "Invalid _location config. " _full_location " does not exist"
; Save _location to the clipboard
else
Clipboard := "%appdata%" _location
; Check that the other config values are one of the provided options
; then pull the values for that option from above
if !_region_options.HasKey(StringLower _region)
throw "Invalid _region config"
_region := _region_options[StringLower _region]
if !_privacy_options.HasKey(StringLower _privacy)
throw "Invalid _privacy config"
_privacy := _privacy_options[StringLower _privacy]
if !_action_options.HasKey(StringLower _action)
throw "Invalid _action config"
_action := _action_options[StringLower _action]
; Basic initialization
#SingleInstance Force
#InstallKeybdHook
SendMode Input
DetectHiddenWindows, On
SetKeyDelay , 50, 30,
CoordMode, Pixel, Window
; Startup hotkey
Delete::
ID := WinExist("A")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Make sure we're ready to upload
; Setting up an error folder
if !InStr(FileExist(_full_location "/errorlogs"), "D")
FileCreateDir % _full_location "/errorlogs"
; Check that there are files in the logs folder
_file_count := list_files(_full_location).Length()
if _file_count < 3
throw "Too few logs"
; Check that the user is logged in
if _check_color(_login_button_check, _login_button_check_color, False)
throw "Not logged in"
; Ensure we're on the correct tab
_reset_tab()
; Check that specific raids is not checked - uncheck if it is
if _check_color(_specific_raids_check, _specific_button_check_color)
_click(_specific_raids_click)
; Set configured options
_click(_target_click)
_click(_personal_logs_click)
_click(_region_click)
_click(_region)
_click(_privacy_click)
_click(_privacy)
; Start looping through the logs
_broken_in_a_row = 0
Loop
{
; Unsure why, but this needs global'd inside any loop - unlike other vars
global _click_time
; Count the number of logs, make sure we still have some
_file_count := list_files(_full_location).Length()
if _file_count < 1
{
MsgBox "All logs processed!"
break
}
; Check how many errors have occurred in a row, stopping if too many
if _broken_in_a_row > 2
{
MsgBox "3 errors in a row. Stopping. All upload-able logs likely done!"
break
}
; Selecting a log
; Click to choose a file
_click(_choose_file_click)
sleep _click_time
sleep _click_time
; Type location of logs, and go to it
send !d ; alt+d to focus navbar
Send ^v ; paste the location
sleep _click_time
send {enter} ; the enter's need a lot of time in here ... idk
sleep _click_time
; Go to the search bar, type Network*.log in the search bar, and search
send {tab}
sleep _click_time
send {N}
send {e}
send {t}
send {w}
send {o}
send {r}
send {k}
send {*}
send {.}
send {l}
send {o}
send {g}
sleep _click_time
send {enter}
sleep _click_time
; Get into the list of files
send {tab 2} ; Get to the list of files
send {down} ; IDK why, but have to down+up instead of just tab or enter x2
send {up}
; Grab file name in case it errors
send {tab}
sleep _click_time
send ^c
; Select the file
sleep _click_time
send {enter}
sleep _click_time
; Uploading the log
; Getting active window back
WinActivate ahk_pid ID
sleep _click_time
; Start the upload
_click(_go_button_click)
; Eternal loop until the upload finishes
Loop
{
if _check_color(_cancel_gone_check, _cancel_check_color)
{
break
}
}
; Check for an error
if _check_color(_error_present_check, _error_check_color)
{
_broken_in_a_row++ ; Record if broken
_reset_tab() ; Release file
sleep _click_time ; Wait for release
FileMove ; Move file
, % _full_location "\" Clipboard
, % _full_location "\errorlogs\broken." Clipboard ; Folder and name
sleep _click_time
continue ; Skip to next log
}
_broken_in_a_row = 0
; Click archive/delete (per config) to continue
_click(_action)
_click(_yes_button_click)
_click(_done_button_click)
; Reset the clipboard
Clipboard := "%appdata%" _location
sleep _click_time
}
; Restore the clipboard to what was saved
Clipboard := SavedClip
; Delete:: is now done, script complete!
return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Basic functions
; Shorter Click function
_click(coords, adjust := True)
{
; If there are ads, move the coordinates
global _have_ads
global _ad_y_shift
_y := (_have_ads && adjust) ? (coords[2] - _ad_y_shift) : (coords[2])
; Click the coordinates
MouseClick,, coords[1], _y
; Wait a moment, to show clicking position and give other actions time
global _click_time
sleep _click_time
return
}
; Quick color checks
_check_color(coords, compare_color, adjust := True)
{
; If there are ads, move the coordinates
global _have_ads
global _ad_y_shift
_y := (_have_ads && adjust) ? (coords[2] - _ad_y_shift) : (coords[2])
; Get the color of the pixel
PixelGetColor
, actual_color
, coords[1]
, _y
, RGB
; Compare it to the requested color
return StringLower actual_color == StringLower compare_color
}
; Reset tab to the upload one
_reset_tab()
{
global _click
global _click_time
global _split_log_click
global _upload_log_click
_click(_split_log_click, False) ; click the split log tab
send {enter} ; press enter to cancel an upload
sleep _click_time ; wait until window active
_click(_upload_log_click, False) ; click the upload tab
}
; Listing files
list_files(Directory)
{
files := []
; Loop through the directory's files
Loop %Directory%\*.log
{
; Save the file name to the list
file := Directory "\" A_LoopFileName
files.Push(file)
}
return files
}
; Hotkeys
; Pausing
Home::Pause,Toggle
; Quitting
F1::
Clipboard := SavedClip
ExitApp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment