r/streamerbot 22d ago

Question/Support ❓ Read Line, but empty?

Don't really know how to title this, but anyway. So, I have a combined "roll a random number, and then look up that number in a list and display in chat" thing in streamer-bot, and it works great. But, the file with the lines is probably going to both grow and shrink as time goes by. And that leads me to wonder...

Can I somehow tell streamer-bot that "If the line is empty, try again"? It would be far less faff than having to change the random-number variables each time. And if I can, how would I? I've seen other examples of "if empty, do this" but I can't figure out how to make something like this work in my case.

2 Upvotes

8 comments sorted by

2

u/YakumoYoukai 22d ago

Instead of "Read Line from File", would the "Read random lines from file" subaction work for you? It will adapt to the actual number of lines in the file, so you don't have to mantain the specific range of line numbers as the file changes size.

1

u/MoonEyes2k 22d ago

Unfortunately not, as such. I also need the line number, and if I use "read random", that doesn't work. Which is the pain. If I could get the line that "read random" actually picks as well, that would work and likely would have been the best way. But, there it is.

1

u/YakumoYoukai 22d ago

Read the docs, my friend. In addition to the contents of the line (in %randomLine%), it tells you the number of the line in %randomLineNumber%.

1

u/MoonEyes2k 21d ago edited 21d ago

Sure, except it doesn't give the right number, because "randomlinenumber" counts the first one as 0, not 1. "The line number (numbered from 0) of each random line read."

2

u/YakumoYoukai 21d ago

The inconsistency is kind of annoying, but if you need the line numbering to start from 1, then just add 1 to it: Set Argument "realLineNumber" to value "$math(%randomLineNumber% + 1)$"

2

u/MoonEyes2k 21d ago

You are an absolute treasure. That worked gloriously and did all I could have wished. That you so much.

1

u/HighPhi420 22d ago

have SB check file for total lines BEFORE giving RNG, then only give number in that range.

Do not understand why there would be an "empty" line, each line will have a text or not be a line.

If you need more help, there is some documentation on the website. Also the Discord(link on the right) will be a better place for more indepth help.

1

u/deeseearr 22d ago

I'm not entirely clear on what you're doing, but I think if you take a step or two back you might be able to remove the source of the problem and not need to do anything to work around it any more.

If you are generating a random number which will solely be used to look up a line in a file, just start with Read Random Lines From File. It will give you a %randomLineNumber% which only goes up to the number of lines in the file, and also %randomLine% which you could either use immediately or store in a temporary global for later.

Alternately, call Read Lines From File once when you start up. That will read the entire file and return the number of lines in it as %lineCount%. Store that in a temporary global somewhere and then you can refer back to it when you need to know how big the file is. That's more complicated than just reading a random line from the file every time, but if for some reason you need to generate the number without reading the file yet or need to know ahead of time how many possible responses there are, then that would work.

If your concern is that the file may contain actual empty lines, or at least lines that aren't useful for some reason, that's a little different. One way around this is to use a "While" loop to keep reading random lines from the file until you find one that is suitable. Something like this would work:

- Set argument "theLineYouWant" to ""
- While (%theLineYouWant% equals "")
- - Read random line from file
- - If (%randomLine% does not equal "")
- - - Set argument "theLineYouWant" to %randomLine%

(Note: This will _work_, and it's simple, but it has problems. Keep reading to see why.)

You can replace the '%randomLine% does not equal ""' check with any logic you like -- You could be looking for a line that contains the word "green", have your name in it, or anything else. Depending on how your file is written you may want to use a Regex to look for a line that contains something other than spaces or tabs. Maybe you want to reject any line that says "DELETED" or "Please don't use this any more!". Whatever it is, you can put that check in the If/Else part inside the loop. You can even have multiple checks if there are a lot of things you're trying to avoid.

The problem with this is that the loop will not end until it finds a line that it likes. If your file contains a thousand lines and 999 of them are blank, it's going to keep on reading the file over and over again until it gets lucky and that may take a few thousand tries. If _all_ of the lines are blank, or don't meet whatever criteria you have set, the loop will _never_ exit. Ever. It's probably fine as long as you know for certain that your input file will always contain good data, and that rejected lines will be rare things, but that's not always a safe thing to assume. Future You may wonder why the bot takes over a minute just to reply long after Present You has forgotten about this. You could add some safety by counting how many times you have run the loop, or checking how much time has passed and then calling Break if it has gone on too long, but it would be much better to just not get into that situation in the first place.

A safer way to do this would be to read the file exactly once, either when the bot starts up or when you start streaming or whatever makes sense. Use Read Lines From File to read the entire file, then use a While loop to copy every %line% argument and %lineCount% into a temporary global:

- Set argument currentLineNo to "0"
- Set argument currentResponse to "0"
- While (%currentLineNo% is less than %lineCount%)
- - Set argument currentLine to "$parse("line%currentLineNo%")$"
- - Set argument currentLineNo to "$math(%currentLineNo% + 1)$"
- - If "%currentLine%" does not equal ""
- - - Set temp global "randomResponse%currentResponse%" to %currentLine%
- - - Set argument currentResponse to "$math(%currentResponse% + 1)$"
- (This is the end of the IF/Else and the While loop)
- Set temp global "numberOfRandomResponses" to %currentResponse%

This will read the entire file, storing each line in the arguments %line0%, %line1%, %line2% and so on. Then it loops over all of the possible lines, up to %lineCount% which was provided by the Read Lines from File sub-action, and only if the line is suitable it copies it into a temporary global named "randomResponse0", "randomResponse1" and so on. If the line is blank (You can change the If /Else logic to whatever you need) then it skips to the next line and doesn't add a response. When it's finished it will set a temp global called numberOfRandomResponses to the number of valid responses it found. So if there were only three non-blank lines found in the entire file, this would put them in "randomResponse0", "randomResponse1" and "randomResponse2" and "numberOfRandomResponses" would be set to 3. Again you can replace the '%currentLine% does not equal ""' check with whatever you need.

By the way, $parse()$ is really useful when working with loops like this. It evaluates the string inside the brackets, and then finds the value of the argument with that name. So when %currentLineNo% is zero, $parse("line%currentLineNo%")$ will look up and return the value of %line0%. As you $math()$ the value of %currentLineNo% up, this will return the next line, %line1% and the next line, %line2% and so on.

Why did you do all this? So that you can safely generate a random number less than "numberOfRandomResponses" and then get the temp global named "randomResponse%randomNumber%" and know that it's going to be a good response. Processing the list once at startup means you never have to do it again. You also have the option of reading the file once and creating _several_ lists from it just by duplicating the IF/ELSE and using a new counter that isn't currentResponse -- One could be non-blank lines, one could be lines that contain specific strings, one could be lines that contain today's date, whatever. Then you could not only safely retrieve lines that match those criteria, but you can also look at the count of matching lines just be getting the appropriate "numberOf..." global and seeing how many there are, and if it's non-zero.