diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0391a7e --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +Settings.ini +VideoLinks.ini +body.txt +**/ErrorLogging +**/chrome-win64 +**/Downloads +**/Chromedriver-Mover.exe +**/ChromedriverMover.ini +**/Test Videos +**/Backups +**/Debug +**/Templates +**/Testing +*/ConnectToActiveChromeTab.ahk +**ConnectToActiveChromeTab.ahk +Freedomain Social Media Poster*.exe +Freedomain Clips Uploader.exe +Compile Scripts to EXE.ahk +Freedomain Video Uploader.exe +Lib/LBRY Process Killer.exe +Lib/chrome-win64 +Lib/Version.ini \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d36704c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Lib/Freedomain-Posters-Shared-Functions"] + path = Lib/Freedomain-Posters-Shared-Functions + url = https://freedomain.dev/yuriy/posters-shared-functions.git diff --git a/Freedomain Livestream Scheduler.ahk b/Freedomain Livestream Scheduler.ahk new file mode 100644 index 0000000..0e1dad7 --- /dev/null +++ b/Freedomain Livestream Scheduler.ahk @@ -0,0 +1,157 @@ +; ENVIRONMENT +;------------------------------------------------ +#Requires AutoHotkey v1.0 +#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. +;#Warn ; Enable warnings to assist with detecting common errors. +;DetectHiddenWindows, On +#SingleInstance, Force +SendMode Input ; Recommended for new scripts due to its superior speed and reliability. +SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. +;SetKeyDelay, 500 +CoordMode, ToolTip, Screen +CoordMode, Mouse, Screen +;#NoTrayIcon + +; Notes/Extra Info/#Includes +;------------------------------------------------ + +; Included Files and Libraries +; ------------------------------------------------ +; These have to be included at the top for the Global variables to get registered early +#Include %A_ScriptDir%\Lib\Freedomain-Posters-Shared-Functions\Locals-Functions.ahk +#Include %A_ScriptDir%\Lib\Freedomain-Posters-Shared-Functions\General-Functions.ahk +#Include %A_ScriptDir%\Lib\Freedomain-Posters-Shared-Functions\Selenium-Functions.ahk +#Include %A_ScriptDir%\Lib\Freedomain-Posters-Shared-Functions\Chrome-Functions.ahk +#Include %A_ScriptDir%\Lib\Freedomain-Posters-Shared-Functions\Gitea-Functions.ahk +#Include %A_ScriptDir%\Lib\Freedomain-Posters-Shared-Functions\API-Functions.ahk +#Include %A_ScriptDir%\Lib\Freedomain-Posters-Shared-Functions\JSON.ahk +#Include %A_ScriptDir%\Lib\Freedomain-Posters-Shared-Functions\RunCMD.ahk +#include %A_ScriptDir%\Lib\Freedomain-Posters-Shared-Functions\StdOutToVar.ahk +#include %A_ScriptDir%\Lib\Freedomain-Posters-Shared-Functions\Zip.ahk +#include %A_ScriptDir%\Lib\Freedomain-Posters-Shared-Functions\URLDownloadToVar.ahk +#Include %A_ScriptDir%\Modules\Miscellaneous-Functions.ahk + + + + + +; VARIABLES +;------------------------------------------------ + +;---Global Variables--- +;------------------------------------------------ +global ScriptNameav +global ScriptVersion +global FullScriptName +global LBRYResolveAPICommand +global LBRYPermanentURL +global VideoTitle +global VideoFilepath +global VideoThumbFilepath +global VideoTags +global VideoDescription +global SocialMediaDescription +global DiscordErrorLoggingWebhookBotURL +global DiscordVideosWebhookURL +global VideoFolderDir +global LogErrorsToMsgbox +; global LogErrorsToTextFile +global CurrentSite +global Driver +global DriverStatus +global ChromeProfile +global ShowTooltipProgressCheckStatus +global ShowTooltipProgress +ShowTooltipProgress := 1 +global ErrorLogSummary +global DiscordParlerWebhookURL +global ErrorLoggingFilePath +; global TotalTabLoops + +global ErrorLogVar +ErrorLogVar := + +global DevMode + +; Check if Lib folder exists and create it if not +LibFolder := A_ScriptDir . "\Lib" +ErrorLoggingFolder := A_ScriptDir . "\Lib\ErrorLogging" +FileCreateDir, %ErrorLoggingFolder% + +; Set filepaths for different files and folders +global SettingsIniFilepath +SettingsIniFilepath := A_ScriptDir . "\Settings.ini" + +global ScriptSettingsSection +ScriptSettingsSection := "Livestream-Scheduler" + + +FileInstall, Version.ini, %A_ScriptDir%\Lib\Version.ini, 1 +IniRead, ScriptVersion, %A_ScriptDir%\Lib\Version.ini,%ScriptSettingsSection%, Version, 0.0 +IniRead, ScriptName, %A_ScriptDir%\Lib\Version.ini,%ScriptSettingsSection%, Name, %ScriptSettingsSection% + +FullScriptName := ScriptName . " - " . ScriptVersion + + +; GUI Variables +; ------------------------------------------------ +GUIEditBoxWidths := 600 + + +; MAIN SCRIPT +;------------------------------------------------ +Gui, Font, S15 +Gui, Add, Text,, Title +Gui, Add, Edit,w%GUIEditBoxWidths% vLivestreamTitle, We are going to have a livestream! + +Gui, Add, Text,, Description +Gui, Add, Edit,w%GUIEditBoxWidths% h200 vLivestreamDescription, This livestream is happening soon! + + +Gui, Add, Text,, Date and Time of Livestream +Gui, Add, DateTime, vLivestreamDate, MM/dd/yyyy +Gui, Add, DateTime, vLivestreamTime, HH:mm +Gui, Add, Text,, Websites + +Gui, Add, Checkbox,, Dlive +Gui, Add, Checkbox,, Locals +Gui, Add, Checkbox,, Odysee +Gui, Add, Button,gSchedulePost, Schedule + +Gui, Show +Return + + + + + + + + +; Functions +;------------------------------------------------ +SchedulePost: +Gui, submit, NoHide + + + + + + + + + + +; #Include %A_ScriptDir%\Modules\Rumble-Schedule.ahk +#Include %A_ScriptDir%\Modules\Locals-Schedule.ahk + + +msgbox, done! +Return + + + +; Misc +;------------------------------------------------ + +; Escape::ExitApp \ No newline at end of file diff --git a/Lib/Freedomain-Posters-Shared-Functions b/Lib/Freedomain-Posters-Shared-Functions new file mode 160000 index 0000000..5671242 --- /dev/null +++ b/Lib/Freedomain-Posters-Shared-Functions @@ -0,0 +1 @@ +Subproject commit 5671242faff9800cf19672c738f6adf58b9af06b diff --git a/Modules/Locals-Check-Login-Status.ahk b/Modules/Locals-Check-Login-Status.ahk new file mode 100644 index 0000000..d58cf2f --- /dev/null +++ b/Modules/Locals-Check-Login-Status.ahk @@ -0,0 +1,14 @@ + + +Message = Checking Login Status +SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") + +Try, PageURL := driver.Url +if(InStr(PageURL, "/register")) +{ + LoginPageURL := LocalsPostPageURL . "/login" + Message = Website Login Expired. Trying to log back in. Navigating to: %LoginPageURL% + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + try, driver.Get(LoginPageURL) ;Open selected URL + +} diff --git a/Modules/Locals-Schedule.ahk b/Modules/Locals-Schedule.ahk new file mode 100644 index 0000000..c643b00 --- /dev/null +++ b/Modules/Locals-Schedule.ahk @@ -0,0 +1,163 @@ +LocalsSchedule: +;------------------------------------------------ +CurrentSite := "Locals" +SaveOrPostProgress(Message:="Scheduling Post in Locals",PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") + +IniRead, LocalsPostPageURL, %SettingsIniFilepath%, General, LocalsPostPageURL, %A_Space% +if(LocalsPostPageURL = ""){ + Message = LocalsPostPageURL is blank in Settings.ini. Please add the Locals server URL Under [General]`nLocalsPostPageURL= + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + Return +} +else { + ; Reformat URL in case it has any extras we don't need. + LocalsPostPageURLArray := StrSplit(LocalsPostPageURL,".locals.com") + LocalsPostPageURL := LocalsPostPageURLArray[1] . ".locals.com/share?livestream" +} + + + +Status := NavigateFromBaseURLTo(LocalsPostPageURL) +if(Status) +Return + + +try driver.executeScript("return document.readyState").equals("complete") ; wait until page loads completely before proceeding + +CheckForAlerts() + +; Check Login Status on Locals +#Include, %A_ScriptDir%\Modules\Locals-Check-Login-Status.ahk + + +; Input Title and Description into Create a Livestream - First Screen +; ------------------------------------------------ +Xpath = //input[@id='title'] +; try, driver.FindElementByXPath(Xpath).SendKeys("TEST STRINGHERE") + +Status := Selenium_LoopToSendValueToXpath(Xpath:=Xpath,NumOfLoops:=2,SleepLength:=1000,StringTextContent:=LivestreamTitle) + +Xpath = //textarea[@id='body'] +Status := Selenium_LoopToSendValueToXpath(Xpath:=Xpath,NumOfLoops:=2,SleepLength:=1000,StringTextContent:=LivestreamDescription) + +; click next button +Xpath = //span[contains(text(),'Next')] +Status := Selenium_LoopToClickXpath(Xpath:=Xpath,NumOfLoops:=2,SleepLength:=1000) + + + +; Create a Livestream - Second Screen +; ------------------------------------------------ +; check if "Schedule Livestream" checkbox is checked, check it if not +LivestreamScheduledCheckbox := driver.findElementByID("is_scheduled_livestream").isSelected() ;Checks if a checkbox is ticked or not and saves it to a variable, usually: 0 = Unchecked, -1 = Checked +if(LivestreamScheduledCheckbox = 0){ + Xpath = //label[normalize-space()='Schedule this live stream?'] + Status := Selenium_LoopToClickXpath(Xpath:=Xpath,NumOfLoops:=2,SleepLength:=1000) + + LivestreamScheduledCheckbox := driver.findElementByID("is_scheduled_livestream").isSelected() + if(LivestreamScheduledCheckbox = 0){ + Message = Failed to select the "Schedule Livestream" checkbox + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") + } +} + +; Make sure the "Notify Users" checkbox is checked +NotifyUsersCheckbox := driver.findElementByID("is_do_promo").isSelected() ;Checks if a checkbox is ticked or not and saves it to a variable, usually: 0 = Unchecked, -1 = Checked +if(NotifyUsersCheckbox = 0){ + Xpath = //label[@for='is_do_promo'] + Status := Selenium_LoopToClickXpath(Xpath:=Xpath,NumOfLoops:=2,SleepLength:=1000) + + NotifyUsersCheckbox := driver.findElementByID("is_do_promo").isSelected() + if(NotifyUsersCheckbox = 0){ + Message = Failed to select the "Notify Users" checkbox + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") + } + +} + +FormatTime, LocalsLivestreamDate , %LivestreamDate%, MM/dd/yyyy ; _hhmmss +FormatTime, LocalsLivestreamTime , %LivestreamTime%, hh:mm tt ; _hhmmss + +; clear data from date box and input date +Xpath = //input[@id='stream_schedule_date'] +try, driver.FindElementByXPath(Xpath).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace) +Status := Selenium_LoopToSendValueToXpath(Xpath:=Xpath,NumOfLoops:=2,SleepLength:=1000,StringTextContent:=LocalsLivestreamDate) + +; clear data from time box and input time +Xpath = //input[@id='stream_schedule_time'] +try, driver.FindElementByXPath(Xpath).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace).SendKeys(driver.Keys.BackSpace) +Status := Selenium_LoopToSendValueToXpath(Xpath:=Xpath,NumOfLoops:=2,SleepLength:=1000,StringTextContent:=LocalsLivestreamTime) + + +; click schedule button +Xpath = //span[normalize-space()='Schedule'] +Status := Selenium_LoopToClickXpath(Xpath:=Xpath,NumOfLoops:=2,SleepLength:=1000) +if(Status){ + Message = Failed to click schedule post button + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") +} + +LivestreamURL := GrabLocalsPostURLUsingTitle(LivestreamTitle) + +if(!InStr(LivestreamURL, "https")){ + ; If url was not grabbed. wait 1 minute, reload page and then try grabbing URL again + ; @todo +} + +; Navigate to the post +Message = Navigating to Livestream Page to grab RTMP Settings +SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") + +try, driver.Get(LivestreamURL) ;Open selected URL +driver.executeScript("return document.readyState").equals("complete") ; wait until page loads completely before proceeding + + +; Switch to RSTP mode +Xpath = //a[normalize-space()='switch to RTMP'] +Status := Selenium_LoopToClickXpath(Xpath:=Xpath,NumOfLoops:=2,SleepLength:=1000) +if(Status){ + Message = Failed to switch Livestream to RTMP mode + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") +} + + + +; Open Stream Settings Popup Window +Xpath = //button[normalize-space()='Stream Settings'] +Status := Selenium_LoopToClickXpath(Xpath:=Xpath,NumOfLoops:=2,SleepLength:=1000) + + +; Get RTMP Values from the popup +Xpath = //input[@id='rtmp_url'] +try, LocalsRTMPURL := driver.findelementbyxpath(Xpath).Attribute("value") + +/*Xpath = //div[@class='modal-wrapper modal-wrapper_stream']//div[5] +try, LocalsRTMPKey := driver.findelementbyxpath(Xpath).Attribute("value") +*/ + + +Xpath = //div[@class='modal-wrapper modal-wrapper_stream']//div[5] +; Try ElementOuterHTML := driver.findelementbyxpath(Xpath).Attribute("outerHTML") ;XPATH-ID & Tag + +; Pull Out the RTMPKey from the OuterHTML using RegEx +RTMPKey := GetHTMLValueFromXpathOuterHTML(XPATH, "value") +Msgbox % "RTMPKey: " RTMPKey +/* +regexMatch := RegExMatch(ElementOuterHTML, "value=""([^""]+)""", match) +if (regexMatch) +{ + LocalsRTMPKey := match1 +} +else { + Message = Failed to Pull out RTMPKey from OuterHTML of RTMPKey Element + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") +} + +*/ + + +; Msgbox % "LocalsRTMPURL: " LocalsRTMPURL +; Msgbox % "LocalsRTMPKey: " LocalsRTMPKey + + +Return diff --git a/Modules/Miscellaneous-Functions.ahk b/Modules/Miscellaneous-Functions.ahk new file mode 100644 index 0000000..02e6a36 --- /dev/null +++ b/Modules/Miscellaneous-Functions.ahk @@ -0,0 +1,271 @@ + +; -------------------------------Functions------------------------------- + +OnMsgBoxConfirmChromiumOverwrite() { + DetectHiddenWindows, On + Process, Exist + If (WinExist("ahk_class #32770 ahk_pid " . ErrorLevel)) { + ControlSetText Button1, Cancel + ControlSetText Button2, Yes + } +} + +; https://www.autohotkey.com/docs/v2/Functions.htm#Variadic +Join(sep, params*) { + For index, param in params + str .= param . sep + return SubStr(str, 1, -StrLen(sep)) +} + + +CheckLBRYProcess(){ + ; Check if LBRY Process exists + Process, Exist,LBRY.exe + if(ErrorLevel = 0) ; if doesn't exist + { + Message = Not Running. Starting up LBRY.exe + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile") + + LBRYExeFilepath = C:\Program Files\LBRY\LBRY.exe + if(!FileExist(LBRYExeFilepath)){ + Message = Failed to Find LBRY.exe executable. LBRY not installed? + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + Return + } + + Message = Checking LBRY daemon_settings.yml file for Odysee Wallet Servers + SaveOrPostProgress(Message:=Message,PostType:=",ErrorLoggingTextFile,DiscordErrorLogging") + + FileRead, daemon_settingsFileContent, C:\Users\%A_UserName%\AppData\Local\lbry\lbrynet\daemon_settings.yml + + if(!InStr(daemon_settingsFileContent, "a-hub1.odysee.com")){ + Message = Odysee wallet server is not in daemon_settings.yml. Replacing File with required settings. + SaveOrPostProgress(Message:=Message,PostType:=",DiscordErrorLogging") + + LBRYDaemonSettingsFP = C:\Users\%A_UserName%\AppData\Local\lbry\lbrynet\daemon_settings.yml + LBRYDaemonSettingsBackupFP = C:\Users\%A_UserName%\AppData\Local\lbry\lbrynet\daemon_settings_BU.yml + + + ; Msgbox % "daemon_settingsText: " daemon_settingsText + FileMove, %LBRYDaemonSettingsFP%, %LBRYDaemonSettingsBackupFP%, 1 ; Dest [, Flag (1 = overwrite)] + + UrlDownloadToFile, https://freedomain.dev/yuriy/video-uploader/raw/branch/main/Assets/daemon_settings.yml , %LBRYDaemonSettingsFP% + + sleep, 1000 + + if(!FileExist(LBRYDaemonSettingsFP)){ + Message = Failed to download the custom daemon_settings.yml file from git. Restoring Original File + SaveOrPostProgress(Message:=Message,PostType:=",ErrorLoggingTextFile,DiscordErrorLogging") + FileMove,%LBRYDaemonSettingsBackupFP%,%LBRYDaemonSettingsFP%, 1 + } + } + + + try run, "%LBRYExeFilepath%" + Message = Waiting 1 Minute for LBRY to start up + SaveOrPostProgress(Message:=Message,PostType:="Tooltip") + Sleep, 60000 ; 1 minute + + Process, Exist,LBRY.exe + if(ErrorLevel = 0) ; if doesn't exist + { + Message = Failed to Start LBRY.exe after 60 seconds of waiting + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + Return + } + WinMinimize, LBRY + } + Return +} + + +GetPermanentLBRYURL(UploadResult){ + SingleQuotationmark = " + + UploadResult := StrSplit(UploadResult, "`n") ; split results by new line + + ; Iterate through the array of the results + Loop % UploadResult.Length() { + PermanentURL := UploadResult[A_Index] + if(InStr(PermanentURL, "permanent_url")) + Break + } + + ; Starting Result: "permanent_url": "lbry://Test-Video-161-Numbered#c9ad9afe54c7178d6f870b59bbe129aef8efc3ff", + PermanentURL := StrSplit(PermanentURL, "lbry:") + PermanentURL := "lbry:" . PermanentURL[2] + PermanentURL := StrReplace(PermanentURL, ",", "") + PermanentURL := StrReplace(PermanentURL, SingleQuotationmark, "") + PermanentURL := StrReplace(PermanentURL, "`n", "") + PermanentURL := StrReplace(PermanentURL, "`r", "") + + ; End Result lbry://Test-Video-161-Numbered#c9ad9afe54c7178d6f870b59bbe129aef8efc3ff + Return PermanentURL +} + + +GetLBRYCanonicalURL(LBRYJSONObject){ ; input json string + ; ResolveURL := StrSplit(LBRYResolveAPICommand, "lbry://") + ; ResolveURL := "lbry://" . ResolveURL[2] + ; StrReplace(Haystack, SearchText [, ReplaceText, OutputVarCount, Limit := -1]) + LBRYPermanentURLJsonOBJ := StrReplace(LBRYJSONObject, LBRYPermanentURL, "LBRYPermanentURL") + ; clipboard := LBRYPermanentURLJsonOBJ + ; DevModeMsgBox(LBRYPermanentURLJsonOBJ) + + try parsed := JSON.Load(LBRYPermanentURLJsonOBJ) + try LBRYCanonicalURL := parsed.LBRYPermanentURL.canonical_url + + ; DevModeMsgBox(LBRYCanonicalURL) + + if(LBRYCanonicalURL = ""){ + Return "" ; return blank + } + + ; otherwise return the LBRY url + LBRYCanonicalURL := StrReplace(LBRYCanonicalURL, "lbry://", "https://lbry.tv/") + Return LBRYCanonicalURL +} + + +LBRYCMDTextReplacement(LBRYURLSlug){ + SingleQUote = " + LBRYURLSlug := StrReplace(LBRYURLSlug, " ", "_") ; replace all spaces with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, ":", "_") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, ",", "_") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, "?", "") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, "!", "") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, "`;", "_") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, "/", "_") ; replace all colons with dashes + ; LBRYURLSlug := StrReplace(LBRYURLSlug, "?", "") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, "<", "_") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, ">", "_") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, SingleQUote, "") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, "'", "") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, "=", "") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, ";", "") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, ")", "") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, "(", "") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, "___", "_") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, "__", "_") ; replace all colons with dashes + LBRYURLSlug := StrReplace(LBRYURLSlug, "__", "_") ; replace all colons with dashes + Return LBRYURLSlug +} + +GetLBRYAPIErrorFromString(UploadResult){ + UploadResultArray := StrSplit(UploadResult, "message") + LBRYAPIError := UploadResultArray[2] + ; LBRYAPIErrorStrLen := StrLen(LBRYAPIError) + + ; LBRYAPIErrorStrToTrim := LBRYAPIErrorStrLen - 3 + ; Msgbox % "LBRYAPIErrorStrToTrim: " LBRYAPIErrorStrToTrim + LBRYAPIError := SubStr(LBRYAPIError, 4) + LBRYAPIError := StrReplace(LBRYAPIError, "}", "") + + + ; Msgbox % "LBRYAPIError: " LBRYAPIError + Return LBRYAPIError + +} + + +LogErrorToTextFile(Error){ +/* if(LogErrorsToTextFile != 1) + Return + */ + ErrorLoggingFile := VideoFolderDir . "\" . "ErrorLogging.txt" + FormatTime, TodayDate , YYYYMMDDHH24MISS, yyyyMMdd_hhmmss + text = + ( + + + ---------------%TodayDate%--------------- + %CurrentSite%: %Error% + + + ) + if(LogErrorsToMsgbox) + Msgbox % "Text: " Text + + FileAppend, %Text%, %ErrorLoggingFile% + } ; End of Function + +/* +*/ + +AddToTotalVideosUploadedCount(){ + ; IniRead, TotalVideosUploaded, %SettingsIniFilepath%, General, TotalVideosUploaded, %A_Space% + TotalVideosUploaded += 1 + ; IniWrite, %TotalVideosUploaded%, %SettingsIniFilepath%, General, TotalVideosUploaded +} + + + +OnMsgBoxPodcastFinish() { + DetectHiddenWindows, On + Process, Exist + If (WinExist("ahk_class #32770 ahk_pid " . ErrorLevel)) { + WinMove,, 0 + } +} + +OnMsgBoxSocialMediaPoster() { + DetectHiddenWindows, On + Process, Exist + If (WinExist("ahk_class #32770 ahk_pid " . ErrorLevel)) { + ControlSetText Button1, Yes + ControlSetText Button2, Not Now + } +} + + + +Check_For_Stuck_Video_Upload(Index_Number, Upload_Status){ + if(A_index = 1){ ; Create a blank array + ProgressStatusArray := [] + Return + } + + Message = Upload Status: %Upload_Status% + SaveOrPostProgress(Message:=Message,PostType:="Tooltip") + + ; if we reached the last loop number: + if(A_index = %Number_of_loops_to_Check_Upload_status%){ + Message = Upload Most Likely Failed: Video Hasn't Finished Uploading after 1 hour. + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + SaveDriverURLOFErrorPage() + Return "Failed" + } + + ; If progress is still the same after a ten minute interval then error out + if(HasVal(Array_Index_Num_of_Upload_StatusChecks, A_index)){ ; if current index is in Array of index numbers to check status during + + ; Send a notification message of upload status + Message = Upload Status: %Upload_Status% + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") + + ; if current upload_status is in the array of values that are updated every 10 mins + if(HasVal(ProgressStatusArray, Upload_Status)){ + Message = Upload Failed (E#4508)`nUpload Stuck at same point for 10 minutes. Stuck Status: %ProgressStatus% + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + SaveDriverURLOFErrorPage() + Return "Failed" + } + ProgressStatusArray.Push(Upload_Status) ; append current status to array + } + } ; end of func + + +; Find the longest word in a string of words + FindLongestWordInString(m, calloutNumber, pos, haystack, pattern){ + Global wordLength, longestWord + + len := StrLen(m) + + If ( len > wordLength ) + { + wordLength := len + longestWord := m + + ; MsgBox, %m% + } + } \ No newline at end of file diff --git a/Modules/Rumble-Schedule.ahk b/Modules/Rumble-Schedule.ahk new file mode 100644 index 0000000..4f90962 --- /dev/null +++ b/Modules/Rumble-Schedule.ahk @@ -0,0 +1,363 @@ + +RumbleUpload: +;------------------------------------------------ + +CurrentSite := "Rumble" +SaveOrPostProgress(Message:="Scheduling Post in Rumble Studio",PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") + +Status := NavigateFromBaseURLTo("https://studio.rumble.com/api/signin") +if(Status) +Return + + +try driver.executeScript("return document.readyState").equals("complete") ; wait until page loads completely before proceeding + +CheckForAlerts() + +Message = Checking Login Status +SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") + + +try CurrentURL := driver.URL +if(InStr(CurrentURL, "/sso/auth/consent")){ + Message = Rumble Studio Logged out. Trying to log back in. + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") + + ; login button in middle of page + Xpath = //button[@class='consent-page--button header-user'] + Status := Selenium_LoopToClickXpath(Xpath:=Xpath,NumOfLoops:=2,SleepLength:=1000) + + sleep, 2000 + try CurrentURL := driver.URL + if(InStr(CurrentURL, "/sso/auth/consent")){ + Message = Failed to login to Rumble Studio + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + Return + } +} + + + + + + + + + + + + + + + + + + +try CurrentURL := driver.URL +if(InStr(CurrentURL, "/login.php")){ + + if(AutoLogin){ + Message = Logging in Automatically by clicking into the UN+PW fields for info to register + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile") + + ; have to click into username and password field for page to register that there's input + ; clicking with JS doesn't make it register, but with xpath selenium it does + Xpath = //input[@id='login-username'] + driver.FindElementByXPath(Xpath).click() + + Xpath = //input[@id='login-password'] + driver.FindElementByXPath(Xpath).click() + + + js = document.querySelector("button[type='submit']").click(); + driver.executeScript(js) + + + ; Do a double check to make sure that login worked + Message = Checking Login Status + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") + + try CurrentURL := driver.URL + + if(!InStr(CurrentURL, "/upload")){ + Message = Failed to log back in. Please Log Back In Manually + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + SaveDriverURLOFErrorPage() + Return + } + + + } + else, { ; notify user and return + Message = Login Expired. Please Log Back in + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + SaveDriverURLOFErrorPage() + Return + } + + Message = Waiting 5 seconds for page to fully load + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile") + sleep, 5000 +} + +; CheckForAlerts() + +Message = Uploading Video File +SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") +; SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile") + +Xpath = //input[@id='Filedata'] +Status := Selenium_LoopToSendValueToXpath(Xpath:=Xpath,NumOfLoops:=2,SleepLength:=1000,StringTextContent:=VideoFilepath) +if(Status){ + try, CurrentURL := GetCurrentTabURlBase() + Message = Failed to Upload Video File`nCurrent Tab URL: %CurrentURL% + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + SaveDriverURLOFErrorPage() + Return +} + + +; Input Title +try driver.findElementsByName("title").item[1].SendKeys(VideoTitle) ;selects element based on Name and sends variable to it. +catch e { + Message = Video Upload Failed, Please Check Login Status + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + SaveDriverURLOFErrorPage() + Return +} +; Input Description +Loop, 5 { ; Attempt to input video description a couple of times + TooltipThis("Inputting Description `nAttempt Number: " A_index) + + status := js_SendAndCheckWithID(Element:="description",ValueToCheck:="value",SleepLength:=3000,JSStringText:=JSVideoDescription) + if(!Status) + Break + +/* if(A_index = 5){ + Clipboard := VideoDescription + Message = Unable to Input Video Description`nDescription copied to clipboard, please paste it in at your earliest convenience. + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + Return + } + + js = document.getElementsByName('description')[1].value = "%JSVideoDescription%"; ; Send content through javascript (Great for getting around emoji chrome limitaitons) + try driver.executeScript(js) ;Executes a Javascript on the webpage, mostly used for buttons. + + try Description := driver.findElementsByName("description").item[2].Attribute("value") ;XPath: ID=site-title & span tag + if(Description != "") + Break + sleep, 2000 + */ +} + + + + +; sleep, 5000 + + +Message = Selecting Channel +SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile") + + + +; try driver.findElementsByID("channelId").item[1].click() + +; @todo replace with regex +js = return document.querySelector("#channelId").innerHTML; +try, ChannelIDNumber := driver.executeScript(js) +; Msgbox % "ChannelIDNumber: " ChannelIDNumber +ChannelIDNumber := StrSplit(ChannelIDNumber, "option value=") + +; Msgbox % "ChannelIDNumber: " ChannelIDNumber + +ChannelIDNumber := ChannelIDNumber[3] +; Msgbox % "ChannelIDNumber: " ChannelIDNumber + +SingleQuote = " +ChannelIDNumber := StrSplit(ChannelIDNumber, "data-private") +ChannelIDNumber := ChannelIDNumber[1] +ChannelIDNumber := StrReplace(ChannelIDNumber, SingleQuote, "") +ChannelIDNumber := StrReplace(ChannelIDNumber, " ", "") + +; Msgbox % "ChannelIDNumber: " ChannelIDNumber + + +; js = return document.querySelector("#channelId").value; +; try, ChannelIDNumber := driver.executeScript(js) +; Msgbox % "ChannelIDNumber: " ChannelIDNumber +if(ChannelIDNumber = ""){ + Message = ChannelIDNumber is blank. Unable to select Upload Channel + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + SaveDriverURLOFErrorPage() + Return +} + + +ChannelIDNumber = 6070526 ; freedomain +; ChannelIDNumber = 762377 ; personal + +Xpath = //option[@value='%ChannelIDNumber%'] +try driver.FindElementByXPath(Xpath).click() +catch e { + Message = Failed to click on Channel using %ChannelIDNumber%. + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + SaveDriverURLOFErrorPage() + Return + ; SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + ; SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") +} + + + +; Input Tags +Message = Inputting Tags +SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile") + +try driver.findElementsByName("tags").item[1].SendKeys(VideoTags) ;selects element based on Name and sends variable to it. + + + +; Custom Thumbnail +if(VideoThumbFilepath != "") { + TooltipThis("Uploading Thumbnail") + Xpath = //input[@name='customThumb'] + Status := Selenium_LoopToSendValueToXpath(Xpath:=Xpath,NumOfLoops:=2,SleepLength:=1000,StringTextContent:=VideoThumbFilepath) + if(Status){ + Message = Failed to Upload Thumbanil + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + } + + + ; @todo: Add a check to see if progress gets stuck + ; Check Upload Percentage + TooltipThis("Waiting for Video to Finish Uploading") + Loop, %Number_of_loops_to_Check_Upload_status% { + sleep, %Time_Between_Loops_Upload_Status% + + jscheck = return document.getElementsByClassName('num_percent')[0].textContent; + try RumbleUploadPercent := driver.executeScript(jsCheck) + + ; try RumbleUploadPercent := driver.findelementbyxpath(Xpath).Attribute("textContent") + RumbleUploadPercent := StrSplit(RumbleUploadPercent, " ") + RumbleUploadPercent := RumbleUploadPercent[1] + + if(InStr(RumbleUploadPercent, "100%")) ; once variable contains 100%, then we can break out of loop and continue + Break + + + Status := Check_For_Stuck_Video_Upload(A_index, RumbleUploadPercent) + if(Status = "Failed") + Return + ; if(HasVal(Array_Index_Num_of_Upload_StatusChecks, A_index)) { ; 30 minutes and 60 minutes - send a notification message + ; Message = Upload Progress: %RumbleUploadPercent% + ; SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") + ; } + + } + + ; Msgbox % "RumbleUploadPercent: " RumbleUploadPercent + + ; Click on one of the video thumbnail options first + ; Seems to be a bug on rumble, in order to be able to select a custom thumb through js, gotta select on of the generated ones first. + ; Xpath = /html/body/main/div/div/div/section/form[1]/div/div[2]/div[3]/a[2] ; thumbnail option #3 + ; try driver.FindElementByXPath(Xpath).click() ;Clicks on Xpath based on variable. + + + + +/* + js = document.getElementById('customThumb').click(); + driver.executeScript(js) ;Executes a Javascript on the webpage, mostly used for buttons. + Status := InputFilePathIntoOpenWindow(VideoThumbFilepath) + if(Status) + { + Message = Upload Failed:`nUnable to Find "Open File" window to input filepath into + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + Return + } + + */ + + +} + + +if(ConfirmBeforeSubmit) +msgbox, Please check that all data was input correctly and then click OK to Publish Video + +try UploadPageURL := driver.URL + +; Submit Button +js = document.getElementById('submitForm').click(); +try driver.executeScript(js) ; + + +try driver.executeScript("return document.readyState").equals("complete") ; wait until page loads completely before proceeding + + +; Select Rumble Only Licensing +js = document.getElementsByClassName('greenLink mRight last')[0].click(); ; Send content through javascript (Great for getting around emoji chrome limitaitons) +try driver.executeScript(js) ;Executes a Javascript on the webpage, mostly used for buttons. + +; Check off condition 1 +js = document.getElementById("crights").click() +try driver.executeScript(js) + +; Check off condition 2 +js = document.getElementById("cterms").click() +try driver.executeScript(js) + +; Click the Submit Button +js = document.getElementById("submitForm2").click() +try driver.executeScript(js) + + +; Loop until able to grab the direct link from the result page. +Loop, 24 { + TooltipThis("Waiting for Result Page to load to grab Video URL") + Sleep, 5000 + + js = return document.getElementById("error_files_2").textContent; + RumbleError := driver.executeScript(js) ;Executes a Javascript on the webpage, mostly used for buttons. + if(RumbleError != "") { + Message = Rumble Upload Failed due to:`n%RumbleError% + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + SaveDriverURLOFErrorPage() + Return + } + + js = return document.getElementById('direct').value; + try RumbleURL := driver.executeScript(js) ;Executes a Javascript on the webpage, mostly used for buttons. + +/* try RumbleURL := driver.findElementsByID("direct").item[1].Attribute("value") ;grab Direct Link from the result page + catch e { ; if not able to grab it, then sleep for 5 seconds and then loop again + Continue + } + */ + if(RumbleURL != ""){ ; If URL is grabbed from result page, then kick out of loop + Break + } + if(A_Index = 10) ; if looped for 5 minutes and still no URL grabbed + { ; @todo: add error check if submit button clicked and error appears + + Xpath = /html/body/main/div/div/div/section/form[2]/div/div[9] ; grab inner content of where error usually appears. + try RumbleUploadError := driver.findelementbyxpath(Xpath).Attribute("innerText") ; Grabb innertext + ; Msgbox % "UseThumbUploadToolTextExist: " UseThumbUploadToolTextExist + + + Message = Upload Error (E#1341)`nVideo Uploaded but not able to be finalized.`nPlease fix the issue and click the final submit button. `nError: %RumbleUploadError% + SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,ErrorSummaryVar,DiscordErrorLogging") + SaveDriverURLOFErrorPage() + Return + } +} + +IniWrite, %RumbleURL%, %VideoLinksIniFile%, URLs, RumbleURL + +Message = Upload Complete: %RumbleURL% +SaveOrPostProgress(Message:=Message,PostType:="Tooltip,ErrorLoggingTextFile,DiscordErrorLogging") +SaveDriverURL() +AddToTotalVideosUploadedCount() + +Return