Newer
Older
Twilight / src / main / kotlin / net / taehui / twilight / system / TVSystem.kt
@Taehui Taehui on 16 Dec 3 KB v1.0-SNAPSHOT
package net.taehui.twilight.system

import net.taehui.twilight.Logger
import org.openqa.selenium.By
import org.openqa.selenium.TimeoutException
import org.openqa.selenium.WebDriver
import org.openqa.selenium.edge.EdgeDriver
import org.openqa.selenium.edge.EdgeOptions
import org.openqa.selenium.support.ui.ExpectedConditions
import org.openqa.selenium.support.ui.WebDriverWait
import java.time.Duration
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit

object TVSystem : Logger {
    class TVItem(val href: String, val title: String, val text: String) {
        override fun hashCode(): Int {
            return href.hashCode()
        }

        override fun equals(other: Any?): Boolean {
            return href == (other as TVItem).href
        }

        override fun toString(): String {
            return text
        }
    }

    private val ses: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor {
        Executors.defaultThreadFactory().newThread(it).apply {
            isDaemon = true
        }
    }
    private var tv: WebDriver? = null
    private var future: ScheduledFuture<*>? = null

    fun handleSystem() {
        if (tv != null) {
            logInfo("TV is already running")
        } else if (Configure.mode.tv) {
            try {
                tv = EdgeDriver(EdgeOptions().apply {
                    addArguments("--headless", "--no-sandbox")
                })
                val pendingElements = mutableMapOf<TVItem, Int>()
                var lastElements = emptySet<TVItem>()

                future = ses.scheduleWithFixedDelay({
                    tv?.let { it ->
                        it.get("https://www.twitch.tv/directory/game/Qwilight")
                        val dataTest = By.cssSelector("[data-test-selector=TitleAndChannel]")
                        val elements = try {
                            WebDriverWait(
                                it,
                                Duration.ofSeconds(1)
                            ).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(dataTest))
                            it.findElements(dataTest) ?: throw TimeoutException()
                        } catch (e: TimeoutException) {
                            emptyList()
                        }.map { element ->
                            TVItem(
                                element.getAttribute("href"),
                                element.findElement(By.tagName("h3")).text,
                                element.findElement(By.tagName("p")).text
                            )
                        }.toSet()
                        elements.subtract(lastElements).filter {
                            pendingElements.remove(it) == null
                        }.forEach {
                            SiteHandler.putSiteYell(it)
                        }
                        lastElements.subtract(elements).forEach {
                            pendingElements[it] = 0
                        }
                        pendingElements.toMap().forEach {
                            if (it.value < 5) {
                                pendingElements[it.key] = it.value + 1
                            } else {
                                pendingElements.remove(it.key)
                            }
                        }
                        lastElements = elements
                    }
                }, 0L, 1L, TimeUnit.MINUTES)
            } catch (e: Throwable) {
                logFault(e)
            }
        } else {
            logInfo("TV is disabled")
        }
    }

    val tvStatus: String
        get() = "{Title: ${tv?.title}, Page: ${tv?.pageSource}, URL: ${tv?.currentUrl}, Handles: [${tv?.windowHandles?.joinToString()}]}"

    fun dispose() {
        future?.cancel(false)
        tv?.quit()
        tv = null
    }
}