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.

[Solved]Voice/devoice script with extra features

Requests for complete scripts or modifications/fixes for scripts you didn't write. Response not guaranteed, and no thread bumping!
User avatar
m4s
Halfop
Posts: 97
Joined: Mon Jan 30, 2017 3:24 pm

[Solved]Voice/devoice script with extra features

Post by m4s »

Hello!

I looked for autovoice scripts in the archive (there are many) but I want a bit more.

"Normal" features are:
- autovoice everyone joining my channel
- turn on and off the script via DCC: .chanset #channel +av.
- public and private commands for my bot would be !voice nick, !devoice nick;
"Extras" would be:
- If a user devoiced with "!devoice user" or "mode #chanel -v user"
and if the devoiced user parts my channel and joins again to gain +v, bot must not give the +v flag to him only if a pre-defined time has gone. This time should be set in the script config section in hours.
- If a devoiced user stays in my channel but changes his nick to gain +v,
bot must not give the +v flag to him.
- I don't want to send any message to the user who is trying to gain +v after devoiced.


My I ask If anyone create this tcl?

I found a similar scripts but it is not working well (mute.tcl).

Thank You!
Last edited by m4s on Wed Feb 07, 2018 3:47 pm, edited 1 time in total.
User avatar
caesar
Mint Rubber
Posts: 3776
Joined: Sun Oct 14, 2001 8:00 pm
Location: Mint Factory

Post by caesar »

Here's something I think should do what you asked BUT the kicker is that I haven't tested anything so not sure if works or not.

The !voice/!devoice commands accept multiple nicks per line, the duration is in seconds, the script stores ignores in user@host format and cleanup is done automatically every minute (can be changed later on cos is a cron job).

Load this on a test bot and see what happens:
- if when someone joins the bot gives voice
- remove it's voice via !devoice <nick> and have him rejoin the channel
- give his voice via !voice and then ask him to rejoin the channel
- do the same stuff mentioned above but with 2 members (!devoice <nick 1> <nick 2>)
- devoice one either by you changing the channel mode ( you set -v on the user) or via !devoice. have user rejoin and then wait 1 minute and do another rejoin.

Test the stuff out and let me know the outcome.

Code: Select all

namespace eval av {

	set duration 360

	setudef flag av
	array set ignoreList {}

	bind join - * [namespace current]::joining
	bind pub o|o !voice [namespace current]::voice
	bind pub o|o !devoice [namespace current]::devoice 
	bind mode - "% +v" [namespace current]::mcVoice
	bind mode - "% -v" [namespace current]::mcDevoice
	bind cron - {*/1 * * * *} [namespace current]::reset

	proc joining {nick uhost hand chan} {
		global ignoreList
		if {![channel get $chan av] || [isbotnick $nick] || ![botisop $chan]} return
		if {[lsearch -nocase [dict keys [join $ignoreList($chan)]] $uhost] < 0} {
			pushmode $chan +v $nick
		}
	}

	proc voice {nick uhost hand chan text} {
		if {![channel get $chan av] || ![botisop $chan] || ![llength $text]} return
		foreach user [split $text] {
			if {[isbotnick $user] || ![onchan $user] || [isvoice $user $chan]} continue
			lappend voiceList $user
		}
		if {[info exists voiceList]} { 
			push $chan "+" $voiceList
		}
	}

	proc devoice {nick uhost hand chan text} {
		if {![channel get $chan av] || ![botisop $chan] || ![llength $text]} return
		foreach user [split $text] {
			if {[isbotnick $user] || ![onchan $user] || ![isvoice $user $chan]} continue
			lappend voiceList $user
		}
		if {[info exists voiceList]} { 
			push $chan "-" $voiceList
		}
	}

	proc push {chan mc userList} {
		set max 6
		set len [llength $userList]
		while {$len > 0} {
			if {$len > $max} {
				set mode [string repeat "v" $max]
				set users [join [lrange $userList 0 [expr {$max - 1}]]]
				set userList [lrange $userList $max end]
				incr len -$max
			} else {
				set mode [string repeat "v" $len]
				set users [join $userList]
				set len 0
			}
			pushmode $chan $mc$mode $users
		}
	}

	proc mcVoice {nick uhost hand chan mc target} {
		global ignoreList
		if {![channel get $chan av] || ![botisop $chan]} return
		if {[array get ignoreList $chan] != {}} {
			set pos [lsearch -nocase [dict keys [join $ignoreList($chan)]] $uhost]
			if ($pos >= 0) {
				set ignoreList($chan) [lreplace $ignoreList($chan) $pos $pos]
			}
		}
	}

	proc mcDevoice {nick uhost hand chan mc target} {
		global ignoreList
		if {![channel get $chan av] || ![botisop $chan]} return
		set now [clock seconds]
		if {[array get ignoreList $chan] != {}} {
			set pos [lsearch -nocase [dict keys [join $ignoreList($chan)]] $uhost]
			if ($pos >= 0) {
				set ignoreList($chan) [lreplace $ignoreList($chan) $pos $pos [list $uhost $now]]
				return
			}
		}
		lappend ignoreList($chan) [list $uhost $now]
	}

	proc reset {min hour day month weekday} {
		global ignoreList
		global duration
		set now [clock seconds]
		foreach chan [channels] {
			if {![channel get $chan av]} {
				if {[array get ignoreList $chan] != {}} {	
					array unset ignoreList $chan
				}
				continue
			}
			if {[array get ignoreList $chan] != {}} {
				set x 0
				foreach time [dict values [join $ignoreList(a)]] {
					if {($now - $time) >=  $duration} {
						set ignoreList($chan) [lreplace $ignoreList($chan) $x $x]
						incr x
					}
				}
			}
		}
	}
}
Edit: Fixed binds. /facepalm
Last edited by caesar on Mon Jan 15, 2018 3:42 pm, edited 1 time in total.
Once the game is over, the king and the pawn go back in the same box.
User avatar
m4s
Halfop
Posts: 97
Joined: Mon Jan 30, 2017 3:24 pm

Post by m4s »

Hi Caesar!

First thank you to help me, that is kind of you. :)

First test results are:

Script is loaded I set the +av flag via DCC.
Bot doesn't give +v after someone joining to my channel and the public commands don't work. There are no error messages in the partyline.
The bot is opped on the test channel and the script is loaded.
(I added this line to the script to see it: putlog "\002*Caesar's autovoice script has been successfully LOADED")

I used the .binds *av* to see 'something', I got this:
cron -|- */1 * * * * 14 ::av::reset
mode -|- % -v 0 ::av::mcDevoice
mode -|- % +v 0 ::av::mcVoice


P.s.: I forgot to mention but it would be great if the public commands work for only users who has the +o flag.
User avatar
caesar
Mint Rubber
Posts: 3776
Joined: Sun Oct 14, 2001 8:00 pm
Location: Mint Factory

Post by caesar »

The commands and that voice on joining part doesn't work because I'm an idiot. Don't know how i missed that and why you don't get any errors. /facepalm

Make this change:

Code: Select all

bind join - * [namespace current]::joining
bind pub o|o !voice [namespace current]::voice
bind pub o|o !devoice [namespace current]::devoice 
Once the game is over, the king and the pawn go back in the same box.
User avatar
m4s
Halfop
Posts: 97
Joined: Mon Jan 30, 2017 3:24 pm

Post by m4s »

Everyone makes mistakes...that is normal. :)

I made the changes.
I got this error after joining:
Tcl error [::av::joining]: can't read "ignoreList(#mychannel)": no such variable

!voice nick and !devoice nick work, but !voice nick1 nick2 don't.
I got this continously:
Tcl error [::av::reset]: can't read "ignoreList(a)": no such element in array

If I use /mode #channel +v nick to give +v I got this:
Tcl error [::av::mcVoice]: unbalanced open paren
in expression "(-1"

But I guess my explanation was not good sorry about it. I try to explain my request again.
The bot should give +v to everyone who joins to my channel. That is the default.
Nick1 joins bot sets mode +v.
- If an op devoices nick1, and nick1 parts and joins again bot must not give the +v.
Here I thought to set a timer. Bot should wait for example six hours. If nick1 leaves and joins after six hours bot can give the +v.
- If an op devoices nick1 and nick1 changes his nick to nick2 bot must not give the +v to nick2.
-Public commands !voice, !devoice for +o flag users.

