This is the new home of the egghelp.org community forum.
All data has been migrated (including user logins/passwords) to a new phpBB version.


For more information, see this announcement post. Click the X in the top right-corner of this box to dismiss this message.

base64

General support and discussion of Eggdrop bots.
Post Reply
b
blake
Master
Posts: 201
Joined: Mon Feb 23, 2009 9:42 am
Contact:

base64

Post by blake »

Hey

Im trying to use a twitter script but keep getting the following error can any one help with how i would install this package
[01:22:22] Tcl error in file 'eggdrop.conf':
[01:22:22] can't find package base64
while executing
"package require base64"
(file "scripts/twitter.tcl" line 43)
invoked from within
"source scripts/twitter.tcl"
(file "eggdrop.conf" line 1352)
[01:22:22] * CONFIG FILE NOT LOADED (NOT FOUND, OR ERROR)
many thanks
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

Your system is missing the base64 tcl-package (not to be confused with distribution packages such as deb's and rpm's). A good source for this would be the tcllib project (http://sourceforge.net/projects/tcllib/). Just download and follow the installation instructions...
NML_375
b
blake
Master
Posts: 201
Joined: Mon Feb 23, 2009 9:42 am
Contact:

Post by blake »

nml375 wrote:Your system is missing the base64 tcl-package (not to be confused with distribution packages such as deb's and rpm's). A good source for this would be the tcllib project (http://sourceforge.net/projects/tcllib/). Just download and follow the installation instructions...
I have sorted that but i now get the following error

Code: Select all

[22:54] <TwitterBot> [01:54:08] HTTP query failed: 401 (URL: http://twitter.com/statuses/friends.json) (QUERY_LIST: ) (QUERY: ) (METHOD: ) (USED METHOD: GET)
Im assuming that the script may be out dated

Code: Select all

# 0.1 - Feb 6 2010
#
# Created by fedex and cd. www.summercat.com for updates
#
# Requirements: Tcl 8.5+ and tcllib of some version (for base64, json)
#
# Essentially a twitter client for IRC. Follow updates from tweets of all
# those you follow on the given account.
#
# Usage notes:
#  - Stores states in variable $idfile file in eggdrop root directory
#  - Default time between tweet fetches is 10 minutes. Alter the "bind time"
#    option below to change to a different setting. Right now there is only
#    options for 1 minute or 10 minutes.
#  - Accepts commands issued by anyone right now! Perhaps if you wish to use
#    in a channel with untrusted people, have one channel for output and one
#    for controlling the script client style (+twitter)
#
# Setup:
#  - Place your username and pass in the variables user and pas
#  - Set the channel variable as the channel where tweets will be output
#  - .chanset #channel +twitter to provide access to !commands in #channel
#
# Commands:
#  - !twit - send a tweet
#  - !twit_msg
#  - !twit_trends
#  - !follow
#  - !unfollow
#  - !twit_updates
#  - !twit_msgs
#  - !twit_search
#  - !followers
#  - !following
#  - !retweet
#
# TODO:
#

package require http
# tcllib packages
package require base64
package require json

namespace eval twitter {
	variable user "xxxxxxx"
	variable pass "xxxxxxx"
	variable channel "#Tweets"

	# Only have one of these uncommented
	# Check for tweets every 1 min
	#bind time - "* * * * *" twitter::update
	# Check for tweets every 10 min
	bind time - "?0 * * * *" twitter::update

	variable idfile "twitter.last_id"

	#variable output_cmd "cd::putnow"
	variable output_cmd "putserv"

	variable last_id
	variable last_update
	variable last_msg

	variable status_url "http://twitter.com/statuses/update.json"
	variable home_url "http://api.twitter.com/1/statuses/home_timeline.json"
	variable msg_url "http://twitter.com/direct_messages/new.xml"
	variable msgs_url "http://twitter.com/direct_messages.json"
	variable trends_curr_url "http://search.twitter.com/trends/current.json"
	variable follow_url "http://twitter.com/friendships/create.json"
	variable unfollow_url "http://twitter.com/friendships/destroy.json"
	variable search_url "http://search.twitter.com/search.json"
	variable followers_url "http://twitter.com/statuses/followers.json"
	variable following_url "http://twitter.com/statuses/friends.json"
	variable retweet_url "http://api.twitter.com/1/statuses/retweet/"

	bind pub	-|- "!twit" twitter::tweet
	bind pub	-|- "!twit_msg" twitter::msg
	bind pub	-|- "!twit_trends" twitter::trends
	bind pub	-|- "!follow" twitter::follow
	bind pub	-|- "!unfollow" twitter::unfollow
	bind pub	-|- "!twit_updates" twitter::updates
	bind pub	-|- "!twit_msgs" twitter::msgs
	bind pub	-|- "!twit_search" twitter::search
	bind pub	-|- "!followers" twitter::followers
	bind pub	-|- "!following" twitter::following
	bind pub	-|- "!retweet" twitter::retweet
	bind evnt	-|- "save" twitter::write_states

	setudef flag twitter
}


# Output decoded/split string to given channel
proc twitter::output {chan str} {
	set str [twitter::decode_html $str]
	foreach line [twitter::split_line 400 $str] {
		$twitter::output_cmd "PRIVMSG $chan :$line"
	}
}


# Format status updates and output
proc twitter::output_update {chan name id text} {
	twitter::output $chan "\[\002$name\002\] $text ($id)"
}


# Retweet given id
proc twitter::retweet {nick uhost hand chan argv} {
	if {![channel get $chan twitter]} { return }

	if {[string length $argv] < 1 || ![regexp {^\d+$} $argv]} {
		$twitter::output_cmd "PRIVMSG $chan :Usage: !retweet <id>"
		return
	}

	# Setup url since id is not given as params for some reason...
	set url "${twitter::retweet_url}${argv}.json"

	if {[catch {twitter::query $url {} POST} result]} {
		$twitter::output_cmd "PRIVMSG $chan :Retweet failure. ($argv) (You can't retweet your own updates!)"
		return
	}

	$twitter::output_cmd "PRIVMSG $chan :Retweet sent."
}


# Follow a user (by screen name)
proc twitter::follow {nick uhost hand chan argv} {
	if {![channel get $chan twitter]} { return }

	if {[string length $argv] < 1} {
		$twitter::output_cmd "PRIVMSG $chan :Usage: !follow <screen name>"
		return
	}

	if {[catch {twitter::query $twitter::follow_url [list screen_name $argv]} result]} {
		$twitter::output_cmd "PRIVMSG $chan :Twitter failed or already friends with $argv!"
		return
	}

	if {[dict exists $result error]} {
		twitter::output $chan "Follow failed ($argv): [dict get $result error]"
		return
	}

	twitter::output $chan "Now following [dict get $result screen_name]!"
}


# Unfollow a user (by screen name)
proc twitter::unfollow {nick uhost hand chan argv} {
	if {![channel get $chan twitter]} { return }

	if {[string length $argv] < 1} {
		$twitter::output_cmd "PRIVMSG $chan :Usage: !unfollow <screen name>"
		return
	}

	if {[catch {twitter::query $twitter::unfollow_url [list screen_name $argv]} result]} {
		$twitter::output_cmd "PRIVMSG $chan :Unfollow failed. ($argv)"
		return
	}

	if {[dict exists $result error]} {
		twitter::output $chan "Unfollow failed ($argv): [dict get $result error]"
		return
	}

	twitter::output $chan "Unfollowed [dict get $result screen_name]."
}


# Get last n, n [1, 20] updates
proc twitter::updates {nick uhost hand chan argv} {
	if {![channel get $chan twitter]} { return }

	if {[string length $argv] < 1 || ![string is integer $argv] || $argv > 20 || $argv < 1} {
		$twitter::output_cmd "PRIVMSG $chan :Usage: !twit_updates <#1 to 20>"
		return
	}

	if {[catch {twitter::query $twitter::home_url [list count $argv]} result]} {
		$twitter::output_cmd "PRIVMSG $chan :Retrieval error."
		return
	}

	if {[llength $result] == 0} {
		$twitter::output_cmd "PRIVMSG $chan :No updates."
		return
	}

	set result [lreverse $result]
	foreach status $result {
		dict with status {
#			twitter::output $chan "\[\002[dict get $user screen_name]\002\] $text"
			twitter::output_update $chan [dict get $user screen_name] $id $text
		}
	}
}


# Return top 5 results for query $argv
proc twitter::search {nick uhost hand chan argv} {
	if {![channel get $chan twitter]} { return }

	if {[string length $argv] < 1 || [string length $argv] > 140} {
		$twitter::output_cmd "PRIVMSG $chan :Usage: !twit_search <string 140 chars or less>"
		return
	}

	if {[catch {twitter::query $twitter::search_url [list q $argv]} data]} {
		$twitter::output_cmd "PRIVMSG $chan :Search error ($argv)"
		return
	}

	if {[dict exists $data error]} {
		twitter::output $chan "Search failed ($argv): [dict get $result error]"
		return
	}

	set results [dict get $data results]
	set count 0
	foreach result $results {
		twitter::output $chan "#[incr count] \002[dict get $result from_user]\002 [dict get $result text]"
		if {$count > 4} {
			break
		}
	}
}


# Return latest followers (up to 100)
proc twitter::followers {nick uhost hand chan argv} {
	if {![channel get $chan twitter]} { return }

	if {[catch {twitter::query $twitter::followers_url} result]} {
		$twitter::output_cmd "PRIVMSG $chan :Error fetching followers."
	}

	# Make first followers -> last followers
	set result [lreverse $result]

	set followers []
	foreach user $result {
		set followers "$followers[dict get $user screen_name] "
	}

	twitter::output $chan "Followers: $followers"
}


# Returns the latest users following acct is following (up to 100)
proc twitter::following {nick uhost hand chan argv} {
	if {![channel get $chan twitter]} { return }

	if {[catch {twitter::query $twitter::following_url} result]} {
		$twitter::output_cmd "PRIVMSG $chan :Error fetching friends."
		return
	}

	# Make first following -> last following
	set result [lreverse $result]

	set following []
	foreach user $result {
		set following "$following[dict get $user screen_name] "
	}

	twitter::output $chan "Following: $following"
}


# Get trends
proc twitter::trends {nick uhost hand chan argv} {
	if {![channel get $chan twitter]} { return }

	if {[catch {twitter::query $twitter::trends_curr_url} result]} {
		$twitter::output_cmd "PRIVMSG $chan :Trend fetch failed!"
		return
	}

	set trends [dict get $result trends]
	set output []
	set count 0
	foreach day [dict keys $trends] {
		foreach trend [dict get $trends $day] {
			set output "$output\002#[incr count]\002 [dict get $trend name] "
		}
	}

	twitter::output $chan $output
}


# Direct messages
# Get last n, n [1, 20] messages or new if no argument
proc twitter::msgs {nick uhost hand chan argv} {
	if {![channel get $chan twitter]} { return }

	if {[string length $argv] == 1 && [string is integer $argv] && $argv < 20} {
		set params [list count $argv]
	} else {
		set params [list since_id $twitter::last_msg]
	}

	if {[catch {twitter::query $twitter::msgs_url $params GET} result]} {
		$twitter::output_cmd "PRIVMSG $chan :Messages retrieval failed."
		return
	}

	if {[llength $result] == 0} {
		$twitter::output_cmd "PRIVMSG $chan :No new messages."
		return
	}

	foreach msg $result {
		dict with msg {
			if {$id > $twitter::last_msg} {
				set twitter::last_msg $id
			}
			twitter::output $chan "\002From\002 $sender_screen_name: $text ($created_at)"
		}
	}
}


# Send direct message to a user
proc twitter::msg {nick uhost hand chan argv} {
	if {![channel get $chan twitter]} { return }

	if {[llength [split $argv]] < 2 || [string length [join [lrange [split $argv] 1 end]]] > 140} {
		$twitter::output_cmd "PRIVMSG $chan :Usage: !twit_msg <username> <msg 140 chars or less>"
		return
	}

	set l [list screen_name [lindex $argv 0] text [lrange $argv 1 end]]

	if {[catch {twitter::query $twitter::msg_url $l} data]} {
		$twitter::output_cmd "PRIVMSG $chan :Message to \002$argv\002 failed! (Are they following you?)"
	} else {
		twitter::output $chan "Message sent."
	}
}


# Send status update (tweet)
proc twitter::tweet {nick uhost hand chan argv} {
	if {![channel get $chan twitter]} { return }

	if {[string length $argv] > 140 || $argv == ""} {
		$twitter::output_cmd "PRIVMSG $chan :Usage: !tweet <less than 140 characters>"
	}

	if {[catch {twitter::query $twitter::status_url [list status $argv]} result]} {
		$twitter::output_cmd "PRIVMSG $chan :Tweet failed! HTTP error. ($argv)"
		return
	}

	set update_id [dict get $result id]
	if {$update_id == $twitter::last_update} {
		$twitter::output_cmd "PRIVMSG $chan :Tweet failed: Duplicate of tweet #$update_id. ($argv)"
		return
	}
	set twitter::last_update $update_id

	twitter::output $chan "Tweet sent."
}


# Grab unseen status updates
proc twitter::update {min hour day month year} {
	if {[catch {twitter::query $twitter::home_url [list since_id $twitter::last_id]} result]} {
		putlog "Twitter is busy."
		return
	}

	set result [lreverse $result]

	foreach status $result {
		dict with status {
#			twitter::output $twitter::channel "\[\002[dict get $user screen_name]\002\] $text"
			twitter::output_update $twitter::channel [dict get $user screen_name] $id $text

			if {$id > $twitter::last_id} {
				set twitter::last_id $id
			}
		}
	}
}


# Twitter http query
proc twitter::query {url {query_list {}} {http_method {}}} {
	set auth [base64::encode "${twitter::user}:${twitter::pass}"]
	set header [list Authorization [concat "Basic" $auth]]

	# Set http mode of query
	if {$http_method eq "" && $query_list ne ""} {
		set method POST
	} elseif {$http_method eq "" && $query_list eq ""} {
		set method GET
	} else {
		set method $http_method
	}

	set query [http::formatQuery {*}$query_list]
	set token [http::geturl $url -headers $header -query $query -method $method]

#	if {$query_list ne ""} {
#		set query [http::formatQuery {*}$query_list]
#		set token [http::geturl $url -headers $header -query $query]
#	} else {
#		set token [http::geturl $url -headers $header]
#	}

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

	if {$ncode != 200} {
		putlog "HTTP query failed: $ncode (URL: $url) (QUERY_LIST: $query_list) (QUERY: $query) (METHOD: $http_method) (USED METHOD: $method)"
		error "HTTP query failed: $ncode"
	}

	return [json::json2dict $data]
}


# Get saved ids/state
proc twitter::get_states {} {
	if {[catch {open $twitter::idfile r} fid]} {
		set twitter::last_id 1
		set twitter::last_update 1
		set twitter::last_msg 1
		return
	}

	set data [read -nonewline $fid]
	set states [split $data \n]

	close $fid

	set twitter::last_id [lindex $states 0]
	set twitter::last_update [lindex $states 1]
	set twitter::last_msg [lindex $states 2]
}


# Save states to file
proc twitter::write_states {args} {
	set fid [open $twitter::idfile w]
	puts $fid $twitter::last_id
	puts $fid $twitter::last_update
	puts $fid $twitter::last_msg
	close $fid
}


# Split long line into list of strings for multi line output to irc
# Splits into strings of ~max
# by fedex
proc twitter::split_line {max str} {
	set last [expr {[string length $str] -1}]
	set start 0
	set end [expr {$max -1}]

	set lines []

	while {$start <= $last} {
		if {$last >= $end} {
			set end [string last { } $str $end]
		}

		lappend lines [string trim [string range $str $start $end]]
		set start $end
		set end [expr {$start + $max}]
	}

	return $lines
}

# From perpleXa's urbandictionary script
# Replaces html special chars with their hex equivalent
proc twitter::decode_html {str} {
	set escapes {
		  \x20 " \x22 & \x26 &apos; \x27 – \x2D
		< \x3C > \x3E ˜ \x7E € \x80 ¡ \xA1
		¢ \xA2 £ \xA3 ¤ \xA4 ¥ \xA5 ¦ \xA6
		§ \xA7 ¨ \xA8 © \xA9 ª \xAA « \xAB
		¬ \xAC ­ \xAD ® \xAE &hibar; \xAF ° \xB0
		± \xB1 ² \xB2 ³ \xB3 ´ \xB4 µ \xB5
		¶ \xB6 · \xB7 ¸ \xB8 ¹ \xB9 º \xBA
		» \xBB ¼ \xBC ½ \xBD ¾ \xBE ¿ \xBF
		À \xC0 Á \xC1 Â \xC2 Ã \xC3 Ä \xC4
		Å \xC5 Æ \xC6 Ç \xC7 È \xC8 É \xC9
		Ê \xCA Ë \xCB Ì \xCC Í \xCD Î \xCE
		Ï \xCF Ð \xD0 Ñ \xD1 Ò \xD2 Ó \xD3
		Ô \xD4 Õ \xD5 Ö \xD6 × \xD7 Ø \xD8
		Ù \xD9 Ú \xDA Û \xDB Ü \xDC Ý \xDD
		Þ \xDE ß \xDF à \xE0 á \xE1 â \xE2
		ã \xE3 ä \xE4 å \xE5 æ \xE6 ç \xE7
		è \xE8 é \xE9 ê \xEA ë \xEB ì \xEC
		í \xED î \xEE ï \xEF ð \xF0 ñ \xF1
		ò \xF2 ó \xF3 ô \xF4 õ \xF5 ö \xF6
		÷ \xF7 ø \xF8 ù \xF9 ú \xFA û \xFB
		ü \xFC ý \xFD þ \xFE ÿ \xFF
	}

	return [string map $escapes $str]
}

# Read states on load
twitter::get_states

putlog "twitter 0.1 (c) fedex"
User avatar
Trixar_za
Op
Posts: 143
Joined: Wed Nov 18, 2009 1:44 pm
Location: South Africa
Contact:

Post by Trixar_za »

Blake: Try speechless' twitter script named Birdy (http://forum.egghelp.org/viewtopic.php?t=17556). It also comes with the oauth.tcl and base64.tcl scripts, so you don't really need tcllib to use it.
Post Reply