From c3f941c56728d0c227973d6ab485bfba9f54e1f0 Mon Sep 17 00:00:00 2001 From: "anatoly.k" Date: Wed, 8 Mar 2023 16:44:27 +0300 Subject: [PATCH 1/3] Add password support --- vimeo_downloader/__init__.py | 81 ++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/vimeo_downloader/__init__.py b/vimeo_downloader/__init__.py index 47d9866..2254134 100644 --- a/vimeo_downloader/__init__.py +++ b/vimeo_downloader/__init__.py @@ -27,7 +27,7 @@ from collections import namedtuple from typing import List, NamedTuple, Optional from urllib.parse import parse_qs, urlparse - +from base64 import b64encode import requests from tqdm import tqdm @@ -35,8 +35,9 @@ "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0", } config = "https://player.vimeo.com/video/{}/config" +password_config ="https://player.vimeo.com/video/{}/check-password" details = "http://vimeo.com/api/v2/video/{}.json" - +session = requests.Session() class URLNotSupported(Exception): pass @@ -113,7 +114,6 @@ def download( """ Downloads the video with progress bar if `mute=False` """ - if (filename is None) and (self.title is None): try: filename = re.findall(r"\/(\d+\.mp4|webm$)", self._direct_url)[0] @@ -126,7 +126,7 @@ def download( else: if not filename.endswith(".mp4"): filename += ".mp4" - r = requests.get(self._direct_url, stream=True, headers=headers) + r = session.get(self._direct_url, stream=True, headers=headers, verify=False,) if not r.ok: if r.status_code == 410: raise URLExpired("The download URL has expired.") @@ -161,7 +161,7 @@ def filesize(self) -> str: Returns str with filesize in MB. """ - r = requests.get(self._direct_url, stream=True, headers=headers) + r = session.get(self._direct_url, stream=True, headers=headers, verify=False,) return str(int(r.headers.get("content-length")) / 10**6) + " MB" @@ -175,6 +175,7 @@ def __init__( url: str, embedded_on: Optional[str] = None, cookies: Optional[str] = None, + password: Optional[str] = None, ): self._url = ( urlparse(url)._replace(query=None).geturl() @@ -183,6 +184,7 @@ def __init__( self._headers = headers self._cookies = dict(cookies_are=cookies) self._params = self._extract_query(url) + self._password = b64encode(password.encode()).decode() if password else None if embedded_on: self._headers["Referer"] = embedded_on @@ -215,26 +217,39 @@ def _extractor(self) -> dict: """ Extracts the direct mp4 link for the vimeo video """ - if self._cookies.get("cookies_are") is not None: - js_url = requests.get( - config.format(self._video_id), - headers=self._headers, - cookies=self._cookies, - params=self._params, - ) + if not self._password: + if self._cookies.get("cookies_are") is not None: + js_url = session.get( + config.format(self._video_id), + headers=self._headers, + cookies=self._cookies, + params=self._params, + verify=False + ) + else: + js_url = session.get( + config.format(self._video_id), + headers=self._headers, + params=self._params, + verify=False + + ) else: - js_url = requests.get( - config.format(self._video_id), + js_url = session.post( + password_config.format(self._video_id), headers=self._headers, params=self._params, + data=dict(password=self._password), + verify=False ) + if not js_url.ok: if js_url.status_code == 403: # If the response is forbidden it tries another way to fetch link try: - html = requests.get( - self._url, headers=self._headers, params=self._params + html = session.get( + self._url, headers=self._headers, params=self._params, verify=False ) except AttributeError: raise RequestError( @@ -250,7 +265,7 @@ def _extractor(self) -> dict: r"\/", "/" ) - js_url = requests.get(request_conf_link, headers=self._headers) + js_url = session.get(request_conf_link, headers=self._headers, verify=False) return js_url.json() except IndexError: raise UnableToParseHtml("Couldn't find config url") @@ -281,22 +296,36 @@ def _get_meta_data(self): """ Retrieves meta data for the video """ - if self._cookies: - video_info = requests.get( - details.format(self._video_id), - headers=self._headers, - cookies=self._cookies, - ) + if not self._password: + if self._cookies: + video_info = session.get( + details.format(self._video_id), + headers=self._headers, + verify=False, + cookies=self._cookies, + ) + else: + video_info = session.get( + details.format(self._video_id), headers=self._headers + ) else: - video_info = requests.get( - details.format(self._video_id), headers=self._headers + video_info = session.post( + password_config.format(self._video_id), + headers=self._headers, + params=self._params, + data=dict(password=self._password), + verify=False ) + + if not video_info.ok: raise RequestError( f"{video_info.status_code}: Unable to retrieve meta data." ) try: video_info = video_info.json() + if self._password: + video_info = [video_info.get('video', {})] except Exception as e: raise RequestError(f"Couldn't retrieve meta data: {e}") return video_info @@ -340,7 +369,7 @@ def streams(self) -> List[_Stream]: dl = [] for stream in js_url["request"]["files"]["progressive"]: url = stream["url"] - if not requests.get(url, stream=True).ok: + if not session.get(url, stream=True, verify=False,).ok: continue stream_object = _Stream( quality=stream["quality"], direct_url=url, title=title From 507e8c71b160e4789736b26f3e0451a56379790d Mon Sep 17 00:00:00 2001 From: "anatoly.k" Date: Wed, 8 Mar 2023 16:58:04 +0300 Subject: [PATCH 2/3] Comment out embedded test --- tests/test_vimeo_downloader.py | 13 +++++++------ vimeo_downloader/__init__.py | 2 ++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/test_vimeo_downloader.py b/tests/test_vimeo_downloader.py index e589cc1..1f3d371 100644 --- a/tests/test_vimeo_downloader.py +++ b/tests/test_vimeo_downloader.py @@ -14,12 +14,13 @@ "title": "We Don't Have To Know - Keli Holiday", "id": "503166067", }, - { - "url": "https://player.vimeo.com/video/498617513", - "title": "NEET ekalavya all", - "embedded_on": "https://atpstar.com/plans-162.html", - "id": "498617513", - }, + # I have to comment out this test, because this video is abscent + # { + # "url": "https://player.vimeo.com/video/498617513", + # "title": "NEET ekalavya all", + # "embedded_on": "https://atpstar.com/plans-162.html", + # "id": "498617513", + # }, { "url": "https://player.vimeo.com/video/98044508?some_random_p=parameter", "title": "Pier Solar OUYA Official Trailer", diff --git a/vimeo_downloader/__init__.py b/vimeo_downloader/__init__.py index 2254134..75d4a17 100644 --- a/vimeo_downloader/__init__.py +++ b/vimeo_downloader/__init__.py @@ -384,12 +384,14 @@ def from_video_id( video_id: str, embedded_on: Optional[str] = None, cookies: Optional[str] = None, + password: Optional[str] = None, ): self = cls.__new__(cls) self._video_id = video_id self._headers = headers self._cookies = dict(cookies_are=cookies) self._params = {} + self._password = b64encode(password.encode()).decode() if password else None if embedded_on: self._headers["Referer"] = embedded_on return self From c37f661c7f9f73bdb83049aa180a177e31e3a1cb Mon Sep 17 00:00:00 2001 From: "anatoly.k" Date: Wed, 8 Mar 2023 17:01:16 +0300 Subject: [PATCH 3/3] Remove unverified requests --- vimeo_downloader/__init__.py | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/vimeo_downloader/__init__.py b/vimeo_downloader/__init__.py index 75d4a17..1f6d444 100644 --- a/vimeo_downloader/__init__.py +++ b/vimeo_downloader/__init__.py @@ -126,7 +126,7 @@ def download( else: if not filename.endswith(".mp4"): filename += ".mp4" - r = session.get(self._direct_url, stream=True, headers=headers, verify=False,) + r = session.get(self._direct_url, stream=True, headers=headers) if not r.ok: if r.status_code == 410: raise URLExpired("The download URL has expired.") @@ -161,7 +161,7 @@ def filesize(self) -> str: Returns str with filesize in MB. """ - r = session.get(self._direct_url, stream=True, headers=headers, verify=False,) + r = session.get(self._direct_url, stream=True, headers=headers) return str(int(r.headers.get("content-length")) / 10**6) + " MB" @@ -223,15 +223,13 @@ def _extractor(self) -> dict: config.format(self._video_id), headers=self._headers, cookies=self._cookies, - params=self._params, - verify=False + params=self._params ) else: js_url = session.get( config.format(self._video_id), headers=self._headers, - params=self._params, - verify=False + params=self._params ) else: @@ -239,8 +237,7 @@ def _extractor(self) -> dict: password_config.format(self._video_id), headers=self._headers, params=self._params, - data=dict(password=self._password), - verify=False + data=dict(password=self._password) ) @@ -249,7 +246,7 @@ def _extractor(self) -> dict: # If the response is forbidden it tries another way to fetch link try: html = session.get( - self._url, headers=self._headers, params=self._params, verify=False + self._url, headers=self._headers, params=self._params ) except AttributeError: raise RequestError( @@ -265,7 +262,7 @@ def _extractor(self) -> dict: r"\/", "/" ) - js_url = session.get(request_conf_link, headers=self._headers, verify=False) + js_url = session.get(request_conf_link, headers=self._headers) return js_url.json() except IndexError: raise UnableToParseHtml("Couldn't find config url") @@ -300,8 +297,7 @@ def _get_meta_data(self): if self._cookies: video_info = session.get( details.format(self._video_id), - headers=self._headers, - verify=False, + headers=self._headers, cookies=self._cookies, ) else: @@ -313,8 +309,7 @@ def _get_meta_data(self): password_config.format(self._video_id), headers=self._headers, params=self._params, - data=dict(password=self._password), - verify=False + data=dict(password=self._password) ) @@ -369,7 +364,7 @@ def streams(self) -> List[_Stream]: dl = [] for stream in js_url["request"]["files"]["progressive"]: url = stream["url"] - if not session.get(url, stream=True, verify=False,).ok: + if not session.get(url, stream=True).ok: continue stream_object = _Stream( quality=stream["quality"], direct_url=url, title=title