• Log InLog In
  • Register
Liquid`
Team Liquid Liquipedia
EDT 10:18
CEST 16:18
KST 23:18
  • Home
  • Forum
  • Calendar
  • Streams
  • Liquipedia
  • Features
  • Store
  • EPT
  • TL+
  • StarCraft 2
  • Brood War
  • Smash
  • Heroes
  • Counter-Strike
  • Overwatch
  • Liquibet
  • Fantasy StarCraft
  • TLPD
  • StarCraft 2
  • Brood War
  • Blogs
Forum Sidebar
Events/Features
News
Featured News
Code S RO4 & Finals Preview: herO, Rogue, Classic, GuMiho0TL Team Map Contest #5: Presented by Monster Energy4Code S RO8 Preview: herO, Zoun, Bunny, Classic7Code S RO8 Preview: Rogue, GuMiho, Solar, Maru3BGE Stara Zagora 2025: Info & Preview27
Community News
Firefly suspended by EWC, replaced by Lancer2Classic & herO RO8 Interviews: "I think it’s time to teach [Rogue] a lesson."2Rogue & GuMiho RO8 interviews: "Lifting that trophy would be a testament to all I’ve had to overcome over the years and how far I’ve come on this journey.8Code S RO8 Results + RO4 Bracket (2025 Season 2)14BGE Stara Zagora 2025 - Replay Pack2
StarCraft 2
General
Firefly suspended by EWC, replaced by Lancer Jim claims he and Firefly were involved in match-fixing How herO can make history in the Code S S2 finals Rogue & GuMiho RO8 interviews: "Lifting that trophy would be a testament to all I’ve had to overcome over the years and how far I’ve come on this journey. Code S RO8 Results + RO4 Bracket (2025 Season 2)
Tourneys
RSL: Revival, a new crowdfunded tournament series [GSL 2025] Code S: Season 2 - Semi Finals & Finals WardiTV Mondays Sparkling Tuna Cup - Weekly Open Tournament $3,500 WardiTV European League 2025
Strategy
Simple Questions Simple Answers [G] Darkgrid Layout
Custom Maps
[UMS] Zillion Zerglings
External Content
Mutation # 478 Instant Karma Mutation # 477 Slow and Steady Mutation # 476 Charnel House Mutation # 475 Hard Target
Brood War
General
ASL20 Preliminary Maps BW General Discussion BGH Auto Balance -> http://bghmmr.eu/ Recent recommended BW games FlaSh Witnesses SCV Pull Off the Impossible vs Shu
Tourneys
[Megathread] Daily Proleagues [BSL 2v2] ProLeague Season 3 - Friday 21:00 CET Small VOD Thread 2.0 [BSL20] ProLeague Bracket Stage - Day 4
Strategy
I am doing this better than progamers do. [G] How to get started on ladder as a new Z player
Other Games
General Games
Nintendo Switch Thread Stormgate/Frost Giant Megathread Path of Exile Beyond All Reason What do you want from future RTS games?
Dota 2
Official 'what is Dota anymore' discussion
League of Legends
Which UAE App Developers Are Leading the Innovatio
Heroes of the Storm
Simple Questions, Simple Answers Heroes of the Storm 2.0
Hearthstone
Heroes of StarCraft mini-set
TL Mafia
Vanilla Mini Mafia TL Mafia Community Thread
Community
General
US Politics Mega-thread Things Aren’t Peaceful in Palestine UK Politics Mega-thread Russo-Ukrainian War Thread Vape Nation Thread
Fan Clubs
SKT1 Classic Fan Club! Maru Fan Club
Media & Entertainment
Korean Music Discussion [Manga] One Piece
Sports
2024 - 2025 Football Thread Formula 1 Discussion NHL Playoffs 2024 TeamLiquid Health and Fitness Initiative For 2023
World Cup 2022
Tech Support
Computer Build, Upgrade & Buying Resource Thread
TL Community
The Automated Ban List
Blogs
A Better Routine For Progame…
TrAiDoS
StarCraft improvement
iopq
Heero Yuy & the Tax…
KrillinFromwales
I was completely wrong ab…
jameswatts
Need Your Help/Advice
Glider
Trip to the Zoo
micronesia
Customize Sidebar...

Website Feedback

Closed Threads



Active: 33242 users

4 million views – the power of automation

Blogs > snipealot
Post a Reply
1 2 Next All
snipealot *
Profile Blog Joined February 2011
Korea (South)494 Posts
Last Edited: 2013-10-14 13:42:03
October 14 2013 13:16 GMT
#1
Warning: This post has a lot of really bad code. If you are a professional programmer you will likely cringe and go 'wtf' when you see some of it.

It has been a crazy 2 months. The automated bot system went online for snipe2 mid-august, and the 3 additional streams became available for 24/7 streaming early September. The arrival of Jangbi and Bisu on afreeca led to a 40% increase in viewer hours in September compared to August. If Bisu continues to stream every single day like he has so far this month we will probably see a similar increase in October. The interest in Bisu seems to have died down somewhat since he set 4 consecutive concurrent viewer records in September – the final one ending at 2373 viewers – but I have a feeling it’ll pick back up again when he participates in his first SOSPA event. Still, this is what the October viewer hours graph looks like so far thanks to Bisu:

[image loading]

Although graphs and statistics are interesting that’s not what this blog post is about. In this post I will go over the crude functions and mangled code that make up the snipealot bot systems, mainly focusing on the snipealot2 bot. There are a few differences in how they are all set up, but I will point this out when I get to those functions.

As with everything, the realization that it could all be automated popped into my head as I was working hard on finishing my dissertation. The deadline was coming up, so of course my brain was trying hard to make me focus on other things. My dissertation was on the rise of esports in Korea, so it wasn’t completely unrelated I guess. If anyone wants to read this they can find it HERE. (in korean)

Testing new code is always a 2-step process for me. I initially always write code and test it on my main computer before porting it to the relevant system – sometimes even testing important code on snipe3 before porting it to snipe2. The entire system relies on two simple scripting languages, mSL(mIRC scripting) and AHK(autohotkey). Although there are ways to have AHK send commands directly to mIRC, I’ve found the simplest way to have them communicate is by using simple text files. Both programs have the ability to read, write to and delete text files, and this combined with the timer system in mSL makes anything possible. To start with I’ll go over the code required to open/restart the standalone afreeca client. This code is used on snipe2 to restart the stream and on snipe3 every time it starts up. However it is not used on snipe0/snipe1 as they use IE and Silverlight to watch streams.

First the mIRC script:

+ Show Spoiler +
on *:text:!restartafreeca:#snipealot2 {
if ($read(c:allowedusers.txt, ns, $nick)) {
/run C:restartafreeca.ahk
}
}


This is the most basic function you can find in the code, the basis upon every single command is built. A command is written, the user who ran the command is checked vs a text file with all the moderators. If found the restartafreeca.ahk script is executed. This AHK script looks like this:

+ Show Spoiler +
Process, Close, afreecaplayer.exe
Process, Close, iexplore.exe
Sleep, 1000
ComObjError(0)
Pwb := ComObjCreate("InternetExplorer.Application")
Pwb.Visible := True
Pwb.Navigate("http://gametv.afreeca.com/broad/index.html")
IELoad(Pwb) ;You need to send the IE handle to the function unless you define it as global.
{
If !Pwb ;If Pwb is not a valid pointer then quit
Return False
Loop ;Otherwise sleep for .1 seconds untill the page starts loading
Sleep,100
Until (Pwb.busy)
Loop ;Once it starts loading wait until completes
Sleep,100
Until (!Pwb.busy)
Loop ;optional check to wait for the page to completely load
Sleep,100
Until (Pwb.Document.Readystate = "Complete")
Return True
}
If IELoad(Pwb) = True
Pwb.Navigate("javascript:runPlayer('app_player')")
Sleep, 15000
Loop
{
FileReadLine, var1, C:setplayer.txt, 1
if ErrorLevel
break
ControlClick, x120 y50, afreeca list
Sleep, 500
ControlSend, Internet Explorer_Server1, {ctrl down}{shift down}{left}{ctrl up}{shift up}, afreeca list
Sleep, 1000
ControlSend, Internet Explorer_Server1, %var1%{enter}, afreeca list
Sleep, 1000
ControlClick, x50 y313, afreeca list
return
}
ComObjError(1)
Return


To explain it as a step by step process it works like this:

1. Close all instances of both IE and afreeca
2. Create an instance of Internet Explorer using ComObj
3. Navigate to the gametv afreeca page
4. Wait until the page is finished loading
5. Click the app_player button using javascript
6. After 15 seconds manually input the last player that was put on and try to enter the main room

This last part where it manually attempts to enter a room is a remnant from the first iteration of the stream-load code. I haven’t bothered to rewrite it yet on snipe2 as it works fine most of the time. This command is rarely used anyway on snipe2, and on snipe3 it has been rewritten and combined with the !setplayer command. This command is obviously used a lot and looks like this:

+ Show Spoiler +
on *:text:!setplayer*:#snipealot2 {
if (($read(c:allowedusers.txt, ns, $nick)) && (%playerchangechecktimer != 1)) {
if ($scanforplayer($2)) {
/remove c:streamdisconnected.txt
set %playerchangechecktimer 1
setplayer $scanforid($2)
unset %autovote.check
/timeravotestart off
/timerendautovote off
/run C:setplayer.ahk
if (%commercialtime != 1) {
set %commercialtime 1
msg $chan .commercial 60
inc %adruns. [ $+ [ $nick ] ]
set %commercial15limit 1
/timercommerciallimit off
/timercommerciallimit 1 900 /unset %commercial15limit
msg $chan Player change initiated - Running 60 second commercial break
/timer 1 480 /unset %commercialtime
}
msg $chan Changing to $2
/timercheckpreview 1 60 /checkpreview
/timer 1 80 /unset %playerchangechecktimer
/timer 1 5 /setoverlay $2
/quick_update $2 is now live!
/timerweibo 1 20 /weibo $2 is now live!
set %playedtime $calc($ctime - %playerstarttime)
write c:streamplayerstats.txt %currentplayer %playedtime %playerrace
if (%autovote == on) /resetautovote
set %currentplayername $2
set %currentplayer $scanforid($2)
set %playerstarttime $ctime
set %playerrace $findrace(%currentplayer)
/timerchecksetplayererror 1 13 /checksetplayererror
/tlsocket
/setafreecatext
}
else {
msg $chan No such Player found. If you wish to set an afreeca ID manually, use !setmanual
}
}
else if ($read(c:allowedusers.txt, ns, $nick)) {
msg $chan Player change too recent, please wait 1 minute.
}
}


Oh my god wall of text. It might look complicated but it really isn’t. In order to understand this command one needs to understand a few others first. As afreeca IDs are different from the players nicknames, these have to be used in order to let mods simply set players. These being the $scanforplayer, $scanforid and $setplayer aliases.
$scanforplayer + Show Spoiler +
 scanforplayer return $read(c:playerdatabase3.txt, nw, * $+ $1 $+ *) 

$scanforid + Show Spoiler +
 scanforid return $read(c:playerdatabase2.txt, ns, $1) 

$setplayer + Show Spoiler +
 setplayer write -c c:setplayer.txt $1 


The first one looks through playerdatabase3.txt for the nickname, the second looks through playerdatabase2.txt for the ID. Ignoring the /timerX off commands and variable unsets this command is pretty simple.

1. If the players nickname is found in the database using $scanforplayer, continue
2. Use $setplayer and $scanforid to find the ID of player $2 (the input after !setplayer) and write this to setplayer.txt
3. Disable a bunch of timers and unset variables in case this is a mod overriding the autovote system.
4. Run setplayer.ahk to put the player on stream
5. If a commercial has not been run within the past 8 minutes, run a commercial break to coincide with the afreeca ads
6. Write to the channel that player $2 is being put on
7. Start a timer to check for the afreeca preview screen (if the room is full this will trigger)
8. Start a timer preventing another !setplayer command for 80 seconds
9. Set the overlay (on a 5 second timer to allow for hiccups reading textfiles)
10. Attempt to post a tweet ($quick_update command) – Note weibo as well though this is disabled for now
11. Use a bunch of variables to write to a textfile how many seconds the previous player was on, then set these variables again for the current player. This is used for statistics and include the players afreecaID, seconds on stream this session and the players race(gotten from a database using the $findrace command)
12. Set a timer checking for an error message text file using the $checksetplayererror command after 13 seconds
13. Update the TL streamlist using $tlsocket
14. Write the current players afreeca streamlink to a text file + post it in the channel using $setafreecatext

This might look complicated but it is really simple. Most of the aliases work similarly, writing and reading from text files. OBSProject lets me set overlays that read from textfiles, so when the $setafreecatext writes this afreeca link to a text file it updates onscreen immediately. The same goes for the playername. The twitter script is written by a guy named FordLawnmower and can be found here. The $checksetplayererror alias simply checks for an error text file that gets created by the setplayer AHK script when a certain error pops up on afreeca. The setplayer autohotkey script looks like this:

+ Show Spoiler +
Process, Close, iexplore.exe
IfWinExist, BroadCastEndding Window
{
ControlClick, x183 y233, BroadCastEndding Window, , left, 1
}
FileDelete, C:setplayererror.txt
FileReadLine, var1, C:setplayer.txt, 1
Var2 = [url=http://live.afreeca.com:8079/app/index.cgi?szBjId=%Var1%]http://live.afreeca.com:8079/app/index.cgi?szBjId=%Var1%[/url]
ComObjError(0)
Pwb := ComObjCreate("InternetExplorer.Application")
Pwb.Visible := False
Pwb.Navigate(Var2)
Sleep, 4000
jsPlayer = javascript:playBroad('%Var1%','app_launch');
Pwb.Navigate(jsPlayer)
Sleep, 5000
if WinExist("ahk_class #32770")
{
FileAppend, %Var1%, C:setplayererror.txt
ControlClick, OK, ahk_class #32770
ControlClick, &No, ahk_class #32770
}
ComObjError(1)


As you can see it uses much of the same code as the other scripts.

1. Close any instances of internet explorer
2. If the afreeca “broadcast has ended” window is present, close it
3. Delete the errorfile
4. Read the setplayer.txt file and put the players ID into a variable
5. Create a second variable that has the players live stream URL
6. Create a hidden IE instance then navigate to this URL
7. Attempt to open up the stream in the standalone player using a javascript function in the browser bar
8. Wait 5 seconds, if an error comes up (stream not on, player already on stream or already loading), create a text file and close the error

When this script is run the player will load up on stream. If the players main room is full it will still load up – but it will have a ‘preview’ bar up top and close down after 1 minute. Luckily this preview overlay is a separate window that AHK can scan for. As you might recall in step 7. Of the !setplayer command a 60s timer checking for this preview window starts up. This is the AHK script that gets run, detectpreview.ahk:

+ Show Spoiler +
IfWinExist, afreeca preview
{
IfWinNotExist, afreeca list
{
Sleep, 200
Click 432, 14
return
}
FileAppend, %FoundX%, c:streaminpreview.txt
FileReadLine, var1, C:setplayer.txt, 1
ControlClick, x160 y50, afreeca list
Sleep, 3000
ControlSend, Internet Explorer_Server1, {BS}{BS}{BS}{BS}{BS}{BS}{BS}{BS}, afreeca list
Sleep, 1000
ControlSend, Internet Explorer_Server1, {BS}{BS}{BS}{BS}{BS}{BS}{BS}{BS}, afreeca list
Sleep, 1000
ControlClick, x150 y50, afreeca list
Sleep, 3000
ControlSend, Internet Explorer_Server1, ^{BS}{BS}{BS}{BS}{BS}{BS}{BS}, afreeca list
Sleep, 1000
ControlSend, Internet Explorer_Server1, %var1%{enter}, afreeca list
Sleep, 3000
ControlClick, x43 y486, afreeca list
Sleep, 3000
ControlClick, x43 y486, afreeca list
Sleep, 3000
Process, Close, iexplore.exe
Sleep, 10000
if WinExist("ahk_class #32770")
{
ControlClick, OK, ahk_class #32770
ControlClick, &No, ahk_class #32770
}
return
}
Else {
Return
}


It is rather complicated because the moment the main room is full it becomes impossible to load streams through javascript functions. The script has to use simulated physical clicks to redirect to an alternate room. Step by step:

1. Check for the preview screen, if it exists continue
2. If the broadcaster list (a window in the afreeca client that lets you search for and find streams) does not exist, open it
3. Create a text file so mIRC knows AHK has found a preview window
4. Grab the afreeca ID from setplayer.txt and put it in a variable
5. Click in the search bar of the afreeca broadcaster list
6. Send a lot of backspace commands to remove any text that may or may not be in this search bar
7. Do it again for good measure
8. Click this god damn search bar again just in case it bugged out
9. Send a ton of backspace commands again this time while holding shift
10. Write the afreeca ID found in setplayer.txt and click enter
11. Click in a space on the list that usually has a secondary room link
12. Click in that spot again because $@!&#*(^@!(*&^!(*&^#
13. Close any instances of IE in case it clicked the wrong spot
14. If an error message pops up (because it clicked twice), close this error message

As some of you may or may not know the mods have the option of running commercials using the !commercial command. As I was looking through the AHK command list I found a pretty cool function that I realized could be used to make even this task automated. After playing around with this function for a while I managed to get it working semi-decently. It’s still a bit buggy when it comes to certain players like HiyA and by.hero, but overall I think it’s working quite well. Every 3 seconds the snipe2 computer runs imagesearch.ahk, a function that scans a part of the screen for the broodwar quit button. The mIRC script function looks like this:

+ Show Spoiler +
runimagesearch {
if (($exists(c:isinmenu.txt)) && (%commercialtime != 1)) {
/remove c:isinmenu.txt
if (%commercial15limit == 1) {
/timer 1 5 /msg #snipealot2 .commercial 60
msg #snipealot2 Player detected in broodwar menu - Running 60s commercial in 5 seconds
}
else {
/timer 1 5 /msg #snipealot2 .commercial 60
msg #snipealot2 Player detected in broodwar menu - Running 60s commercial in 5 seconds
}
/timer 1 5 /set %commercialtime 1
set %commercialoverride 1
/timer 1 5 /unset %commercialoverride
/timerimagesearch off
/inc %autoadcounter
/timer 1 490 /unset %commercialtime
set %commercial15limit 1
/timercommerciallimit off
/timercommerciallimit 1 900 /unset %commercial15limit
/timerrestartimagesearch 1 495 /timerimagesearch 0 3 /runimagesearch
}
else if (%commercialtime == 1) {
/timerimagesearch off
/timerrestartimagesearch 1 480 /timerimagesearch 0 3 /runimagesearch
}
else {
/run c:imagesearch.ahk
}
}


While the function has a few redundancies it works well. It used to have a 15sec delay and only run 30s commercials unless the time since last break was >15mins, but some time mid-september I decided to make it have a 5sec delay and automatic 60s breaks. The code is still in place for the 15min limit in case I ever decide to change it back though. The script is self is really simple.
1. Check for the isinmenu.txt file, if found run an ad, else if a mod has manually ran an ad, go into non-detection mode for 8 minutes - if neither of these match run imagesearch.ahk:

+ Show Spoiler +
FileDelete c:isinmenu.txt
Sleep, 200
CoordMode, Pixel, Screen
ImageSearch, FoundX, FoundY, 11,716, 262, 814, *130 C:quit.png
Sleep, 200
If (FoundX > 0) {
FileAppend, %FoundX%, c:isinmenu.txt
return
}
Else {
Return
}


1. Delete the textfile if it exists for some reason
2. Change to screen-coordinates instead of program-coordinates (in case of resolution change or window position change)
3. Scan the area between x11,y716 and x262, y814 for an image looking like quit.png (a picture of the bw quit button) with a margin of 130
4. If the image is found, create the isinmenu.txt file

Except for !setplayer I’d say the most used mod command is !online. Although it might seem simple this was probably the one I spent the most time on as it was through this command that I learned how to make AHK issue javascript commands as well as mIRC tokens. The process is rather complex but I’ll try to explain it as best I can. First we must start with the first mIRC alias:

+ Show Spoiler +
on *:text:!online:#snipealot2 {
if (($read(c:allowedusers.txt, ns, $nick)) && (%onlinechecktimer != 1)) {
/online
msg $chan List is over 2 minutes old, refreshing... Please wait.
set %onlinechecktimer 1
/timer 1 120 /unset %onlinechecktimer
/timer 1 10 /postonline
}
else if ($read(allowedusers.txt, ns, $nick)) {
msg $chan Players online: %onlineplayers
}
}

online {
if (%onlinechecktimer != 1) {
unset %onlineplayers
/run C:checkforplayers.ahk
/timer 1 10 /onlinewhileloop
}
else {
msg $chan Players online: %onlineplayers
}
}


1. If the command has not been run within the past 2 minutes, reset the %onlineplayers token and run checkforplayers.ahk
2. Start a timer that runs $onlinewhileloop after 10 seconds
3. If it has been run within the past 2 minutes, simply print the last found online players to the chat

This might seem simple enough but the idea is that it is a 3-step process. The first being this script, the second the AHK side of things:

+ Show Spoiler +
Process, Close, iexplore.exe
FileDelete C:playerson.txt
ComObjError(0)
Pwb := ComObjCreate("InternetExplorer.Application")
Pwb.Visible := False
Pwb.Navigate("http://gametv.afreeca.com/broad/index.html")
IELoad(Pwb) ;You need to send the IE handle to the function unless you define it as global.
{
If !Pwb ;If Pwb is not a valid pointer then quit
Return False
Loop ;Otherwise sleep for .1 seconds untill the page starts loading
Sleep,100
Until (Pwb.busy)
Loop ;Once it starts loading wait until completes
Sleep,100
Until (!Pwb.busy)
Loop ;optional check to wait for the page to completely load
Sleep,100
Until (Pwb.Document.Readystate = "Complete")
Return True
}
IELoad(Pwb)
Pwb.Navigate("javascript:ShowBroadListForCate('00040001')")
Sleep, 500
Pwb.Navigate("javascript:setListRow('100')")
Sleep, 1000
Links := Pwb.Document.Links
Loop % Links.Length ; check each link
{
PlayersOnString.=Links[A_Index-1].InnerText
PlayersOnString.=" "
}
ComObjError(1)
FileAppend,
(
%PlayersOnString%
), c:playerson.txt
Return


1. Close IE, delete playerson.txt
2. Open a hidden IE window and navigate to the gametv afreeca page – this page has all the online streamers
3. Wait until the page has completely loaded
4. Using javascript, set the ShowBroadListForCate to starcraft:broodwar (스타 or 00040001)
5. Using javascript, set the number of streams to 100
6. Scan all the links in the page and put them into an array
7. Create a String and put the text from every single link into this string
8. Write this string to playerson.txt

This usually takes a few seconds to complete, but as the page can be slow loading the script has a 10 second window to do all this. After 10 seconds the following mIRC script $onlinewhileloop gets executed:

+ Show Spoiler +
onlinewhileloop {
set %x 1
while (%x <= $filelines) {
findplayer $idfromline(%x)
inc %x
}
}

postonline /msg #snipealot2 Players online: %onlineplayers
filelines return $lines(c:playerdatabase3.txt)
idfromline return $read(c:playerdatabase2.txt, n, $1)


Overall it’s a pretty complicated series of functions but in short the entire thing that happens when the !online command is issued can be explained as follows:
1. Open the afreeca gametv webpage, gather all afreeca IDs on a page that has the top 100 currently online scbw broadcasters and put these IDs into a textfile
2. Scan this textfile and compare afreeca IDs to a database of known players, if found put these players in a token(mirc script kind of array)
3. Write said token in the channel when done using the postonline command

A couple of days after Bisu started streaming late September I was contacted by TL. They were looking into a way for the TL streamlist to automatically update with the current player online. After some deliberation we came to the conclusion that the best way to do this was to write a script similar to the twitter one – basically send a POST to the TL website using mSL $sockwrite. This is what we came up with:

+ Show Spoiler +
on *:SOCKOPEN:tlnet:{
; Set the variables we want to send:
var %string title= $+ %currentplayername $+ &race= $+ %playerrace

; Send POST and Host
sockwrite -n $sockname POST /api/streams/update/xxxxxxx.json HTTP/1.1
sockwrite -n $sockname Host: wvvw.teamliquid.net

; Send the extra content headers
sockwrite -n $sockname Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
sockwrite -n $sockname Content-Length: $len(%string)
sockwrite -n $sockname Content-Type: application/x-wvvw-form-urlencoded

; We are done, remember we have to send the %string last

sockwrite $sockname $crlf
sockwrite $sockname %string
}


This is what triggers when the $tlsocket alias is run at the end of commands like setplayer.

+ Show Spoiler +
tlsocket sockopen tlnet wvvw.teamliquid.net 80 


The final and rather crucial part of the snipealot2 system is the autovote script. Every 30 seconds an autohotkey script is run scanning for the afreeca “broadcast ended” window. If found the window will close and a 2 minute countdown will begin towards an autovote. 10 Seconds before the autovote begins the $online command is used to refresh the online players list from afreeca, then use the top 4 online players (according to the database) in the vote. An alias called $rollingtext is used during the voting in order to live-update the current vote on the screen. This is the same command that triggers when mods use !notify.

+ Show Spoiler +
rollingtext write -c c:streamrollinginfo.txt $1-

checkdisconnect {
if ($exists(c:streamdisconnected.txt)) {
/remove c:streamdisconnected.txt
msg #snipealot2 Streamer has disconnected - an automatic vote will begin in 2 minutes
set %autovote.check 1
/timerautovote 1 110 /autovote
}
else {
/run c:detectdisconnect.ahk
}
}

autovote {
if (%autovote.check == 1) {
msg #snipealot2 Autovote start in 10 seconds
msg #snipealot2 Refreshing online list
/online
/timeravotestart 1 10 /startautovote
}
}


If no mod has set another player or overridden the vote after 2 minutes the $startautovote will trigger:

+ Show Spoiler +
 startautovote {
set %autovote on
set %onlineplayers $addtok(%onlineplayers, NONE1, 32)
set %onlineplayers $addtok(%onlineplayers, NONE2, 32)
set %onlineplayers $addtok(%onlineplayers, NONE3, 32)
set %onlineplayers $addtok(%onlineplayers, NONE4, 32)
set %autovoteid1 $gettok(%onlineplayers, 1, 32)
set %autovoteid2 $gettok(%onlineplayers, 2, 32)
set %autovoteid3 $gettok(%onlineplayers, 3, 32)
set %autovoteid4 $gettok(%onlineplayers, 4, 32)
set %autovote1 0
set %autovote2 0
set %autovote3 0
set %autovote4 0
if (none isin %autovoteid1) /unset %autovoteid1
if (none isin %autovoteid2) /unset %autovoteid2
if (none isin %autovoteid3) /unset %autovoteid3
if (none isin %autovoteid4) /unset %autovoteid4
if (%autovoteid1 == $null) {
msg #snipealot2 No players found, delaying auto-vote for 10 minutes.
/timer 1 600 /autovote
}
else if (%autovoteid2 == $null) {
msg $snipealot Only one player found
/setplayer $scanforid(%autovoteid1)
run c:setplayer.ahk
setoverlay %autovoteid1
/quick_update %autovoteid1 is now live!
}
else {
msg #snipealot2 A vote has been automatically initiated
msg #snipealot2 The autovote will end in 60 seconds
msg #snipealot2 Choose one of the following players: %autovoteid1 %autovoteid2 %autovoteid3 %autovoteid4
/rollingtext AUTOVOTE IN PROGRESS - VOTE IN THE CHAT
/timerendautovote 1 60 /endautovote
/timerresetautovote 1 65 /resetautovote
}
}


This first alias needs to organize and set up the vote. This is done as follows:
1. Add 4 tokens to the %onlineplayers token. Why this is done will be clear in step4
2. Put the first 4 IDs in the %onlineplayers token into 4 distinct variables
3. Set 4 other variables as their total votes
4. If one of these 4 top variables that were set have ‘none’ In them, unset said variables. This is done so that it won’t run a vote for 4 players if only 2 are online
5. Check the first autovoteID if it has been unset, if this is the case either no players are online or the online players script bugged out. Either the afreeca page is lagging or no players are on – wait 10 minutes and try again.
6. Check the second autovoteID if it has been unset, if this is the case only 1 player is online. Put said player online without voting.
7. If the previous two steps returned as false, two or more players are online. Initiate vote and set timers to end and reset the vote after 1 minute.

Viewers will then vote for the players that are presented to them. This is done using the final text scan in the remote script:

+ Show Spoiler +
 on *:text:*:#snipealot2: {
if ((%voteid1 isin $1-) && ($nick !isin %voted)) {
inc %vote1
set %voted %voted $nick
/rollingtextalias
halt
}
elseif ((%voteid2 isin $1-) && ($nick !isin %voted)) {
inc %vote2
set %voted %voted $nick
/rollingtextalias
halt
}
elseif ((%voteid3 isin $1-) && ($nick !isin %voted)) {
inc %vote3
set %voted %voted $nick
/rollingtextalias
halt
}
elseif ((%voteid4 isin $1-) && ($nick !isin %voted)) {
inc %vote4
set %voted %voted $nick
/rollingtextalias
halt
}
elseif ((%autovoteid1 isin $1-) && ($nick !isin %autovoted)) {
inc %autovote1
set %autovoted %autovoted $nick
/rollingtext Autovote in progress: %autovoteid1 ( %autovote1 ) %autovoteid2 ( %autovote2 ) %autovoteid3 ( %autovote3 ) %autovoteid4 ( %autovote4 )
halt
}
elseif ((%autovoteid2 isin $1-) && ($nick !isin %autovoted)) {
inc %autovote2
set %autovoted %autovoted $nick
/rollingtext Autovote in progress: %autovoteid1 ( %autovote1 ) %autovoteid2 ( %autovote2 ) %autovoteid3 ( %autovote3 ) %autovoteid4 ( %autovote4 )
halt
}
elseif ((%autovoteid3 isin $1-) && ($nick !isin %autovoted)) {
inc %autovote3
set %autovoted %autovoted $nick
/rollingtext Autovote in progress: %autovoteid1 ( %autovote1 ) %autovoteid2 ( %autovote2 ) %autovoteid3 ( %autovote3 ) %autovoteid4 ( %autovote4 )
halt
}
elseif ((%autovoteid4 isin $1-) && ($nick !isin %autovoted)) {
inc %autovote4
set %autovoted %autovoted $nick
/rollingtext Autovote in progress: %autovoteid1 ( %autovote1 ) %autovoteid2 ( %autovote2 ) %autovoteid3 ( %autovote3 ) %autovoteid4 ( %autovote4 )
halt
}
else {
halt
}
}


As you might see this script is a bit of a clusterfuck. This is because it is a ‘catch-all’ for all the text in the snipealot chat. So far only the autovote and vote scripts use this but if I want to add the spambot banscript to the snipe2 system this is where I will put it in. If a vote is in progress it will scan the text for the players currently being voted for, then add a point to said player. A vote is only counted once. After 60 seconds are up the timer will initiate the $endautovote alias:

+ Show Spoiler +
 endautovote {
if ((%autovoteid4 == $null) && (%autovoteid3 == $null)) {
msg #snipealot2 Autovote ended: %autovoteid1 ( %autovote1 ), %autovoteid2 ( %autovote2 )
}
elseif (%autovoteid4 == $null) {
msg #snipealot2 Autovote ended: %autovoteid1 ( %autovote1 ), %autovoteid2 ( %autovote2 ), %autovoteid3 ( %autovote3 )
}
else {
msg #snipealot2 Autovote ended: %autovoteid1 ( %autovote1 ), %autovoteid2 ( %autovote2 ), %autovoteid3 ( %autovote3 ), %autovoteid4 ( %vote4 )
}
set %autovotetoken $sorttok(%autovote1 %autovote2 %autovote3 %autovote4, 32, nr)
set %autovotewinner $gettok(%autovotetoken, 1, 32)
if (%autovotewinner == %autovote1) {
setplayer $scanforid(%autovoteid1)
run c:setplayer.ahk
msg #snipealot2 Putting on %autovoteid1
setoverlay %autovoteid1
set %currentplayer $scanforid(%autovoteid1)
set %currentplayername %autovoteid1
/quick_update %autovoteid1 is now live!
}
else if (%autovotewinner == %autovote2) {
setplayer $scanforid(%autovoteid2)
run c:setplayer.ahk
msg #snipealot2 Putting on %autovoteid2
setoverlay %autovoteid2
set %currentplayer $scanforid(%autovoteid2)
set %currentplayername %autovoteid2
/quick_update %autovoteid2 is now live!
}
else if (%autovotewinner == %autovote3) {
setplayer $scanforid(%autovoteid3)
run c:setplayer.ahk
msg #snipealot2 Putting on %autovoteid3
setoverlay %autovoteid3
set %currentplayer $scanforid(%autovoteid3)
set %currentplayername %autovoteid3
/quick_update %autovoteid3 is now live!
}
else if (%autovotewinner == %autovote4) {
setplayer $scanforid(%autovoteid4)
run c:setplayer.ahk
msg #snipealot2 Putting on %autovoteid4
setoverlay %autovoteid4
set %currentplayer $scanforid(%autovoteid4)
set %currentplayername %autovoteid4
/quick_update %autovoteid4 is now live!
}
else {
msg #snipealot2 Error - This shouldn't happen, notify snipealot
}
set %playerrace $findrace(%currentplayer)
/tlsocket
/resetautovote
/setafreecatext
}


This final script tallies the votes and puts on the winner. If there are two winners it will simply put the one listed higher in the database. When a winner is put on it will then post to twitter using the $quick_update command, then send an update to TL using $tlsocket. Finishing up it resets all variables using the $resetautovote alias.

I’m not sure how interesting you all find this but I hope that this can be a resource for someone who wishes to attempt something similar. This has been an amazing learning experience for me as I’ve never really studied programming. In spite of the fact that mSL and AHK are both rather crude scripting languages – I’d hardly call them programming languages – it works really well. Even the scripts that run within vmware on the snipe0/snipe1 work without much trouble at all.

In closing I’d like to say that setting up and programming everything over the past 2 months has been incredibly fun and fulfilling. I still have a long to-do list of things I’d like to implement, but alas I don’t think I’ll be able to do this before I leave. Hopefully I’ll be able to iron out any flaws in the existing system and make it perfectly stable before Christmas. If I can also manage to find a 1 year hosting place I might even be able to keep the stream running smoothly until I’m back here in Korea again.

-snipealot

****
vlaric
Profile Blog Joined July 2007
United States412 Posts
October 14 2013 13:30 GMT
#2
thanks for the stream! i've been watching it every day.
Wannabe zerg player
Epoxide
Profile Blog Joined March 2011
Magic Woods9326 Posts
October 14 2013 13:33 GMT
#3
LiquipediaSouma: EU MM is just Russian Roulette. Literally.
DarkPlasmaBall
Profile Blog Joined March 2010
United States44117 Posts
October 14 2013 13:34 GMT
#4
Congratulations on the milestone and thank you for the streams! They've been great
"There is nothing more satisfying than looking at a crowd of people and helping them get what I love." ~Day[9] Daily #100
BombiZombie
Profile Joined August 2013
Russian Federation27 Posts
October 14 2013 13:37 GMT
#5
[image loading]
Starcraft:Broodwar forever!
TylerThaCreator
Profile Blog Joined May 2011
United States906 Posts
October 14 2013 13:38 GMT
#6
wow, i very eagerly just read every single bit of this blog. althoug you claim your code is sloppy, its very logical and easy to follow. youre also able to explain every little bit of what you do, which is really cool. how do you have the time to do all this and write your thesis!!
aka SethN
Archas
Profile Blog Joined July 2010
United States6531 Posts
October 14 2013 13:40 GMT
#7
The room is ripe with the stench of bitches!
itsjustatank
Profile Blog Joined November 2010
Hong Kong9152 Posts
October 14 2013 14:19 GMT
#8
[image loading]
Photographer"nosotros estamos backamos" - setsuko
BLinD-RawR
Profile Blog Joined April 2010
ALLEYCAT BLUES50107 Posts
October 14 2013 14:32 GMT
#9


cheers!
Brood War EICWoo Jung Ho, never forget.| Twitter: @BLinDRawR
TL+ Member
Stratos
Profile Blog Joined July 2010
Czech Republic6104 Posts
October 14 2013 14:43 GMT
#10
the power of snipealot
En Taro Violet
GrazerRinge
Profile Blog Joined May 2010
999 Posts
October 14 2013 15:03 GMT
#11
"Successful people don't talk much. They listen and take action."
Ghin
Profile Blog Joined January 2005
United States2391 Posts
October 14 2013 15:17 GMT
#12
thanks for making it happen

the power of starcraft
Legalize drugs and murder.
ffswowsucks
Profile Blog Joined August 2005
Greece2294 Posts
October 14 2013 15:40 GMT
#13
Terran in particular is a notoriously strong race for a no brain skillhand bot style.
bGr.MetHiX
Profile Joined February 2011
Bulgaria511 Posts
October 14 2013 17:14 GMT
#14
snipealot , you are my hero.
Top50 GM EU Protoss from Bulgaria. Streaming with commentary : www.twitch.tv/hwbgmethix
FuDDx *
Profile Blog Joined October 2002
United States5008 Posts
October 14 2013 17:23 GMT
#15
snipealot <3 I wish I had the time to watch as much as I used too but I still love being able to watch and with 3 streams its just better and better!! Thank you!!
https://www.facebook.com/pages/Balloon-Man-FuDD/237447769616965?ref=hl
ne4aJIb
Profile Blog Joined July 2011
Russian Federation3209 Posts
October 14 2013 17:26 GMT
#16
streamalot
Bisu,Best,Stork,Jangbi and Flash, Fantasy, Leta, Light and Jaedong, Hydra, Zero, Soulkey assemble in ACE now!
endy
Profile Blog Joined May 2009
Switzerland8970 Posts
October 14 2013 17:55 GMT
#17
Thank you so much
ॐ
Ettick
Profile Blog Joined June 2011
United States2434 Posts
October 14 2013 18:07 GMT
#18
Thanks for making this stream, it's pretty much the only stream I watch at the moment.
Torenhire
Profile Blog Joined April 2009
United States11681 Posts
October 14 2013 18:11 GMT
#19
best stream on TL <3

Grats on the milestone
SirJolt: Well maybe if you weren't so big and stupid, it wouldn't have hit you.
Louuster
Profile Joined November 2010
Canada2869 Posts
October 14 2013 18:27 GMT
#20
Hi, my name is commander Shepard and this is my favorite stream on TL.

As a long time BW fan, being able to see daily FPV gameplay of players like Bisu and Mind is a dream come true
Kim Taek Yong fighting~
1 2 Next All
Please log in or register to reply.
Live Events Refresh
Wardi Open
11:00
$400 Monday #40
WardiTV1350
OGKoka 573
IndyStarCraft 251
Rex178
CranKy Ducklings145
IntoTheiNu 29
Liquipedia
[ Submit Event ]
Live Streams
Refresh
StarCraft 2
OGKoka 573
Lowko373
Harstem 326
IndyStarCraft 251
Hui .231
Rex 178
ProTech73
StarCraft: Brood War
Rain 4722
Horang2 2463
EffOrt 1504
Mini 1254
Stork 500
firebathero 325
Light 290
actioN 279
Snow 236
Zeus 207
[ Show more ]
Mong 150
JYJ113
sSak 104
Sharp 97
Pusan 84
Sea.KH 69
JulyZerg 66
Killer 62
hero 55
PianO 49
Movie 47
GoRush 43
zelot 31
Backho 24
Rush 23
soO 20
scan(afreeca) 17
ajuk12(nOOB) 16
Terrorterran 15
Shine 15
yabsab 10
Rock 10
Sacsri 9
Noble 9
sorry 8
ivOry 5
Stormgate
RushiSC19
Dota 2
qojqva2561
Gorgc558
XcaliburYe369
Fuzer 257
League of Legends
Dendi1992
Counter-Strike
allub250
Other Games
singsing2017
hiko1339
B2W.Neo1232
Beastyqt422
crisheroes284
ArmadaUGS180
elazer137
Liquid`VortiX1
C9.Mang00
Organizations
Dota 2
PGL Dota 2 - Main Stream15074
Other Games
gamesdonequick585
StarCraft: Brood War
Kim Chul Min (afreeca) 6
StarCraft 2
Blizzard YouTube
StarCraft: Brood War
BSLTrovo
sctven
[ Show 14 non-featured ]
StarCraft 2
• intothetv
• AfreecaTV YouTube
• Kozan
• IndyKCrew
• LaughNgamezSOOP
• Migwel
• sooper7s
StarCraft: Brood War
• BSLYoutube
• STPLYoutube
• ZZZeroYoutube
Dota 2
• WagamamaTV353
League of Legends
• Nemesis8820
• Jankos2889
• TFBlade898
Upcoming Events
Monday Night Weeklies
1h 43m
Replay Cast
9h 43m
Replay Cast
19h 43m
RSL Revival
19h 43m
Cure vs Percival
ByuN vs Spirit
PiGosaur Monday
1d 9h
RSL Revival
1d 19h
herO vs sOs
Zoun vs Clem
Replay Cast
2 days
The PondCast
2 days
RSL Revival
2 days
Serral vs SHIN
Solar vs Cham
RSL Revival
3 days
Reynor vs Scarlett
ShoWTimE vs Classic
[ Show More ]
uThermal 2v2 Circuit
4 days
SC Evo League
4 days
Circuito Brasileiro de…
5 days
Sparkling Tuna Cup
5 days
Liquipedia Results

