코드

새 글 자동 댓글 스크립트 (AutoHotkey)

by 이니스프리 posted Nov 26, 2017
?

단축키

Prev이전 문서

Next다음 문서

ESC닫기

크게 작게 위로 아래로 댓글로 가기 인쇄
Extra Form
라이선스 MIT

안녕하세요?

 

어제 모처럼 시간이 나서 헬스장에 가려고 했으나 

 

낙뢰 때문에 부득이 헬스장에 못 가고 이 소스를 짰습니다.

 

전 세계에서 해마다 놀이기구를 타다가 사망하는 사람보다 

 

낙뢰에 의해 사망하는 사람이 더 많다고 들었습니다 ㅎㄷㄷ

(운동 안 하기에 아주 좋은 핑계네요 ㅠㅠ)

 

 

이 스크립트는 새 글 작성시 CMS에서 새 글 표시가 달리는 것을 이용해서 

 

해당 게시글에 자동으로 댓글을 다는 목적으로 제작되었습니다.

 

커뮤니티를 제작하면 초기에는 무플 방지가 필요하다고 생각되어서요 ㅠㅠ

(커뮤니티를 제작하기도 전에 벌써부터 무플 걱정을 하다니 ㅜㅜ)

 

물론 PHP로도 구현할 수 있겠지만

 

CMS와 무관하게 돌아가는 소스를 짜고 싶었습니다.

(실은 제가 어떤 CMS로 커뮤니티를 만들지 아직 정하지 못했거든요 ㅠㅠ)

 

 

이 스크립트는 Autohotkey_L을 기준으로 제작되었고

 

브라우저나 CMS를 가리지 않고 사용할 수 있습니다.

 

다만 마우스 좌표 기반이다보니 부정확한 경우가 있어서

 

중복으로 댓글이 달리는 것을 방지하기 위해

 

마우스 클릭 후 URL이 바뀌는지 여부를 수시로 체크합니다.

 

 

만약 커뮤니티에 새 글 아이콘을 24시간 달리도록 설정하셨다면 

 

윈도우 스케쥴러에서 24시간마다 작동하게 하면 자동으로 돌아갑니다.

 

 

다음 몇 가지를 셋팅하셔야 됩니다.

 

1. new.bmp 파일

 

새 글 작성시 달리는 새 글 표시 아이콘을 new.bmp로 저장합니다.

 

캡쳐하셔도 돌아갑니다.

 

다만 오토핫키의 특성상 bmp나 png 파일은 잘 분석하지만 

 

gif나 jpg 파일은 제대로 작동하지 않을 가능성이 큽니다.

(사실 대부분의 아이콘은 gif나 jpg 파일이죠 ㅠㅠ)

 

그리고 브라우저를 100% 비율로 놓고 사용하지 않으면 캡쳐햐셔야 됩니다 ㅠㅠ

 

 

2. reply.bmp

 

리플 버튼을 캡쳐해서 reply.bmp로 저장합니다.

 

상당수의 커뮤니티에서 리플 버튼이 이미지 파일로 존재하지는 않을테니

 

이건 캡쳐하셔야 될 것 같습니다.

 

 

3. longtime 변수값

 

longtime 변수는 커뮤니티 클릭 후 로딩에 걸리는 시간에 따라 적정한 값을 입력하시면 됩니다.

 

단위는 ms입니다.

 

국내의 무난한 웹호스팅이라면 3000, 벌쳐나 리노드라면 5000, 

 

그리고 테스트 해보지 않았지만 미국이나 호주 서버는 넉넉히 7000 정도 잡으시면 될 것 같습니다.

 

 

4. mention 변수값

 

리플로 남기고 싶은 문구를 mention1~15 변수에 입력하시면 

 

루프가 돌아가면서 순서대로 해당 문구를 리플로 남깁니다.

 

물론 15개 이상 지정하셔도 무방합니다.

 

 

5. PgUP & PgDN

 

이건 화면 해상도에 따라서 달라질 수 있는 부분이네요.

 

new 아이콘과 댓글쓰기 버튼이 화면에 출력될 수 있도록

 

페이지 업과 다운 횟수를 적절히 조절하시면 됩니다.

 

 

6. 크롬 이외의 브라우저

 

이 소스는 모든 브라우저에서 작동하도록 제작되었으며

 

chrome.exe 부분을 변경하면 다른 브라우저에서도 작동하는 것을 확인했습니다.

 

 

첨언하자면 getactiveURL 함수는 오토핫키 공식포럼에 오픈된 소스를 사용하였습니다. 

 

출처는 다음과 같습니다. (atnbueno 님 작성)

 

https://autohotkey.com/boards/viewtopic.php?t=3702

 

사실 크롬에서만 작동하게 하려면 send ^l와 send ^C를 이용해서

 

불과 몇 줄로 간단하게 작성할 수도 있지만 

 

범용으로 제작하다보니 상당히 긴 길이의 함수를 사용하게 되었네요 ㅠㅠ

 

 

