prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  [Site Request] 7plus add login/pass to access 720p resolution
  <!--
  
  ######################################################################
    WARNING!
    IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
  ######################################################################
  
  -->
  
  
  ## Checklist
  
  <!--
  Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
  - First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.09.25. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
  - Search the bugtracker for similar site feature requests: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
  - Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
  -->
  
  - [x] I'm reporting a site feature request
  - [x] I've verified that I'm running yt-dlp version **2021.09.25**
  - [x] I've searched the bugtracker for similar site feature requests including closed ones
  
  
  ## Description
  
  <!--
  Provide an explanation of your site feature request in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
  -->
  
  7Plus has 720p resolution available behind a login/pass.  Current site functionality only pulls 540p.  
  
  </issue>
  <code>
  [start of yt_dlp/extractor/sevenplus.py]
  1 # coding: utf-8
  2 from __future__ import unicode_literals
  3 
  4 import re
  5 
  6 from .brightcove import BrightcoveNewIE
  7 from ..compat import (
  8     compat_HTTPError,
  9     compat_str,
  10 )
  11 from ..utils import (
  12     ExtractorError,
  13     try_get,
  14     update_url_query,
  15 )
  16 
  17 
  18 class SevenPlusIE(BrightcoveNewIE):
  19     IE_NAME = '7plus'
  20     _VALID_URL = r'https?://(?:www\.)?7plus\.com\.au/(?P<path>[^?]+\?.*?\bepisode-id=(?P<id>[^&#]+))'
  21     _TESTS = [{
  22         'url': 'https://7plus.com.au/MTYS?episode-id=MTYS7-003',
  23         'info_dict': {
  24             'id': 'MTYS7-003',
  25             'ext': 'mp4',
  26             'title': 'S7 E3 - Wind Surf',
  27             'description': 'md5:29c6a69f21accda7601278f81b46483d',
  28             'uploader_id': '5303576322001',
  29             'upload_date': '20171201',
  30             'timestamp': 1512106377,
  31             'series': 'Mighty Ships',
  32             'season_number': 7,
  33             'episode_number': 3,
  34             'episode': 'Wind Surf',
  35         },
  36         'params': {
  37             'format': 'bestvideo',
  38             'skip_download': True,
  39         }
  40     }, {
  41         'url': 'https://7plus.com.au/UUUU?episode-id=AUMS43-001',
  42         'only_matching': True,
  43     }]
  44 
  45     def _real_extract(self, url):
  46         path, episode_id = self._match_valid_url(url).groups()
  47 
  48         try:
  49             media = self._download_json(
  50                 'https://videoservice.swm.digital/playback', episode_id, query={
  51                     'appId': '7plus',
  52                     'deviceType': 'web',
  53                     'platformType': 'web',
  54                     'accountId': 5303576322001,
  55                     'referenceId': 'ref:' + episode_id,
  56                     'deliveryId': 'csai',
  57                     'videoType': 'vod',
  58                 })['media']
  59         except ExtractorError as e:
  60             if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:
  61                 raise ExtractorError(self._parse_json(
  62                     e.cause.read().decode(), episode_id)[0]['error_code'], expected=True)
  63             raise
  64 
  65         for source in media.get('sources', {}):
  66             src = source.get('src')
  67             if not src:
  68                 continue
  69             source['src'] = update_url_query(src, {'rule': ''})
  70 
  71         info = self._parse_brightcove_metadata(media, episode_id)
  72 
  73         content = self._download_json(
  74             'https://component-cdn.swm.digital/content/' + path,
  75             episode_id, headers={
  76                 'market-id': 4,
  77             }, fatal=False) or {}
  78         for item in content.get('items', {}):
  79             if item.get('componentData', {}).get('componentType') == 'infoPanel':
  80                 for src_key, dst_key in [('title', 'title'), ('shortSynopsis', 'description')]:
  81                     value = item.get(src_key)
  82                     if value:
  83                         info[dst_key] = value
  84                 info['series'] = try_get(
  85                     item, lambda x: x['seriesLogo']['name'], compat_str)
  86                 mobj = re.search(r'^S(\d+)\s+E(\d+)\s+-\s+(.+)$', info['title'])
  87                 if mobj:
  88                     info.update({
  89                         'season_number': int(mobj.group(1)),
  90                         'episode_number': int(mobj.group(2)),
  91                         'episode': mobj.group(3),
  92                     })
  93 
  94         return info
  95
  [end of yt_dlp/extractor/sevenplus.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/yt_dlp/extractor/sevenplus.py b/yt_dlp/extractor/sevenplus.py
  --- a/yt_dlp/extractor/sevenplus.py
  +++ b/yt_dlp/extractor/sevenplus.py
  @@ -1,6 +1,7 @@
   # coding: utf-8
   from __future__ import unicode_literals
   
  +import json
   import re
   
   from .brightcove import BrightcoveNewIE
  @@ -42,9 +43,52 @@
           'only_matching': True,
       }]
   
  +    def _real_initialize(self):
  +        self.token = None
  +
  +        cookies = self._get_cookies('https://7plus.com.au')
  +        api_key = next((x for x in cookies if x.startswith('glt_')), '')[4:]
  +        if not api_key:  # Cookies are signed out, skip login
  +            return
  +
  +        login_resp = self._download_json(
  +            'https://login.7plus.com.au/accounts.getJWT', None, 'Logging in', fatal=False,
  +            query={
  +                'APIKey': api_key,
  +                'sdk': 'js_latest',
  +                'login_token': cookies[f'glt_{api_key}'].value,
  +                'authMode': 'cookie',
  +                'pageURL': 'https://7plus.com.au/',
  +                'sdkBuild': '12471',
  +                'format': 'json',
  +            }) or {}
  +
  +        if 'errorMessage' in login_resp:
  +            self.report_warning(f'Unable to login: 7plus said: {login_resp["errorMessage"]}')
  +            return
  +        id_token = login_resp.get('id_token')
  +        if not id_token:
  +            self.report_warning('Unable to login: Could not extract id token')
  +            return
  +
  +        token_resp = self._download_json(
  +            'https://7plus.com.au/auth/token', None, 'Getting auth token', fatal=False,
  +            headers={'Content-Type': 'application/json'}, data=json.dumps({
  +                'idToken': id_token,
  +                'platformId': 'web',
  +                'regSource': '7plus',
  +            }).encode('utf-8')) or {}
  +        self.token = token_resp.get('token')
  +        if not self.token:
  +            self.report_warning('Unable to log in: Could not extract auth token')
  +
       def _real_extract(self, url):
           path, episode_id = self._match_valid_url(url).groups()
   
  +        headers = {}
  +        if self.token:
  +            headers['Authorization'] = f'Bearer {self.token}'
  +
           try:
               media = self._download_json(
                   'https://videoservice.swm.digital/playback', episode_id, query={
  @@ -55,7 +99,7 @@
                       'referenceId': 'ref:' + episode_id,
                       'deliveryId': 'csai',
                       'videoType': 'vod',
  -                })['media']
  +                }, headers=headers)['media']
           except ExtractorError as e:
               if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:
                   raise ExtractorError(self._parse_json(
  
verification_info: {"golden_diff": "diff --git a/yt_dlp/extractor/sevenplus.py b/yt_dlp/extractor/sevenplus.py\n--- a/yt_dlp/extractor/sevenplus.py\n+++ b/yt_dlp/extractor/sevenplus.py\n@@ -1,6 +1,7 @@\n # coding: utf-8\n from __future__ import unicode_literals\n \n+import json\n import re\n \n from .brightcove import BrightcoveNewIE\n@@ -42,9 +43,52 @@\n         'only_matching': True,\n     }]\n \n+    def _real_initialize(self):\n+        self.token = None\n+\n+        cookies = self._get_cookies('https://7plus.com.au')\n+        api_key = next((x for x in cookies if x.startswith('glt_')), '')[4:]\n+        if not api_key:  # Cookies are signed out, skip login\n+            return\n+\n+        login_resp = self._download_json(\n+            'https://login.7plus.com.au/accounts.getJWT', None, 'Logging in', fatal=False,\n+            query={\n+                'APIKey': api_key,\n+                'sdk': 'js_latest',\n+                'login_token': cookies[f'glt_{api_key}'].value,\n+                'authMode': 'cookie',\n+                'pageURL': 'https://7plus.com.au/',\n+                'sdkBuild': '12471',\n+                'format': 'json',\n+            }) or {}\n+\n+        if 'errorMessage' in login_resp:\n+            self.report_warning(f'Unable to login: 7plus said: {login_resp[\"errorMessage\"]}')\n+            return\n+        id_token = login_resp.get('id_token')\n+        if not id_token:\n+            self.report_warning('Unable to login: Could not extract id token')\n+            return\n+\n+        token_resp = self._download_json(\n+            'https://7plus.com.au/auth/token', None, 'Getting auth token', fatal=False,\n+            headers={'Content-Type': 'application/json'}, data=json.dumps({\n+                'idToken': id_token,\n+                'platformId': 'web',\n+                'regSource': '7plus',\n+            }).encode('utf-8')) or {}\n+        self.token = token_resp.get('token')\n+        if not self.token:\n+            self.report_warning('Unable to log in: Could not extract auth token')\n+\n     def _real_extract(self, url):\n         path, episode_id = self._match_valid_url(url).groups()\n \n+        headers = {}\n+        if self.token:\n+            headers['Authorization'] = f'Bearer {self.token}'\n+\n         try:\n             media = self._download_json(\n                 'https://videoservice.swm.digital/playback', episode_id, query={\n@@ -55,7 +99,7 @@\n                     'referenceId': 'ref:' + episode_id,\n                     'deliveryId': 'csai',\n                     'videoType': 'vod',\n-                })['media']\n+                }, headers=headers)['media']\n         except ExtractorError as e:\n             if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:\n                 raise ExtractorError(self._parse_json(\n", "issue": "[Site Request] 7plus add login/pass to access 720p resolution\n<!--\r\n\r\n######################################################################\r\n  WARNING!\r\n  IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE\r\n######################################################################\r\n\r\n-->\r\n\r\n\r\n## Checklist\r\n\r\n<!--\r\nCarefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:\r\n- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.09.25. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.\r\n- Search the bugtracker for similar site feature requests: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.\r\n- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)\r\n-->\r\n\r\n- [x] I'm reporting a site feature request\r\n- [x] I've verified that I'm running yt-dlp version **2021.09.25**\r\n- [x] I've searched the bugtracker for similar site feature requests including closed ones\r\n\r\n\r\n## Description\r\n\r\n<!--\r\nProvide an explanation of your site feature request in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.\r\n-->\r\n\r\n7Plus has 720p resolution available behind a login/pass.  Current site functionality only pulls 540p.  \n", "before_files": [{"content": "# coding: utf-8\nfrom __future__ import unicode_literals\n\nimport re\n\nfrom .brightcove import BrightcoveNewIE\nfrom ..compat import (\n    compat_HTTPError,\n    compat_str,\n)\nfrom ..utils import (\n    ExtractorError,\n    try_get,\n    update_url_query,\n)\n\n\nclass SevenPlusIE(BrightcoveNewIE):\n    IE_NAME = '7plus'\n    _VALID_URL = r'https?://(?:www\\.)?7plus\\.com\\.au/(?P<path>[^?]+\\?.*?\\bepisode-id=(?P<id>[^&#]+))'\n    _TESTS = [{\n        'url': 'https://7plus.com.au/MTYS?episode-id=MTYS7-003',\n        'info_dict': {\n            'id': 'MTYS7-003',\n            'ext': 'mp4',\n            'title': 'S7 E3 - Wind Surf',\n            'description': 'md5:29c6a69f21accda7601278f81b46483d',\n            'uploader_id': '5303576322001',\n            'upload_date': '20171201',\n            'timestamp': 1512106377,\n            'series': 'Mighty Ships',\n            'season_number': 7,\n            'episode_number': 3,\n            'episode': 'Wind Surf',\n        },\n        'params': {\n            'format': 'bestvideo',\n            'skip_download': True,\n        }\n    }, {\n        'url': 'https://7plus.com.au/UUUU?episode-id=AUMS43-001',\n        'only_matching': True,\n    }]\n\n    def _real_extract(self, url):\n        path, episode_id = self._match_valid_url(url).groups()\n\n        try:\n            media = self._download_json(\n                'https://videoservice.swm.digital/playback', episode_id, query={\n                    'appId': '7plus',\n                    'deviceType': 'web',\n                    'platformType': 'web',\n                    'accountId': 5303576322001,\n                    'referenceId': 'ref:' + episode_id,\n                    'deliveryId': 'csai',\n                    'videoType': 'vod',\n                })['media']\n        except ExtractorError as e:\n            if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:\n                raise ExtractorError(self._parse_json(\n                    e.cause.read().decode(), episode_id)[0]['error_code'], expected=True)\n            raise\n\n        for source in media.get('sources', {}):\n            src = source.get('src')\n            if not src:\n                continue\n            source['src'] = update_url_query(src, {'rule': ''})\n\n        info = self._parse_brightcove_metadata(media, episode_id)\n\n        content = self._download_json(\n            'https://component-cdn.swm.digital/content/' + path,\n            episode_id, headers={\n                'market-id': 4,\n            }, fatal=False) or {}\n        for item in content.get('items', {}):\n            if item.get('componentData', {}).get('componentType') == 'infoPanel':\n                for src_key, dst_key in [('title', 'title'), ('shortSynopsis', 'description')]:\n                    value = item.get(src_key)\n                    if value:\n                        info[dst_key] = value\n                info['series'] = try_get(\n                    item, lambda x: x['seriesLogo']['name'], compat_str)\n                mobj = re.search(r'^S(\\d+)\\s+E(\\d+)\\s+-\\s+(.+)$', info['title'])\n                if mobj:\n                    info.update({\n                        'season_number': int(mobj.group(1)),\n                        'episode_number': int(mobj.group(2)),\n                        'episode': mobj.group(3),\n                    })\n\n        return info\n", "path": "yt_dlp/extractor/sevenplus.py"}]}