Compare commits

...

10 commits

Author SHA1 Message Date
8f58b5b6e6 chore: bump version
Signed-off-by: moonleay <contact@moonleay.net>
2023-10-15 15:46:40 +02:00
5d14fa9a35 feat: added SendFeedExtension, CleanUpExtension
Signed-off-by: moonleay <contact@moonleay.net>
2023-10-15 15:46:26 +02:00
0e2e3c8022 feat: improved FeedUpdater message
Signed-off-by: moonleay <contact@moonleay.net>
2023-10-15 15:46:04 +02:00
d60b7ba92f feat!: removed unused funcs, added getUnixTimeFromStamp
Signed-off-by: moonleay <contact@moonleay.net>
2023-10-15 15:30:37 +02:00
0c7f51ba72 feat: improved RSSEmbed
Signed-off-by: moonleay <contact@moonleay.net>
2023-10-15 15:27:20 +02:00
e4a593b7d3 feat: added getHTMLtoMarkdownOptions func
Signed-off-by: moonleay <contact@moonleay.net>
2023-10-15 15:23:41 +02:00
9468efa10d fix: added Subscription timestamp 2023-10-15 15:22:32 +02:00
f217e4ff07 feat: added SendFeedExtension 2023-10-15 15:18:02 +02:00
39802598b2 feat: added CleanUpExtension 2023-10-15 15:17:53 +02:00
63e1d5b283 feat!: added subscriptionTimestamp to SubscriptionsTable 2023-10-15 15:17:15 +02:00
12 changed files with 201 additions and 52 deletions

View file

@ -14,7 +14,7 @@ val ownerID = 372703841151614976L
group = "net.moonleay.rssbot" group = "net.moonleay.rssbot"
version = System.getenv("CI_COMMIT_TAG")?.let { "$it-${System.getenv("CI_COMMIT_SHORT_SHA")}-prod" } version = System.getenv("CI_COMMIT_TAG")?.let { "$it-${System.getenv("CI_COMMIT_SHORT_SHA")}-prod" }
?: System.getenv("CI_COMMIT_SHORT_SHA")?.let { "$it-dev" } ?: System.getenv("CI_COMMIT_SHORT_SHA")?.let { "$it-dev" }
?: "0.2.1" ?: "0.3.0"
val kordver = "1.5.10-SNAPSHOT" val kordver = "1.5.10-SNAPSHOT"
val coroutinesver = "1.7.3" val coroutinesver = "1.7.3"
@ -67,6 +67,9 @@ dependencies {
//rss //rss
shadow("com.prof18.rssparser:rssparser:$rssparserver") shadow("com.prof18.rssparser:rssparser:$rssparserver")
// html to markdown
shadow("com.kotcrab.remark:remark:1.2.0")
} }

View file

