All pastes #751551 Raw Edit

Jemand

public text v1 · immutable
#751551 ·published 2007-10-27 14:59 UTC
rendered paste body
#
# Start of Settings
#

namespace eval ::rss-synd {
	variable rss



	set rss(Trackerrss)	{
				 "url"		"http://torrent-space.hopto.org/rss.php"
				 "output" "[Neue Torrents] \037\002\0034@@item:title@@\003\002\037\ - \0033@@item:link@@"
				 "database"	"./scripts/feeds/ss.db"
				 "trigger"	"!neu"
                 "channels"	"#Torrent-Space"
				}

	set default		{
				 "max-output"	4
				 "remove-empty"	1
				 "max-depth"	5
				 "eval-tcl"	0
				 "update"	10
				 "timeout"	30000
				 "channels"	"#Spam"
				 "trigger"	"!rss @@feedid@@"
				 "output" "\037\002\0034@@item:title@@\003\002\037\ - \0033@@item:link@@"
				 "useragent"	"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.10) Gecko/20050716 Firefox/1.0.6"
				}
}

#
# End of Settings
#
###############################################################################

proc ::rss-synd::init {args} {
	variable rss
	variable default

	package require http

	foreach feed [array names rss] {
		array set tmp $default
		array set tmp $rss($feed)

		set required [list "max-depth" "update" "timeout" "channels" "output" "useragent" "url" "database"]
		foreach {key value} [array get tmp] {
			if {[set ptr [lsearch -exact $required $key]] >= 0} {
				set required [lreplace $required $ptr $ptr]
			}
		}

		regsub -nocase -all -- {@@feedid@@} $tmp(trigger) $feed tmp(trigger)

		if {[llength $required] == 0} {
			if {([file exists $tmp(database)]) && ([set mtime [file mtime $tmp(database)]] < [unixtime])} {
				set tmp(updated) [file mtime $tmp(database)]
			} else {
				set tmp(updated) 0
			}
			set rss($feed) [array get tmp]
		} else {
			putlog "\002RSS Error\002: Unable to load feed \"$feed\", missing one or more required settings. \"[join $required ", "]\""
			unset rss($feed)
		}

		unset tmp
	}

	bind evnt -|- prerehash [namespace current]::deInit
	bind time -|- {* * * * *} [namespace current]::getFeeds
	bind pubm -|- {* *} [namespace current]::pubFeeds
}

proc ::rss-synd::deInit {args} {
	catch {unbind evnt -|- prerehash [namespace current]::deInit}
	catch {unbind time -|- {* * * * *} [namespace current]::getFeeds}
	catch {unbind pubm -|- {* *} [namespace current]::pubFeeds}

	namespace delete [namespace current]
}

proc ::rss-synd::getFeeds {args} {
	variable rss

	set i 0
	foreach name [array names rss] {
		if {$i == 3} { break }

		array set feed $rss($name)

		if {$feed(updated) <= [expr { [unixtime] - ($feed(update) * 60) }]} {
			::http::config -useragent $feed(useragent)

			catch {::http::geturl "$feed(url)" -command "[namespace current]::processFeed {[array get feed] depth 0}" -timeout $feed(timeout)}

			set feed(updated) [unixtime]
			set rss($name) [array get feed]
			incr i
		}

		unset feed
	}
}

proc ::rss-synd::pubFeeds {nick user handle chan text} {
	variable rss

	foreach name [array names rss] {
		array set feed $rss($name)

		if {[string match -nocase $text $feed(trigger)]} {
			if {[[namespace current]::channelCheck $feed(channels) $chan]} {
				set feed(channels) $chan

				set data ""
				if {[catch {open $feed(database) "r"} fp] == 0} {
					while {![eof $fp]} {
						gets $fp line
						append data $line
					}

					close $fp

					[namespace current]::outputFeed [array get feed] $data
				} else { putserv "PRIVMSG $chan :\002RSS Warning\002: [string totitle $fp]." }
			}
		}
	}
}

