Commit af51e4ee authored by Sven Greiner's avatar Sven Greiner
Browse files

Initial commit

Working bot with some TODOs:
    - better building
    - create jar file
    - commandline options
    - LICENSE and README files
parents
#!/bin/bash
if [ ! -d bin ]; then
mkdir bin
cp config.xml.skel bin/config.xml
fi
scalac -classpath lib/pircbot.jar -sourcepath src/main -d bin src/main/de/sammyshp/announcebot/AnnounceBot.scala
<configuration>
<server port="">irc.example.com</server>
<user identify="">ScalaAnnounce</user>
<feed interval="60000">http://example.com/rss</feed>
<channels>
<channel>#example</channel>
<channel>#anotherexample</channel>
</channels>
</configuration>
File added
#!/bin/bash
cd bin
scala -classpath ../lib/pircbot.jar de.sammyshp.announcebot.AnnounceBot
package de.sammyshp.announcebot
import org.jibble.pircbot._
import scala.util.control.Breaks._
class AnnounceBot(config: Configuration) extends PircBot {
var wasConnected = false
def start() {
setName(config.nick)
setEncoding("UTF-8")
setAutoNickChange(true)
onDisconnect()
new PeriodicRssFetcher(config.url, config.pollInterval,
(s: String) => config.channels.map(sendMessage(_, s))) start
}
override def onConnect() {
wasConnected = true
config.identify match {
case None => ()
case Some(s) => identify(s)
}
Log.d("Join channels " + config.channels.mkString(", "))
config.channels.map(joinChannel)
}
override def onDisconnect() {
if (wasConnected)
Log.e("Lost connection to server")
Log.d("Connect to server")
try {
(config.host, config.port) match {
case (server: String, None) => connect(server)
case (server: String, Some(port)) => connect(server, port)
case _ => throw new ConfigurationException("Malformed configuration: server")
}
} catch {
case e => {
Log.e("Cannot connect to server:\n " + e)
Log.d("Try reconnect in 1 minute.")
Thread sleep 60 * 1000
onDisconnect()
}
}
}
override def onPrivateMessage(sender: String, login: String, hostname: String, message: String) {
Log.d("Receive private message: " + sender + ": " + message)
val command = message.split(' ')(0)
command toLowerCase match {
case "!help" => {
sendMessage(sender, "!help Zeige diese Hilfe an")
sendMessage(sender, "!source Wo gibt es den Source?")
sendMessage(sender, "!author Kontakt zum Entwickler des Bots")
sendMessage(sender, "!about Informationen zum Bot")
}
case "!source" => sendMessage(sender, "http://github.com/SammysHP/ScalaAnnounceBot")
case "!author" => sendMessage(sender, "Sven Karsten Greiner (SammysHP), sven@sammyshp.de")
case "!about" => {
sendMessage(sender, "Lizenz: GPL")
sendMessage(sender, "Unter Verwendung von PircBot (http://jibble.org/pircbot.php, GPL) und geschrieben in Scala.")
sendMessage(sender, "Siehe auch !author und !source")
}
case _ => sendMessage(sender, "Befehl nicht erkannt, probiere \"!help\"")
}
}
}
object AnnounceBot {
def main(args: Array[String]) {
Log.d("Start bot")
Log.d("Interrupt (Ctrl+C) to stop")
try {
val bot = new AnnounceBot(Configuration("config.xml"))
bot start
} catch {
case e: ConfigurationException => {
Log.e("Error in configuration, exit.")
Log.e(e.toString)
System.exit(1)
}
}
}
}
package de.sammyshp.announcebot
class Configuration(
val host: String,
val port: Option[Int],
val channels: List[String],
val nick: String,
val identify: Option[String],
val url: String,
val pollInterval: Long) {
}
object Configuration {
def apply(configFile: String) = {
try {
val xml = scala.xml.XML.loadFile(configFile)
val host = xml \ "server" text
val port = xml \ "server" \ "@port" text match {
case "" => None
case i => Some(i.toInt)
}
val channels: List[String] = xml \\ "channel" map(_ text) toList
val nick = xml \ "user" text
val identify = xml \ "user" \ "@identify" text match {
case "" => None
case s => Some(s)
}
val url = xml \ "feed" text
val pollInterval = xml \ "feed" \ "interval" text match {
case "" => 60000
case i => i.toLong
}
new Configuration(host, port, channels, nick, identify, url, pollInterval)
} catch {
case e => throw new ConfigurationException(e.toString)
}
}
}
case class ConfigurationException(s: String) extends Exception(s) {}
package de.sammyshp.announcebot
object Log {
val LEVEL_ERROR = 1
val LEVEL_WARNING = 2
val LEVEL_DEBUG = 4
def e(msg: String) {
log(LEVEL_ERROR, msg)
}
def w(msg: String) {
log(LEVEL_WARNING, msg)
}
def d(msg: String) {
log(LEVEL_DEBUG, msg)
}
private def log(level: Int, msg: String) {
level match {
case LEVEL_ERROR => println("ERROR: " + msg)
case LEVEL_WARNING => println("WARNING: " + msg)
case LEVEL_DEBUG => println("DEBUG: " + msg)
}
}
}
package de.sammyshp.announcebot
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
class PeriodicRssFetcher(url: String, pollInterval: Long, callback: String => Unit) extends Thread {
val dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US)
var lastMessageTime: Long = 0;
override def run() {
while (true) {
Log.d("Fetch RSS: " + url)
try {
val xml = scala.xml.XML.load(new java.net.URL(url))
val posts = (xml \\ "item")
.map(x => (x \ "title" text, x \ "link" text, dateFormat.parse(x \ "pubDate" text).getTime))
.filter(x => x._3 > lastMessageTime)
.groupBy(x => x._1)
.map(x => { val y = x._2(0); (y._1, y._2, y._3, x._2.size) })
.toList
.sortBy(x => x._3)
if (lastMessageTime > 0) {
Log.d("" + posts.size + " new posts")
posts.foreach(x => callback(
(if (x._4 == 1)
"Neuer Beitrag"
else
("" + x._4 + " neue Beiträge"))
+ " im Thema \""
+ x._1
+ "\": "
+ x._2))
} else {
Log.d("" + posts.size + " new posts, but this was the first fetch")
}
lastMessageTime = posts.last._3
} catch {
case e => Log.e("Cannot fetch or post RSS: " + e)
}
Thread sleep pollInterval
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment