jaraco / irc

Full-featured Python IRC library for Python.
MIT License
390 stars 85 forks source link

No way to get current topic of channel #132

Closed hiviah closed 6 years ago

hiviah commented 6 years ago

It seems that there is no way to get the topic of a channel. There is connection.topic() to change topic, but I don't see a way how to get current topic.

szero commented 6 years ago

Hi, in order to get the topic you indeed use the topic() method, but after that, you have to listen for currenttopic or notopic events produced by the server. Here is a bot example, based on the irccat2.py file from this project. Check IRCCat class to see how its done:

 #! /usr/bin/env python
#
# Example program using irc.client.
#
# This program is free without restrictions; do anything you like with
# it.
#
# Joel Rosdahl <joel@rosdahl.net>

import irc.client
import sys

class IRCCat(irc.client.SimpleIRCClient):
    def __init__(self, target):
        irc.client.SimpleIRCClient.__init__(self)
        self.target = target

    def on_welcome(self, connection, event):
        if irc.client.is_channel(self.target):
            connection.join(self.target)

    """
    The topic query will be triggered everytime someone posts 
    a public message in the channel
    """
    def on_pubmsg(self, connection, event):
        connection.topic(self.target)

    def on_currenttopic(self, connection, event):
        print(event.arguments[1])

    def on_notopic(self, connection, event):
        print(event.arguments[1])

    def on_disconnect(self, connection, event):
        sys.exit(0)

def main():
    if len(sys.argv) != 4:
        print("Usage: irccat2 <server[:port]> <nickname> <target>")
        print("\ntarget is a nickname or a channel.")
        sys.exit(1)

    s = sys.argv[1].split(":", 1)
    server = s[0]
    if len(s) == 2:
        try:
            port = int(s[1])
        except ValueError:
            print("Error: Erroneous port.")
            sys.exit(1)
    else:
        port = 6667
    nickname = sys.argv[2]
    target = sys.argv[3]

    c = IRCCat(target)
    try:
        c.connect(server, port, nickname)
    except irc.client.ServerConnectionError as x:
        print(x)
        sys.exit(1)
    c.start()

if __name__ == "__main__":
    main()
hiviah commented 6 years ago

Thank you very much, closing this issue.

hiviah commented 6 years ago

Is this possible if I have instance of ServerConnection instead of IRCClient? BTW I couldn't find the documentation for on_currenttopic either.

szero commented 6 years ago

The events are part of the IRC spec and are defined here. I also found this nice site which gives a brief description of each event. As for using ServerConnection class, here is an example that does the same thing as my previous one but without using IRCClient, you may want to look up add_global_handler method in the code, its well commented and explained how to use it there:

#! /usr/bin/env python

import sys
import irc.client

target = None # this will be our target channel

def welcome_cb(connection, event):
    if irc.client.is_channel(target):
        connection.join(target)

def pubmsg_cb(connection, event):
    connection.topic(target)

def currenttopic_cb(connection, event):
    print(event.arguments[1])

def notopic_cb(connection, event):
    print(event.arguments[1])

def disconnect_cb(connection, event):
    sys.exit(0)

def main():

    if len(sys.argv) != 4:
        print("Usage: irccat2 <server[:port]> <nickname> <target>")
        print("\ntarget is a nickname or a channel.")
        sys.exit(1)

    s = sys.argv[1].split(":", 1)
    server = s[0]
    if len(s) == 2:
        try:
            port = int(s[1])
        except ValueError:
            print("Error: Erroneous port.")
            sys.exit(1)
    else:
        port = 6667
    nickname = sys.argv[2]
    global target
    target = sys.argv[3]

    react = irc.client.Reactor()
    """
    server method from Reactor class creates an object of ServerConnection class
    """
    c = react.server()
    try:
        c.connect(server, port, nickname)
    except irc.client.ServerConnectionError as x:
        print(x)
        sys.exit(1)
    c.add_global_handler("welcome", welcome_cb)
    c.add_global_handler("pubmsg", pubmsg_cb)
    c.add_global_handler("currenttopic", currenttopic_cb)
    c.add_global_handler("notopic", notopic_cb)
    c.add_global_handler("disconnect", disconnect_cb)

    react.process_forever()

if __name__ == "__main__":
    main()

As you may notice, the biggest difference here is use of global keyword to pass extra arguments to our callbacks. This can be troublesome when our program grows so doing this objective way, as its made with SimpleIRCClient would be recommended.