I found a very similar script but it is not working for me and perhaps helps something.
(https://gist.github.com/anonymous/2a5d3 ... 0f41835e59).
User avatar
caesar
Mint Rubber
Posts: 3776
Joined: Sun Oct 14, 2001 8:00 pm
Location: Mint Factory

Post by caesar »

A quick fix of some of the bugs: replace global with variable, replace $ignoreList(a) with $ignoreList($chan)

Will have to do some testing of my own cos I'm making a fool of myself with posting untested stuff. :roll:

Edit: From the limited testing I've done the mass voice/devoice should work. Not sure how mode change works, I mean if it's triggered for each mode change or just once for all modes if are in a single line.

The script you mentioned is the same mute.tcl that at first glance doesn't know how to mute more than one member. Anyway, will get back to this as soon as I done some proper testing.

Second edit: Here's an updated and slightly tested code. Ignore the above.

Code: Select all

namespace eval av {

        set duration 60

        setudef flag av
        array set ignoreList {}

        bind join * * [namespace current]::joining
        bind pub o !voice [namespace current]::voice
        bind pub o !devoice [namespace current]::devoice
        bind mode - "% +v" [namespace current]::mcVoice
        bind mode - "% -v" [namespace current]::mcDevoice
        bind cron - {*/1 * * * *} [namespace current]::reset

        proc joining {nick uhost hand chan} {
                variable ignoreList
                if {![channel get $chan av] || [isbotnick $nick] || ![botisop $chan]} return
                if {[array get ignoreList $chan] != {}} {
                        if {[lsearch -nocase [dict keys [join $ignoreList($chan)]] $uhost] != -1} return
                }
                pushmode $chan +v $nick
        }

        proc voice {nick uhost hand chan text} {
                variable ignoreList
                if {![channel get $chan av] || ![botisop $chan] || ![llength $text]} return
                foreach user [split $text] {
                        if {[isbotnick $user] || ![onchan $user $chan] || [isvoice $user $chan]} continue
                        lappend voiceList $user
                }
                if {[info exists voiceList]} {
                        push $chan "+" $voiceList
                }
        }

        proc devoice {nick uhost hand chan text} {
                if {![channel get $chan av] || ![botisop $chan] || ![llength $text]} return
                foreach user [split $text] {
                        if {[isbotnick $user] || ![onchan $user $chan] || ![isvoice $user $chan]} continue
                        lappend voiceList $user
                }
                if {[info exists voiceList]} {
                        push $chan "-" $voiceList
                }
        }

        proc push {chan mc userList} {
                set max 6
                set len [llength $userList]
                while {$len > 0} {
                        if {$len > $max} {
                                set mode [string repeat "v" $max]
                                set users [join [lrange $userList 0 [expr {$max - 1}]]]
                                set userList [lrange $userList $max end]
                                incr len -$max
                        } else {
                                set mode [string repeat "v" $len]
                                set users [join $userList]
                                set len 0
                        }
                        pushmode $chan $mc$mode $users
                }
        }

        proc mcVoice {nick uhost hand chan mc target} {
                variable ignoreList
                if {![channel get $chan av] || ![botisop $chan]} return
                if {[array get ignoreList $chan] != {}} {
                        set pos [lsearch -nocase [dict keys [join $ignoreList($chan)]] [getchanhost $target $chan]]
                        if {$pos >= 0} {
                                set ignoreList($chan) [lreplace $ignoreList($chan) $pos $pos]
                        }
                }
        }

        proc mcDevoice {nick uhost hand chan mc target} {
                variable ignoreList
                if {![channel get $chan av] || ![botisop $chan]} return
                set now [clock seconds]
				set uhost [getchanhost $target $chan]
                if {[array get ignoreList $chan] != {}} {
                        set pos [lsearch -nocase [dict keys [join $ignoreList($chan)]] $uhost]
                        if {$pos >=0 } {
                                set ignoreList($chan) [lreplace $ignoreList($chan) $pos $pos [list $uhost $now]]
                                return
                        }
                }
                lappend ignoreList($chan) [list $uhost $now]
        }

        proc reset {min hour day month weekday} {
                variable ignoreList
                variable duration
                set now [clock seconds]
                foreach chan [channels] {
                        if {![channel get $chan av]} {
                                if {[array get ignoreList $chan] != {}} {
                                        array unset ignoreList $chan
                                }
                                continue
                        }
                        if {[array get ignoreList $chan] != {}} {
                                set x 0
                                foreach time [dict values [join $ignoreList($chan)]] {
                                        if {($now - $time) >=  $duration} {
                                                set ignoreList($chan) [lreplace $ignoreList($chan) $x $x]
                                                incr x
                                        }
                                }
                        }
                }
        }
}
I can't test if it works with multiple voiced/devoiced members at the same time so need you test this for me and reply with the result.
Once the game is over, the king and the pawn go back in the same box.
User avatar
m4s
Halfop
Posts: 97
Joined: Mon Jan 30, 2017 3:24 pm

Post by m4s »

Caesar!

It's a great job from you! Thank You!
The main features work I got no error messages! :)
The only thing (but this was not my request) is the "!voice nick1 nick2" and the "!devoice nick1 nick2" don't work. But it is not important for me.

I have questions. :)
What time is the "set durations"?
How do you mean "cleanup is done automatically every minute (can be changed later on cos is a cron job)."

