NHLGames icon indicating copy to clipboard operation
NHLGames copied to clipboard

Ad skip module for replays based on AdDetection

Open tomasjanak opened this issue 6 years ago • 4 comments

Hi, I would like to create an AdDetection module that would automatically skip the ad in case it is skip-able, that is when I am watching a replay, so that I don't have to get up from the sofa OR buy a remote control for my PC. I am a coder myself, but I have no experience with either VB or this application, so I would like to ask for help with how to implement it (or explanation of why it is not as easy as it looks on the first sight). Of course, if somebody from your team just wants to do it themselves, please go ahead :)

So after reviewing the AdDetection.vb and related code, my idea is simple: when the beginning of an ad is detected, skip the stream ahead by some small amount of time (10s-1min), then again check if there is still an ad playing (IsAdCurrentlyPlaying()) and do it until there is no ad playing.

How to do that (TL/DR at the bottom): I checked the Spotify module and if I understand correctly, it uses SendKeys to actually simulate key presses, so if there isn't any "cleaner" way to do it, it could even work that way, i.e. for example SendKeys(up) for the mpv player (which moves the stream 1 minute ahead), or other keys for other players (user might have to be required to fill in the correct key in the settings GUI). However, I would prefer if there was some way to directly send some seek(time) signal to the player and use smaller than 1 minute chunks to avoid missing some portion of the first minute of play (I think 10s skips would be fine). Another thing I am not sure how to do is how to check if it is even possible to skip, i.e. if it is a replay, so that you wouldn't have to turn off the module when watching live game. But maybe that doesn't matter - if it can't skip, it will just attempt to skip and it will do nothing anyway? Will try manually when there is a live stream on.

In terms of actual implementation, one issue I see is that the current IAdModule interface only has AdStarted and AdEnded events, but this skipping module would require some modification to the main loop of AdDetection. I can think of the following, let me know which you find the most agreeable:

  • Add an "AdRunning" event, which is triggered in the main loop (the AdDetection::LoopForever()) by If newAdPlayingState And previousAdPlayingState Then .... The currently existing modules could implement this by empty functions, I think it shouldn't cause any noticable performance issues (but I could be wrong).

  • AdStarted would perform the skips in a while(IsAdCurrentlyPlaying()) loop. This would require the IsAdCurrentlyPlaying function to be somehow available in the module. Honestly, this does not look like a very clean design to me, but it would get the job done.

  • Have the skipping not as a module, but rather a core functionality of AdDetection and do the whole skipping directly inside AdDetection::LoopForever(). Benefit of this is that it could cleanly bypass the Await Task.Delay(PollPeriodMilliseconds) for fastest possible skipping.

To sum up my main questions:

  • What is the best way to send a "seek" command to the video player from an AdDetection module? Is SendKeys good/reliable enough?

  • How to detect that the stream is in a "replay mode", i.e. that it is possible to skip ahead? Alternatively, does issuing the seek command when it is not possible to skip (when it is live) have any repercussions (because if not, we don't care about trying to skip)?

tomasjanak avatar Apr 29 '19 20:04 tomasjanak

Add an "AdRunning" event

no need for that, the module can handle the loop on its side until adEnded is called

Have the skipping not as a module

it can be a module

What is the best way to send a "seek" command to the video player

all players support >, sendKey is good enough

How to detect that the stream is in a "replay mode"

Access settings

if somebody from your team just wants to do it themselves

i had already looked at it a bit, and i have a module that skips at the right time. but since we want it to skip fast, adDetection won't have time to listen to the feed to know if the game started, because it fetchs for we don't know how long. even if we process with an image analyzer to see if the NHL commercial break is in progress is still visible and listen to the sound of the feed, it won't be enough, you actually don't know if the image is stuck and it has no sound because it's still fetching, fetching can be infinite. So when do you press > again ? may be hard, but possible

For debugging: I simulated the fetching with a thread.sleep of 3 secs and it's still not enough sometimes, so why skipping 10 secs to wait 3secs, may need to skip 30 secs instead and have a chance to miss a bit (NHL documentation says that their commercial goes from 30 secs to 15 minutes)

jwallet avatar May 01 '19 03:05 jwallet

i had already looked at it a bit, and i have a module that skips at the right time. but since we want it to skip fast, adDetection won't have time to listen to the feed to know if the game started, because it fetchs for we don't know how long. even if we process with an image analyzer to see if the NHL commercial break is in progress is still visible and listen to the sound of the feed, it won't be enough, you actually don't know if the image is stuck and it has no sound because it's still fetching, fetching can be infinite. So when do you press > again ? may be hard, but possible

I was just thinking about that yesterday when I played with it "manually"...thanks for confirming my fears. Yes, if it needs to wait 3-4s to skip even 30s bits, it's not worth it. I have one idea, but it's a wild one: when ad is detected, pause the stream, seek for the right amount of time to skip in a different stream which runs in the lowest bit-rate possible (audio only?) in the background, then move the "main" stream by the right time (press > the correct amount of times) and unpause. But a) not sure if it would help all that much, i.e. don't know what's the "fastest" stream we can get b) it would have to somehow run in parallel with the "main" stream almost perfectly in sync and on mute (at least when it is not used for the detection).

Regardless, for detecting whether it's is stuck or not, we could compare two images couple frames apart from each other - since the "NHL" logo is animated in those, if the image is exactly the same = it is still fetching, if not = commercial break still in progress. But again, this adds some delay...

tomasjanak avatar May 01 '19 08:05 tomasjanak

the module that i did yesterday can be completed by adding an image analyzer that take screenshots every second, and compare between them, once one differ from each other, it means the playback runs, if the image looks like an ad we can skip otherwise the game has started, but i think it won't work with mpv since it adds a progress bar right in the middle of the screen. and an image analyzer can be so tricky some times and not properly works, i can already imagine the module having a deadlock in a loop and can't stop skipping to a next segment

right amount of time to skip in a different stream which runs in the lowest bit-rate possible (audio only?) in the background

it will be way harder to get it right than an image analyzer ( i think)

jwallet avatar May 01 '19 14:05 jwallet

Ad breaks are ALWAYS 2 minutes long. In between intermissions (from the time of the buzzer to the next faceoff is usually about 19 minutes 30 seconds). Not sure how to handle that one automatically though since they don't always go to an ad, and those breaks aren't easy to differentiate between normal breaks.

scottismyname avatar Nov 08 '19 00:11 scottismyname