dropin

alternative frontend for dropout.tv
git clone https://git.ce9e.org/dropin.git

commit
6b688a2690d62035d70660015cd6be423fab71ed
parent
2b34d3f9eb284327359fd70aee3c6d160da2622e
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2025-02-07 09:50
only use credentials when actually needed

Diffstat

M dropin.py 28 +++++++++++++++++++++-------

1 files changed, 21 insertions, 7 deletions


diff --git a/dropin.py b/dropin.py

@@ -61,7 +61,7 @@ env.filters['duration'] = duration
   61    61 
   62    62 
   63    63 class Auth:
   64    -1     def __init__(self, email, password):
   -1    64     def __init__(self, email=None, password=None):
   65    65         self.email = email
   66    66         self.password = password
   67    67         self.future = None
@@ -76,8 +76,8 @@ class Auth:
   76    76                 pass
   77    77         raise ValueError(s)
   78    78 
   79    -1     async def login(self):
   80    -1         print('authenticating as', self.email)
   -1    79     async def auth(self):
   -1    80         print(f'fetch subscription token for {self.email}')
   81    81         async with aiohttp.ClientSession() as session:
   82    82             async with session.get('https://www.dropout.tv/login') as response:
   83    83                 response.raise_for_status()
@@ -93,11 +93,21 @@ class Auth:
   93    93                 html = await response.text()
   94    94                 return re.search(r'token: "([^"]+)', html).group(1)
   95    95 
   -1    96     async def unauth(self):
   -1    97         print('fetch non-subscription token')
   -1    98         async with aiohttp.ClientSession() as session:
   -1    99             async with session.get('https://www.dropout.tv/browse') as response:
   -1   100                 html = await response.text()
   -1   101                 return re.search(r'token: "([^"]+)', html).group(1)
   -1   102 
   96   103     async def get_token(self, timeout=300):
   97   104         if not self.future or (self.future.done() and self.exp < time.time() + timeout):
   98   105             self.future = asyncio.Future()
   99   106             try:
  100    -1                 token = await self.login()
   -1   107                 if self.password:
   -1   108                     token = await self.auth()
   -1   109                 else:
   -1   110                     token = await self.unauth()
  101   111                 parsed = self.jwt_parse(token)
  102   112                 self.exp = parsed['exp']
  103   113                 self.future.set_result(token)
@@ -107,6 +117,7 @@ class Auth:
  107   117         return await self.future
  108   118 
  109   119 auth = Auth(os.getenv('DROPOUT_EMAIL'), os.getenv('DROPOUT_PASSWORD'))
   -1   120 unauth = Auth()
  110   121 
  111   122 
  112   123 def async_cache(maxsize=128):
@@ -131,11 +142,14 @@ def async_cache(maxsize=128):
  131   142 
  132   143 
  133   144 @async_cache()
  134    -1 async def fetch(url, **params):
   -1   145 async def fetch(url, *, need_auth=False, **params):
  135   146     print('fetch', url)
  136   147 
  137   148     async with aiohttp.ClientSession() as session:
  138    -1         token = await auth.get_token()
   -1   149         if need_auth:
   -1   150             token = await auth.get_token()
   -1   151         else:
   -1   152             token = await unauth.get_token()
  139   153         async with session.get(
  140   154             url,
  141   155             headers={'Authorization': f'Bearer {token}'},
@@ -257,7 +271,7 @@ async def file_view(request):
  257   271     id = request.match_info['id']
  258   272     quality = request.match_info['quality']
  259   273     format = request.match_info['format']
  260    -1     files = await fetch(f'https://api.vhx.tv/videos/{id}/files')
   -1   274     files = await fetch(f'https://api.vhx.tv/videos/{id}/files', need_auth=True)
  261   275     filtered = [file for file in files if file['format'] == format]
  262   276     if not filtered:
  263   277         raise web.HTTPNotFound