Completed

Proleague 2025-06-11
2025 GSL S2
Heroes 10 EU

Ongoing

JPL Season 2
BSL 2v2 Season 3
BSL Season 20
KCM Race Survival 2025 Season 2
NPSL S3
Rose Open S1
CSL 17: 2025 SUMMER
Copa Latinoamericana 4
Murky Cup #2
BLAST.tv Austin Major 2025
ESL Impact League Season 7
IEM Dallas 2025
PGL Astana 2025
Asian Champions League '25
BLAST Rivals Spring 2025
MESA Nomadic Masters
CCT Season 2 Global Finals
IEM Melbourne 2025
YaLLa Compass Qatar 2025
PGL Bucharest 2025

Upcoming

CSLPRO Last Chance 2025
CSLPRO Chat StarLAN 3
K-Championship
SEL Season 2 Championship
Esports World Cup 2025
HSC XXVII
Championship of Russia 2025
RSL Revival: Season 1
BLAST Open Fall 2025
Esports World Cup 2025
BLAST Bounty Fall 2025
BLAST Bounty Fall Qual
IEM Cologne 2025
FISSURE Playground #1
TLPD

1. ByuN
2. TY
3. Dark
4. Solar
5. Stats
6. Nerchio
7. sOs
8. soO
9. INnoVation
10. Elazer
1. Rain
2. Flash
3. EffOrt
4. Last
5. Bisu
6. Soulkey
7. Mini
8. Sharp
Sidebar Settings...

Advertising | Privacy Policy | Terms Of Use | Contact Us

Original banner artwork: Jim Warren
The contents of this webpage are copyright © 2025 TLnet. All Rights Reserved.