Add Twitter integration

Add Job Listening Integration
Various Refactorings
This commit is contained in:
Wieland Schöbl
2021-05-28 22:09:32 +02:00
parent fa00466eb0
commit f23a4d9ce5
12 changed files with 271 additions and 113 deletions

124
.idea/uiDesigner.xml generated Normal file
View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

50
.idea/workspace.xml generated
View File

@@ -4,12 +4,23 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="1aabf22b-2f57-46ac-9973-367d8668ffd3" name="Default Changelist" comment="Update stuff">
<list default="true" id="1aabf22b-2f57-46ac-9973-367d8668ffd3" name="Default Changelist" comment="Add shards count configuration">
<change afterPath="$PROJECT_DIR$/.idea/uiDesigner.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/web/Parser.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/AdminCli.kt" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/AdminCli.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/DataIO.kt" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/DataIO.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/Main.kt" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/Main.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/extensions/Jsoup.kt" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/extensions/Jsoup.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/model/BlogPostPreview.kt" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/model/BlogPostPreview.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/model/JobListingPreview.kt" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/model/JobListingPreview.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/web/BlogPostParser.kt" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/web/JobListingParser.kt" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/web/SiteWatcher.kt" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/web/SiteWatcher.kt" afterDir="false" />
</list>
<list id="44283a45-f406-407f-bce2-a31bb9bfc0cc" name="Changes by Valentin" comment="">
<change beforePath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/Channels.kt" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/kotlin/de/wulkanat/Channels.kt" afterDir="false" />
</list>
<list id="44283a45-f406-407f-bce2-a31bb9bfc0cc" name="Changes by Valentin" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@@ -43,10 +54,10 @@
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Class" />
<option value="Kotlin Class" />
<option value="Kotlin Object" />
<option value="Kotlin File" />
<option value="Class" />
</list>
</option>
</component>
@@ -58,6 +69,14 @@
</option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="GitSEFilterConfiguration">
<file-type-list>
<filtered-out-file-type name="LOCAL_BRANCH" />
<filtered-out-file-type name="REMOTE_BRANCH" />
<filtered-out-file-type name="TAG" />
<filtered-out-file-type name="COMMIT_BY_MESSAGE" />
</file-type-list>
</component>
<component name="HighlightingSettingsPerFile">
<setting file="file://$PROJECT_DIR$/build.gradle" root0="SKIP_INSPECTION" />
</component>
@@ -78,14 +97,18 @@
<property name="aspect.path.notification.shown" value="true" />
<property name="codeWithMe.voiceChat.enabledByDefault" value="false" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="node.js.detected.package.eslint" value="true" />
<property name="node.js.detected.package.tslint" value="true" />
<property name="node.js.selected.package.eslint" value="(autodetect)" />
<property name="node.js.selected.package.tslint" value="(autodetect)" />
<property name="project.structure.last.edited" value="Project" />
<property name="project.structure.proportion" value="0.15" />
<property name="project.structure.side.proportion" value="0.2" />
<property name="settings.editor.selected.configurable" value="preferences.pluginManager" />
</component>
<component name="RecentsManager">
<key name="MoveKotlinTopLevelDeclarationsDialog.RECENTS_KEY">
<recent name="de.wulkanat" />
<key name="CreateClassDialog.RecentsKey">
<recent name="org.hmcore" />
</key>
<key name="CopyFile.RECENT_KEYS">
<recent name="E:\Projects\Kotlin_Proj\HytaleUpdateBot\build\libs" />
@@ -95,6 +118,9 @@
<recent name="E:\Projects\Kotlin_Proj\HytaleUpdateBot" />
<recent name="E:\Projects\Kotlin_Proj\HytaleUpdateBot\src\main\kotlin\de\wulkanat" />
</key>
<key name="MoveKotlinTopLevelDeclarationsDialog.RECENTS_KEY">
<recent name="de.wulkanat" />
</key>
</component>
<component name="RunManager" selected="Kotlin.Main">
<configuration default="true" type="ArquillianJUnit" factoryName="" nameIsGenerated="true">
@@ -203,7 +229,7 @@
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1597322033373</updated>
<workItem from="1622225780094" duration="598000" />
<workItem from="1622225780094" duration="6687000" />
</task>
<task id="LOCAL-00001" summary="Add auto publish feature">
<created>1597437833375</created>
@@ -254,7 +280,14 @@
<option name="project" value="LOCAL" />
<updated>1622224992757</updated>
</task>
<option name="localTasksCounter" value="8" />
<task id="LOCAL-00008" summary="Add shards count configuration">
<created>1622226400158</created>
<option name="number" value="00008" />
<option name="presentableId" value="LOCAL-00008" />
<option name="project" value="LOCAL" />
<updated>1622226400158</updated>
</task>
<option name="localTasksCounter" value="9" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@@ -280,7 +313,8 @@
<MESSAGE value="prepare twitter integration" />
<MESSAGE value="Update Json Serialization" />
<MESSAGE value="Update stuff" />
<option name="LAST_COMMIT_MESSAGE" value="Update stuff" />
<MESSAGE value="Add shards count configuration" />
<option name="LAST_COMMIT_MESSAGE" value="Add shards count configuration" />
</component>
<component name="XDebuggerManager">
<watches-manager>