An example: I devoiced nick1, and I don't want to give the +v only after 12 hours.
How can I set this?

Thanks!
User avatar
caesar
Mint Rubber
Posts: 3776
Joined: Sun Oct 14, 2001 8:00 pm
Location: Mint Factory

Post by caesar »

I did some limited testing on voicing/devoicing multiple nicks and worked. Will try to do a live test cos can't see right now what's not working properly.

12 hours in seconds means 12 x 60 x 60 and is equal with 43200, so if you change the set duration 60 in set duration 43200 then rehash the bot to "notice" the change. I left it to 60 seconds for my testing.

The "cleanup" is done automatically by the "reset" function that is executed once every 1 minute (this {*/1 * * * *} actually). If you want to do a cleanup let's say every 10 minutes then that becomes {*/10 * * * *} for example. If you google crontab will find plenty of examples how to set a different moment to execute that function.

Keep in mind that if for instance you muted someone at let's say 10:00:01 for let's say 1 hour then the bot will not lift the mute at 11:00:01 but at 11:01:00 when the cleanup function is executed again, so the user will actually be muted for 1 hour and 59 seconds. I didn't opt for another method to run the cleanup every second because you said hours in first post so 1 minute give or take is not really that much. :)
Once the game is over, the king and the pawn go back in the same box.
User avatar
m4s
Halfop
Posts: 97
Joined: Mon Jan 30, 2017 3:24 pm

Post by m4s »

Thanks Caesar I see!

I started to use your script. I want to wait a bit to see it is working well -i am sure it will!
If I find something I will post it here but I think this topic will be closed soon! ;)
User avatar
m4s
Halfop
Posts: 97
Joined: Mon Jan 30, 2017 3:24 pm

Post by m4s »

Hi Caesar,

A tested a bit. The only thing which is not working is the "!voice nick1 nick2" and
"!devoice nick1 nick2".

Test1:
!voice nick1 nick2 -> nothing happens -> no error msg
!voice nick1, nick2 -> voice is only given to nick2 -> no error msg

I gave voice to nick1 and nick2 to run test2.

Test2:
!devoice nick1 nick2- > nothing happens -> no error msg
!devoice nick1, nick2 -> bot took v from only nick2 -> no error msg


Is it possibly to use the !voice, !devoice commands via the bot? I mean in private commands.
User avatar
SpiKe^^
Owner
Posts: 831
Joined: Fri May 12, 2006 10:20 pm
Location: Tennessee, USA
Contact:

Don't use pushmode here!

Post by SpiKe^^ »

Is my opinion that [pushmode] only works with simple 1 item mode change, and not a combined mode change like this script is feeding it.

As a test, search out this line in the script...

Code: Select all

pushmode $chan $mc$mode $users
and change it to more like this...

Code: Select all

putquick "MODE $chan $mc$mode $users"
SpiKe^^

Get BogusTrivia 2.06.4.7 at www.mytclscripts.com
or visit the New Tcl Acrhive at www.tclarchive.org
.
User avatar
m4s
Halfop
Posts: 97
Joined: Mon Jan 30, 2017 3:24 pm

Re: Don't use pushmode here!

Post by m4s »

Thank You SpiKe^^!
That was the problem. Now it works!! :)
User avatar
m4s
Halfop
Posts: 97
Joined: Mon Jan 30, 2017 3:24 pm

1st error message

Post by m4s »

But on my testbot I got this error message:

Tcl error [::av::reset]: list doesn't contain element 1

I just used !voice nick1 nick2 and !devoice nick1 nick2....
User avatar
m4s
Halfop
Posts: 97
Joined: Mon Jan 30, 2017 3:24 pm

Post by m4s »

Hi,

The script works fine for some days,
I want to close this topic but before I do I have two questions. :)

My channel is not too big so I could not test it.
1. If more then one user joins the channel at the same time will this script give the +v in one line?
I mean:
[19:10] Nick joined the channel
[19:10] Nick2 joined the channel
I want: bot sets mode +vv nick1 nick2

Shall I change this line:
pushmode $chan +v $nick
to:
putquick "MODE $chan +v $nick"
2. The error message I shared with you in my previous post means nothing?
I haven't met with it since then...

Thank you for the replies!
User avatar
caesar
Mint Rubber
Posts: 3776
Joined: Sun Oct 14, 2001 8:00 pm
Location: Mint Factory

Post by caesar »

Sorry for the delay, lately I've been very busy with work and didn't get to do some proper testing.

Will see tomorrow if will have some to test a few things and see from and under what circumstances you get that error and reply back.
Once the game is over, the king and the pawn go back in the same box.
Post Reply