def _get_imgur_secrets(self, imgur_secrets: str) -> configparser.ConfigParser: """ _get_imgur_secrets checks if the Imgur api secrets file exists. - If the file exists, this methods reads the the files and returns the secrets in as a dict. - If the file doesn't exist it asks the user over stdin to supply these values and then saves them into the imgur_secrets file Arguments: imgur_secrets (string): file name of secrets file for API credentials Returns: imgur_config (dict): Dictionary containing the client id and client secret needed to login to Imgur """ if not os.path.exists(imgur_secrets): self.logger.warning( 'Imgur API keys not found. (See wiki if you need help).') # Whitespaces are stripped from input: https://stackoverflow.com/a/3739939 imgur_client_id = ''.join( input("[ .. ] Enter Imgur client ID: ").split()) imgur_client_secret = ''.join( input("[ .. ] Enter Imgur client secret: ").split()) # Make sure authentication is working try: imgur_client = ImgurClient(imgur_client_id, imgur_client_secret) # If this call doesn't work, it'll throw an ImgurClientError imgur_client.get_album('dqOyj') # It worked, so save the keys to a file imgur_config = configparser.ConfigParser() imgur_config['Imgur'] = { 'ClientID': imgur_client_id, 'ClientSecret': imgur_client_secret, } with open(imgur_secrets, 'w') as file: imgur_config.write(file) file.close() except ImgurClientError as imgur_error: self.logger.error('Error while logging into Imgur: %s', imgur_error) self.logger.error(FATAL_TOOTBOT_ERROR) sys.exit(1) else: # Read API keys from secret file imgur_config = configparser.ConfigParser() imgur_config.read(imgur_secrets) return imgur_config
def get_img(path): global pin client = ImgurClient(client_id, client_secret,'61c2a536adcd40eeedbd8e6fba18999f413bf5dc', 'aee3d76d7956080282f5d272f76ef12f19509a47') ## if pin == None: ## authorization_url = client.get_auth_url('pin') ## print("Go to the following URL: {0}".format(authorization_url)) ## pin = input("Enter pin code: ") ## else: ## pass ## credentials = client.authorize(pin, 'pin') ## client.set_user_auth(credentials['access_token'], credentials['refresh_token']) # Example request album_id = '2hzdSFn' config = { 'album': album_id, 'name': 'test-name!', 'title': 'test-title', 'description': 'test-description' } print(client.get_album(album_id)) client.upload_from_path(path,config=config,anon=False) images = client.get_album_images(album_id) url = images[len(images)-1].link return url
def main(): parser = argparse.ArgumentParser(description="Generate BBCode from an Imgur album") parser.add_argument("-c", "--clientid", help="Imgur client ID", required=True) parser.add_argument("-s", "--secret", help="Imgur secret", required=True) parser.add_argument("-a", "--album", help="Album ID", required=True) args = parser.parse_args() client = ImgurClient(args.clientid, args.secret) try: album = client.get_album(args.album) except ImgurClientError as e: print "Error fetching album - %s:" % (e.status_code) print e.error_message exit() print '[B][SIZE="4"]%s[/SIZE][/B]' % (album.title) thumb_regex = re.compile(r"^(.*)\.(.{3,4})$") for img in album.images: if img['title']: print '[SIZE="3"]%s[/SIZE]\n' % (img['title']) # Use "large thumbnail" size print '[IMG]%s[/IMG]' % (thumb_regex.sub("\\g<1>l.\\2", img['link'])) description = img['description'] if img['description'] else "" print description print
def get_img(): client_id = 'b9ae77105014a61' client_secret = '720fc83b0d748eb6131f987949280e15bf3a6e66' client = ImgurClient(client_id, client_secret) authorization_url = client.get_auth_url('pin') print("Go to the following URL: {0}".format(authorization_url)) if os.path.isfile('pin.txt'): with open('pin.txt', 'r') as f: pin = f.read() else: pin = input("Enter pin code: ") with open('pin.txt', 'w') as f: f.write(pin) credentials = client.authorize(pin, 'pin') client.set_user_auth(credentials['access_token'], credentials['refresh_token']) # Example request album_id = 'ARm1Dtq' config = { 'album': album_id, 'name': 'test-name!', 'title': 'test-title', 'description': 'test-description' } print(client.get_album('ARm1Dtq')) client.upload_from_path('D:/python/linebot/linebot/in.jpg', config=config, anon=False) images = client.get_album_images(album_id) url = images[len(images) - 1].link return url
class API: def __init__(self, _client_id, _client_secret): self.client_id = _client_id self.client_secret = _client_secret self.client = ImgurClient(_client_id, _client_secret) pass def get_album_image_urls(self, _album_id): images = self.client.get_album(_album_id).__dict__['images'] links = [] for image in images: links.append(image['link']) pass return links pass def get_favorites_image_urls(self, username): images = self.client.get_account_favorites(username) links = [] for image in images: links.append(image.__dict__['link']) pass return links pass pass
def get_url(submission): def what_is_inside(url): header = requests.head(url).headers if 'Content-Type' in header: return header['Content-Type'] else: return '' url = submission.url url_content = what_is_inside(url) if ('image/jpeg' == url_content or 'image/png' == url_content): return 'img', url, url_content.split('/')[1] if 'image/gif' in url_content: return 'gif', url, 'gif' if url.endswith('.gifv'): if 'image/gif' in what_is_inside(url[0:-1]): return 'gif', url[0:-1], 'gif' if submission.is_self is True: # Self submission with text return 'text', None, None if urlparse(url).netloc == 'imgur.com': # Imgur imgur_config = yaml.load(open('imgur.yml').read()) imgur_client = ImgurClient(imgur_config['client_id'], imgur_config['client_secret']) path_parts = urlparse(url).path.split('/') if path_parts[1] == 'gallery': # TODO: gallary handling return 'other', url, None elif path_parts[1] == 'topic': # TODO: topic handling return 'other', url, None elif path_parts[1] == 'a': # An imgur album album = imgur_client.get_album(path_parts[2]) story = {} for num, img in enumerate(album.images): number = num + 1 story[number] = { 'link': img['link'], 'gif': img['animated'], 'type': img['type'].split('/')[1] } return 'album', story, None else: # Just imgur img img = imgur_client.get_image(path_parts[1].split('.')[0]) if not img.animated: return 'img', img.link, img.type.split('/')[1] else: return 'gif', img.link, 'gif' else: return 'other', url, None
def get_random_caturday_image(): """Return url to random caturday image from album""" client = ImgurClient( CFG.get('imgur').get('clientid'), CFG.get('imgur').get('clientsecret') ) album = client.get_album(CFG.get('imgur').get('caturdayalbum')) return choice([image.get('link') for image in album.images])
async def caturday(ctx): """Show a random cat gif on caturdays""" ctx.channel.typing() client = ImgurClient( CFG.get('imgur').get('clientid'), CFG.get('imgur').get('clientsecret')) album = client.get_album(CFG.get('imgur').get('caturdayalbum')) image = choice([image.get('link') for image in album.images]) await ctx.channel.send(image)
def venue(): u = User.query.get(1) client = ImgurClient( current_app.config['IMGUR_CLIENT_ID'], current_app.config['IMGUR_CLIENT_SECRET'], access_token=u.access_token, refresh_token=u.refresh_token) album = client.get_album('izwJA') if client.auth.current_access_token != u.access_token: u.access_token = client.auth.current_access_token db.session.add(u) db.session.commit() return render_template('venue.html', album=album)
def getImgurData(url): path = urllib.parse.urlparse(url).path path = str(path.split('/')[-1]) logging.info(path) try: client = ImgurClient(config.imgur_client_id, config.imgur_client_secret) items = client.get_album(path) except: logging.info("Bad Link Error") return 0, 0, 0 #logging.info(items.title) #logging.info(items.images_count) #logging.info(items.images) return items.images_count, items.images, path
def photos(album=None): if album is None: return redirect(url_for('public.photos', album='63Tp6')) u = User.query.get(1) client = ImgurClient( current_app.config['IMGUR_CLIENT_ID'], current_app.config['IMGUR_CLIENT_SECRET'], access_token=u.access_token, refresh_token=u.refresh_token) albums = client.get_account_albums('timandmikaela') for a in albums: if a.id == album: break else: abort(404) a = client.get_album(album) if client.auth.current_access_token != u.access_token: u.access_token = client.auth.current_access_token db.session.add(u) db.session.commit() return render_template('photos.html', album=a, albums=albums)
def saveAlbum(album, author, sub, sub_title, direct): counter = 0 client = ImgurClient(Im_client_id, Im_client_secret) #Imgur client try: album_data = client.get_album(album) #Whole album folderName = album_data.title #album title if not folderName: folderName = sub_title + " - " + str(album) folderName = formatName(folderName) else: folderName = folderName.replace(' ', '_') folderName = formatName(folderName) print(album) images = client.get_album_images(album) print(album) for image in images: #print(str(image.link)) #print(str(image.description)) print(image.type) folder = direct + '/' + sub + '/' + author + '/' + str( folderName) + '/' #folder = re.sub('[?/|\:<>*"]', '', folder) if not os.path.exists(folder): os.makedirs(folder) writeDescription(image.description, image.id, folder, counter) urllib.request.urlretrieve( image.link, folder + "(" + str(counter) + ") " + str(image.id) + str(image.type).replace('image/', '.')) counter = counter + 1 except imgurpython.helpers.error.ImgurClientError: with open(direct + '/error.txt', 'a') as logFile: logFile.write('ImgurClientError: ' + album + '\n') logFile.close()
def download_cubari_moe(url, chapters_asked, download_path, manga_name): if not os.path.exists(download_path + manga_name + os.path.sep): os.makedirs(download_path + manga_name + os.path.sep) download_path = download_path + manga_name + os.path.sep config = configparser.ConfigParser() config.read("mangas_dl/conf.ini") client = ImgurClient(config["IMGUR"]["ClientID"], config["IMGUR"]["ClientSecret"]) for chp_src, chp_nb in chapters_asked: sys.stdout.write('\033[K') print('Loading chapter ', chp_nb, end='\r') if not os.path.exists(download_path + 'temp' + os.path.sep): os.makedirs(download_path + 'temp' + os.path.sep) album = client.get_album(chp_src) srcs = [img["link"] for img in album.images] download_and_convert_to_pdf(srcs, download_path, chp_nb)
def upload_photo(image_url, image_name): client_id = 'YOUR_CLIENT_ID' client_secret = 'YOUR_CLIENT_SECRET' access_token = 'YOUR_ACCESS_TOKEN' refresh_token = 'YOUR_REFRESH_TOKEN' client = ImgurClient(client_id, client_secret, access_token, refresh_token) album_id = 'YOUR_ALBUM_ID' album = client.get_album(album_id) # check whether image have been upload ever for image in album.images: if image['name'] == image_name: print('Find image in Album {}!'.format(album_id)) return image['link'] # set configuration config = { 'album': album_id, 'name': image_name } print('Uploading image to imgur.com ... ...') image = client.upload_from_url(image_url, config=config, anon=False) print('Upload Done~') return image['link']
import praw from imgurpython import ImgurClient from praw.models import Message from praw.models import Comment import random import time import sys from _operator import contains client_id = '*********' client_secret = '*********' client = ImgurClient(client_id, client_secret) #items = client.gallery() items = client.get_album('FlHzl') #numPictures = items.__sizeof__() reddit = praw.Reddit(client_id='*********', client_secret="********", password='******', user_agent='eyebleachbot (by /u/su5)', username='******') messageBod = '''User: {0} Subject: {1} Body: {2}''' response = '''NSFL? Yikes! [Eye Bleach!](%s)
reddit_config.read('reddit.secret') REDDIT_AGENT = reddit_config['Reddit']['Agent'] REDDIT_CLIENT_SECRET = reddit_config['Reddit']['ClientSecret'] # Setup and verify Imgur access if not os.path.exists('imgur.secret'): print( '[WARN] API keys for Imgur not found. Please enter them below (see wiki if you need help).' ) # Whitespaces are stripped from input: https://stackoverflow.com/a/3739939 IMGUR_CLIENT = ''.join(input("[ .. ] Enter Imgur client ID: ").split()) IMGUR_CLIENT_SECRET = ''.join( input("[ .. ] Enter Imgur client secret: ").split()) # Make sure authentication is working try: imgur_client = ImgurClient(IMGUR_CLIENT, IMGUR_CLIENT_SECRET) test_gallery = imgur_client.get_album('dqOyj') # It worked, so save the keys to a file imgur_config = configparser.ConfigParser() imgur_config['Imgur'] = { 'ClientID': IMGUR_CLIENT, 'ClientSecret': IMGUR_CLIENT_SECRET } with open('imgur.secret', 'w') as f: imgur_config.write(f) f.close() except BaseException as e: print('[EROR] Error while logging into Imgur:', str(e)) print('[EROR] Tootbot cannot continue, now shutting down') exit() else: # Read API keys from secret file
print '[*] imgur Album Downloader is now running' # api stuff client_id = '273e0cd6a27f629' client_secret = '820135d39a35932f025b88b0a9d56b8bb6929096' client = ImgurClient(client_id, client_secret) # test link: http://imgur.com/a/pthXN id = '' while id == '': test = raw_input('[*] Please enter an imgur album link: ') if test == "exit": sys.exit() try: test_id = test[test.index('a/')+2:] album = client.get_album(test_id) id = test_id except Exception,e: print '[-] Error: Invalid imgur album link' # test path: C:/Users/st/Documents/GitHub/Auto-Scripts/ dest = '' while dest == '': tet_dest = raw_input('[*] Please enter a destination path: ') if os.path.exists(test_dest): dest = test_dest else: print '[-] Error: Invalid destination path' print '[+] Downloading imgur album...' images = client.get_album_images(id)
def get_url(submission, mp4_instead_gif=True): ''' return TYPE, URL E.x.: return 'img', 'http://example.com/pic.png' ''' def what_is_inside(url): header = requests.head(url).headers if 'Content-Type' in header: return header['Content-Type'] else: return '' # If reddit native gallery if hasattr(submission, 'gallery_data'): dict_of_dicts_of_pics = dict() list_of_media = dict() for item in submission.gallery_data['items']: list_of_media[item['id']] = item['media_id'] counter = 0 for item in sorted(list_of_media.items(), key=lambda item: item[0]): if counter % 10 == 0: dict_of_dicts_of_pics[counter // 10] = dict() item_with_media = submission.media_metadata[item[1]]['s'] if 'u' in item_with_media: # It's a pic dict_of_dicts_of_pics[counter // 10][counter] = { 'url': item_with_media['u'], 'type': 'pic' } else: # It's a gif dict_of_dicts_of_pics[counter // 10][counter] = { 'url': item_with_media['mp4'], 'type': 'video' } counter += 1 return TYPE_GALLERY, dict_of_dicts_of_pics url = submission.url url_content = what_is_inside(url) if submission.is_video: if 'reddit_video' in submission.media: if submission.media['reddit_video'].get('is_gif', False): return TYPE_GIF, submission.media['reddit_video'][ 'fallback_url'] return TYPE_VIDEO, submission.media['reddit_video']['fallback_url'] # return TYPE_OTHER, url try: if len(submission.crosspost_parent_list) > 0: parent_submission_json = submission.crosspost_parent_list[0] if parent_submission_json['is_video'] == True: if 'reddit_video' in parent_submission_json['media']: if parent_submission_json['media']['reddit_video'].get( 'is_gif', False): return TYPE_GIF, parent_submission_json['media'][ 'reddit_video']['fallback_url'] return TYPE_VIDEO, parent_submission_json['media'][ 'reddit_video']['fallback_url'] except: # Not a crosspost pass if (CONTENT_JPEG == url_content or CONTENT_PNG == url_content): return TYPE_IMG, url if CONTENT_GIF in url_content: if url.endswith('.gif') and mp4_instead_gif: # Let's try to find .mp4 file. url_mp4 = url[:-4] + '.mp4' if CONTENT_MP4 == what_is_inside(url_mp4): return TYPE_GIF, url_mp4 return TYPE_GIF, url if url.endswith('.gifv'): if mp4_instead_gif: url_mp4 = url[:-5] + '.mp4' if CONTENT_MP4 == what_is_inside(url_mp4): return TYPE_GIF, url_mp4 if CONTENT_GIF in what_is_inside(url[0:-1]): return TYPE_GIF, url[0:-1] if submission.is_self is True: # Self submission with text return TYPE_TEXT, None if urlparse(url).netloc == 'imgur.com': # Imgur imgur_config = yaml.safe_load( open(os.path.join('configs', 'imgur.yml')).read()) imgur_client = ImgurClient(imgur_config['client_id'], imgur_config['client_secret']) path_parts = urlparse(url).path.split('/') if path_parts[1] == 'gallery': # TODO: gallary handling return TYPE_OTHER, url elif path_parts[1] == 'topic': # TODO: topic handling return TYPE_OTHER, url elif path_parts[1] == 'a': # An imgur album album = imgur_client.get_album(path_parts[2]) story = dict() for num, img in enumerate(album.images): number = num + 1 what = TYPE_IMG link = img['link'] ext = img['type'].split('/')[1] if img['animated']: what = TYPE_GIF link = img['mp4'] if mp4_instead_gif else img['gifv'][:-1] ext = 'mp4' if mp4_instead_gif else 'gif' story[number] = {'url': link, 'what': what, 'ext': ext} if len(story) == 1: return story[1]['what'], story[1]['url'] return TYPE_ALBUM, story else: # Just imgur img img = imgur_client.get_image(path_parts[1].split('.')[0]) if not img.animated: return TYPE_IMG, img.link else: if mp4_instead_gif: return TYPE_GIF, img.mp4 else: # return 'gif', img.link return TYPE_GIF, img.gifv[:-1] elif 'gfycat.com' in urlparse(url).netloc: rname = re.findall(r'gfycat.com\/(?:detail\/)?(\w*)', url)[0] try: r = requests.get(GFYCAT_GET + rname) if r.status_code != 200: logging.info('Gfy fail prevented!') return TYPE_OTHER, url urls = r.json()['gfyItem'] if mp4_instead_gif: return TYPE_GIF, urls['mp4Url'] else: return TYPE_GIF, urls['max5mbGif'] except KeyError: logging.info('Gfy fail prevented!') return TYPE_OTHER, url else: return TYPE_OTHER, url
from reportlab.platypus import SimpleDocTemplate, Paragraph, Image, Spacer, PageBreak from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.pagesizes import letter from reportlab.lib.units import inch from reportlab.lib.enums import TA_JUSTIFY import requests import shutil import os # trying to fix the error messages import urllib3 urllib3.disable_warnings() album = raw_input('Album ID:') client = ImgurClient(client_id, client_secret) album_data = client.get_album(album) album_file = album_data.title.replace(' ', '_') + ".pdf" doc = SimpleDocTemplate(album_file, pagesize=letter, rightMargin=25, leftMargin=25, topMargin=25, bottomMargin=25) ParagraphStyle(name='Normal', fontName="Verdana", fontSize=11, leading=15, alignment=TA_JUSTIFY, allowOrphans=0, spaceBefore=20, spaceAfter=20,
class SpiffyTitles(callbacks.Plugin): """Displays link titles when posted in a channel""" threaded = True callBefore = ["Web"] link_cache = [] handlers = {} wall_clock_timeout = 8 max_request_retries = 3 imgur_client = None def __init__(self, irc): self.__parent = super(SpiffyTitles, self) self.__parent.__init__(irc) self.wall_clock_timeout = self.registryValue("wallClockTimeoutInSeconds") self.default_handler_enabled = self.registryValue("defaultHandlerEnabled") self.add_handlers() def add_handlers(self): """ Adds all handlers """ self.add_youtube_handlers() self.add_imdb_handlers() self.add_imgur_handlers() self.add_coub_handlers() self.add_vimeo_handlers() self.add_dailymotion_handlers() self.add_wikipedia_handlers() def add_dailymotion_handlers(self): self.handlers["www.dailymotion.com"] = self.handler_dailymotion def add_vimeo_handlers(self): self.handlers["vimeo.com"] = self.handler_vimeo def add_coub_handlers(self): self.handlers["coub.com"] = self.handler_coub def add_wikipedia_handlers(self): self.handlers["en.wikipedia.org"] = self.handler_wikipedia def handler_dailymotion(self, url, info, channel): """ Handles dailymotion links """ dailymotion_handler_enabled = self.registryValue("dailymotionHandlerEnabled", channel=channel) log.debug("SpiffyTitles: calling dailymotion handler for %s" % url) title = None video_id = None """ Get video ID """ if dailymotion_handler_enabled and "/video/" in info.path: video_id = info.path.lstrip("/video/").split("_")[0] if video_id is not None: api_url = "https://api.dailymotion.com/video/%s?fields=id,title,owner.screenname,duration,views_total" % video_id log.debug("SpiffyTitles: looking up dailymotion info: %s", api_url) agent = self.get_user_agent() headers = { "User-Agent": agent } request = requests.get(api_url, headers=headers) ok = request.status_code == requests.codes.ok if ok: response = json.loads(request.text) if response is not None and "title" in response: video = response dailymotion_template = Template(self.registryValue("dailymotionVideoTitleTemplate", channel=channel)) video["views_total"] = "{:,}".format(int(video["views_total"])) video["duration"] = self.get_duration_from_seconds(video["duration"]) video["ownerscreenname"] = video["owner.screenname"] title = dailymotion_template.render(video) else: log.debug("SpiffyTitles: received unexpected payload from video: %s" % api_url) else: log.error("SpiffyTitles: dailymotion handler returned %s: %s" % (request.status_code, request.text[:200])) if title is None: log.debug("SpiffyTitles: could not get dailymotion info for %s" % url) return self.handler_default(url, channel) else: return title def handler_vimeo(self, url, domain, channel): """ Handles Vimeo links """ vimeo_handler_enabled = self.registryValue("vimeoHandlerEnabled", channel=channel) log.debug("SpiffyTitles: calling vimeo handler for %s" % url) title = None video_id = None """ Get video ID """ if vimeo_handler_enabled: result = re.search(r'^(http(s)://)?(www\.)?(vimeo\.com/)?(\d+)', url) if result is not None: video_id = result.group(5) if video_id is not None: api_url = "https://vimeo.com/api/v2/video/%s.json" % video_id log.debug("SpiffyTitles: looking up vimeo info: %s", api_url) agent = self.get_user_agent() headers = { "User-Agent": agent } request = requests.get(api_url, headers=headers) ok = request.status_code == requests.codes.ok if ok: response = json.loads(request.text) if response is not None and "title" in response[0]: video = response[0] vimeo_template = Template(self.registryValue("vimeoTitleTemplate", channel=channel)) """ Some videos do not have this information available """ if "stats_number_of_plays" in video: video["stats_number_of_plays"] = "{:,}".format(int(video["stats_number_of_plays"])) else: video["stats_number_of_plays"] = 0 if "stats_number_of_comments" in video: video["stats_number_of_comments"] = "{:,}".format(int(video["stats_number_of_comments"])) else: video["stats_number_of_comments"] = 0 video["duration"] = self.get_duration_from_seconds(video["duration"]) title = vimeo_template.render(video) else: log.debug("SpiffyTitles: received unexpected payload from video: %s" % api_url) else: log.error("SpiffyTitles: vimeo handler returned %s: %s" % (request.status_code, request.text[:200])) if title is None: log.debug("SpiffyTitles: could not get vimeo info for %s" % url) return self.handler_default(url, channel) else: return title def handler_coub(self, url, domain, channel): """ Handles coub.com links """ coub_handler_enabled = self.registryValue("coubHandlerEnabled", channel=channel) log.debug("SpiffyTitles: calling coub handler for %s" % url) title = None """ Get video ID """ if coub_handler_enabled and "/view/" in url: video_id = url.split("/view/")[1] """ Remove any query strings """ if "?" in video_id: video_id = video_id.split("?")[0] api_url = "http://coub.com/api/v2/coubs/%s" % video_id agent = self.get_user_agent() headers = { "User-Agent": agent } request = requests.get(api_url, headers=headers) ok = request.status_code == requests.codes.ok if ok: response = json.loads(request.text) if response: video = response coub_template = Template(self.registryValue("coubTemplate")) video["likes_count"] = "{:,}".format(int(video["likes_count"])) video["recoubs_count"] = "{:,}".format(int(video["recoubs_count"])) video["views_count"] = "{:,}".format(int(video["views_count"])) title = coub_template.render(video) else: log.error("SpiffyTitles: coub handler returned %s: %s" % (request.status_code, request.text[:200])) if title is None: if coub_handler_enabled: log.debug("SpiffyTitles: %s does not appear to be a video link!" % url) return self.handler_default(url, channel) else: return title def add_imgur_handlers(self): # Images mostly self.handlers["i.imgur.com"] = self.handler_imgur_image # Albums, galleries, etc self.handlers["imgur.com"] = self.handler_imgur def initialize_imgur_client(self, channel): """ Check if imgur client id or secret are set, and if so initialize imgur API client """ if self.imgur_client is None: imgur_client_id = self.registryValue("imgurClientID") imgur_client_secret = self.registryValue("imgurClientSecret") imgur_handler_enabled = self.registryValue("imgurHandlerEnabled", channel=channel) if imgur_handler_enabled and imgur_client_id and imgur_client_secret: log.debug("SpiffyTitles: enabling imgur handler") # Initialize API client try: from imgurpython import ImgurClient from imgurpython.helpers.error import ImgurClientError try: self.imgur_client = ImgurClient(imgur_client_id, imgur_client_secret) except ImgurClientError as e: log.error("SpiffyTitles: imgur client error: %s" % (e.error_message)) except ImportError as e: log.error("SpiffyTitles ImportError: %s" % str(e)) else: log.debug("SpiffyTitles: imgur handler disabled or empty client id/secret") def doPrivmsg(self, irc, msg): """ Observe each channel message and look for links """ channel = msg.args[0] ignore_actions = self.registryValue("ignoreActionLinks", channel=msg.args[0]) is_channel = irc.isChannel(channel) is_ctcp = ircmsgs.isCtcp(msg) message = msg.args[1] title = None bot_nick = irc.nick origin_nick = msg.nick is_message_from_self = origin_nick.lower() == bot_nick.lower() requires_capability = len(str(self.registryValue("requireCapability", channel=msg.args[0]))) > 0 if is_message_from_self: return """ Check if we require a capability to acknowledge this link """ if requires_capability: user_has_capability = self.user_has_capability(msg) if not user_has_capability: return """ Configuration option determines whether we should ignore links that appear within an action """ if is_ctcp and ignore_actions: return if is_channel: channel_is_allowed = self.is_channel_allowed(channel) url = self.get_url_from_message(message) ignore_match = self.message_matches_ignore_pattern(message) if ignore_match: log.debug("SpiffyTitles: ignoring message due to linkMessagePattern match") return if url: # Check if channel is allowed based on white/black list restrictions if not channel_is_allowed: log.debug("SpiffyTitles: not responding to link in %s due to black/white list restrictions" % (channel)) return info = urlparse(url) domain = info.netloc is_ignored = self.is_ignored_domain(domain) if is_ignored: log.debug("SpiffyTitles: URL ignored due to domain blacklist match: %s" % url) return is_whitelisted_domain = self.is_whitelisted_domain(domain) if self.registryValue("whitelistDomainPattern") and not is_whitelisted_domain: log.debug("SpiffyTitles: URL ignored due to domain whitelist mismatch: %s" % url) return title = self.get_title_by_url(url, channel) if title is not None and title: ignore_match = self.title_matches_ignore_pattern(title, channel) if ignore_match: return else: irc.sendMsg(ircmsgs.privmsg(channel, title)) else: if self.default_handler_enabled: log.debug("SpiffyTitles: could not get a title for %s" % (url)) else: log.debug("SpiffyTitles: could not get a title for %s but default handler is disabled" % (url)) def get_title_by_url(self, url, channel): """ Retrieves the title of a website based on the URL provided """ info = urlparse(url) domain = info.netloc title = None """ Check if we have this link cached according to the cache lifetime. If so, serve link from the cache instead of calling handlers. """ cached_link = self.get_link_from_cache(url) if cached_link is not None: title = cached_link["title"] else: if domain in self.handlers: handler = self.handlers[domain] title = handler(url, info, channel) else: if self.default_handler_enabled: title = self.handler_default(url, channel) if title is not None: title = self.get_formatted_title(title, channel) # Update link cache log.debug("SpiffyTitles: caching %s" % (url)) now = datetime.datetime.now() self.link_cache.append({ "url": url, "timestamp": now, "title": title }) return title def t(self, irc, msg, args, query): """ Retrieves title for a URL on demand """ message = msg.args[1] channel = msg.args[0] url = self.get_url_from_message(message) title = None error_message = self.registryValue("onDemandTitleError", channel=channel) try: if url: title = self.get_title_by_url(query, channel) except: pass if title is not None and title: irc.sendMsg(ircmsgs.privmsg(channel, title)) else: irc.sendMsg(ircmsgs.privmsg(channel, error_message)) t = wrap(t, ['text']) def get_link_from_cache(self, url): """ Looks for a URL in the link cache and returns info about if it's not stale according to the configured cache lifetime, or None. If linkCacheLifetimeInSeconds is 0, then cache is disabled and we can immediately return """ cache_lifetime_in_seconds = int(self.registryValue("linkCacheLifetimeInSeconds")) if cache_lifetime_in_seconds == 0: return # No cache yet if len(self.link_cache) == 0: return cached_link = None now = datetime.datetime.now() stale = False seconds = 0 for link in self.link_cache: if link["url"] == url: cached_link = link break # Found link, check timestamp if cached_link is not None: seconds = (now - cached_link["timestamp"]).total_seconds() stale = seconds >= cache_lifetime_in_seconds if stale: log.debug("SpiffyTitles: %s was sent %s seconds ago" % (url, seconds)) else: log.debug("SpiffyTitles: serving link from cache: %s" % (url)) return cached_link def add_imdb_handlers(self): """ Enables meta info about IMDB links through the OMDB API """ self.handlers["www.imdb.com"] = self.handler_imdb self.handlers["imdb.com"] = self.handler_imdb def add_youtube_handlers(self): """ Adds handlers for Youtube videos. The handler is matched based on the domain used in the URL. """ self.handlers["youtube.com"] = self.handler_youtube self.handlers["www.youtube.com"] = self.handler_youtube self.handlers["youtu.be"] = self.handler_youtube self.handlers["m.youtube.com"] = self.handler_youtube def is_channel_allowed(self, channel): """ Checks channel whitelist and blacklist to determine if the current channel is allowed to display titles. """ channel = channel.lower() is_allowed = False white_list = self.filter_empty(self.registryValue("channelWhitelist")) black_list = self.filter_empty(self.registryValue("channelBlacklist")) white_list_empty = len(white_list) == 0 black_list_empty = len(black_list) == 0 # Most basic case, which is that both white and blacklist are empty. Any channel is allowed. if white_list_empty and black_list_empty: is_allowed = True # If there is a white list, blacklist is ignored. if white_list: is_allowed = channel in white_list # Finally, check blacklist if not white_list and black_list: is_allowed = channel not in black_list return is_allowed def filter_empty(self, input): """ Remove all empty strings from a list """ return set([channel for channel in input if len(channel.strip())]) def is_ignored_domain(self, domain): """ Checks domain against a regular expression """ pattern = self.registryValue("ignoredDomainPattern") if pattern: log.debug("SpiffyTitles: matching %s against %s" % (domain, str(pattern))) try: pattern_search_result = re.search(pattern, domain) if pattern_search_result is not None: match = pattern_search_result.group() return match except re.Error: log.error("SpiffyTitles: invalid regular expression: %s" % (pattern)) def is_whitelisted_domain(self, domain): """ Checks domain against a regular expression """ pattern = self.registryValue("whitelistDomainPattern") if pattern: log.debug("SpiffyTitles: matching %s against %s" % (domain, str(pattern))) try: pattern_search_result = re.search(pattern, domain) if pattern_search_result is not None: match = pattern_search_result.group() return match except re.Error: log.error("SpiffyTitles: invalid regular expression: %s" % (pattern)) def get_video_id_from_url(self, url, info): """ Get YouTube video ID from URL """ try: path = info.path domain = info.netloc video_id = "" if domain == "youtu.be": video_id = path.split("/")[1] else: parsed = cgi.parse_qsl(info.query) params = dict(parsed) if "v" in params: video_id = params["v"] if video_id: return video_id else: log.error("SpiffyTitles: error getting video id from %s" % (url)) except IndexError as e: log.error("SpiffyTitles: error getting video id from %s (%s)" % (url, str(e))) def handler_youtube(self, url, domain, channel): """ Uses the Youtube API to provide additional meta data about Youtube Video links posted. """ youtube_handler_enabled = self.registryValue("youtubeHandlerEnabled", channel=channel) developer_key = self.registryValue("youtubeDeveloperKey") if not youtube_handler_enabled: return None if not developer_key: log.info("SpiffyTitles: no Youtube developer key set! Check the documentation for instructions.") return None log.debug("SpiffyTitles: calling Youtube handler for %s" % (url)) video_id = self.get_video_id_from_url(url, domain) yt_template = Template(self.registryValue("youtubeTitleTemplate", channel=channel)) title = "" if video_id: options = { "part": "snippet,statistics,contentDetails", "maxResults": 1, "key": developer_key, "id": video_id } encoded_options = urlencode(options) api_url = "https://www.googleapis.com/youtube/v3/videos?%s" % (encoded_options) agent = self.get_user_agent() headers = { "User-Agent": agent } log.debug("SpiffyTitles: requesting %s" % (api_url)) request = requests.get(api_url, headers=headers) ok = request.status_code == requests.codes.ok if ok: response = json.loads(request.text) if response: try: if response["pageInfo"]["totalResults"] > 0: items = response["items"] video = items[0] snippet = video["snippet"] title = snippet["title"] statistics = video["statistics"] view_count = 0 like_count = 0 dislike_count = 0 comment_count = 0 favorite_count = 0 if "viewCount" in statistics: view_count = "{:,}".format(int(statistics["viewCount"])) if "likeCount" in statistics: like_count = "{:,}".format(int(statistics["likeCount"])) if "dislikeCount" in statistics: dislike_count = "{:,}".format(int(statistics["dislikeCount"])) if "favoriteCount" in statistics: favorite_count = "{:,}".format(int(statistics["favoriteCount"])) if "commentCount" in statistics: comment_count = "{:,}".format(int(statistics["commentCount"])) channel_title = snippet["channelTitle"] duration_seconds = self.get_total_seconds_from_duration(video["contentDetails"]["duration"]) """ #23 - If duration is zero, then it"s a LIVE video """ if duration_seconds > 0: duration = self.get_duration_from_seconds(duration_seconds) else: duration = "LIVE" timestamp = self.get_timestamp_from_youtube_url(url) yt_logo = self.get_youtube_logo() compiled_template = yt_template.render({ "title": title, "duration": duration, "timestamp": timestamp, "view_count": view_count, "like_count": like_count, "dislike_count": dislike_count, "comment_count": comment_count, "favorite_count": favorite_count, "channel_title": channel_title, "yt_logo": yt_logo }) title = compiled_template else: log.debug("SpiffyTitles: video appears to be private; no results!") except IndexError as e: log.error("SpiffyTitles: IndexError parsing Youtube API JSON response: %s" % (str(e))) else: log.error("SpiffyTitles: Error parsing Youtube API JSON response") else: log.error("SpiffyTitles: Youtube API HTTP %s: %s" % (request.status_code, request.text)) # If we found a title, return that. otherwise, use default handler if title: return title else: log.debug("SpiffyTitles: falling back to default handler") return self.handler_default(url, channel) def get_duration_from_seconds(self, duration_seconds): m, s = divmod(duration_seconds, 60) h, m = divmod(m, 60) duration = "%02d:%02d" % (m, s) """ Only include hour if the video is at least 1 hour long """ if h > 0: duration = "%02d:%s" % (h, duration) return duration def get_youtube_logo(self): colored_letters = [ "%s" % ircutils.mircColor("You", fg="red", bg="white"), "%s" % ircutils.mircColor("Tube", fg="white", bg="red") ] yt_logo = "".join(colored_letters) return yt_logo def get_total_seconds_from_duration(self, input): """ Duration comes in a format like this: PT4M41S which translates to 4 minutes and 41 seconds. This method returns the total seconds so that the duration can be parsed as usual. """ pattern = regex = re.compile(""" (?P<sign> -?) P (?:(?P<years> \d+) Y)? (?:(?P<months> \d+) M)? (?:(?P<days> \d+) D)? (?: T (?:(?P<hours> \d+) H)? (?:(?P<minutes>\d+) M)? (?:(?P<seconds>\d+) S)? )? """, re.VERBOSE) duration = regex.match(input).groupdict(0) delta = timedelta(hours=int(duration['hours']), minutes=int(duration['minutes']), seconds=int(duration['seconds'])) return delta.total_seconds() def get_timestamp_from_youtube_url(self, url): """ Get YouTube timestamp """ pattern = r"[?&]t=([^&]+)" match = re.search(pattern, url) if match: timestamp = match.group(1).upper() try: seconds = float(timestamp) except ValueError: seconds = self.get_total_seconds_from_duration("PT" + timestamp) if seconds > 0: return self.get_duration_from_seconds(seconds) else: return "" def handler_default(self, url, channel): """ Default handler for websites """ default_handler_enabled = self.registryValue("defaultHandlerEnabled", channel=channel) if default_handler_enabled: log.debug("SpiffyTitles: calling default handler for %s" % (url)) default_template = Template(self.registryValue("defaultTitleTemplate", channel=channel)) html = self.get_source_by_url(url) if html is not None and html: title = self.get_title_from_html(html) if title is not None: title_template = default_template.render(title=title) return title_template else: log.debug("SpiffyTitles: default handler fired but doing nothing because disabled") def handler_imdb(self, url, info, channel): """ Handles imdb.com links, querying the OMDB API for additional info Typical IMDB URL: http://www.imdb.com/title/tt2467372/ """ headers = self.get_headers() result = None if not self.registryValue("imdbHandlerEnabled", channel=channel): log.debug("SpiffyTitles: IMDB handler disabled. Falling back to default handler.") return self.handler_default(url, channel) # Don't care about query strings if "?" in url: url = url.split("?")[0] # We can only accommodate a specific format of URL here if "/title/" in url: imdb_id = url.split("/title/")[1].rstrip("/") omdb_url = "http://www.omdbapi.com/?i=%s&plot=short&r=json&tomatoes=true" % (imdb_id) try: request = requests.get(omdb_url, timeout=10, headers=headers) if request.status_code == requests.codes.ok: response = json.loads(request.text) result = None imdb_template = Template(self.registryValue("imdbTemplate")) not_found = "Error" in response unknown_error = response["Response"] != "True" if not_found or unknown_error: log.debug("SpiffyTitles: OMDB error for %s" % (omdb_url)) else: result = imdb_template.render(response) else: log.error("SpiffyTitles OMDB API %s - %s" % (request.status_code, request.text)) except requests.exceptions.Timeout as e: log.error("SpiffyTitles imdb Timeout: %s" % (str(e))) except requests.exceptions.ConnectionError as e: log.error("SpiffyTitles imdb ConnectionError: %s" % (str(e))) except requests.exceptions.HTTPError as e: log.error("SpiffyTitles imdb HTTPError: %s" % (str(e))) if result is not None: return result else: log.debug("SpiffyTitles: IMDB handler failed. calling default handler") return self.handler_default(url, channel) def handler_wikipedia(self, url, domain, channel): """ Queries wikipedia API for article extracts. """ wikipedia_handler_enabled = self.registryValue("wikipedia.enabled", channel=channel) if not wikipedia_handler_enabled: return self.handler_default(url, channel) self.log.debug("SpiffyTitles: calling Wikipedia handler for %s" % (url)) pattern = r"/(?:w(?:iki))/(?P<page>[^/]+)$" info = urlparse(url) match = re.search(pattern, info.path) if not match: self.log.debug("SpiffyTitles: no title found.") return self.handler_default(url, channel) elif info.fragment and self.registryValue("wikipedia.ignoreSectionLinks", channel=channel): self.log.debug("SpiffyTitles: ignoring section link.") return self.handler_default(url, channel) else: page_title = match.groupdict()['page'] default_api_params = { "format": "json", "action": "query", "prop": "extracts", "exsentences": "2", "exlimit": "1", "exintro": "", "explaintext": "" } extra_params = dict(parse_qsl('&'.join(self.registryValue("wikipedia.apiParams", channel=channel)))) title_param = { self.registryValue("wikipedia.titleParam", channel=channel): page_title } # merge dicts api_params = default_api_params.copy() api_params.update(extra_params) api_params.update(title_param) api_url = "https://en.wikipedia.org/w/api.php?%s" % ('&'.join("%s=%s" % (key, val) for (key,val) in api_params.iteritems())) agent = self.get_user_agent() headers = { "User-Agent": agent } extract = "" self.log.debug("SpiffyTitles: requesting %s" % (api_url)) request = requests.get(api_url, headers=headers) ok = request.status_code == requests.codes.ok if ok: response = json.loads(request.text) if response: try: extract = response['query']['pages'].values()[0]['extract'] except KeyError as e: self.log.error("SpiffyTitles: KeyError parsing Wikipedia API JSON response: %s" % (str(e))) else: self.log.error("SpiffyTitles: Error parsing Wikipedia API JSON response") else: self.log.error("SpiffyTitles: Wikipedia API HTTP %s: %s" % (request.status_code, request.text)) if extract: if (self.registryValue("wikipedia.removeParentheses")): extract = re.sub(r' ?\([^)]*\)', '', extract) max_chars = self.registryValue("wikipedia.maxChars", channel=channel) if len(extract) > max_chars: extract = extract[:max_chars - 3].rsplit(' ', 1)[0].rstrip(',.') + '...' wikipedia_template = Template(self.registryValue("wikipedia.extractTemplate", channel=channel)) return wikipedia_template.render({"extract": extract}) else: self.log.debug("SpiffyTitles: falling back to default handler") return self.handler_default(url, channel) def is_valid_imgur_id(self, input): """ Tests if input matches the typical imgur id, which seems to be alphanumeric. Images, galleries, and albums all share their format in their identifier. """ match = re.match(r"[a-z0-9]+", input, re.IGNORECASE) return match is not None def handler_imgur(self, url, info, channel): """ Queries imgur API for additional information about imgur links. This handler is for any imgur.com domain. """ self.initialize_imgur_client(channel) is_album = info.path.startswith("/a/") is_gallery = info.path.startswith("/gallery/") is_image_page = not is_album and not is_gallery and re.match(r"^\/[a-zA-Z0-9]+", info.path) result = None if is_album: result = self.handler_imgur_album(url, info, channel) #elif is_image_page: # result = self.handler_imgur_image(url, info) else: result = self.handler_default(url, channel) return result def handler_imgur_album(self, url, info, channel): """ Handles retrieving information about albums from the imgur API. imgur provides the following information about albums: https://api.imgur.com/models/album """ from imgurpython.helpers.error import ImgurClientRateLimitError from imgurpython.helpers.error import ImgurClientError self.initialize_imgur_client(channel) if self.imgur_client: album_id = info.path.split("/a/")[1] """ If there is a query string appended, remove it """ if "?" in album_id: album_id = album_id.split("?")[0] if self.is_valid_imgur_id(album_id): log.debug("SpiffyTitles: found imgur album id %s" % (album_id)) try: album = self.imgur_client.get_album(album_id) if album: imgur_album_template = Template(self.registryValue("imgurAlbumTemplate", channel=channel)) compiled_template = imgur_album_template.render({ "title": album.title, "section": album.section, "view_count": "{:,}".format(album.views), "image_count": "{:,}".format(album.images_count), "nsfw": album.nsfw }) return compiled_template else: log.error("SpiffyTitles: imgur album API returned unexpected results!") except ImgurClientRateLimitError as e: log.error("SpiffyTitles: imgur rate limit error: %s" % (e.error_message)) except ImgurClientError as e: log.error("SpiffyTitles: imgur client error: %s" % (e.error_message)) else: log.debug("SpiffyTitles: unable to determine album id for %s" % (url)) else: return self.handler_default(url, channel) def handler_imgur_image(self, url, info, channel): """ Handles retrieving information about images from the imgur API. Used for both direct images and imgur.com/some_image_id_here type links, as they're both single images. """ self.initialize_imgur_client(channel) from imgurpython.helpers.error import ImgurClientRateLimitError from imgurpython.helpers.error import ImgurClientError title = None if self.imgur_client: """ If there is a period in the path, it's a direct link to an image. If not, then it's a imgur.com/some_image_id_here type link """ if "." in info.path: path = info.path.lstrip("/") image_id = path.split(".")[0] else: image_id = info.path.lstrip("/") if self.is_valid_imgur_id(image_id): log.debug("SpiffyTitles: found image id %s" % (image_id)) try: image = self.imgur_client.get_image(image_id) if image: imgur_template = Template(self.registryValue("imgurTemplate", channel=channel)) readable_file_size = self.get_readable_file_size(image.size) compiled_template = imgur_template.render({ "title": image.title, "type": image.type, "nsfw": image.nsfw, "width": image.width, "height": image.height, "view_count": "{:,}".format(image.views), "file_size": readable_file_size, "section": image.section }) title = compiled_template else: log.error("SpiffyTitles: imgur API returned unexpected results!") except ImgurClientRateLimitError as e: log.error("SpiffyTitles: imgur rate limit error: %s" % (e.error_message)) except ImgurClientError as e: log.error("SpiffyTitles: imgur client error: %s" % (e.error_message)) else: log.error("SpiffyTitles: error retrieving image id for %s" % (url)) if title is not None: return title else: return self.handler_default(url, channel) def get_readable_file_size(self, num, suffix="B"): """ Returns human readable file size """ for unit in ["","Ki","Mi","Gi","Ti","Pi","Ei","Zi"]: if abs(num) < 1024.0: return "%3.1f%s%s" % (num, unit, suffix) num /= 1024.0 return "%.1f%s%s" % (num, "Yi", suffix) def get_formatted_title(self, title, channel): """ Remove cruft from title and apply bold if applicable """ useBold = self.registryValue("useBold", channel=channel) # Replace anywhere in string title = title.replace("\n", " ") title = title.replace("\t", " ") title = re.sub(" +", " ", title) if useBold: title = ircutils.bold(title) title = title.strip() return title def get_title_from_html(self, html): """ Retrieves value of <title> tag from HTML """ soup = BeautifulSoup(html, "lxml") if soup is not None: """ Some websites have more than one title tag, so get all of them and take the last value. """ head = soup.find("head") titles = head.find_all("title") if titles is not None and len(titles): title_text = titles[-1].get_text() if len(title_text): stripped_title = title_text.strip() return stripped_title @timeout_decorator.timeout(wall_clock_timeout) def get_source_by_url(self, url, retries=1): """ Get the HTML of a website based on a URL """ max_retries = self.registryValue("maxRetries") if retries is None: retries = 1 if retries >= max_retries: log.debug("SpiffyTitles: hit maximum retries for %s" % url) return None log.debug("SpiffyTitles: attempt #%s for %s" % (retries, url)) try: headers = self.get_headers() log.debug("SpiffyTitles: requesting %s" % (url)) request = requests.get(url, headers=headers, timeout=10, allow_redirects=True) if request.status_code == requests.codes.ok: # Check the content type which comes in the format: "text/html; charset=UTF-8" content_type = request.headers.get("content-type").split(";")[0].strip() acceptable_types = self.registryValue("mimeTypes") log.debug("SpiffyTitles: content type %s" % (content_type)) if content_type in acceptable_types: text = request.content if text: return text else: log.debug("SpiffyTitles: empty content from %s" % (url)) else: log.debug("SpiffyTitles: unacceptable mime type %s for url %s" % (content_type, url)) else: log.error("SpiffyTitles HTTP response code %s - %s" % (request.status_code, request.content)) except timeout_decorator.TimeoutError: log.error("SpiffyTitles: wall timeout!") self.get_source_by_url(url, retries+1) except requests.exceptions.MissingSchema as e: urlWithSchema = "http://%s" % (url) log.error("SpiffyTitles missing schema. Retrying with %s" % (urlWithSchema)) return self.get_source_by_url(urlWithSchema) except requests.exceptions.Timeout as e: log.error("SpiffyTitles Timeout: %s" % (str(e))) self.get_source_by_url(url, retries+1) except requests.exceptions.ConnectionError as e: log.error("SpiffyTitles ConnectionError: %s" % (str(e))) self.get_source_by_url(url, retries+1) except requests.exceptions.HTTPError as e: log.error("SpiffyTitles HTTPError: %s" % (str(e))) except requests.exceptions.InvalidURL as e: log.error("SpiffyTitles InvalidURL: %s" % (str(e))) def get_headers(self): agent = self.get_user_agent() self.accept_language = self.registryValue("language") headers = { "User-Agent": agent, "Accept-Language": ";".join((self.accept_language, "q=1.0")) } return headers def get_user_agent(self): """ Returns a random user agent from the ones available """ agents = self.registryValue("userAgents") return random.choice(agents) def message_matches_ignore_pattern(self, input): """ Checks message against linkMessageIgnorePattern to determine whether the message should be ignored. """ match = False pattern = self.registryValue("linkMessageIgnorePattern") if pattern: match = re.search(pattern, input) return match def title_matches_ignore_pattern(self, input, channel): """ Checks message against ignoredTitlePattern to determine whether the title should be ignored. """ match = False pattern = self.registryValue("ignoredTitlePattern", channel=channel) if pattern: match = re.search(pattern, input) if match: log.debug("SpiffyTitles: title %s matches ignoredTitlePattern for %s" % (input, channel)) return match def get_url_from_message(self, input): """ Find the first string that looks like a URL from the message """ url_re = self.registryValue("urlRegularExpression") match = re.search(url_re, input) if match: raw_url = match.group(0).strip() url = self.remove_control_characters(unicode(raw_url)) return url def remove_control_characters(self, s): return "".join(ch for ch in s if unicodedata.category(ch)[0]!="C") def user_has_capability(self, msg): channel = msg.args[0] mask = msg.prefix required_capability = self.registryValue("requireCapability") cap = ircdb.makeChannelCapability(channel, required_capability) has_cap = ircdb.checkCapability(mask, cap, ignoreDefaultAllow=True) if has_cap: log.debug("SpiffyTitles: %s has required capability '%s'" % (mask, required_capability)) else: log.debug("SpiffyTitles: %s does NOT have required capability '%s'" % (mask, required_capability)) return has_cap
for link in raw_links: # Check if imgur is in the reddit link's url if "imgur" not in link: continue file_extension = link.split(".")[-1] # Different ways to handle images, image sources, and albums/galleries if "jpg" in file_extension or "png" in file_extension: img_links.append(link) elif "gallery" in link.split("/") or "a" in link.split("/"): for index, value in enumerate(link.split("/")): if value == "gallery" or value == "a": imgur_album = client.get_album(link.split("/")[index + 1]) break images = imgur_album.images for image in images: img_links.append(image["link"]) else: imgur_r = urllib.urlopen(link).read() imgur_soup = BeautifulSoup(imgur_r, "lxml") imgur_link = imgur_soup.find("div", {"class": "post-image"}).find("a")["href"] if "//i.imgur.com" in imgur_link: img_links.append("https:" + imgur_link) # Iterate through compiled list of links to save and name images img_number = 0
class ImgurDownloader: """Handler for Imgur downloads. Attributes ---------- client : ImgurClient Instance of an Imgur API connection. """ def __init__(self, client_id, client_secret): self.client = ImgurClient(client_id, client_secret) #FIXME: Implement this def check_rate_limit(self): pass def get_imgur_id(self, url): """Get an Imgur id from a url. Returns ------- imgur_id : string The id of the content at the url. """ if "imgur" not in url: return None imgur_id = url[url.rfind('/') + 1:] # Remove the file extension if it exists. extension_index = imgur_id.find('.') if extension_index != -1: imgur_id = imgur_id[:extension_index] return imgur_id #FIXME: Add error checking def download_album(self, url, output_dirpath): """Downloads the imgur album from the given url. Parameters ---------- url : string URL for the imgur album. output_dirpath : pathlib.Path Path to the directory for saving images. Returns ------- success : bool Whether the album downloaded successfully. """ if "imgur.com/a/" not in url: return False imgur_id = self.get_imgur_id(url) album = self.client.get_album(imgur_id) # Create a directory for just the album. output_dir_str = str(output_dirpath) if not output_dir_str.endswith('/'): output_dir_str = output_dir_str + '/' if album.title: output_dir_str = output_dir_str + album.title + '/' else: output_dir_str = output_dir_str + imgur_id + '/' output_dirpath = pathlib.Path(output_dir_str) output_dirpath.mkdir(parents=True, exist_ok=True) for image in album.images: if type(image) is dict: image_id = image["id"] image_type = image["type"] image_link = image["link"] else: image_id = image.id image_type = image.type image_link = image.link output_filename = output_dir_str + image_id + " - imgur." + image_type[ 6:] with open(output_filename, 'wb') as handle: response = requests.get(image_link, stream=True) if not response.ok: print(response) return False for block in response.iter_content(1024): if not block: break handle.write(block) return True # FIXME: Implement this def download_gallery(self, url, output_path): return False
class Imgur(Plugin): CONFIG_DEFAULTS = { 'client_id': None, 'client_secret': None, } CONFIG_ENVVARS = { 'client_id': ['IMGUR_CLIENT_ID'], 'client_secret': ['IMGUR_CLIENT_SECRET'], } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.client = ImgurClient(self.config_get('client_id'), self.config_get('client_secret')) @Plugin.integrate_with('linkinfo') def integrate_with_linkinfo(self, linkinfo): linkinfo.register_handler(lambda url: url.netloc in ('imgur.com', 'i.imgur.com'), self._linkinfo_handler, exclusive=True) def _linkinfo_handler(self, url, match): # Split up endpoint and ID: /<image>, /a/<album> or /gallery/<id> kind, _, id = url.path.lstrip('/').rpartition('/') # Strip file extension from direct image links id = id.partition('.')[0] try: if kind == '': nsfw, title = self._format_image(self.client.get_image(id)) elif kind == 'a': nsfw, title = self._format_album(self.client.get_album(id), url.fragment) elif kind == 'gallery': data = self.client.gallery_item(id) if data.is_album: nsfw, title = self._format_album(data, None) else: nsfw, title = self._format_image(data) else: nsfw, title = False, None except ImgurClientError as e: return LinkInfoResult(url, str(e), is_error=True) if title: return LinkInfoResult(url, title, nsfw=nsfw) else: return None @staticmethod def _format_image(data): title = data.title or '' return data.nsfw or 'nsfw' in title.lower(), title @staticmethod def _format_album(data, image_id): title = '{0} ({1})'.format(data.title or 'Untitled album', pluralize(data.images_count, 'image', 'images')) images = {i['id']: i for i in data.images} image = images.get(image_id) if image and image['title']: title += ': ' + image['title'] return data.nsfw or 'nsfw' in title.lower(), title
''' import praw from imgurpython import ImgurClient from praw.models import Message from praw.models import Comment import random import time import sys from _operator import contains client_id = '*********' client_secret = '*********' client = ImgurClient(client_id, client_secret) #items = client.gallery() items = client.get_album('FlHzl') #numPictures = items.__sizeof__() reddit = praw.Reddit(client_id='*********', client_secret="********", password='******', user_agent='eyebleachbot (by /u/su5)', username='******') messageBod = '''User: {0} Subject: {1} Body: {2}''' response = '''NSFL? Yikes!
def get_imgur_ids_from_gallery(gallery): return True for post in submissions: sleep(1) #make sure it's a link # pprint(vars(post)) if not post.is_self: if get_url_type(post.url) == "directLink": directUrls['directLinks'].append(post.url) elif get_url_type(post.url) == "imgurAlbum": try: albumID = get_imgur_album_id(post.url) if not imgurclient.get_album(albumID).title: albumTitle = albumID else: albumTitle = imgurclient.get_album(albumID).title.replace("/","|") print "scraping " + albumTitle imgurIDs = get_imgur_ids_from_album(albumID) directUrls[albumTitle] = list() for imgurID in imgurIDs: directUrls[albumTitle].append( imgurID.link ) except: pass elif get_url_type(post.url) == "imgurGallery": print post.url
class imgur(commands.Cog): def __init__(self, bot): self.bot = bot self.clientID = bot.config.get('imgur_client_id') self.secretID = bot.config.get('imgur_client_secret') self.imgur_client = ImgurClient(self.clientID, self.secretID) @is_admin() @commands.command(aliases=['addalbum', 'aa']) async def album(self, ctx, link: str = None, *, album_name: str = None): """addalbum [album link] [album name] - Adds an album, link, and name. ex; .addalbum https://imgur.com/gallery/MnIjj3n a phone and 'pickone a phone' would call this album. """ if not link or not album_name: await ctx.send( 'Please include a link to the album and a name for the album.') return possible_links = [ 'https://imgur.com/gallery/', 'https://imgur.com/a/' ] #leaving this for additions later if not any(x in link for x in possible_links): await ctx.send('That doesnt look like a valid link.') else: album_name = album_name.lower() fetch_albums = await self.bot.fetch.all( f"SELECT * FROM Albums WHERE GuildID=?", (ctx.guild.id, )) fetch_album_names = list([album[2] for album in fetch_albums ]) if fetch_albums else [] if album_name not in fetch_album_names: await self.bot.db.execute( f"INSERT INTO Albums(GuildID, AlbumName, AlbumLink) VALUES (?, ?, ?)", ( ctx.guild.id, album_name, link, )) await self.bot.db.commit() await ctx.send(f'"{album_name}" has been added!') else: await ctx.send(f'"{album_name}" already exists') @is_admin() @commands.command(aliases=['delalbum', 'remalbum', 'da', 'ra']) async def deletealbum(self, ctx, *, album_name: str = None): """ deletealbum [album name] - Deletes an album, name. ex; .deletealbum a phone """ if not album_name: await ctx.send('Please provide an album name.') if album_name: album_name = album_name.lower() fetch_album = await self.bot.fetch.one( f"SELECT * FROM Albums WHERE GuildID=? AND AlbumName=?", (ctx.guild.id, album_name)) if fetch_album: await self.bot.db.execute( f"DELETE FROM Albums WHERE GuildID=? And AlbumName=?", ( ctx.guild.id, album_name, )) await self.bot.db.commit() await ctx.send(f'Removed album "{album_name}"') else: await ctx.send( f'Couldn\'t find an album the name of "{album_name}"') @commands.command(aliases=['p1', 'po', 'pick']) async def pickone(self, ctx, *, album_name: str = None): """ pickone (Optional album name) - picks a random image from the album. ex; .pickone a phone If only one album exists you do not provide an album name. """ grab_content_title_config = await self.bot.fetch.one( f"SELECT Content, Title FROM GuildConfig WHERE ID=?", (ctx.guild.id, )) content = grab_content_title_config[0] title = grab_content_title_config[1] if content is None and title is None: content = 'You asked me to pick a picture...' title = 'I Chose...' if album_name: album_name = album_name.lower() fetch_album = await self.bot.fetch.one( f"SELECT * FROM Albums WHERE GuildID=? AND AlbumName=?", ( ctx.guild.id, album_name, )) if not fetch_album: return await ctx.send("Couldnt find an album by that name") if len(fetch_album) == 0: return await ctx.send( 'You should probably add an album first..') imgur_link = fetch_album[3] if not album_name: fetch_albums = await self.bot.fetch.all( f"SELECT AlbumName, AlbumLink FROM Albums WHERE GuildID=?", (ctx.guild.id, )) if not fetch_albums: return await ctx.send("Might want to add an album first!") if len(fetch_albums) >= 2: return await ctx.send( 'Seems you forgot to provide an album name!') imgur_link = fetch_albums[0][1] try: await ctx.message.add_reaction( discord.utils.get(self.bot.emojis, name='check')) except: pass try: tail = imgur_link.split('/')[4] the_list = list( item.link for item in self.imgur_client.get_album_images(tail)) item = random.choice(the_list) item_id = item.split('/')[3][0:-4] if title in ['album title', 'Album Title']: title = self.imgur_client.get_album(tail).title if content in ['description', 'Description']: content = self.imgur_client.get_image(item_id).description if (self.imgur_client.get_image(item_id).size * 1e-6) > 8.0: return await ctx.send( f"{self.imgur_client.get_image(item_id).link} was too big to send." ) get_stream_status = await self.bot.fetch.one( f"SELECT Stream FROM GuildConfig WHERE ID=?", (ctx.guild.id, )) stream = get_stream_status[0] async with self.bot.aiohttp.get(item) as resp: link = await resp.read() if item.endswith('.gif'): f = discord.File(io.BytesIO(link), filename="image.gif") e = discord.Embed( title=title, colour=discord.Colour(0x278d89), ) if stream: e.set_image(url=f'''attachment://image.gif''') else: e.set_image( url=f'{self.imgur_client.get_image(item_id).link}') else: f = discord.File(io.BytesIO(link), filename="image.png") e = discord.Embed( title=title, colour=discord.Colour(0x278d89), ) if stream: e.set_image(url=f'''attachment://image.png''') else: e.set_image( url=f'{self.imgur_client.get_image(item_id).link}') e.set_footer( text= f'storage is currently: {"link" if not stream else "stream"} \n' f'if images aren\'t showing up, try toggling this with .stream' ) if stream: await ctx.send(file=f, embed=e, content=content) if not stream: await ctx.send(embed=e, content=content) except Exception as e: print( f'{e}, tail: {tail if tail else None} link: {imgur_link}, item: {item if item else None}' ) if isinstance(e, ImgurClientError): print(f'{e.error_message}') return await ctx.send(f'{e.error_message}') elif not isinstance(e, ImgurClientError): return await ctx.send( f'There was an issue processing this command.\nDebug: `{e}`' ) @commands.command(aliases=['al', 'list']) async def albumlist(self, ctx): """albumlist - displays all currently added albums by name. """ fetch_albums = await self.bot.fetch.all( f"SELECT * FROM Albums WHERE GuildID=?", (ctx.guild.id, )) if fetch_albums: list_album_names = ", ".join( list([album[2] for album in fetch_albums])) await ctx.send(f"{list_album_names}") else: await ctx.send('It doesnt seem that you have added an ablum.') @is_admin() @commands.command(aliases=['adda', 'admin']) async def addadmin(self, ctx, member: discord.Member = None): """addadmin [user name] - Adds an admin ex; .addadmin @ProbsJustin#0001 You can attempt to use just a string name; eg ProbsJustin but recommend a mention. """ if not member: await ctx.send('You should probably include a member.') return else: check_if_pwr_user = await self.bot.fetch.one( f"SELECT * FROM Permissions WHERE MemberID=? AND GuildID=?", ( ctx.author.id, ctx.guild.id, )) if not check_if_pwr_user: await self.bot.db.execute( f"INSERT INTO Permissions(MemberID, GuildID) VALUES (?, ?)", ( ctx.author.id, ctx.guild.id, )) await self.bot.db.commit() await ctx.send(f'{member.mention} has been added as an admin.') else: await ctx.send('That user is already an admin!') @is_admin() @commands.command(aliases=['remadmin', 'deladmin', 'deleteadmin']) async def removeadmin(self, ctx, member: discord.Member = None): """removeadmin [user name] - Remove an admin ex; .removeadmin @ProbsJustin#0001 You can attempt to use just a string name; eg ProbsJustin but recommend a mention. """ if not member: await ctx.send('You should probably include a member.') return else: chck_if_usr_is_admin = await self.bot.fetch.one( f"SELECT * FROM Permissions WHERE MemberID=? AND GuildID=?", ( ctx.author.id, ctx.guild.id, )) if chck_if_usr_is_admin: await self.bot.db.execute( f"DELETE FROM Permissions WHERE MemberID=? AND GuildID=?", ( ctx.author.id, ctx.guild.id, )) await self.bot.db.commit() await ctx.send( f'{member.mention} has been removed as an admin.') else: await ctx.send('I couldnt find that user in the admin list.') @addadmin.error @removeadmin.error async def member_not_found_error(self, ctx, exception): #so this is a thing. if not isinstance(exception, NotAuthorized): await ctx.send('Member not found! Try mentioning them instead.') @is_admin() @commands.command() async def set(self, ctx, content_title: str = None, *, message: str = ''): """set [content/title] [name] - Change the title/content from "I Chose..." "you asked.." """ editable_args = ['content', 'title'] if not content_title: await ctx.send( f"Please provide either {' or '.join(editable_args)}.") return content_title = content_title.lower() if content_title in editable_args: if content_title == "title": await self.bot.db.execute( f"UPDATE GuildConfig SET Title=? WHERE ID=?", ( message, ctx.guild.id, )) if content_title == 'content': await self.bot.db.execute( f"UPDATE GuildConfig SET Content=? WHERE ID=?", ( message, ctx.guild.id, )) await self.bot.db.commit() await ctx.send(f'{content_title.lower()} updated.') else: await ctx.send("Invalid parameters.") @is_admin() @commands.command() async def stream(self, ctx): """ Toggles how the images are sent to discord, if images aren't showing up try toggling this. """ get_stream_status = await self.bot.fetch.one( f"SELECT Stream FROM GuildConfig WHERE ID=?", (ctx.guild.id, )) update_stream_status = await self.bot.db.execute( f"UPDATE GuildConfig SET Stream=? WHERE ID=?", (not get_stream_status[0], ctx.guild.id)) await self.bot.db.commit() await ctx.send( f"Streaming turned {'on' if not get_stream_status[0] else 'off'}")
u = urllib.URLopener() srcreddits = ('Pics', 'EarthPorn', 'LavaPorn', 'AbandonedPorn', 'SpacePorn') for sub in srcreddits: print "Getting Most Recent Images From Subreddit: r/" + sub imgs += imgur.subreddit_gallery(sub, sort='time', window='day', page=0) for img in imgs: # If an album according to API only cover img available when accessed as gallery # Use API get_album method to grab all the images in the album if img.is_album == True: print "Getting album " + img.id i = imgur.get_album(img.id) for pix in i.images: filename = pix['link'].split('/')[-1] #print "Album branch, pix['link'] is " + pix['link'] + " file is " + file if int(pix['width']) > int(pix['height']): if os.path.isfile('/home/pi/Pictures/' + filename): print "Album Branch - File already exists" else: print "Downloading album image " + pix[ 'link'] + " to file " + filename u.retrieve(pix['link'], "/home/pi/Pictures/" + filename)
class Bot: def __init__(self, videobot, slave_bot): """ Initializes the Imgur Bot with credentials stored in environment variables. :return: ImgurClient object """ IMGUR_CLIENT_ID = os.environ.get("IMGUR_CLIENT_ID") IMGUR_CLIENT_SECRET = os.environ.get("IMGUR_CLIENT_SECRET") self.client = ImgurClient(IMGUR_CLIENT_ID, IMGUR_CLIENT_SECRET) self.supported_video_formats = ['gif','gifv', 'webm', 'mp4'] self.slave_bot = slave_bot self.video_bot = videobot def handle_album(self, album_link): """ handles imgur links of the format: imgur.com/a/<id>, imgur.com/<id>#<img id> :type album_link: 'str' :rtype message: 'str' - Analysis message from Bot. :rtype status: <Dict> - {'nsfw':<float>, 'sfw':<float>} """ temp = album_link.split('/')[-1] album_id = temp.split('#')[0] message = None status = {} try: album = self.client.get_album(album_id=album_id) imgur_flag = album.nsfw if imgur_flag: message = 'Album marked NSFW on Imgur.' message = '**[Hover to reveal](#s "' + message + '")**' # reddit spoiler tag added. elif not imgur_flag: images_list = self.client.get_album_images(album_id) links = [item.link for item in images_list[0:10] if item.type.split('/')[-1] not in self.supported_video_formats] links_videos = [item.link for item in images_list[0:10] if item.type.split('/')[-1] in self.supported_video_formats] # Ensures only 10 images/gifs are processed in case album is very large. temp1, _ = self.handle_videos(links_videos) temp2, _ = self.handle_images(links) status.update(temp1) status.update(temp2) # for all images, if SFW - mark SFW. # if any image is not SFW, find out which one. max_nsfw= (None, 0) min_sfw = (None, 100) for k,v in status.items(): labels = sorted(status[k].items(), key=operator.itemgetter(1), reverse=True) tag, confidence = labels[0] if tag is 'SFW' and confidence<=min_sfw[1]: min_sfw = labels[0] elif tag is not 'SFW' and confidence>max_nsfw[1]: max_nsfw = labels[0] if max_nsfw != (None, 0): message = "Album has "+str(max_nsfw[0])+" image(s). I'm {0:.2f}% confident.".format(max_nsfw[1]) elif max_nsfw == (None, 0): message = "Album has "+str(min_sfw[0])+" image(s). I'm {0:.2f}% confident.".format(min_sfw[1]) message = '**[Hover to reveal](#s "'+message+' ")**' #reddit spoiler tag added. except error.ImgurClientError as e: status = None message = None print ('Imgur Error:', e.error_message) return status, message def handle_images(self, links): status = {} message = None valid_links = [self.ensure_extension(aLink) for aLink in links if aLink.split('.')[-1].lower() not in ['gif', 'gifv', 'mp4', 'webm']] status = self.slave_bot.analyze(valid_links) if len(valid_links) == 1: link = valid_links[0] labels = sorted(status[link].items(), key=operator.itemgetter(1), reverse=True) tag, confidence = labels[0] message = tag + ". I'm {0:.2f}% confident.".format(confidence) if tag is 'SFW': manning_distance = self.slave_bot.clarifai_bot.match_template(link, 'manning') if manning_distance is not None and manning_distance <= 0.01: message += ' Might be Manning Face.' message = '**[Hover to reveal](#s "' + message + ' ")**' # reddit spoiler tag added. return status, message def handle_gallery(self, gallery_link): item_id = gallery_link.split('/')[-1] # user linked to either an album or an image from the imgur gallery. # assume it is album. if it's a 404, assume it is an image. message = '' status = {} try: album = self.client.get_album(album_id=item_id) imgur_flag = album.nsfw if imgur_flag: status = {} message = 'Album marked NSFW on Imgur.' message = '**[Hover to reveal](#s "' + message + '")**' # reddit spoiler tag added. elif not imgur_flag: status, message = self.handle_album(album.link) except error.ImgurClientError as e: try: image = self.client.get_image(item_id) imgur_flag = image.nsfw if imgur_flag: message = 'Item marked NSFW on Imgur.' message = '**[Hover to reveal](#s "' + message + '")**' # reddit spoiler tag added. elif not imgur_flag: if image.type.split('/')[-1] in self.supported_video_formats: status, message = self.handle_videos([image.link]) else: status, message = self.handle_images([image.link]) except error.ImgurClientError as e: status = None message = None print('Imgur Error', e.error_message) return status, message def handle_videos(self, links): status = {} message = None for each_url in links: link = self.ensure_extension(each_url) # link is now 'imgur.com/id.extension' video_id = link.split('/')[-1].split('.')[0] filename = video_id+'.mp4' mp4_link = 'http://i.imgur.com/'+filename urllib.urlretrieve(mp4_link, filename) status.update({each_url:self.video_bot.make_prediction(filename)}) if os.path.exists(filename): os.remove(filename) if len(links) == 1: link = links[0] labels = sorted(status[link].items(), key=operator.itemgetter(1), reverse=True) tag, confidence = labels[0] message = tag + ". I'm {0:.2f}% confident.".format(confidence) message = '**[Hover to reveal](#s "' + message + ' ")**' # reddit spoiler tag added. return status, message def ensure_extension(self, url): temp = url.split('/')[-1] # will be <image_id>.<extension> or <image_id> if '.' not in temp: image_id = temp url = self.client.get_image(image_id).link return url else: return url
if sys.version_info[0]== 2: pass elif sys.version_info[0] == 3: from builtins import input # trying to fix the error messages import urllib3 urllib3.disable_warnings() parser = argparse.ArgumentParser(description='imgur2pdf - convert an imgur gallery to pdf for archival purposes') parser.add_argument('album', metavar='album', help='id of imgur album') parser.add_argument('destination', metavar='destination', help='location to save to') args = parser.parse_args() client = ImgurClient(client_id, client_secret) album_data = client.get_album(args.album) album_file = album_data.title.replace(' ','_')+".pdf" path = args.destination[:-1] + '/' + album_file if os.path.isfile(path) == True: # we found something! print("found file %s, try with another destination" % path) quit() else: # nothing found, lets make stuff pass doc = SimpleDocTemplate(path,pagesize=letter, rightMargin=25,leftMargin=25,
def get_url(submission, mp4_instead_gif=True): ''' return TYPE, URL, EXTENSION E.x.: return 'img', 'http://example.com/pic.png', 'png' ''' def what_is_inside(url): header = requests.head(url).headers if 'Content-Type' in header: return header['Content-Type'] else: return '' url = submission.url url_content = what_is_inside(url) if (CONTENT_JPEG == url_content or CONTENT_PNG == url_content): return TYPE_IMG, url, url_content.split('/')[1] if CONTENT_GIF in url_content: if url.endswith('.gif') and mp4_instead_gif: # Let's try to find .mp4 file. url_mp4 = url[:-4] + '.mp4' if CONTENT_MP4 == what_is_inside(url_mp4): return TYPE_GIF, url_mp4, 'mp4' return TYPE_GIF, url, 'gif' if url.endswith('.gifv'): if mp4_instead_gif: url_mp4 = url[:-5] + '.mp4' if CONTENT_MP4 == what_is_inside(url_mp4): return TYPE_GIF, url_mp4, 'mp4' if CONTENT_GIF in what_is_inside(url[0:-1]): return TYPE_GIF, url[0:-1], 'gif' if submission.is_self is True: # Self submission with text return 'text', None, None if urlparse(url).netloc == 'imgur.com': # Imgur imgur_config = yaml.load(open('imgur.yml').read()) imgur_client = ImgurClient(imgur_config['client_id'], imgur_config['client_secret']) path_parts = urlparse(url).path.split('/') if path_parts[1] == 'gallery': # TODO: gallary handling return 'other', url, None elif path_parts[1] == 'topic': # TODO: topic handling return 'other', url, None elif path_parts[1] == 'a': # An imgur album album = imgur_client.get_album(path_parts[2]) story = {} for num, img in enumerate(album.images): number = num + 1 what = TYPE_IMG link = img['link'] ext = img['type'].split('/')[1] if img['animated']: what = TYPE_GIF link = img['mp4'] if mp4_instead_gif else img['gifv'][:-1] ext = 'mp4' if mp4_instead_gif else 'gif' story[number] = {'url': link, 'what': what, 'ext': ext} return 'album', story, None else: # Just imgur img img = imgur_client.get_image(path_parts[1].split('.')[0]) if not img.animated: return TYPE_IMG, img.link, img.type.split('/')[1] else: if mp4_instead_gif: return TYPE_GIF, img.mp4, 'mp4' else: # return 'gif', img.link, 'gif' return TYPE_GIF, img.gifv[:-1], 'gif' else: return 'other', url, None
# TODO: add metrics downloaded x images in x {min or sec} q = Queue.Queue(maxsize=0) # Change the number of simultaneous threads num_threads = 10 client_id = '' client_secret = '' client = ImgurClient(client_id, client_secret) gallery_url = raw_input('Enter gallery URL: ').split('/')[-1] try: gallery = client.gallery_item(gallery_url) except(imgurpython.helpers.error.ImgurClientError): gallery = client.get_album(gallery_url) download_path = os.path.join('c:', os.environ['HOMEPATH'], 'Downloads') os.chdir(download_path) if isinstance(gallery.title, unicode) is False: print 'has no title' gallery.title = gallery.id else: gallery.title = str(gallery.title).translate(None, string.punctuation) print(gallery.title) os.mkdir(gallery.title) os.chdir(gallery.title)
from imgurpython import ImgurClient import BotIDs import re album = "http://imgur.com/a/ES0Zc" albumID = re.findall(r"imgur.com/a/(\w+)", album)[0] client = ImgurClient(BotIDs.imgur_clientID, BotIDs.imgur_Secret) albumObj = client.get_album(albumID) albumPics = client.get_album_images(albumID) stickers = {} for pic in albumPics: stickers[pic.description] = pic.link
def zipdir(path, ziph): for root, dirs, files in os.walk(path): for file in files: ziph.write(os.path.join(root, file)) album_id = sys.argv[1] client_id = 'a17235ad4b51446' client_secret = '66b1c6fc9c7ffd4b665ea7ba9cb6beb67a4d47c7' client = ImgurClient(client_id, client_secret) album = client.get_album(album_id) album_dir = '%s - %s' % (album.id, album.title) os.mkdir(album_dir) seq = 0 for image in album.images: seq += 1 therest, filename = image['link'].rsplit('/', 1) filename, extension = filename.rsplit('.', 1) urllib.request.urlretrieve(image['link'], "%s/%04d.%s" % (album_dir, seq, extension)) print(("%0" + str(len(str(len(album.images)))) + "d/%d") % (seq, len(album.images)), image['link']) zipf = zipfile.ZipFile("%s.cbz" % album_dir, 'w', zipfile.ZIP_STORED)
class imgur(commands.Cog): def __init__(self, bot): self.bot = bot self.clientID = bot.config.data.get('config').get('imgur_client_id') self.secretID = bot.config.data.get('config').get( 'imgur_client_secret') self.imgur_client = ImgurClient(self.clientID, self.secretID) async def fetch_one(self, arg): get = await self.bot.db.execute(arg) results = await get.fetchone() return results async def fetch_all(self, arg): get = await self.bot.db.execute(arg) results = await get.fetchall() return results @is_admin() @commands.command(aliases=['addalbum', 'aa']) async def album(self, ctx, link: str = None, *, album_name: str = None): """addalbum [album link] [album name] - Adds an album, link, and name. ex; .addalbum https://imgur.com/gallery/MnIjj3n a phone and 'pickone a phone' would call this album. """ if not link or not album_name: await ctx.send( 'Please include a link to the album and a name for the album.') return possible_links = [ 'https://imgur.com/gallery/', 'https://imgur.com/a/' ] #leaving this for additions later if not any(x in link for x in possible_links): await ctx.send('That doesnt look like a valid link.') else: album_name = album_name.lower() get_albums = await imgur.fetch_all( self, f'SELECT AlbumLink FROM GuildAlbums WHERE GuildID={ctx.guild.id}' ) if link not in list(albumlink[0] for albumlink in get_albums): await self.bot.db.execute( f"INSERT INTO GuildAlbums(GuildID, AlbumLink, AlbumName) " f"VALUES (?, ?, ?)", (ctx.guild.id, link, album_name)) await self.bot.db.commit() await ctx.send(f'"{album_name}" has been added!') else: albums_name = await imgur.fetch_one( self, f'SELECT AlbumName FROM GuildAlbums WHERE AlbumLink="{link}"' ) await ctx.send(f'{link} already exists as {albums_name[0]}.') @is_admin() @commands.command(aliases=['delalbum', 'remalbum', 'da', 'ra']) async def deletealbum(self, ctx, *, album_name: str = None): """deletealbum [album name] - Deletes an album, name. ex; .deletealbum a phone """ if not album_name: await ctx.send('Please provide an album name.') get_albums = await imgur.fetch_all( self, f'SELECT AlbumName FROM GuildAlbums WHERE GuildID={ctx.guild.id}') if album_name.lower() in list(albumnames[0] for albumnames in get_albums): await self.bot.db.execute( f'DELETE FROM GuildAlbums WHERE GuildID=? and AlbumName=?', (ctx.guild.id, album_name.lower())) await self.bot.db.commit() await ctx.send(f'Removed album "{album_name}"') else: await ctx.send(f'Couldnt find an album the name of "{album_name}"') @commands.command(aliases=['p1', 'po', 'pick']) async def pickone(self, ctx, *, album_name: str = None): """pickone (Optional album name) - picks a random image from the album. ex; .pickone a phone If only one album exists you do not provide an album name. """ album_names = await imgur.fetch_all( self, f'SELECT AlbumName FROM GuildAlbums WHERE GuildID={ctx.guild.id}') if not album_names: await ctx.send('You should probably add an album first..') return content = await imgur.fetch_one( self, f'SELECT Content FROM GuildConfig WHERE ID={ctx.guild.id}') title = await imgur.fetch_one( self, f'SELECT Title FROM GuildConfig WHERE ID={ctx.guild.id}') await ctx.message.add_reaction( discord.utils.get(self.bot.emojis, name='check')) content = 'You asked me to pick a picture...' if not content[ 0] else content[0] title = 'I Chose...' if not title[0] else title[0] if album_name: if album_name.lower() in list(albumnames[0] for albumnames in album_names): album_link = await imgur.fetch_one( self, f'SELECT AlbumLink FROM GuildAlbums WHERE ' f'AlbumName="{album_name.lower()}" and GuildID={ctx.guild.id}' ) tail = album_link[0].split('/')[4] the_list = list( item.link for item in self.imgur_client.get_album_images(tail)) else: await ctx.send( f'I couldnt find an album by the name of "{album_name}"') if not album_name: if len(album_names) >= 2: await ctx.send('Seems you forgot to provide an album name!') return if len(album_names) == 1: album_link = await imgur.fetch_one( self, f'SELECT AlbumLink FROM GuildAlbums WHERE ' f'AlbumName="{album_names[0][0]}" and GuildID={ctx.guild.id}' ) tail = album_link[0].split('/')[4] the_list = list( item.link for item in self.imgur_client.get_album_images(tail)) try: item = random.choice(the_list) item_id = item.split('/')[3][0:-4] if title in ['album title', 'Album Title']: title = self.imgur_client.get_album(tail).title if content in ['description', 'Description']: content = self.imgur_client.get_image(item_id).description async with self.bot.aiohttp.get(item) as resp: link = await resp.read() if item.endswith('.gif'): f = discord.File(io.BytesIO(link), filename="image.gif") e = discord.Embed(title=title, colour=discord.Colour(0x278d89)) e.set_image(url=f'''attachment://image.gif''') else: f = discord.File(io.BytesIO(link), filename="image.png") e = discord.Embed(title=title, colour=discord.Colour(0x278d89)) e.set_image(url=f'''attachment://image.png''') await ctx.send(file=f, embed=e, content=content) except Exception as e: if isinstance(e, ImgurClientError): print(f'{e.error_message}') await ctx.send(f'{e.error_message}') elif not isinstance(e, ImgurClientError): await ctx.send( f'There was an issue processing this command. {e}') @commands.command(aliases=['al', 'list']) async def albumlist(self, ctx): """albumlist - displays all currently added albums by name. """ album_names = await imgur.fetch_all( self, f'SELECT AlbumName FROM GuildAlbums WHERE GuildID={ctx.guild.id}') if len(album_names) is not 0: await ctx.send( f"The list of albums I see are: {', '.join(list(an[0] for an in album_names))}." ) else: await ctx.send('It doesnt seem that you have added an ablum.') @is_admin() @commands.command(aliases=['adda', 'admin']) async def addadmin(self, ctx, member: discord.Member = None): """addadmin [user name] - Adds an admin ex; .addadmin @ProbsJustin#0001 You can attempt to use just a string name; eg ProbsJustin but recommend a mention. """ if not member: await ctx.send('You should probably include a member.') return else: get_admins = await imgur.fetch_all( self, f'SELECT AdminID FROM GuildAdmins WHERE GuildID={ctx.guild.id}' ) if member.id not in list(admin[0] for admin in get_admins): await self.bot.db.execute( f"INSERT INTO GuildAdmins(GuildID, AdminID) VALUES (?, ?)", (ctx.guild.id, member.id)) await self.bot.db.commit() await ctx.send(f'{member.mention} has been added as an admin.') else: await ctx.send('That user is already an admin!') @is_admin() @commands.command(aliases=['remadmin', 'deladmin', 'deleteadmin']) async def removeadmin(self, ctx, member: discord.Member = None): """removeadmin [user name] - Remove an admin ex; .removeadmin @ProbsJustin#0001 You can attempt to use just a string name; eg ProbsJustin but recommend a mention. """ if not member: await ctx.send('You should probably include a member.') return else: get_admins = await imgur.fetch_all( self, f'SELECT AdminID FROM GuildAdmins WHERE GuildID={ctx.guild.id}' ) if member.id in list(admin[0] for admin in get_admins): await self.bot.db.execute( f'DELETE FROM GuildAdmins WHERE GuildID=? and AdminID=?', (ctx.guild.id, member.id)) await self.bot.db.commit() await ctx.send( f'{member.mention} has been removed as an admin.') else: await ctx.send('I couldnt find that user in the admin list.') @addadmin.error @removeadmin.error async def member_not_found_error(self, ctx, exception): #so this is a thing. if not isinstance(exception, NotAuthorized): await ctx.send('Member not found! Try mentioning them instead.') @is_admin() @commands.command() async def set(self, ctx, content_title: str = None, *, message: str = ''): """set [content/title] [name] - Change the title/content from "I Chose..." "you asked.." """ editable_args = ['content', 'title'] if not content_title: await ctx.send( f"Please provide either {' or '.join(editable_args)}.") return if content_title.lower() in editable_args: await self.bot.db.execute( f'UPDATE GuildConfig SET {content_title.title()}="{message}" ' f'WHERE ID={ctx.guild.id}') await self.bot.db.commit() await ctx.send(f'{content_title.lower()} updated.') else: await ctx.send("Invalid parameters.")
def execute(self, subreddit, BANNER, LIMIT): global r client = ImgurClient(cfg_file.get('imgur', 'client_id'), cfg_file.get('imgur', 'client_secret')) album_id = get_album_id(self.url) album = client.get_album(album_id) album_title = self.title album = album.images COUNT = len(album) if COUNT < LIMIT: print('Not enough images!') send_error_message(cfg_file.get('reddit', 'owner_username'), subreddit.display_name, 'Not enough ' ' images in album ["{0}"]({1})'.format(album_title, self.url)) return # Pick x random ones if greater than limit if COUNT > LIMIT: album = random.sample(album, COUNT) banner_number = 0 sidebar_format = '* [{title}]({link} "{desc}")' sidebar_lines = [] bigpic = [] for image in album: if image['size'] > 512000: print ('too big: %s' %(image['link'])) title = '{0} - ({1} kB) - {2}px x {3}px'.format(image['link'], float(image['size'])/1000, image['width'], image['height']) bigpic.append(sidebar_format.format(title=title, link=image['link'], desc=image['description'])) continue banner_number += 1 url = image['link'] local_name = localize_name(album_id, url) download_image(url, local_name) title = image['title'] if image['title'] else 'Untitled' description = image['description'] if image['description'] else ' ' line = sidebar_format.format(title=title, link='#s', desc=description) css_name = BANNER + '%d' % banner_number print('%s: adding %s to stylesheet...' % (subreddit, css_name)) try: r.upload_image(subreddit, local_name, css_name) except Exception as e: print (e) return sidebar_lines.append(line) if banner_number >= LIMIT: break if banner_number < LIMIT: print ('Not enough valid images') send_error_message(cfg_file.get('reddit', 'owner_username'), subreddit.display_name, 'Not enough valid' ' images in album ["{0}"]({1}); check that the following image sizes are less than 500kB. ' 'Images ideally should be greater than 300px wide and 1:1 or greater aspect ratio: \n\n{2}'.format(album_title, self.url, '\n'.join(bigpic))) return bar = '\n'.join(sidebar_lines) bar = '##### ' + album_title + '\n' + bar + '\n\n' r.config.decode_html_entities = True current_sidebar = subreddit.get_settings()['description'] current_sidebar = HTMLParser.HTMLParser().unescape(current_sidebar) replace_pattern = re.compile('%s.*?%s' % (re.escape(cfg_file.get('reddit', 'start_delimiter')), re.escape(cfg_file.get('reddit', 'end_delimiter'))), re.IGNORECASE|re.DOTALL|re.UNICODE) new_sidebar = re.sub(replace_pattern, '%s\\n\\n%s\\n%s' % (cfg_file.get('reddit', 'start_delimiter'), bar, cfg_file.get('reddit', 'end_delimiter')), current_sidebar) r.update_settings(subreddit, description=new_sidebar) print ('%s sidebar updated!' %subreddit) subreddit.set_stylesheet(subreddit.get_stylesheet()['stylesheet']) print ('%s stylesheet set!' %subreddit) if bigpic: send_error_message(cfg_file.get('reddit', 'owner_username'), subreddit.display_name, 'The following ' ' images in album ["{0}"]({1}) were not valid and were skipped; check that the following image sizes are less than 500kB. ' 'Images ideally should be greater than 300px wide and 1:1 or greater aspect ratio: \n\n{2}'.format(album_title, self.url, '\n'.join(bigpic)))
import os from imgurpython import ImgurClient from urllib import urlretrieve client_id = os.environ['IMGUR_ID'] client_secret = os.environ['IMGUR_SECRET'] client = ImgurClient(client_id, client_secret) imgURL = sys.argv[1] imgID = '' if 'imgur.com/a/' in imgURL: match = re.search(r'(imgur.com/a/)(\w+)', imgURL) info = client.get_album(match.group(2)) imgURL = 'http://i.imgur.com/' + info.cover + 'l.jpg' imgID = info.cover elif 'imgur.com/gallery' in imgURL: match = re.search(r'(imgur.com/gallery/)(\w+)', imgURL) try: info = client.get_album(match.group(2)) imgURL = 'http://i.imgur.com/' + info.cover + 'l.jpg' imgID = info.cover except: imgURL = 'http://i.imgur.com/' + match.group(2) + 'l.jpg' imgID = match.group(2) elif 'imgur.com/r/' in imgURL: match = re.search(r'(imgur.com/r/\w+/)(\w+)', imgURL)
def get_url(submission, mp4_instead_gif=True): ''' return TYPE, URL, EXTENSION E.x.: return 'img', 'http://example.com/pic.png', 'png' ''' def what_is_inside(url): header = requests.head(url).headers if 'Content-Type' in header: return header['Content-Type'] else: return '' url = submission.url url_content = what_is_inside(url) if (CONTENT_JPEG == url_content or CONTENT_PNG == url_content): return TYPE_IMG, url, url_content.split('/')[1] if CONTENT_GIF in url_content: if url.endswith('.gif') and mp4_instead_gif: # Let's try to find .mp4 file. url_mp4 = url[:-4] + '.mp4' if CONTENT_MP4 == what_is_inside(url_mp4): return TYPE_GIF, url_mp4, 'mp4' return TYPE_GIF, url, 'gif' if url.endswith('.gifv'): if mp4_instead_gif: url_mp4 = url[:-5] + '.mp4' if CONTENT_MP4 == what_is_inside(url_mp4): return TYPE_GIF, url_mp4, 'mp4' if CONTENT_GIF in what_is_inside(url[0:-1]): return TYPE_GIF, url[0:-1], 'gif' if submission.is_self is True: # Self submission with text return TYPE_TEXT, None, None if urlparse(url).netloc == 'imgur.com': # Imgur imgur_config = yaml.load(open(os.path.join('configs', 'imgur.yml')).read()) imgur_client = ImgurClient(imgur_config['client_id'], imgur_config['client_secret']) path_parts = urlparse(url).path.split('/') if path_parts[1] == 'gallery': # TODO: gallary handling return TYPE_OTHER, url, None elif path_parts[1] == 'topic': # TODO: topic handling return TYPE_OTHER, url, None elif path_parts[1] == 'a': # An imgur album album = imgur_client.get_album(path_parts[2]) story = dict() for num, img in enumerate(album.images): number = num + 1 what = TYPE_IMG link = img['link'] ext = img['type'].split('/')[1] if img['animated']: what = TYPE_GIF link = img['mp4'] if mp4_instead_gif else img['gifv'][:-1] ext = 'mp4' if mp4_instead_gif else 'gif' story[number] = { 'url': link, 'what': what, 'ext': ext } if len(story) == 1: return story[1]['what'], story[1]['url'], story[1]['ext'] return TYPE_ALBUM, story, None else: # Just imgur img img = imgur_client.get_image(path_parts[1].split('.')[0]) if not img.animated: return TYPE_IMG, img.link, img.type.split('/')[1] else: if mp4_instead_gif: return TYPE_GIF, img.mp4, 'mp4' else: # return 'gif', img.link, 'gif' return TYPE_GIF, img.gifv[:-1], 'gif' elif 'gfycat.com' in urlparse(url).netloc: client = GfycatClient() rname = re.findall(r'gfycat.com\/(?:detail\/)?(\w*)', url)[0] try: urls = client.query_gfy(rname)['gfyItem'] if mp4_instead_gif: return TYPE_GIF, urls['mp4Url'], 'mp4' else: return TYPE_GIF, urls['max5mbGif'], 'gif' except KeyError: logging.info('Gfy fail prevented!') return TYPE_OTHER, url, None else: return TYPE_OTHER, url, None
return True for post in submissions: sleep(1) #make sure it's a link # pprint(vars(post)) if not post.is_self: if get_url_type(post.url) == "directLink": directUrls['directLinks'].append(post.url) elif get_url_type(post.url) == "imgurAlbum": try: albumID = get_imgur_album_id(post.url) if not imgurclient.get_album(albumID).title: albumTitle = albumID else: albumTitle = imgurclient.get_album(albumID).title.replace( "/", "|") print "scraping " + albumTitle imgurIDs = get_imgur_ids_from_album(albumID) directUrls[albumTitle] = list() for imgurID in imgurIDs: directUrls[albumTitle].append(imgurID.link) except: pass elif get_url_type(post.url) == "imgurGallery":