View File

@@ -1,8 +1,7 @@
package de.wulkanat
import de.wulkanat.model.BlogPostPreview
import de.wulkanat.web.fakeUpdateBlogPost
import net.dv8tion.jda.api.hooks.ListenerAdapter
import de.wulkanat.web.SiteWatcher
import net.dv8tion.jda.api.EmbedBuilder
import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent
import org.hmcore.TwitterJob
@@ -24,14 +23,9 @@ class AdminCli : ListenerAdapter() {
when (command[0].value) {
"stop" -> exitProcess(1)
"fakeUpdate" -> {
SiteWatcher.newestBlog = BlogPostPreview(
title = "FakePost",
imgUrl = "",
fullPostUrl = "",
author = "wulkanat",
date = "now",
description = "Lorem Ipsum"
)
// TODO: implement fake update for blog posts
// BLOG_POST_WATCHER.current = setOf()
fakeUpdateBlogPost()
TwitterJob.lastTweetID = "poggers"

View File

@@ -2,7 +2,11 @@
package de.wulkanat
import de.wulkanat.extensions.ensureExists
import de.wulkanat.model.BlogPostPreview
import de.wulkanat.model.JobListingPreview
import kotlinx.serialization.Required
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.io.File
@@ -28,23 +32,32 @@ data class CustomMessage(
@Serializable
data class AdminFile(
val adminId: Long = 12345,
val token: String = "12345",
val updateMs: Long = 30000,
val shards: Int = 6,
val watchingMessage: String = "for new Blogposts",
val offlineMessage: String = "CONNECTION FAILED",
var twitterApi: TwitterApi? = TwitterApi()
@Required val adminId: Long = 12345,
@Required val token: String = "12345",
@Required val updateMs: Long = 30000,
@Required val shards: Int = 6,
@Required val watchingMessage: String = "for new Blogposts",
@Required val offlineMessage: String = "CONNECTION FAILED",
@Required var twitterApi: TwitterApi? = TwitterApi()
)
@Serializable
data class TwitterApi(
val accessToken: String = "accessTokenHere",
val accessTokenSecret: String = "accessTokenSecretHere",
val apiKey: String = "apiKeyHere",
val apiKeySecret: String = "Api Key secret here"
@Required val accessToken: String = "accessTokenHere",
@Required val accessTokenSecret: String = "accessTokenSecretHere",
@Required val apiKey: String = "apiKeyHere",
@Required val apiKeySecret: String = "Api Key secret here"
)
@Serializable
data class Webhooks(
@Required val blogPostsWebhookUrl: String = "https://...",
@Required val jobListingsWebhookUrl: String = "https://...",
)
val WEBHOOKS_FILE = File("webhooks.json").ensureExists(Json.encodeToString(Webhooks()))
val WEBHOOKS = Json.decodeFromString<Webhooks>(WEBHOOKS_FILE.readText())
val SERVERS_FILE = File("servers.json").ensureExists(Json.encodeToString(listOf<DiscordChannel>()))
val SERVICE_CHANNELS_FILE =
File("service_channels.json").ensureExists(Json.encodeToString(listOf<ServiceChannel>()))

View File

@@ -1,6 +1,6 @@
package de.wulkanat
import de.wulkanat.web.SiteWatcher
import de.wulkanat.web.getNewBlogPosts
import net.dv8tion.jda.api.JDA
import net.dv8tion.jda.api.JDABuilder
import net.dv8tion.jda.api.MessageBuilder
@@ -59,8 +59,8 @@ object Main {
})
timer("Updater", daemon = true, initialDelay = 0L, period = Admin.updateMs) {
if (SiteWatcher.hasNewBlogPost()) {
Channels.sentToAll(MessageBuilder().setEmbed(SiteWatcher.newestBlog!!.toMessageEmbed()).build())
getNewBlogPosts()?.forEach {
Channels.sentToAll(MessageBuilder().setEmbed(it.toMessageEmbed()).build())
}
}

View File

@@ -7,4 +7,5 @@ operator fun Element.get(className: String): Elements =
this.getElementsByClass(className)
val Elements.text get() = text().trim()
val Element.absUrl get(): String = child(0).absUrl("href")
val Element.absUrl get(): String = child(0).absUrl("href")
val Element.imgSrc get(): String = child(0).attr("src")

View File

@@ -3,7 +3,9 @@ package de.wulkanat.model
import net.dv8tion.jda.api.EmbedBuilder
import net.dv8tion.jda.api.entities.MessageEmbed
import de.wulkanat.extensions.hex2Rgb
import kotlinx.serialization.Serializable
@Serializable
data class BlogPostPreview(
val title: String,
val description: String,

View File

@@ -1,10 +1,12 @@
package de.wulkanat.model
import de.wulkanat.extensions.hex2Rgb
import kotlinx.serialization.Serializable
import net.dv8tion.jda.api.EmbedBuilder
import net.dv8tion.jda.api.entities.MessageEmbed
class JobListingPreview(
@Serializable
data class JobListingPreview(
val title: String,
val department: String,
val location: String,

View File

@@ -1,24 +0,0 @@
package de.wulkanat.web
import de.wulkanat.model.BlogPostPreview
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
object BlogPostParser {
fun getFistBlog(doc: Document): BlogPostPreview {
val posts = doc.getElementsByClass("postWrapper")
return parseBlog(posts.first())
}
private fun parseBlog(elm: Element): BlogPostPreview {
return BlogPostPreview(
title = elm.getElementsByClass("post__details__heading").first().text(),
imgUrl = elm.getElementsByClass("post__image__frame").first().child(0).attr("src"),
fullPostUrl = elm.child(0).absUrl("href"),
date = elm.getElementsByClass("post__details__meta__date").first().text(),
author = elm.getElementsByClass("post__details__meta__author").first().text(),
description = elm.getElementsByClass("post__details__body").first().text()
)
}
}

View File

@@ -1,21 +0,0 @@
package de.wulkanat.web
import de.wulkanat.extensions.get
import de.wulkanat.extensions.text
import de.wulkanat.extensions.absUrl
import de.wulkanat.model.JobListingPreview
import org.jsoup.nodes.Document
fun parseJobListings(doc: Document) =
doc["current-jobs__departments"].flatMap { jobDepartment ->
val jobDepartmentName = jobDepartment["current-jobs__department-name"].text
jobDepartment["current-jobs__job"].map { job ->
JobListingPreview(
title = job["current-jobs__job-title"].text,
department = jobDepartmentName,
location = job["current-jobs__job-location"].text,
fullListingUrl = job.absUrl
)
}
}

View File

@@ -0,0 +1,40 @@
package de.wulkanat.web
import de.wulkanat.extensions.absUrl
import de.wulkanat.extensions.get
import de.wulkanat.extensions.imgSrc
import de.wulkanat.extensions.text
import de.wulkanat.model.BlogPostPreview
import de.wulkanat.model.JobListingPreview
private const val BLOG_POST_STATE_FILE_NAME = "blog_state.json"
fun fakeUpdateBlogPost() = removeFirstFromSiteSave<BlogPostPreview>(BLOG_POST_STATE_FILE_NAME)
fun getNewBlogPosts() = updateSite("https://hytale.com/news", BLOG_POST_STATE_FILE_NAME) { doc ->
doc["postWrapper"].map {
BlogPostPreview(
title = it["post__details__heading"].text,
imgUrl = it["post__image__frame"].first().imgSrc,
fullPostUrl = it.absUrl,
date = it["post__details__meta__date"].text,
author = it["post__details__meta__author"].text,
description = it["post__details__body"].text,
)
}
}
private const val JOB_LISTING_STATE_FILE_NAME = "jobs_state.json"
fun fakeUpdateJobListings() = removeFirstFromSiteSave<JobListingPreview>(JOB_LISTING_STATE_FILE_NAME)
fun getNewJobListings() = updateSite("https://hypixelstudios.com/jobs/", JOB_LISTING_STATE_FILE_NAME) { doc ->
doc["current-jobs__departments"].flatMap { jobDepartment ->
val jobDepartmentName = jobDepartment["current-jobs__department-name"].text
jobDepartment["current-jobs__job"].map { job ->
JobListingPreview(
title = job["current-jobs__job-title"].text,
department = jobDepartmentName,
location = job["current-jobs__job-location"].text,
fullListingUrl = job.absUrl
)
}
}
}

View File

@@ -1,44 +1,37 @@
package de.wulkanat.web
import de.wulkanat.Admin
import de.wulkanat.DiscordRpc
import de.wulkanat.model.BlogPostPreview
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import java.io.File
import java.io.IOException
object SiteWatcher {
private const val BLOG_INDEX_URL = "https://www.hytale.com/news"
var newestBlog: BlogPostPreview? = null
private var siteOnline = false
/**
* Removes the first element of a saved JSON list file
*/
inline fun <reified T>
removeFirstFromSiteSave(fileName: String) = File(fileName).takeIf { it.exists() }?.let {
it.writeText(Json.encodeToString(Json.decodeFromString<List<T>>(it.readText()).toMutableList().apply { removeFirst() }))
}
fun hasNewBlogPost(): Boolean {
try {
val doc = Jsoup.connect(BLOG_INDEX_URL).get()
val newBlog = BlogPostParser.getFistBlog(doc)
inline fun <reified T> updateSite(url: String, fileName: String, parser: (Document) -> List<T>) = try {
val currentStateFile = File(fileName)
if (newestBlog == newBlog) {
return false
}
val retrievedElements = parser(Jsoup.connect(url).get())
var currentElements = if (currentStateFile.exists())
Json.decodeFromString(currentStateFile.readText()) else retrievedElements
if (newestBlog == null) {
newestBlog = newBlog
return false
} else {
newestBlog = newBlog
}
} catch (e: IOException) {
Admin.error("Connection to Hytale Server failed", e.message ?: e.localizedMessage)
siteOnline = false
DiscordRpc.updatePresence(siteOnline)
val newElements = retrievedElements - currentElements
currentElements = retrievedElements
currentStateFile.writeText(Json.encodeToString(currentElements))
return false
}
newElements
} catch (e: IOException) {
// TODO: put this somewhere else
// Admin.error("""Fetching "$url" failed!""", e.message ?: e.localizedMessage)
// DiscordRpc.updatePresence(canUpdate.also { canUpdate = false })
if (!siteOnline) {
siteOnline = true
DiscordRpc.updatePresence(siteOnline)
}
return true
}
}
null
}