prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Vaughnlive changed IP's to break Streamlink
  This will be a very brief bug report... As of tonight the head vaughnlive.py references IPs which were disconnected by vaughn to thwart streamlinking. I've observed vaughn serving video now from "66.90.93.44","66.90.93.35" and have personally gotten it to work overwriting the IP's in rtmp_server_map with those two alternating. I would submit the commit but I think some more testing is needed as I only use streamlink with one occasional stream and don't know how far those IPs will get more frequent SL users.
  
   #1187 contains lengthy discussion on the history of the war vaughn has waged against streamlink, this is probably not the last time the IPs will change.
  
  </issue>
  <code>
  [start of src/streamlink/plugins/vaughnlive.py]
  1 import random
  2 import re
  3 import itertools
  4 import ssl
  5 import websocket
  6 
  7 from streamlink.plugin import Plugin
  8 from streamlink.plugin.api import useragents, http
  9 from streamlink.stream import RTMPStream
  10 
  11 _url_re = re.compile(r"""
  12     http(s)?://(\w+\.)?
  13     (?P<domain>vaughnlive|breakers|instagib|vapers|pearltime).tv
  14     (/embed/video)?
  15     /(?P<channel>[^/&?]+)
  16 """, re.VERBOSE)
  17 
  18 
  19 class VLWebSocket(websocket.WebSocket):
  20     def __init__(self, **_):
  21         self.session = _.pop("session")
  22         self.logger = self.session.logger.new_module("plugins.vaughnlive.websocket")
  23         sslopt = _.pop("sslopt", {})
  24         sslopt["cert_reqs"] = ssl.CERT_NONE
  25         super(VLWebSocket, self).__init__(sslopt=sslopt, **_)
  26 
  27     def send(self, payload, opcode=websocket.ABNF.OPCODE_TEXT):
  28         self.logger.debug("Sending message: {0}", payload)
  29         return super(VLWebSocket, self).send(payload + "\n\x00", opcode)
  30 
  31     def recv(self):
  32         d = super(VLWebSocket, self).recv().replace("\n", "").replace("\x00", "")
  33         return d.split(" ", 1)
  34 
  35 
  36 class VaughnLive(Plugin):
  37     servers = ["wss://sapi-ws-{0}x{1:02}.vaughnlive.tv".format(x, y) for x, y in itertools.product(range(1, 3),
  38                                                                                                    range(1, 6))]
  39     origin = "https://vaughnlive.tv"
  40     rtmp_server_map = {
  41         "594140c69edad": "66.90.93.42",
  42         "585c4cab1bef1": "66.90.93.34",
  43         "5940d648b3929": "66.90.93.42",
  44         "5941854b39bc4": "198.255.0.10"
  45     }
  46     name_remap = {"#vl": "live", "#btv": "btv", "#pt": "pt", "#igb": "instagib", "#vtv": "vtv"}
  47     domain_map = {"vaughnlive": "#vl", "breakers": "#btv", "instagib": "#igb", "vapers": "#vtv", "pearltime": "#pt"}
  48 
  49     @classmethod
  50     def can_handle_url(cls, url):
  51         return _url_re.match(url)
  52 
  53     def api_url(self):
  54         return random.choice(self.servers)
  55 
  56     def parse_ack(self, action, message):
  57         if action.endswith("3"):
  58             channel, _, viewers, token, server, choked, is_live, chls, trns, ingest = message.split(";")
  59             is_live = is_live == "1"
  60             viewers = int(viewers)
  61             self.logger.debug("Viewers: {0}, isLive={1}", viewers, is_live)
  62             domain, channel = channel.split("-", 1)
  63             return is_live, server, domain, channel, token, ingest
  64         else:
  65             self.logger.error("Unhandled action format: {0}", action)
  66 
  67     def _get_info(self, stream_name):
  68         server = self.api_url()
  69         self.logger.debug("Connecting to API: {0}", server)
  70         ws = websocket.create_connection(server,
  71                                          header=["User-Agent: {0}".format(useragents.CHROME)],
  72                                          origin=self.origin,
  73                                          class_=VLWebSocket,
  74                                          session=self.session)
  75         ws.send("MVN LOAD3 {0}".format(stream_name))
  76         action, message = ws.recv()
  77         return self.parse_ack(action, message)
  78 
  79     def _get_rtmp_streams(self, server, domain, channel, token):
  80         rtmp_server = self.rtmp_server_map.get(server, server)
  81 
  82         url = "rtmp://{0}/live?{1}".format(rtmp_server, token)
  83 
  84         yield "live", RTMPStream(self.session, params={
  85             "rtmp": url,
  86             "pageUrl": self.url,
  87             "playpath": "{0}_{1}".format(self.name_remap.get(domain, "live"), channel),
  88             "live": True
  89         })
  90 
  91     def _get_streams(self):
  92         m = _url_re.match(self.url)
  93         if m:
  94             stream_name = "{0}-{1}".format(self.domain_map[(m.group("domain").lower())],
  95                                            m.group("channel"))
  96 
  97             is_live, server, domain, channel, token, ingest = self._get_info(stream_name)
  98 
  99             if not is_live:
  100                 self.logger.info("Stream is currently off air")
  101             else:
  102                 for s in self._get_rtmp_streams(server, domain, channel, token):
  103                     yield s
  104 
  105 
  106 __plugin__ = VaughnLive
  107
  [end of src/streamlink/plugins/vaughnlive.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/src/streamlink/plugins/vaughnlive.py b/src/streamlink/plugins/vaughnlive.py
  --- a/src/streamlink/plugins/vaughnlive.py
  +++ b/src/streamlink/plugins/vaughnlive.py
  @@ -38,10 +38,10 @@
                                                                                                      range(1, 6))]
       origin = "https://vaughnlive.tv"
       rtmp_server_map = {
  -        "594140c69edad": "66.90.93.42",
  -        "585c4cab1bef1": "66.90.93.34",
  -        "5940d648b3929": "66.90.93.42",
  -        "5941854b39bc4": "198.255.0.10"
  +        "594140c69edad": "192.240.105.171:1935",
  +        "585c4cab1bef1": "192.240.105.171:1935",
  +        "5940d648b3929": "192.240.105.171:1935",
  +        "5941854b39bc4": "192.240.105.171:1935"
       }
       name_remap = {"#vl": "live", "#btv": "btv", "#pt": "pt", "#igb": "instagib", "#vtv": "vtv"}
       domain_map = {"vaughnlive": "#vl", "breakers": "#btv", "instagib": "#igb", "vapers": "#vtv", "pearltime": "#pt"}
  @@ -99,6 +99,7 @@
               if not is_live:
                   self.logger.info("Stream is currently off air")
               else:
  +                self.logger.info("Stream powered by VaughnSoft - remember to support them.")
                   for s in self._get_rtmp_streams(server, domain, channel, token):
                       yield s
  