제가 크롬, IE, 파폭 등 브라우저에서 돌아가는 것을 확인하였지만 

 

급히 만들다보니 소스에 여러 군더더기가 있습니다. 

 

특히 while 문의 첫번째 루프 돌리는 부분을 더 깔끔하게 만들었어야 했는데 말이죠.

 

군더더기나 부족한 부분이 있으면 스포어의 회원님들께서 지적해주시면 감사하겠습니다. 

 

 

마지막으로 이 소스를 조금 수정하면 게시판 도배 등에 악용될 수도 있을테니 

 

부디 좋은 목적으로만 사용해주셨으면 합니다 ㅠㅠ

 

그럼 편안한 저녁 되시고 여러모로 부족한 제게 많은 가르침을 주시는 스포어 회원 분들께 항상 감사드립니다.

 

 

longtime = 6000
times = 0
 
mention1 =
mention2 =
mention3 =
mention4 =
mention5 =
mention6 =
mention7 =
mention8 =
mention9 =
mention10 =
mention11 =
mention12 =
mention13 =
mention14 =
mention15 =
 
ModernBrowsers := "ApplicationFrameWindow,Chrome_WidgetWin_0,Chrome_WidgetWin_1,Maxthon3Cls_MainFrm,MozillaWindowClass,Slimjet_WidgetWin_1"
LegacyBrowsers := "IEFrame,OperaWindowClass"
longtime = 6000
 
Run, Chrome.exe "www.google.com"
sleep, 3000
 
ret:=IME_CHECK("Google")
If %ret% <> 0
{
Send,{vk15sc138}
}
 
 
Run, Chrome.exe "URL"
sleep %longtime%
SendInput, {Home}
sleep 2000
SendInput, {PgDn}
sleep 2000
 
sURL := GetActiveBrowserURL()
sleep 1500
sURL1 := sURL
 
 
Imagesearch, vx, vy, 500, 0, 1700, 1200, *80 new.bmp
 
 
 
While (Errorlevel=0) ; The Loop
{
SendInput, {Home}
sleep 2000
SendInput, {PgDn}
sleep 2000
 
times := times + 1
If (times > 1)
{
vylimit := vy + 20
}
If (times = 1)
{
vylimit := vy - 20
}

Imagesearch, vx, vy, 500, %vylimit%, 1700, 1200, *80 new.bmp
sleep 200
 
If (Errorlevel = 0)
{
sleep 200
vx1 := vx - 60
vy1 := vy + 10
sleep 200
Mouseclick, Left, %vx1%, %vy1%
sleep, %longtime%
SendInput, {END}
sleep, 2000
SendInput, {PgUp}
sleep, 2000
SendInput, {PgUp}
sleep, 2000
 
 
sURL := GetActiveBrowserURL()
sleep 1500
If (sURL1 = sURL)
{
Break
}

 
 
 
Imagesearch wx, wy, 800, 0, 1920, 1200, *90 reply.bmp
sleep 200
If (Errorlevel = 0)
{
wx1 := wx + 20
wx2 := wx - 100
wy1 := wy + 20
Mouseclick, Left, %wx2%, %wy1%
SendInput, % mention%times%
sleep 200
Mouseclick, Left, %wx1%, %wy1%
sleep, %longtime%
}
}
 
If (Errorlevel > 0)
{
break
}
 
sURL1 := sURL
sleep 200
Run, chrome.exe "URL"
sleep, %longtime%
}
 
Return
 
 
 
 
; funtion
 
 
GetActiveBrowserURL() {
global ModernBrowsers, LegacyBrowsers
WinGetClass, sClass, A
If sClass In % ModernBrowsers
Return GetBrowserURL_ACC(sClass)
Else If sClass In % LegacyBrowsers
Return GetBrowserURL_DDE(sClass) ; empty string if DDE not supported (or not a browser)
Else
Return ""
}
 
; "GetBrowserURL_DDE" adapted from DDE code by Sean, (AHK_L version by maraskan_user)
; Found at http://autohotkey.com/board/topic/17633-/?p=434518
 