@ -24,9 +24,7 @@ import dev.kord.core.event.gateway.ReadyEvent
import dev.kord.core.on import dev.kord.core.on
import net.moonleay.rssbot.data.CredentialManager import net.moonleay.rssbot.data.CredentialManager
import net.moonleay.rssbot.data.database.DB import net.moonleay.rssbot.data.database.DB
import net.moonleay.rssbot.extensions.FeedExtension import net.moonleay.rssbot.extensions.*
import net.moonleay.rssbot.extensions.FeedsExtension
import net.moonleay.rssbot.extensions.StuffExtension
import net.moonleay.rssbot.jobs.FeedUpdater import net.moonleay.rssbot.jobs.FeedUpdater
import net.moonleay.rssbot.jobs.component.JobManager import net.moonleay.rssbot.jobs.component.JobManager
import net.moonleay.rssbot.util.Logger import net.moonleay.rssbot.util.Logger
@ -77,6 +75,8 @@ object Bot {
add(::FeedExtension) add(::FeedExtension)
add(::StuffExtension) add(::StuffExtension)
add(::FeedsExtension) add(::FeedsExtension)
add(::SendFeedExtension)
add(::CleanUpExtension)
} }
this.presence { this.presence {

View file

@ -27,4 +27,5 @@ data class SubscriptionData(
val feedColor: FeedColor, val feedColor: FeedColor,
val feedName: String, val feedName: String,
val feedUrl: String, val feedUrl: String,
val subscriptionTimestamp: Long,
) )

View file

@ -38,7 +38,8 @@ object SubscriptionRepository {
it[SubscriptionsTable.channelId], it[SubscriptionsTable.channelId],
EmbedUtil.getColorFromString(it[SubscriptionsTable.subscriptionColor]), EmbedUtil.getColorFromString(it[SubscriptionsTable.subscriptionColor]),
it[SubscriptionsTable.subscriptionName], it[SubscriptionsTable.subscriptionName],
it[SubscriptionsTable.feedUrl] it[SubscriptionsTable.feedUrl],
it[SubscriptionsTable.subscriptionTimestamp]
) )
) )
} }
@ -59,7 +60,8 @@ object SubscriptionRepository {
it[SubscriptionsTable.channelId], it[SubscriptionsTable.channelId],
EmbedUtil.getColorFromString(it[SubscriptionsTable.subscriptionColor]), EmbedUtil.getColorFromString(it[SubscriptionsTable.subscriptionColor]),
it[SubscriptionsTable.subscriptionName], it[SubscriptionsTable.subscriptionName],
it[SubscriptionsTable.feedUrl] it[SubscriptionsTable.feedUrl],
it[SubscriptionsTable.subscriptionTimestamp]
) )
) )
} }
@ -80,7 +82,8 @@ object SubscriptionRepository {
it[SubscriptionsTable.channelId], it[SubscriptionsTable.channelId],
EmbedUtil.getColorFromString(it[SubscriptionsTable.subscriptionColor]), EmbedUtil.getColorFromString(it[SubscriptionsTable.subscriptionColor]),
it[SubscriptionsTable.subscriptionName], it[SubscriptionsTable.subscriptionName],
it[SubscriptionsTable.feedUrl] it[SubscriptionsTable.feedUrl],
it[SubscriptionsTable.subscriptionTimestamp]
) )
} }
} }
@ -115,6 +118,7 @@ object SubscriptionRepository {
it[subscriptionColor] = data.feedColor.readableName it[subscriptionColor] = data.feedColor.readableName
it[subscriptionName] = data.feedName it[subscriptionName] = data.feedName
it[feedUrl] = data.feedUrl it[feedUrl] = data.feedUrl
it[subscriptionTimestamp] = data.subscriptionTimestamp
} }
} }

View file

@ -28,4 +28,5 @@ object SubscriptionsTable : Table(name = "subscriptions") {
val subscriptionColor = text("subscription_color") val subscriptionColor = text("subscription_color")
val subscriptionName = text("subscription_name") val subscriptionName = text("subscription_name")
val feedUrl = text("feed_url") val feedUrl = text("feed_url")
val subscriptionTimestamp = long("subscription_timestamp")
} }

View file

@ -0,0 +1,39 @@
package net.moonleay.rssbot.extensions
import com.kotlindiscord.kord.extensions.extensions.Extension
import com.kotlindiscord.kord.extensions.extensions.ephemeralSlashCommand
import com.kotlindiscord.kord.extensions.types.respond
import kotlinx.coroutines.flow.filter
import net.moonleay.rssbot.Bot
import net.moonleay.rssbot.data.database.repository.SubscriptionRepository
import net.moonleay.rssbot.util.EmbedColor
import net.moonleay.rssbot.util.MessageUtil
class CleanUpExtension : Extension() {
override val name = "cleanup"
override val allowApplicationCommandInDMs: Boolean
get() = false
override suspend fun setup() {
ephemeralSlashCommand() {
name = "cleanup"
description = "Clean all messages from this bot in this channel"
this.action {
val user = this.user.asUser()
this.channel.messages.filter { it.author?.id == Bot.bot.kordRef.selfId }.collect { it.delete() }
this.respond {
this.embeds.add(
MessageUtil.getEmbed(
EmbedColor.INFO,
"Cleaned up",
"Cleaned up all messages from this bot in this channel",
user.username
)
)
}
}
}
}
}

View file

@ -106,7 +106,8 @@ class FeedExtension : Extension() {
this.channel.id.value.toLong(), this.channel.id.value.toLong(),
feedColor, feedColor,
feedName, feedName,
feedUrl feedUrl,
System.currentTimeMillis()
) )
) )
Logger.out("added feed as id ${id.resultedValues!!.first()[SubscriptionsTable.id]}") Logger.out("added feed as id ${id.resultedValues!!.first()[SubscriptionsTable.id]}")

View file