verification_info: {"golden_diff": "diff --git a/src/streamlink/plugins/vaughnlive.py b/src/streamlink/plugins/vaughnlive.py\n--- a/src/streamlink/plugins/vaughnlive.py\n+++ b/src/streamlink/plugins/vaughnlive.py\n@@ -38,10 +38,10 @@\n                                                                                                    range(1, 6))]\n     origin = \"https://vaughnlive.tv\"\n     rtmp_server_map = {\n-        \"594140c69edad\": \"66.90.93.42\",\n-        \"585c4cab1bef1\": \"66.90.93.34\",\n-        \"5940d648b3929\": \"66.90.93.42\",\n-        \"5941854b39bc4\": \"198.255.0.10\"\n+        \"594140c69edad\": \"192.240.105.171:1935\",\n+        \"585c4cab1bef1\": \"192.240.105.171:1935\",\n+        \"5940d648b3929\": \"192.240.105.171:1935\",\n+        \"5941854b39bc4\": \"192.240.105.171:1935\"\n     }\n     name_remap = {\"#vl\": \"live\", \"#btv\": \"btv\", \"#pt\": \"pt\", \"#igb\": \"instagib\", \"#vtv\": \"vtv\"}\n     domain_map = {\"vaughnlive\": \"#vl\", \"breakers\": \"#btv\", \"instagib\": \"#igb\", \"vapers\": \"#vtv\", \"pearltime\": \"#pt\"}\n@@ -99,6 +99,7 @@\n             if not is_live:\n                 self.logger.info(\"Stream is currently off air\")\n             else:\n+                self.logger.info(\"Stream powered by VaughnSoft - remember to support them.\")\n                 for s in self._get_rtmp_streams(server, domain, channel, token):\n                     yield s\n", "issue": "Vaughnlive changed IP's to break Streamlink\nThis will be a very brief bug report... As of tonight the head vaughnlive.py references IPs which were disconnected by vaughn to thwart streamlinking. I've observed vaughn serving video now from \"66.90.93.44\",\"66.90.93.35\" and have personally gotten it to work overwriting the IP's in rtmp_server_map with those two alternating. I would submit the commit but I think some more testing is needed as I only use streamlink with one occasional stream and don't know how far those IPs will get more frequent SL users.\r\n\r\n #1187 contains lengthy discussion on the history of the war vaughn has waged against streamlink, this is probably not the last time the IPs will change.\n", "before_files": [{"content": "import random\nimport re\nimport itertools\nimport ssl\nimport websocket\n\nfrom streamlink.plugin import Plugin\nfrom streamlink.plugin.api import useragents, http\nfrom streamlink.stream import RTMPStream\n\n_url_re = re.compile(r\"\"\"\n    http(s)?://(\\w+\\.)?\n    (?P<domain>vaughnlive|breakers|instagib|vapers|pearltime).tv\n    (/embed/video)?\n    /(?P<channel>[^/&?]+)\n\"\"\", re.VERBOSE)\n\n\nclass VLWebSocket(websocket.WebSocket):\n    def __init__(self, **_):\n        self.session = _.pop(\"session\")\n        self.logger = self.session.logger.new_module(\"plugins.vaughnlive.websocket\")\n        sslopt = _.pop(\"sslopt\", {})\n        sslopt[\"cert_reqs\"] = ssl.CERT_NONE\n        super(VLWebSocket, self).__init__(sslopt=sslopt, **_)\n\n    def send(self, payload, opcode=websocket.ABNF.OPCODE_TEXT):\n        self.logger.debug(\"Sending message: {0}\", payload)\n        return super(VLWebSocket, self).send(payload + \"\\n\\x00\", opcode)\n\n    def recv(self):\n        d = super(VLWebSocket, self).recv().replace(\"\\n\", \"\").replace(\"\\x00\", \"\")\n        return d.split(\" \", 1)\n\n\nclass VaughnLive(Plugin):\n    servers = [\"wss://sapi-ws-{0}x{1:02}.vaughnlive.tv\".format(x, y) for x, y in itertools.product(range(1, 3),\n                                                                                                   range(1, 6))]\n    origin = \"https://vaughnlive.tv\"\n    rtmp_server_map = {\n        \"594140c69edad\": \"66.90.93.42\",\n        \"585c4cab1bef1\": \"66.90.93.34\",\n        \"5940d648b3929\": \"66.90.93.42\",\n        \"5941854b39bc4\": \"198.255.0.10\"\n    }\n    name_remap = {\"#vl\": \"live\", \"#btv\": \"btv\", \"#pt\": \"pt\", \"#igb\": \"instagib\", \"#vtv\": \"vtv\"}\n    domain_map = {\"vaughnlive\": \"#vl\", \"breakers\": \"#btv\", \"instagib\": \"#igb\", \"vapers\": \"#vtv\", \"pearltime\": \"#pt\"}\n\n    @classmethod\n    def can_handle_url(cls, url):\n        return _url_re.match(url)\n\n    def api_url(self):\n        return random.choice(self.servers)\n\n    def parse_ack(self, action, message):\n        if action.endswith(\"3\"):\n            channel, _, viewers, token, server, choked, is_live, chls, trns, ingest = message.split(\";\")\n            is_live = is_live == \"1\"\n            viewers = int(viewers)\n            self.logger.debug(\"Viewers: {0}, isLive={1}\", viewers, is_live)\n            domain, channel = channel.split(\"-\", 1)\n            return is_live, server, domain, channel, token, ingest\n        else:\n            self.logger.error(\"Unhandled action format: {0}\", action)\n\n    def _get_info(self, stream_name):\n        server = self.api_url()\n        self.logger.debug(\"Connecting to API: {0}\", server)\n        ws = websocket.create_connection(server,\n                                         header=[\"User-Agent: {0}\".format(useragents.CHROME)],\n                                         origin=self.origin,\n                                         class_=VLWebSocket,\n                                         session=self.session)\n        ws.send(\"MVN LOAD3 {0}\".format(stream_name))\n        action, message = ws.recv()\n        return self.parse_ack(action, message)\n\n    def _get_rtmp_streams(self, server, domain, channel, token):\n        rtmp_server = self.rtmp_server_map.get(server, server)\n\n        url = \"rtmp://{0}/live?{1}\".format(rtmp_server, token)\n\n        yield \"live\", RTMPStream(self.session, params={\n            \"rtmp\": url,\n            \"pageUrl\": self.url,\n            \"playpath\": \"{0}_{1}\".format(self.name_remap.get(domain, \"live\"), channel),\n            \"live\": True\n        })\n\n    def _get_streams(self):\n        m = _url_re.match(self.url)\n        if m:\n            stream_name = \"{0}-{1}\".format(self.domain_map[(m.group(\"domain\").lower())],\n                                           m.group(\"channel\"))\n\n            is_live, server, domain, channel, token, ingest = self._get_info(stream_name)\n\n            if not is_live:\n                self.logger.info(\"Stream is currently off air\")\n            else:\n                for s in self._get_rtmp_streams(server, domain, channel, token):\n                    yield s\n\n\n__plugin__ = VaughnLive\n", "path": "src/streamlink/plugins/vaughnlive.py"}]}