import asyncio
import re

import aiohttp
import lxml.html

from seabird.plugin import Plugin


class URLPlugin(Plugin):
    url_regex = re.compile(r'https?://[^ ]+')

    def irc_privmsg(self, msg):
        for match in URLPlugin.url_regex.finditer(msg.trailing):
            url = match.group(0)

            # As a fallback, use our own internal URL handler
            if True:
                loop = asyncio.get_event_loop()
                loop.create_task(self.url_callback(msg, url))

    async def url_callback(self, msg, url):
        async with aiohttp.get(url) as resp:
            # Read up to 1m
            data = await resp.content.read(1024*1024)
            if not data:
                return

            tree = lxml.html.fromstring(data)
            title = tree.find(".//title")
            if title is None:
                return

            self.bot.reply(msg, 'Title: {}'.format(title.text))

import asyncio
import re

import aiohttp
import lxml.html

from seabird.plugin import Plugin


class URLMixin:
    """Simple marker class to mark a plugin as a url plugin

    A URL plugin requires only one thing:
    - A method named url_match which takes a msg and url as an argument and
      returns True if the url matches this plugin.

    Note that callback functions are not required to be coroutines in case they
    need to access data from other plugins, but most should have a background
    task as almost every one will need to do some form of background processing
    or data transfer.
    """
    def url_match(self, msg, url):
        raise NotImplementedError


class URLPlugin(Plugin):
    url_regex = re.compile(r'https?://[^ ]+')

    def irc_privmsg(self, msg):
        for match in URLPlugin.url_regex.finditer(msg.trailing):
            url = match.group(0)

            matching_plugin = False
            for plugin in self.bot.plugins:
                if isinstance(plugin, URLMixin) and plugin.url_match(msg, url):
                    matching_plugin = True

            # As a fallback, use our own internal URL handler
            if not matching_plugin:
                loop = asyncio.get_event_loop()
                loop.create_task(self.url_callback(msg, url))

    async def url_callback(self, msg, url):
        async with aiohttp.get(url) as resp:
            # Read up to 1m
            data = await resp.content.read(1024*1024)
            if not data:
                return

            tree = lxml.html.fromstring(data)
            title = tree.find(".//title")
            if title is None:
                return

            self.bot.reply(msg, 'Title: {}'.format(title.text))

Add a method for plugins to add their own URL handlers
Add a method for plugins to add their own URL handlers

  import asyncio
  import re
  
  import aiohttp
  import lxml.html
  
  from seabird.plugin import Plugin
  
  
+ class URLMixin:
+     """Simple marker class to mark a plugin as a url plugin
+ 
+     A URL plugin requires only one thing:
+     - A method named url_match which takes a msg and url as an argument and
+       returns True if the url matches this plugin.
+ 
+     Note that callback functions are not required to be coroutines in case they
+     need to access data from other plugins, but most should have a background
+     task as almost every one will need to do some form of background processing
+     or data transfer.
+     """
+     def url_match(self, msg, url):
+         raise NotImplementedError
+ 
+ 
  class URLPlugin(Plugin):
      url_regex = re.compile(r'https?://[^ ]+')
  
      def irc_privmsg(self, msg):
          for match in URLPlugin.url_regex.finditer(msg.trailing):
              url = match.group(0)
  
+             matching_plugin = False
+             for plugin in self.bot.plugins:
+                 if isinstance(plugin, URLMixin) and plugin.url_match(msg, url):
+                     matching_plugin = True
+ 
              # As a fallback, use our own internal URL handler
-             if True:
+             if not matching_plugin:
                  loop = asyncio.get_event_loop()
                  loop.create_task(self.url_callback(msg, url))
  
      async def url_callback(self, msg, url):
          async with aiohttp.get(url) as resp:
              # Read up to 1m
              data = await resp.content.read(1024*1024)
              if not data:
                  return
  
              tree = lxml.html.fromstring(data)
              title = tree.find(".//title")
              if title is None:
                  return
  
              self.bot.reply(msg, 'Title: {}'.format(title.text))
  
Add a method for plugins to add their own URL handlers
## Code Before:
import asyncio
import re

import aiohttp
import lxml.html

from seabird.plugin import Plugin


class URLPlugin(Plugin):
    url_regex = re.compile(r'https?://[^ ]+')

    def irc_privmsg(self, msg):
        for match in URLPlugin.url_regex.finditer(msg.trailing):
            url = match.group(0)

            # As a fallback, use our own internal URL handler
            if True:
                loop = asyncio.get_event_loop()
                loop.create_task(self.url_callback(msg, url))

    async def url_callback(self, msg, url):
        async with aiohttp.get(url) as resp:
            # Read up to 1m
            data = await resp.content.read(1024*1024)
            if not data:
                return

            tree = lxml.html.fromstring(data)
            title = tree.find(".//title")
            if title is None:
                return

            self.bot.reply(msg, 'Title: {}'.format(title.text))

## Instruction:
Add a method for plugins to add their own URL handlers
## Code After:
import asyncio
import re

import aiohttp
import lxml.html

from seabird.plugin import Plugin


class URLMixin:
    """Simple marker class to mark a plugin as a url plugin

    A URL plugin requires only one thing:
    - A method named url_match which takes a msg and url as an argument and
      returns True if the url matches this plugin.

    Note that callback functions are not required to be coroutines in case they
    need to access data from other plugins, but most should have a background
    task as almost every one will need to do some form of background processing
    or data transfer.
    """
    def url_match(self, msg, url):
        raise NotImplementedError


class URLPlugin(Plugin):
    url_regex = re.compile(r'https?://[^ ]+')

    def irc_privmsg(self, msg):
        for match in URLPlugin.url_regex.finditer(msg.trailing):
            url = match.group(0)

            matching_plugin = False
            for plugin in self.bot.plugins:
                if isinstance(plugin, URLMixin) and plugin.url_match(msg, url):
                    matching_plugin = True

            # As a fallback, use our own internal URL handler
            if not matching_plugin:
                loop = asyncio.get_event_loop()
                loop.create_task(self.url_callback(msg, url))

    async def url_callback(self, msg, url):
        async with aiohttp.get(url) as resp:
            # Read up to 1m
            data = await resp.content.read(1024*1024)
            if not data:
                return

            tree = lxml.html.fromstring(data)
            title = tree.find(".//title")
            if title is None:
                return

            self.bot.reply(msg, 'Title: {}'.format(title.text))