@ -0,0 +1,113 @@
/*
* RSSBot
* Copyright (C) 2023 moonleay
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.moonleay.rssbot.extensions
import com.kotlindiscord.kord.extensions.commands.Arguments
import com.kotlindiscord.kord.extensions.commands.converters.impl.string
import com.kotlindiscord.kord.extensions.extensions.Extension
import com.kotlindiscord.kord.extensions.extensions.ephemeralSlashCommand
import com.kotlindiscord.kord.extensions.types.respond
import com.overzealous.remark.Options
import com.overzealous.remark.Remark
import com.prof18.rssparser.RssParser
import com.prof18.rssparser.model.RssChannel
import com.prof18.rssparser.model.RssItem
import dev.kord.rest.builder.message.EmbedBuilder.Limits.title
import net.moonleay.rssbot.data.database.repository.RSSRepository
import net.moonleay.rssbot.data.database.repository.SubscriptionRepository
import net.moonleay.rssbot.extensions.components.FeedColor
import net.moonleay.rssbot.util.EmbedColor
import net.moonleay.rssbot.util.EmbedUtil
import net.moonleay.rssbot.util.MessageUtil
class SendFeedExtension : Extension() {
override val name = "sendfeed"
override val allowApplicationCommandInDMs: Boolean
get() = false
override suspend fun setup() {
ephemeralSlashCommand(::StuffArguments) {
name = "sendfeed"
description = "Send a feed to this channel"
this.action {
val feedUrl = arguments.feedUrl
val user = this.user.asUser()
if (feedUrl == null) {
this.respond {
this.embeds.add(
MessageUtil.getEmbed(
EmbedColor.ERROR,
"Missing Arguments",
"You are missing one or more arguments",
user.username
)
)
}
return@action
}
val parser = RssParser()
var rss: RssChannel? = null
runCatching { // this sucks
rss = parser.getRssChannel(feedUrl)
}.onFailure {
this.respond {
this.embeds.add(
MessageUtil.getEmbed(
EmbedColor.ERROR,
"Invalid Feed",
"The feed you provided is invalid",
user.username
)
)
}
return@action
}
if (rss == null)
return@action
rss!!.items.forEach {
this.respond {
this.embeds.add(
MessageUtil.getRSSEmbed(
FeedColor.GREEN,
it.author ?: "Anonymous",
it.title ?: "Untitled",
if (it.description == null) "No description" else Remark(EmbedUtil.getHTMLtoMarkdownOptions()).convertFragment(it.description!!),
it.link ?: "https://moonleay.net/",
it.image ?: "",
if (it.link != null) EmbedUtil.getSiteLogo(it.link!!) else "https://static.moonleay.net/img/no-image.png",
"Manual Feed",
it.pubDate?: "unknown"
)
)
}
}
}
}
}
inner class StuffArguments : Arguments() {
val feedUrl by string {
this.name = "url"
this.description = "The url of the feed to send"
}
}
}

View file

@ -18,6 +18,7 @@
package net.moonleay.rssbot.jobs package net.moonleay.rssbot.jobs
import com.overzealous.remark.Remark
import com.prof18.rssparser.RssParser import com.prof18.rssparser.RssParser
import com.prof18.rssparser.model.RssChannel import com.prof18.rssparser.model.RssChannel
import dev.inmo.krontab.KronScheduler import dev.inmo.krontab.KronScheduler
@ -35,6 +36,7 @@ import net.moonleay.rssbot.jobs.component.ICronjob
import net.moonleay.rssbot.util.EmbedUtil import net.moonleay.rssbot.util.EmbedUtil
import net.moonleay.rssbot.util.Logger import net.moonleay.rssbot.util.Logger
import net.moonleay.rssbot.util.MessageUtil import net.moonleay.rssbot.util.MessageUtil
import net.moonleay.rssbot.util.TimeUtil
object FeedUpdater : ICronjob { object FeedUpdater : ICronjob {
override val jobName: String override val jobName: String
@ -72,7 +74,13 @@ object FeedUpdater : ICronjob {
if (rss == null) if (rss == null)
continue continue
for (rssData in rss!!.items) { for (rssData in rss!!.items) {
if (rssData.guid == null || RSSRepository.exists(RSSData(rssData.guid!!, data.id))) if (rssData.guid == null || RSSRepository.exists(
RSSData(
rssData.guid!!,
data.id
)
) || TimeUtil.getUnixTimeFromStamp(rssData.pubDate!!) < data.subscriptionTimestamp
)
continue continue
val channel = Bot.bot.kordRef.getChannel(Snowflake(data.channelId))!!.asChannelOf<MessageChannel>() val channel = Bot.bot.kordRef.getChannel(Snowflake(data.channelId))!!.asChannelOf<MessageChannel>()
channel.createMessage { channel.createMessage {
@ -81,11 +89,14 @@ object FeedUpdater : ICronjob {
data.feedColor, data.feedColor,
rssData.author ?: "Anonymous", rssData.author ?: "Anonymous",
rssData.title ?: "Untitled", rssData.title ?: "Untitled",
rssData.description ?: "No description", if (rssData.description == null) "No description" else Remark(EmbedUtil.getHTMLtoMarkdownOptions()).convertFragment(
rssData.description!!
),
rssData.link ?: "https://moonleay.net/", rssData.link ?: "https://moonleay.net/",
rssData.image ?: "", rssData.image ?: "",
if (rssData.link != null) EmbedUtil.getSiteLogo(rssData.link!!) else "https://static.moonleay.net/img/no-image.png", if (rssData.link != null) EmbedUtil.getSiteLogo(rssData.link!!) else "https://static.moonleay.net/img/no-image.png",
data.feedName, "Manual Feed",
rssData.pubDate ?: "unknown"
) )
) )
} }

View file

@ -18,6 +18,8 @@
package net.moonleay.rssbot.util package net.moonleay.rssbot.util
import com.overzealous.remark.IgnoredHtmlElement
import com.overzealous.remark.Options
import dev.kord.common.entity.ButtonStyle import dev.kord.common.entity.ButtonStyle
import dev.kord.core.entity.Embed import dev.kord.core.entity.Embed
import dev.kord.rest.builder.component.ActionRowBuilder import dev.kord.rest.builder.component.ActionRowBuilder
@ -141,4 +143,11 @@ object EmbedUtil {
return "https://www.google.com/s2/favicons?domain=${str.split("/")[2]}" return "https://www.google.com/s2/favicons?domain=${str.split("/")[2]}"
} }
fun getHTMLtoMarkdownOptions(): Options {
val o = Options()
o.ignoredHtmlElements.add(IgnoredHtmlElement("img"))
o.inlineLinks = true
return o
}
} }

View file

@ -174,11 +174,12 @@ object MessageUtil {
imageUrl: String, imageUrl: String,
logo: String, logo: String,
feedName: String, feedName: String,
published: String,
): EmbedBuilder { ): EmbedBuilder {
val ebb = EmbedBuilder() val ebb = EmbedBuilder()
val now: LocalDateTime = LocalDateTime.now() val now: LocalDateTime = LocalDateTime.now()
if (title.length > 250) if (title.length > 25)
ebb.title = title.substring(0, 250) + "[...]" ebb.title = title.substring(0, 25) + "..."
else else
ebb.title = title ebb.title = title
ebb.author { ebb.author {
@ -188,7 +189,7 @@ object MessageUtil {
ebb.description = "${if (description != "No description") description else ""}\n[[open full article]]($url)" ebb.description = "${if (description != "No description") description else ""}\n[[open full article]]($url)"
ebb.color = color.color.color ebb.color = color.color.color
ebb.footer { ebb.footer {
this.text = "> rssbot, ($feedName) / sent at ${dtf.format(now)}" this.text = "> rssbot, ($feedName) \n/ pub $published \n/ rel ${dtf.format(now)}"
this.icon = "https://static.moonleay.net/img/rss.png" this.icon = "https://static.moonleay.net/img/rss.png"
} }
ebb.thumbnail { ebb.thumbnail {

View file

@ -18,47 +18,13 @@
package net.moonleay.rssbot.util package net.moonleay.rssbot.util
import kotlinx.datetime.DayOfWeek
import java.time.ZonedDateTime import java.time.ZonedDateTime
import java.util.concurrent.TimeUnit import java.time.format.DateTimeFormatter
object TimeUtil { object TimeUtil {
fun getUnixTimeFromStamp(input: String): Long { // Pattern: Sun, 15 Oct 2023 11:04:57 GMT
fun getTimeFormatedShortend(time2: Long, showS: Boolean): String { val formatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z")
var time = time2 return ZonedDateTime.parse(input, formatter).toEpochSecond() * 1000
val days: Long = TimeUnit.MILLISECONDS
.toDays(time)
time -= TimeUnit.DAYS.toMillis(days)
val hours: Long = TimeUnit.MILLISECONDS
.toHours(time)
time -= TimeUnit.HOURS.toMillis(hours)
val minutes: Long = TimeUnit.MILLISECONDS
.toMinutes(time)
time -= TimeUnit.MINUTES.toMillis(minutes)
val seconds: Long = TimeUnit.MILLISECONDS
.toSeconds(time)
var s = ""
if (days >= 1) {
s += days.toString() + "d "
}
if (hours >= 1) {
s += hours.toString() + "h "
}
if (minutes >= 1) {
s += minutes.toString() + "m "
}
if (seconds >= 1 && hours < 1 && showS) {
s += seconds.toString() + "s"
}
if (s.isEmpty() || s.isBlank()) {
s = "None"
}
return s
}
// Returns the day of the month of the monday of this week
fun getMondayDayOfMonth(): Int {
return ZonedDateTime.now().with(DayOfWeek.MONDAY).dayOfMonth
} }
} }