proc ::rss-synd::processFeed {feedlist args} {
	set token [lindex $args end]
	array set feed $feedlist

	upvar 0 $token state

	if {![string match -nocase $state(status) "ok"]} {
		putlog "\002RSS Error\002: $state(url) (State: $state(status))"
		return 1
	}

	if {([::http::ncode $token] == 302) || ([::http::ncode $token] == 301)} {
		set feed(depth) [expr {$feed(depth) + 1 }]

		array set meta $state(meta)

		if {$feed(depth) < $feed(max-depth)} {
			catch {::http::geturl "$meta(Location)" -command "[namespace current]::processFeed {[array get feed]}" -timeout $feed(timeout)}
		} else {
			putlog "\002RSS Error\002: $state(url) (State: timeout, max refer limit reached)"
		}

		return 1
	} elseif {[::http::ncode $token] != 200} {
		putlog "\002RSS Error\002: $state(url) ($state(http))"
		return 1
	}

	set data [::http::data $token]

	if {[set newsdata [[namespace current]::createList $data]] == ""} {
		putlog "\002RSS Error\002: Unable to parse URL properly. \"$state(url)\""
		return 1
	}

	::http::cleanup $token
	unset data

	set oldfeed ""
	if {[catch {open $feed(database) "r"} fp] == 0} {
		while {![eof $fp]} {
			gets $fp line
			append oldfeed $line
		}

		close $fp
	} else { putlog "\002RSS Warning\002: [string totitle $fp]." }

	foreach {tag value} $newsdata {
		if {[string match -nocase $tag "rss"]} {
			foreach {subtag subvalue} $value {
				if {[string match -nocase $subtag "channel"]} {
					foreach {ssubtag ssubvalue} $subvalue {
						if {[string match -nocase $ssubtag "item"]} {
							lappend news(item) $ssubvalue
						} else {
							lappend news(channel) $ssubtag $ssubvalue
						}
					}
				}
			}

			break
		} elseif {[string match -nocase $tag "rdf:RDF"]} {
			foreach {subtag subvalue} $value {
				lappend news($subtag) $subvalue
			}

			break
		}
	}

	if {[catch {open $feed(database) "w+"} fp] == 0} {
		puts $fp [array get news]
		close $fp
	} else {
		putlog "\002RSS Error\002: [string totitle $fp]."
		return 1
	}

	[namespace current]::outputFeed [array get feed] [array get news] $oldfeed

	return 0
}

proc ::rss-synd::createList {data} {
	set i 0
	set news [list]
	set length [string length $data]

	for {set ptr 1} {$ptr <= $length} {incr ptr} {
		set section [string range $data $i $ptr]

		if {[llength [set match [regexp -inline -- {<(.[^ \n\r>]+)(?: |\n|\r\n|\r|)(.[^>]+|)>} $section]]] > 0} {
			set i [expr { $ptr + 1 } ]

			set tag [lindex $match 1]

			if {([info exists current(tag)]) && ([string match -nocase $current(tag) [string map { "/" "" } $tag]])} {
				set subdata [string range $data $current(pos) [expr { $ptr - ([string length $tag] + 2) } ]]
				if {[set cdata [lindex [regexp -inline -nocase -- {<!\[CDATA\[(.[^\]>]*)\]\]>|(.*)} $subdata] 1]] != ""} {
					set subdata $cdata
				}

				set result [[namespace current]::createList $subdata]

				if {[llength $result] > 0} {
					lappend news $current(tag) $result
				} else {
					lappend news $current(tag) $subdata
				}

				unset current
			} elseif {(![string match {[!\?]*} $tag]) && (![info exists current(tag)])} {
				set current(tag) [string map { "\r" "" "\n" "" "\t" "" } $tag]
				set current(pos) $i
			}
		}
	}

	return $news
}

proc ::rss-synd::outputFeed {feedlist newslist {oldfeed ""}} {
	array set feed $feedlist
	array set news $newslist
	if {$oldfeed != ""} { array set old $oldfeed }

	if {[llength $oldfeed] > 1} { array set last [lindex $old(item) 0] }

	set i 0
	foreach item $news(item) {
		array set tmp $item

		if {([info exists feed(max-output)]) && ($i == $feed(max-output))} { break }
		if {([info exists last(title)]) && ([string match $last(title) $tmp(title)])} { break }

		putserv "PRIVMSG [join $feed(channels) ", "] :[[namespace current]::formatOutput $feedlist $news(channel) $item]"

		incr i
	}
}

proc ::rss-synd::formatOutput {feedlist channel item} {
	array set feed $feedlist
	set output $feed(output)

	if {[llength $channel] == 1} {
		set channel [lindex $channel 0]
	}

	foreach {tag value} $item {
		regsub -nocase -all -- "@@item:$tag@@" $output [string map { "&" "\\\x26" } [[namespace current]::decodeHtml $value]] output
	}

	foreach {tag value} $channel {
		regsub -nocase -all -- "@@channel:$tag@@" $output [string map { "&" "\\\x26" } [[namespace current]::decodeHtml $value]] output
	}

	if {(![info exists feed(remove-empty)]) || ($feed(remove-empty) == 1)} {
		regsub -nocase -all -- "@@.*?@@" $output "" output
	}

	if {([info exists feed(eval-tcl)]) && ($feed(eval-tcl) == 1)} {
		if {[catch {set output [subst $output]} error] != 0} {
			putlog "\002RSS Error\002: $error"
		}
	}

	return $output
}