GetBrowserURL_DDE(sClass) {
WinGet, sServer, ProcessName, % "ahk_class " sClass
StringTrimRight, sServer, sServer, 4
iCodePage := A_IsUnicode ? 0x04B0 : 0x03EC ; 0x04B0 = CP_WINUNICODE, 0x03EC = CP_WINANSI
DllCall("DdeInitialize", "UPtrP", idInst, "Uint", 0, "Uint", 0, "Uint", 0)
hServer := DllCall("DdeCreateStringHandle", "UPtr", idInst, "Str", sServer, "int", iCodePage)
hTopic := DllCall("DdeCreateStringHandle", "UPtr", idInst, "Str", "WWW_GetWindowInfo", "int", iCodePage)
hItem := DllCall("DdeCreateStringHandle", "UPtr", idInst, "Str", "0xFFFFFFFF", "int", iCodePage)
hConv := DllCall("DdeConnect", "UPtr", idInst, "UPtr", hServer, "UPtr", hTopic, "Uint", 0)
hData := DllCall("DdeClientTransaction", "Uint", 0, "Uint", 0, "UPtr", hConv, "UPtr", hItem, "UInt", 1, "Uint", 0x20B0, "Uint", 10000, "UPtrP", nResult) ; 0x20B0 = XTYP_REQUEST, 10000 = 10s timeout
sData := DllCall("DdeAccessData", "Uint", hData, "Uint", 0, "Str")
DllCall("DdeFreeStringHandle", "UPtr", idInst, "UPtr", hServer)
DllCall("DdeFreeStringHandle", "UPtr", idInst, "UPtr", hTopic)
DllCall("DdeFreeStringHandle", "UPtr", idInst, "UPtr", hItem)
DllCall("DdeUnaccessData", "UPtr", hData)
DllCall("DdeFreeDataHandle", "UPtr", hData)
DllCall("DdeDisconnect", "UPtr", hConv)
DllCall("DdeUninitialize", "UPtr", idInst)
csvWindowInfo := StrGet(&sData, "CP0")
StringSplit, sWindowInfo, csvWindowInfo, `" ;"; comment to avoid a syntax highlighting issue in autohotkey.com/boards
Return sWindowInfo2
}
 
GetBrowserURL_ACC(sClass) {
global nWindow, accAddressBar
If (nWindow != WinExist("ahk_class " sClass)) ; reuses accAddressBar if it's the same window
{
nWindow := WinExist("ahk_class " sClass)
accAddressBar := GetAddressBar(Acc_ObjectFromWindow(nWindow))
}
Try sURL := accAddressBar.accValue(0)
If (sURL == "") {
WinGet, nWindows, List, % "ahk_class " sClass ; In case of a nested browser window as in the old CoolNovo (TO DO: check if still needed)
If (nWindows > 1) {
accAddressBar := GetAddressBar(Acc_ObjectFromWindow(nWindows2))
Try sURL := accAddressBar.accValue(0)
}
}
If ((sURL != "") and (SubStr(sURL, 1, 4) != "http")) ; Modern browsers omit "http://"
sURL := "http://" sURL
If (sURL == "")
nWindow := -1 ; Don't remember the window if there is no URL
Return sURL
}
 
; "GetAddressBar" based in code by uname
; Found at http://autohotkey.com/board/topic/103178-/?p=637687
 
GetAddressBar(accObj) {
Try If ((accObj.accRole(0) == 42) and IsURL(accObj.accValue(0)))
Return accObj
Try If ((accObj.accRole(0) == 42) and IsURL("http://" accObj.accValue(0))) ; Modern browsers omit "http://"
Return accObj
For nChild, accChild in Acc_Children(accObj)
If IsObject(accAddressBar := GetAddressBar(accChild))
Return accAddressBar
}
 
IsURL(sURL) {
Return RegExMatch(sURL, "^(?<Protocol>https?|ftp)://(?<Domain>(?:[\w-]+\.)+\w\w+)(?::(?<Port>\d+))?/?(?<Path>(?:[^:/?# ]*/?)+)(?:\?(?<Query>[^#]+)?)?(?:\#(?<Hash>.+)?)?$")
}
 
; The code below is part of the Acc.ahk Standard Library by Sean (updated by jethrow)
; Found at http://autohotkey.com/board/topic/77303-/?p=491516
 
Acc_Init()
{
static h
If Not h
h:=DllCall("LoadLibrary","Str","oleacc","Ptr")
}
Acc_ObjectFromWindow(hWnd, idObject = 0)
{
Acc_Init()
If DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0
Return ComObjEnwrap(9,pacc,1)
}
Acc_Query(Acc) {
Try Return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
Acc_Children(Acc) {
If ComObjType(Acc,"Name") != "IAccessible"
ErrorLevel := "Invalid IAccessible Object"
Else {
Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
If DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
Loop %cChildren%
i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i), Children.Insert(NumGet(varChildren,i-8)=9?Acc_Query(child):child), NumGet(varChildren,i-8)=9?ObjRelease(child):
Return Children.MaxIndex()?Children:
} Else
ErrorLevel := "AccessibleChildren DllCall Failed"
}
}
 
 
 
 
 
 
IME_CHECK(WinTitle)
{
WinGet,hWnd,ID,%WinTitle%
Return Send_ImeControl(ImmGetDefaultIMEWnd(hWnd),0x005,"")
}
 
 
Send_ImeControl(DefaultIMEWnd, wParam, lParam)
{
DetectSave := A_DetectHiddenWindows
DetectHiddenWindows,ON
SendMessage 0x283, wParam,lParam,,ahk_id %DefaultIMEWnd%
if (DetectSave <> A_DetectHiddenWindows)
DetectHiddenWindows,%DetectSave%
return ErrorLevel
}
 
 
ImmGetDefaultIMEWnd(hWnd)
{
return DllCall("imm32\ImmGetDefaultIMEWnd", Uint,hWnd, Uint)
}