# Path: cardinal/decorators.py
# def command(triggers):
#     if isinstance(triggers, str):
#         triggers = [triggers]
# 
#     if not isinstance(triggers, list):
#         raise TypeError("Command must be a trigger string or list of triggers")
# 
#     def wrap(f):
#         f.commands = triggers
#         return f
# 
#     return wrap
# 
# def event(triggers):
#     if isinstance(triggers, str):
#         triggers = [triggers]
# 
#     if not isinstance(triggers, list):
#         raise TypeError("Event must be a trigger string or list of triggers")
# 
#     def wrap(f):
#         f.events = triggers
#         return f
# 
#     return wrap
# 
# def help(lines):
#     # For backwards compatibility
#     if isinstance(lines, str):
#         lines = [lines]
# 
#     if not isinstance(lines, list):
#         raise TypeError("Help must be a help string or list of help strings")
# 
#     def wrap(f):
#         # Create help list or prepend to it
#         if not hasattr(f, 'help'):
#             f.help = lines
#         else:
#             f.help = lines + f.help
# 
#         return f
# 
#     return wrap
# 
# Path: cardinal/exceptions.py
# class EventRejectedMessage(CardinalException):
#     """Raised when an event callback wants to reject an event."""


import datetime
import re
import logging
import requests
from twisted.internet import defer
from twisted.internet.threads import deferToThread
from cardinal.decorators import command, event, help
from cardinal.exceptions import EventRejectedMessage
        result = yield self._form_request("search", params)

        if 'error' in result:
            raise Exception("Error searching Youtube: %s" % result['error'])

        try:
            return result['items'][0]
        except IndexError:
            return None

    @event('urls.detection')
    @defer.inlineCallbacks
    def _get_video_info(self, cardinal, channel, url):
        match = re.match(VIDEO_URL_REGEX, url)
        if not match:
            match = re.match(VIDEO_URL_SHORT_REGEX, url)
        if not match:
            raise EventRejectedMessage

        video_id = match.group(1)
        params = {
            'id': video_id,
            'maxResults': 1,
            'part': 'snippet,statistics,contentDetails',
        }

        try:
            result = yield self._form_request("videos", params)
        except Exception:
            self.logger.exception("Failed to fetch info for %s'" % video_id)

# Path: cardinal/decorators.py
# def command(triggers):
#     if isinstance(triggers, str):
#         triggers = [triggers]
# 
#     if not isinstance(triggers, list):
#         raise TypeError("Command must be a trigger string or list of triggers")
# 
#     def wrap(f):
#         f.commands = triggers
#         return f
# 
#     return wrap
# 
# def event(triggers):
#     if isinstance(triggers, str):
#         triggers = [triggers]
# 
#     if not isinstance(triggers, list):
#         raise TypeError("Event must be a trigger string or list of triggers")
# 
#     def wrap(f):
#         f.events = triggers
#         return f
# 
#     return wrap
# 
# def help(lines):
#     # For backwards compatibility
#     if isinstance(lines, str):
#         lines = [lines]
# 
#     if not isinstance(lines, list):
#         raise TypeError("Help must be a help string or list of help strings")
# 
#     def wrap(f):
#         # Create help list or prepend to it
#         if not hasattr(f, 'help'):
#             f.help = lines
#         else:
#             f.help = lines + f.help
# 
#         return f
# 
#     return wrap
# 
# Path: cardinal/exceptions.py
# class EventRejectedMessage(CardinalException):
#     """Raised when an event callback wants to reject an event."""


# Path: plugins/youtube/plugin.py
import datetime
import re
import logging
import requests
from twisted.internet import defer
from twisted.internet.threads import deferToThread
from cardinal.decorators import command, event, help
from cardinal.exceptions import EventRejectedMessage

        result = yield self._form_request("search", params)

        if 'error' in result:
            raise Exception("Error searching Youtube: %s" % result['error'])

        try:
            return result['items'][0]
        except IndexError:
            return None

    @event('urls.detection')
    @defer.inlineCallbacks
    def _get_video_info(self, cardinal, channel, url):
        match = re.match(VIDEO_URL_REGEX, url)
        if not match:
            match = re.match(VIDEO_URL_SHORT_REGEX, url)
        if not match:
            raise EventRejectedMessage

        video_id = match.group(1)
        params = {
            'id': video_id,
            'maxResults': 1,
            'part': 'snippet,statistics,contentDetails',
        }

        try:
            result = yield self._form_request("videos", params)
        except Exception:
            self.logger.exception("Failed to fetch info for %s'" % video_id)

            raise EventRejectedMessage