proc ::rss-synd::channelCheck {chanlist chan} {
	foreach match [split $chanlist] {
		if {[string match -nocase $match $chan]} { return 1 }
	}

	return 0
}

proc ::rss-synd::decodeHtml {data} {

	array set chars {
			 nbsp	\x20 amp	\x26 quot	\x22 lt		\x3C
			 gt	\x3E iexcl	\xA1 cent	\xA2 pound	\xA3
			 curren	\xA4 yen	\xA5 brvbar	\xA6 brkbar	\xA6
			 sect	\xA7 uml	\xA8 die	\xA8 copy	\xA9
			 ordf	\xAA laquo	\xAB not	\xAC shy	\xAD
			 reg	\xAE hibar	\xAF macr	\xAF deg	\xB0
			 plusmn	\xB1 sup2	\xB2 sup3	\xB3 acute	\xB4
			 micro	\xB5 para	\xB6 middot	\xB7 cedil	\xB8
			 sup1	\xB9 ordm	\xBA raquo	\xBB frac14	\xBC
			 frac12	\xBD frac34	\xBE iquest	\xBF Agrave	\xC0
			 Aacute	\xC1 Acirc	\xC2 Atilde	\xC3 Auml	\xC4
			 Aring	\xC5 AElig	\xC6 Ccedil	\xC7 Egrave	\xC8
			 Eacute	\xC9 Ecirc	\xCA Euml	\xCB Igrave	\xCC
			 Iacute	\xCD Icirc	\xCE Iuml	\xCF ETH	\xD0
			 Dstrok	\xD0 Ntilde	\xD1 Ograve	\xD2 Oacute	\xD3
			 Ocirc	\xD4 Otilde	\xD5 Ouml	\xD6 times	\xD7
			 Oslash	\xD8 Ugrave	\xD9 Uacute	\xDA Ucirc	\xDB
			 Uuml	\xDC Yacute	\xDD THORN	\xDE szlig	\xDF
			 agrave	\xE0 aacute	\xE1 acirc	\xE2 atilde	\xE3
			 auml	\xE4 aring	\xE5 aelig	\xE6 ccedil	\xE7
			 egrave	\xE8 eacute	\xE9 ecirc	\xEA euml	\xEB
			 igrave	\xEC iacute	\xED icirc	\xEE iuml	\xEF
			 eth	\xF0 ntilde	\xF1 ograve	\xF2 oacute	\xF3
			 ocirc	\xF4 otilde	\xF5 ouml	\xF6 divide	\xF7
			 oslash	\xF8 ugrave	\xF9 uacute	\xFA ucirc	\xFB
			 uuml	\xFC yacute	\xFD thorn	\xFE yuml	\xFF
			 ensp	\x20 emsp	\x20 thinsp	\x20 zwnj	\x20
			 zwj	\x20 lrm	\x20 rlm	\x20 euro	\x80
			 sbquo	\x82 bdquo	\x84 hellip	\x85 dagger	\x86
			 Dagger	\x87 circ	\x88 permil	\x89 Scaron	\x8A
			 lsaquo	\x8B OElig	\x8C oelig	\x8D lsquo	\x91
			 rsquo	\x92 ldquo	\x93 rdquo	\x94 ndash	\x96
			 mdash	\x97 tilde	\x98 scaron	\x9A rsaquo	\x9B
			 Yuml	\x9F
			}

	regsub -all -- {([\"\$\[\]\{\}\(\)\\])} $data {\\\1} data
	regsub -all -- {&#([0-9][0-9]?[0-9]?);?} $data {[format %c [scan \1 %d]]} data
	regsub -all -- {&([0-9a-z#]*);} $data {$chars(\1)} data
	regsub -all -nocase -- {&([0-9a-z#]*);} $data {[string tolower \1]} data

	return [subst $data]
}

proc ::rss-synd::splitData {data count} {
	set results [regexp -inline -all -- {<(.*?)>(.*?)</\1>} $data]
	set length [expr { [llength $results] - 1 }]

	if {$length < 1} { return 1 }

	for {set i $length} {$i >= 0} {set i [expr { $i - 1 }]} {
		if {[expr { $i % $count }] == 0} {
			set results [lreplace $results $i $i]
		}
	}

	return $results
}

::rss-synd::init