Compare commits

..

No commits in common. "8f58b5b6e62b2f23426994152fc710f629211724" and "ccf5ef4f0d1ef7c9a27fac70f7c5894e3a62a6b1" have entirely different histories.

12 changed files with 52 additions and 201 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.3.0" ?: "0.2.1"
val kordver = "1.5.10-SNAPSHOT" val kordver = "1.5.10-SNAPSHOT"
val coroutinesver = "1.7.3" val coroutinesver = "1.7.3"
@ -67,9 +67,6 @@ 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,7 +24,9 @@ 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.* import net.moonleay.rssbot.extensions.FeedExtension
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
@ -75,8 +77,6 @@ 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,5 +27,4 @@ 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,8 +38,7 @@ 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]
) )
) )
} }
@ -60,8 +59,7 @@ 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]
) )
) )
} }
@ -82,8 +80,7 @@ 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]
) )
} }
} }
@ -118,7 +115,6 @@ 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,5 +28,4 @@ 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

@ -1,39 +0,0 @@
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,8 +106,7 @@ 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

@ -1,113 +0,0 @@
/*
* 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,7 +18,6 @@
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
@ -36,7 +35,6 @@ 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
@ -74,13 +72,7 @@ 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( if (rssData.guid == null || RSSRepository.exists(RSSData(rssData.guid!!, data.id)))
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 {
@ -89,14 +81,11 @@ object FeedUpdater : ICronjob {
data.feedColor, data.feedColor,
rssData.author ?: "Anonymous", rssData.author ?: "Anonymous",
rssData.title ?: "Untitled", rssData.title ?: "Untitled",
if (rssData.description == null) "No description" else Remark(EmbedUtil.getHTMLtoMarkdownOptions()).convertFragment( rssData.description ?: "No description",
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",
"Manual Feed", data.feedName,
rssData.pubDate ?: "unknown"
) )
) )
} }

View file

@ -18,8 +18,6 @@
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
@ -143,11 +141,4 @@ 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,12 +174,11 @@ 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 > 25) if (title.length > 250)
ebb.title = title.substring(0, 25) + "..." ebb.title = title.substring(0, 250) + "[...]"
else else
ebb.title = title ebb.title = title
ebb.author { ebb.author {
@ -189,7 +188,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) \n/ pub $published \n/ rel ${dtf.format(now)}" this.text = "> rssbot, ($feedName) / sent at ${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,13 +18,47 @@
package net.moonleay.rssbot.util package net.moonleay.rssbot.util
import kotlinx.datetime.DayOfWeek
import java.time.ZonedDateTime import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter import java.util.concurrent.TimeUnit
object TimeUtil { object TimeUtil {
fun getUnixTimeFromStamp(input: String): Long { // Pattern: Sun, 15 Oct 2023 11:04:57 GMT
val formatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z") fun getTimeFormatedShortend(time2: Long, showS: Boolean): String {
return ZonedDateTime.parse(input, formatter).toEpochSecond() * 1000 var time = time2
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
} }
} }