<commit_before>import re

from livestreamer.plugin import Plugin
from livestreamer.plugin.api import http
from livestreamer.stream import HLSStream

SUCCESS_HTTP_CODES = (200,)

STREAM_URL_FORMAT = "http://tvcatchup.com/stream.php?chan={0}"
_url_re = re.compile("http://(?:www\.)?tvcatchup.com/watch/(?P<channel_id>[0-9]+)")


class TVCatchup(Plugin):
    @classmethod
    def can_handle_url(cls, url):
        return _url_re.match(url)

    def _get_streams(self):
        """
        Finds the stream from tvcatchup, they only provide a single 480p stream per channel.
        """
        match = _url_re.match(self.url).groupdict()
        channel_id = match["channel_id"]

        res = http.get(STREAM_URL_FORMAT.format(channel_id))

        stream_url = http.json(res).get('url')

        if stream_url:
            return {"480p": HLSStream(self.session, stream_url)}


__plugin__ = TVCatchup<commit_msg>fixed tvcatchup.com plugin, the website layout changed and the method to find the stream URLs needed to be updated.<commit_after>import re

from livestreamer.plugin import Plugin
from livestreamer.plugin.api import http
from livestreamer.stream import HLSStream

_url_re = re.compile("http://(?:www\.)?tvcatchup.com/watch/\w+")
_stream_re = re.compile(r"\"(?P<stream_url>http://.*m3u8.*clientKey=[^\"]*)\";")


class TVCatchup(Plugin):
    @classmethod
    def can_handle_url(cls, url):
        return _url_re.match(url)

    def _get_streams(self):
        """
        Finds the stream from tvcatchup, they only provide a single 720p stream per channel.
        """
        res = http.get(self.url)

        match = _stream_re.search(res.text, re.IGNORECASE | re.MULTILINE)

        if match:
            stream_url = match.groupdict()["stream_url"]

            if stream_url:
                return {"720p": HLSStream(self.session, stream_url)}


__plugin__ = TVCatchup
{'fraction_non_alphanumeric': 0.12267657992565056, 'fraction_numerical': 0.010621348911311737, 'mean_word_length': 3.262443438914027, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4212986', 'n_tokens_mistral': 650, 'n_tokens_neox': 618, 'n_words': 137}