1
0
Fork 0
mirror of synced 2024-05-20 04:02:36 +12:00
bulk-downloader-for-reddit/bdfr/site_downloaders/imgur.py

86 lines
3.2 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
import json
2021-03-21 14:10:06 +13:00
import re
2021-02-25 23:40:08 +13:00
from typing import Optional
2021-02-07 01:29:13 +13:00
2021-03-21 14:10:06 +13:00
import bs4
2021-02-11 12:10:40 +13:00
from praw.models import Submission
2021-04-23 23:06:16 +12:00
from bdfr.exceptions import SiteDownloaderError
2021-04-12 19:58:32 +12:00
from bdfr.resource import Resource
from bdfr.site_authenticator import SiteAuthenticator
from bdfr.site_downloaders.base_downloader import BaseDownloader
2021-02-07 14:33:19 +13:00
class Imgur(BaseDownloader):
2021-02-15 18:12:27 +13:00
def __init__(self, post: Submission):
super().__init__(post)
self.raw_data = {}
2021-02-26 21:57:05 +13:00
def find_resources(self, authenticator: Optional[SiteAuthenticator] = None) -> list[Resource]:
2021-03-21 14:10:06 +13:00
self.raw_data = self._get_data(self.post.url)
2021-03-21 14:10:06 +13:00
out = []
if 'album_images' in self.raw_data:
images = self.raw_data['album_images']
for image in images['images']:
2021-04-23 22:58:01 +12:00
out.append(self._compute_image_url(image))
else:
2021-04-23 22:58:01 +12:00
out.append(self._compute_image_url(self.raw_data))
2021-02-11 12:10:40 +13:00
return out
2021-04-23 22:58:01 +12:00
def _compute_image_url(self, image: dict) -> Resource:
ext = self._validate_extension(image['ext'])
if image.get('prefer_video', False):
ext = '.mp4'
image_url = 'https://i.imgur.com/' + image['hash'] + ext
return Resource(self.post, image_url, Resource.retry_download(image_url))
2021-03-21 14:10:06 +13:00
@staticmethod
def _get_data(link: str) -> dict:
link = link.rstrip('?')
if re.match(r'(?i).*\.gifv$', link):
2021-03-28 13:15:21 +13:00
link = link.replace('i.imgur', 'imgur')
link = re.sub('(?i)\\.gifv$', '', link)
2021-03-28 13:15:21 +13:00
2021-04-06 12:48:21 +12:00
res = Imgur.retrieve_url(link, cookies={'over18': '1', 'postpagebeta': '0'})
2021-03-21 21:58:32 +13:00
soup = bs4.BeautifulSoup(res.text, 'html.parser')
2021-03-21 14:10:06 +13:00
scripts = soup.find_all('script', attrs={'type': 'text/javascript'})
scripts = [script.string.replace('\n', '') for script in scripts if script.string]
2021-03-21 14:10:06 +13:00
script_regex = re.compile(r'\s*\(function\(widgetFactory\)\s*{\s*widgetFactory\.mergeConfig\(\'gallery\'')
chosen_script = list(filter(lambda s: re.search(script_regex, s), scripts))
if len(chosen_script) != 1:
raise SiteDownloaderError(f'Could not read page source from {link}')
chosen_script = chosen_script[0]
2021-03-21 14:10:06 +13:00
outer_regex = re.compile(r'widgetFactory\.mergeConfig\(\'gallery\', ({.*})\);')
2021-03-21 14:10:06 +13:00
inner_regex = re.compile(r'image\s*:(.*),\s*group')
try:
image_dict = re.search(outer_regex, chosen_script).group(1)
image_dict = re.search(inner_regex, image_dict).group(1)
except AttributeError:
raise SiteDownloaderError(f'Could not find image dictionary in page source')
try:
image_dict = json.loads(image_dict)
except json.JSONDecodeError as e:
raise SiteDownloaderError(f'Could not parse received dict as JSON: {e}')
2021-03-21 14:10:06 +13:00
return image_dict
@staticmethod
def _validate_extension(extension_suffix: str) -> str:
2021-05-19 11:55:03 +12:00
extension_suffix = extension_suffix.strip('?1')
2021-03-21 14:10:06 +13:00
possible_extensions = ('.jpg', '.png', '.mp4', '.gif')
selection = [ext for ext in possible_extensions if ext == extension_suffix]
if len(selection) == 1:
return selection[0]
else:
2021-02-15 19:30:39 +13:00
raise SiteDownloaderError(f'"{extension_suffix}" is not recognized as a valid extension for Imgur')