Exemplo n.º 1
0
def post_to_imgur(imgur: ImgurClient, config: configparser, dir: str,
                  memes: Memes) -> str:
    """
    Uploads images and creates a public albumb of the memes.
    """

    # Upload images
    image_ids: List[str] = []
    for meme in memes:
        response = imgur.upload_from_path(path=os.path.join(dir, meme),
                                          config=None,
                                          anon=False)
        image_ids.append(response["id"])

    # Create album
    ymd = str(date.today())
    title = config.get("daily-memes", "imgur_album_title_prefix")
    desc = config.get("daily-memes", "imgur_album_desc")
    album = imgur.create_album({
        "title": f"{title} {ymd}",
        "desc": desc,
        "ids": ",".join(image_ids),
        "privacy": "public"
    })
    return album["id"]
Exemplo n.º 2
0
def CreateAlbumAndUploadImages(albumName, albumDescription, images):
    access_token, refresh_token, client_id, client_secret = Config.getImgurKeys(
    )
    client = ImgurClient(client_id, client_secret)
    client.set_user_auth(access_token, refresh_token)
    fields = {}
    fields['title'] = albumName
    fields['description'] = albumDescription
    fields['privacy'] = 'public'
    x = client.create_album(fields)
    y = client.album_add_images(x['id'], images)
    return x
Exemplo n.º 3
0
def upload_images(album_title, paths):
    client = ImgurClient(client_id, client_secret)
    client.set_user_auth(imgur_access_token, imgur_refresh_token)
    fields = {"title": album_title}
    album = client.create_album(fields)

    for i, img in enumerate(paths):
        config = {"album": album["id"], "name": str(i), "title": str(i)}
        image = client.upload_from_path(img, config=config, anon=False)
        remove(img)

    return album
Exemplo n.º 4
0
def upload_images(album_title, paths):
    client = ImgurClient(client_id, client_secret)
    client.set_user_auth(imgur_access_token, imgur_refresh_token)
    fields = {'title': album_title}
    album = client.create_album(fields)

    for i, img in enumerate(paths):
        config = {'album': album['id'], 'name': str(i), 'title': str(i)}
        image = client.upload_from_path(img, config=config, anon=False)
        remove(img)

    return album
Exemplo n.º 5
0
 def create_album(self):
     try:
         album_fields={'title':'familabincubator','description':'familabincubator','privacy':'public'}
         #allowed_album_fields = {'ids', 'title', 'description', 'privacy', 'layout', 'cover'}
         client = ImgurClient(IMGUR_ID,IMGUR_TOKEN)
         album_url=client.create_album(album_fields)
         return album_url
     except SNIMissingWarning:
         print "snimissingwarning"
     except InsecurePlatformWarning:
         print "oh noes insecure platform warning"
     except ImgurClientError, error:
             print error.error_message, error.status_code
Exemplo n.º 6
0
class Create_Album():
    def __init__(self):
        self.client_id = os.environ.get('Client_ID')
        self.client_secret = os.environ.get('Client_Secret')
        self.access_token = os.environ.get('access_token')
        self.refresh_token = os.environ.get('refresh_token')
        # self.client_id = config['imgur_api']['Client_ID']
        # self.client_secret = config['imgur_api']['Client_Secret']
        # self.access_token = config['imgur_api']['access_token']
        # self.refresh_token = config['imgur_api']['refresh_token']
        self.client = ImgurClient(self.client_id, self.client_secret,
                                  self.access_token, self.refresh_token)
        self.logger = None

    def exelogging(self, msg):
        if self.logger:
            self.logger.debug(msg)
        else:
            print(msg)

    def create(self, title, description):

        fields = {
            'title': title,
            'description': description,
        }
        self.exelogging(fields)
        self.exelogging("create album... ")
        try:
            reply = self.client.create_album(fields=fields)
        except Exception as e:
            self.exelogging(e)
            return False, dict()

        self.exelogging("Done")

        return True, reply
Exemplo n.º 7
0
    def create(self, client: ImgurClient) -> str:
        """Create new album if it doesn't exist

        :param client: imgur api client
        :type client: ImgurClient
        :return: deletehash of album being uploaded to
        :rtype: str
        """
        if not self.deletehash:
            logging.info("Creating new imgur album with config: %s", self.config)
            album = client.create_album(self.config)
            self.deletehash = album["deletehash"]
            self.album_id = album["id"]
            logging.info(
                'New album created with deletehash "%s" and album_id "%s"',
                self.deletehash,
                self.album_id,
            )
        else:
            logging.info(
                'Imgur album does not need to be created, it already exists with deletehash "%s"',
                self.deletehash,
            )
        return self.deletehash
Exemplo n.º 8
0
class ImgurStorage(Storage):
    """
    A storage class providing access to resources in a Dropbox Public folder.
    """

    def __init__(self, location='/'):
        self.client = ImgurClient(
            CONSUMER_ID,
            CONSUMER_SECRET,
            ACCESS_TOKEN,
            ACCESS_TOKEN_REFRESH)
        logger.info("Logged in Imgur storage")
        self.account_info = self.client.get_account(USERNAME)
        self.albums = self.client.get_account_albums(USERNAME)
        self.location = location
        self.base_url = 'https://api.imgur.com/3/account/{url}/'.format(url=self.account_info.url)

    def _get_abs_path(self, name):
        return os.path.join(self.location, name)

    def _open(self, name, mode='rb'):
        remote_file = self.client.get_image(name, self, mode=mode)
        return remote_file

    def _save(self, name, content):
        name = self._get_abs_path(name)
        directory = os.path.dirname(name)
        logger.info([a.title for a in self.albums])
        logger.info(name)
        logger.info(directory)
        if not self.exists(directory) and directory:
            album = self.client.create_album({"title": directory})
            self.albums = self.client.get_account_albums(USERNAME)
        album = [a for a in self.albums if a.title == directory][0]
        #if not response['is_dir']:
        #     raise IOError("%s exists and is not a directory." % directory)
        response = self._client_upload_from_fd(content, {"album": album.id, "name": name, "title": name}, False)
        return response["name"]

    def _client_upload_from_fd(self, fd, config=None, anon=True):
        """ use a file descriptor to perform a make_request """
        if not config:
            config = dict()

        contents = fd.read()
        b64 = base64.b64encode(contents)

        data = {
            'image': b64,
            'type': 'base64',
        }

        data.update({meta: config[meta] for meta in set(self.client.allowed_image_fields).intersection(config.keys())})
        return self.client.make_request('POST', 'upload', data, anon)

    def delete(self, name):
        name = self._get_abs_path(name)
        self.client.delete_image(name)

    def exists(self, name):
        name = self._get_abs_path(name)
        if len([a for a in self.albums if a.title == name]) > 0:
            return True
        try:
            album = [a for a in self.albums if a.title == os.path.dirname(name)][0]
            images = self.client.get_album_images(album.id)
            metadata = self.client.get_image(name)
            if len([im for im in images if im.name == name]) > 0:
                logger.info(dir(metadata))
                return True
        except ImgurClientError as e:
            if e.status_code == 404: # not found
                return False
            raise e
        except IndexError as e:
            return False
        else:
            return True
        return False

    def listdir(self, path):
        path = self._get_abs_path(path)
        response = self.client.get_image(path)
        directories = []
        files = []
        for entry in response.get('contents', []):
            if entry['is_dir']:
                directories.append(os.path.basename(entry['path']))
            else:
                files.append(os.path.basename(entry['path']))
        return directories, files

    def size(self, path):
        cache_key = 'django-imgur-size:%s' % filepath_to_uri(path)
        size = cache.get(cache_key)

        if not size:
            directory = os.path.dirname(path)
            name = os.path.basename(path)
            album = [a for a in self.albums if a.title == directory][0]
            images = self.client.get_album_images(album.id)
            image = [im for im in images if im.name == path][0]
            size = self.client.get_image(image.id).size
            cache.set(cache_key, size)

        return size

    def url(self, path):
        cache_key = 'django-imgur-url:%s' % filepath_to_uri(path)
        url = cache.get(cache_key)

        if not url:
            directory = os.path.dirname(path)
            name = os.path.basename(path)
            album = [a for a in self.albums if a.title == directory][0]
            images = self.client.get_album_images(album.id)
            image = [im for im in images if im.name == path][0]
            url = self.client.get_image(image.id).link
            cache.set(cache_key, url)

        return url

    def get_available_name(self, name, max_length=None):
        """
        Returns a filename that's free on the target storage system, and
        available for new content to be written to.
        """
        #name = self._get_abs_path(name)
        #dir_name, file_name = os.path.split(name)
        #file_root, file_ext = os.path.splitext(file_name)
        ## If the filename already exists, add an underscore and a number (before
        ## the file extension, if one exists) to the filename until the generated
        ## filename doesn't exist.
        #count = itertools.count(1)
        #while self.exists(name):
        #    # file_ext includes the dot.
        #    name = os.path.join(dir_name, "%s_%s%s" % (file_root, count.next(), file_ext))

        return name
Exemplo n.º 9
0
class Imgur:

   imgur = None

   client_id = None
   client_secret = None

   def __init__(self):
      config = get_config()
      config.read('auth.ini')
      self.client_id = config.get('imgur', 'client_id')
      self.client_secret = config.get('imgur', 'client_secret')

      self.imgur = ImgurClient(self.client_id, self.client_secret)

   def createAlbum(self, album_title):
   	  log.d('Starting album creation...')

   	  fields = {
	  	'Authorization':'Client-ID {' + self.client_id + '}',
		'title':album_title
	  }  

	  try:
	  	album = self.imgur.create_album(fields)
	  	log.d('Album created successfully.')
	  	return album
	  except ImgurClientError as e:
	  	log.e('Failed to create album, aborting.')
	  	log.e(e.error_message)
	  	log.e(e.status_code)
	  	return None

   def uploadImagesToAlbum(self, album, imgList):
      # For anonymous albums, use album's deletehash instead of id
	  config = {
	  	'album': album['deletehash']
	  }

	  log.d(imgList)

	  #Upload images to album
	  for link in imgList:
	  	log.d('Uploading ' + link + '...')
	  	try:
	  		response = self.imgur.upload_from_url(link, config=config, anon=True)
	  		log.d('Image uploaded successfully.')
	  	except ImgurClientError as e:
	  	    print(e.error_message)
	  	    print(e.status_code)
	  	    log.e("Image upload failed, aborting.")
	  	    return 0  

	  	# Wait for n seconds so Imgur doesn't get upset with us
	  	time.sleep(5)    

	  log.d('All images uploaded successfully.') 

	  return 1    	

   def upload(self, imgLinks, albumName):
	  # Create new Imgur album
	  album = self.createAlbum(albumName)

	  if(album is None):
	  	return None

	  success = self.uploadImagesToAlbum(album, imgLinks)

	  if(not success):
	  	return None
	  
	  # Return album URL
	  albumLink = 'https://imgur.com/a/' + album['id']

	  log.d('Album Link: ' + albumLink)

	  return albumLink
Exemplo n.º 10
0
class ImgurStorage(Storage):
    """
    A storage class providing access to resources in a Dropbox Public folder.
    """
    def __init__(self, location='/'):
        self.client = ImgurClient(CONSUMER_ID, CONSUMER_SECRET, ACCESS_TOKEN,
                                  ACCESS_TOKEN_REFRESH)
        logger.info("Logged in Imgur storage")
        self.account_info = self.client.get_account(USERNAME)
        self.albums = self.client.get_account_albums(USERNAME)
        self.location = location
        self.base_url = 'https://api.imgur.com/3/account/{url}/'.format(
            url=self.account_info.url)

    def _get_abs_path(self, name):
        return os.path.join(self.location, name)

    def _open(self, name, mode='rb'):
        remote_file = self.client.get_image(name, self, mode=mode)
        return remote_file

    def _save(self, name, content):
        name = self._get_abs_path(name)
        directory = os.path.dirname(name)
        logger.info([a.title for a in self.albums])
        logger.info(name)
        logger.info(directory)
        if not self.exists(directory) and directory:
            album = self.client.create_album({"title": directory})
            self.albums = self.client.get_account_albums(USERNAME)
        album = [a for a in self.albums if a.title == directory][0]
        #if not response['is_dir']:
        #     raise IOError("%s exists and is not a directory." % directory)
        response = self._client_upload_from_fd(content, {
            "album": album.id,
            "name": name,
            "title": name
        }, False)
        return response["name"]

    def _client_upload_from_fd(self, fd, config=None, anon=True):
        """ use a file descriptor to perform a make_request """
        if not config:
            config = dict()

        contents = fd.read()
        b64 = base64.b64encode(contents)

        data = {
            'image': b64,
            'type': 'base64',
        }

        data.update({
            meta: config[meta]
            for meta in set(self.client.allowed_image_fields).intersection(
                list(config.keys()))
        })
        return self.client.make_request('POST', 'upload', data, anon)

    def delete(self, name):
        name = self._get_abs_path(name)
        self.client.delete_image(name)

    def exists(self, name):
        name = self._get_abs_path(name)
        if len([a for a in self.albums if a.title == name]) > 0:
            return True
        try:
            album = [
                a for a in self.albums if a.title == os.path.dirname(name)
            ][0]
            images = self.client.get_album_images(album.id)
            metadata = self.client.get_image(name)
            if len([im for im in images if im.name == name]) > 0:
                logger.info(dir(metadata))
                return True
        except ImgurClientError as e:
            if e.status_code == 404:  # not found
                return False
            raise e
        except IndexError as e:
            return False
        else:
            return True
        return False

    def listdir(self, path):
        path = self._get_abs_path(path)
        response = self.client.get_image(path)
        directories = []
        files = []
        for entry in response.get('contents', []):
            if entry['is_dir']:
                directories.append(os.path.basename(entry['path']))
            else:
                files.append(os.path.basename(entry['path']))
        return directories, files

    def size(self, path):
        cache_key = 'django-imgur-size:%s' % filepath_to_uri(path)
        size = cache.get(cache_key)

        if not size:
            directory = os.path.dirname(path)
            name = os.path.basename(path)
            album = [a for a in self.albums if a.title == directory][0]
            images = self.client.get_album_images(album.id)
            image = [im for im in images if im.name == path][0]
            size = self.client.get_image(image.id).size
            cache.set(cache_key, size)

        return size

    def url(self, path):
        cache_key = 'django-imgur-url:%s' % filepath_to_uri(path)
        url = cache.get(cache_key)

        if not url:
            directory = os.path.dirname(path)
            name = os.path.basename(path)
            album = [a for a in self.albums if a.title == directory][0]
            images = self.client.get_album_images(album.id)
            image = [im for im in images if im.name == path][0]
            url = self.client.get_image(image.id).link
            cache.set(cache_key, url)

        return url

    def get_available_name(self, name, max_length=None):
        """
        Returns a filename that's free on the target storage system, and
        available for new content to be written to.
        """
        #name = self._get_abs_path(name)
        #dir_name, file_name = os.path.split(name)
        #file_root, file_ext = os.path.splitext(file_name)
        ## If the filename already exists, add an underscore and a number (before
        ## the file extension, if one exists) to the filename until the generated
        ## filename doesn't exist.
        #count = itertools.count(1)
        #while self.exists(name):
        #    # file_ext includes the dot.
        #    name = os.path.join(dir_name, "%s_%s%s" % (file_root, count.next(), file_ext))

        return name
Exemplo n.º 11
0
    return winreg.QueryValueEx(key, "Desktop")[0]


if __name__ == "__main__":
    data = []
    # main()
    client = ImgurClient(client_id, client_secret, access_token, refresh_token)
    try:
        fields = {
            'album': album_id,
            'name': 'test-name!',
            'title': 'test-title',
            'description': 'test-description',
            'privacy': 'hidden'
        }
        test = client.create_album(fields)
        images = client.get_album_images(album_id)
    except ImgurClientError as e:
        print('ERROR: {}'.format(e.error_message))
        print('Status code {}'.format(e.status_code))

    print("Downloading album {} ({!s} images)".format(album_id, len(images)))
    # Download each image
    # count = 0
    # for image in images:
    #     count += 1
    #     # Turn our link HTTPs
    #     link = image.link.replace("http://", "https://")
    #     # Get our file name that we'll save to disk
    #     file_name = link.replace("https://i.imgur.com/", "")
    #     # download_path = os.path.join(args.directory, file_name)
Exemplo n.º 12
0
# check if album with today's date exists
response = client.get_account_albums(get_username())
today_album_exists = False
album_id = ""
for item in response:
    if item.title == today:
        print(f"Found album: {item.title} - {item.id}")
        today_album_exists = True
        album_id = item.id
        break

# otherwise create today's album
if not today_album_exists:
    album_config = {'title': today, 'privacy': 'hidden'}
    response = client.create_album(album_config)
    album_id = response['id']
    print(response)

# Glob together all files in directory that have these extension
full_list = glob.glob('*.{jpg,JPG,png,PNG,gif,GIF,mov,MOV,mp4,MP4}',
                      flags=glob.BRACE)
list.sort(full_list)
print(f"There are {len(full_list)} images to parse.")

# while credits available, upload each file to album
image_config = {'album': album_id}
for image in full_list:
    try:
        now = datetime.now()
        file_extension = image[-4:].lower()
Exemplo n.º 13
0
class ImgurUtils:
    _ACCOUNT_NAME = "DermaGram"
    _CLIENT_ID = "74ab756d286b81b"
    _CLIENT_SECRET = "06e8cbd50c3388b95681efe0bf17e8578f72c8dd"
    _ACCESS_TOKEN = "7a58917273a8734cbbe6bc498d78e390b3c2e56e"
    _REFRESH_TOKEN = "463a35741a82af231b5d150deb7be5e69c48c386"

    def __init__(self):
        self._client = ImgurClient(ImgurUtils._CLIENT_ID,
                                   ImgurUtils._CLIENT_SECRET,
                                   ImgurUtils._ACCESS_TOKEN,
                                   ImgurUtils._REFRESH_TOKEN)

    '''
    Takes a float value and converts to a formatted datetime string

    @param: 'epoch' is of type float (e.g. 123456789.0)
    @return: a formatted string (e.g. '2017-10-16 15:56:03')
    '''

    def _get_local_time(self, epoch):
        logger = logging.getLogger(__name__)
        timestamp = str()
        try:
            timestamp = time.strftime('%Y-%m-%d %H:%M:%S',
                                      time.localtime(epoch))
        except Exception as error_msg:
            logger.error(error_msg)
        return timestamp

    '''
    Retrieves all albums for a given account (e.g. DermaGram). For each
    album, checks if the title matches the current user's uuid. This is
    because we name albums based on the user's uuid.

    @return: a unique album.id if match exists; otherwise, None
    '''

    def _get_album_id_by_title(self, username):
        album_id = None
        albums = self._client.get_account_albums(ImgurUtils._ACCOUNT_NAME)
        for album in albums:
            if (username == album.title):
                album_id = album.id
                break
        return album_id

    '''
    Retrieves all albums for a given account (e.g. DermaGram). For each album,
    adds the 'title' property to a set.

    @return: a set of unique strings corresponding to album titles.
    '''

    def _get_album_titles_as_set(self):
        album_titles = set()
        albums = self._client.get_account_albums(ImgurUtils._ACCOUNT_NAME)
        for album in albums:
            album_titles.add(str(album.title))
        return album_titles

    '''
    Retrieves images from Imgur using an album_id. The image's id, title, description
    and datetime are stored in an object 'image_info' and appended to a list 'image_history'

    @return: a list of objects containing info. about each image.
    '''

    def get_images_from_album(self, album_id):
        logger = logging.getLogger(__name__)
        images_data = {"table": []}
        images = self._client.get_album_images(album_id)

        if images:
            # Sort images in descending chronological order
            images.sort(key=lambda x: x.datetime, reverse=True)
            for image in images:
                #Uncomment to list all properties that may be retrieved from an imgur Image object
                #print dir(image)
                info = self._parse_description(image.description)
                image_info = {
                    'id': str(image.id),
                    'title': str(image.title),
                    'link': str(image.link),
                    'location': info['location'],
                    'classification': info['classification'],
                    'datetime': self._get_local_time(float(image.datetime)),
                }
                images_data['table'].append(image_info)

        else:
            logger.warning('No images returned for album_id: {0}.'
                           '\nget_album_images() response: {1}'.format(
                               album_id, images))
        return images_data

    def _parse_description(self, description):
        info = ""
        try:
            info = json.loads(description)
        except Exception as e:
            print "ERROR: ", e
        return info

    '''
    Checks if album already exists for given uuid. Note: an album's title
    corresponds to the user's uuid.

    @return: boolean True if album exists; otherwise False
    '''

    def _does_album_exist(self, username):
        album_titles = self._get_album_titles_as_set()
        return True if username in album_titles else False

    '''
    Creates a new album where the album's title is the user's uuid.
    An new album id that is created in the process is returned.

    @return: a string variable corresponding to the album's unique id
    '''

    def create_new_album(self, username):
        logger = logging.getLogger(__name__)
        new_album_id = None

        #TODO we need to do check if username already exists as album name
        if (False):
            existing_album_id = self._get_album_id_by_title(username)
            logger.error("The uuid {0} already has an album id: {1}".format(
                username, existing_album_id))
        else:
            logger.info("Creating a new album for {0}".format(username))
            album_info = {"title": username, "privacy": "public"}
            self._client.create_album(album_info)
            new_album_id = self._get_album_id_by_title(username)

            if new_album_id:
                logger.info("The new album id for user {0} is: {1}".format(
                    username, new_album_id))
            else:
                logger.error("There was an error getting the album_id.")

        return new_album_id

    #https://github.com/Imgur/imgurpython/blob/3a285f758bcb8a2ff6aa024b2944f464f50d87d0/examples/upload.py
    def add_image_to_album(self, album_id, title, location, classification,
                           image_path):
        #TODO make this pull correct album and other data from user session
        description = {"location": location, "classification": classification}
        config = {
            'album': album_id,
            'title': title,
            'description': json.dumps(description)
        }
        return self._client.upload_from_path(image_path,
                                             config=config,
                                             anon=False)
Exemplo n.º 14
0
class App:
    def __init__(self):
        self.client = None


    def initialize_client(self):
        with open(os.path.join(dirname, "creds.json"), "r") as f:
            stored_creds = json.load(f)
            if "client_id" not in stored_creds:
                stored_creds["client_id"] = None
            if "client_secret" not in stored_creds:
                stored_creds["client_secret"] = None

        client_id = stored_creds["client_id"]
        client_secret = stored_creds["client_secret"]
        new_creds = False

        while True:
            try:
                self.client = ImgurClient(client_id, client_secret)
                break
            except:
                print("*** Missing or invalid client credentials. ", end="")
                print("You must first register an applicaton with Imgur ", end="")
                print("and provide the client id and secret. ", end="")
                print("See README.md for help.")
                client_id = input("Client ID: ")
                client_secret = input("Client secret: ")
                new_creds = True


        # Update creds file if there was a change.
        if new_creds:
            print("Client credentials successfully validated.\n")

            stored_creds["client_id"] = client_id
            stored_creds["client_secret"] = client_secret

            with open(os.path.join(dirname, "creds.json"), "w") as f:
                json.dump(stored_creds, f)


    def authorize_user(self):
        with open(os.path.join(dirname, "creds.json"), "r") as f:
            stored_creds = json.load(f)
            if "access_token" not in stored_creds:
                stored_creds["access_token"] = None
            if "refresh_token" not in stored_creds:
                stored_creds["refresh_token"] = None

        access_token = stored_creds["access_token"]
        refresh_token = stored_creds["refresh_token"]
        new_tokens = False
        
        while True:
            try:
                self.client.set_user_auth(access_token, refresh_token)
                break
            except:
                print("*** Missing or invalid tokens. ", end="")
                print("Please follow the OAuth flow and enter the pin.")
                webbrowser.open(self.client.get_auth_url("pin"))
                pin = input("Pin: ")

                try:
                    credentials = self.client.authorize(pin, "pin")
                except:
                    print("Invalid pin.")
                    continue

                access_token = credentials["access_token"]
                refresh_token = credentials["refresh_token"]
                new_tokens = True

        # Update creds file if there was a change.
        if new_tokens:
            print("Tokens successfully validated.\n")

            stored_creds["access_token"] = access_token
            stored_creds["refresh_token"] = refresh_token

            with open(os.path.join(dirname, "creds.json"), "w") as f:
                json.dump(stored_creds, f)


    def create_album(self, targets, title, description):
        print("Creating album... ", end="", flush=True)
        album = self.client.create_album({
            "title": title,
            "description": description
        })
        print(f"done. (id={album['id']})")

        config = { "album": album["deletehash"] }

        # If there is only one image, add title/description to the image also.
        if len(targets) == 1:
            config["title"] = title
            config["description"] = description

        images = []
        for target in targets:
            # URL upload.
            if urllib.parse.urlparse(target).scheme in ("http", "https"):
                images += filter(None, [self.upload_image(config, url=target)])
            # File upload.
            elif os.path.isfile(target):
                images += filter(None, [self.upload_image(config, path=target)])
            # Directory upload.
            elif os.path.isdir(target):
                for filepath in glob.glob(f"{target}/**"):
                    images += filter(None,
                            [self.upload_image(config, path=filepath)])
            else:
                print(f"*** Invalid target: {target} ***")

        print("========================================")

        print(f"Album: https://imgur.com/a/{album['id']}")
        if images:
            print(f"First Image: https://imgur.com/{images[0]['id']}.png")
        print("")

        return {
            "album_id": album["id"],
            "image_ids": [i["id"] for i in images]
        }


    def upload_image(self, config, url=None, path=None):
        try:
            if url is not None:
                print(f"Uploading {url}... ", end="", flush=True)
                image = self.client.upload_from_url(url, config=config)
            elif path is not None:
                print(f"Uploading {path}... ", end="", flush=True)
                image = self.client.upload_from_path(path, config=config)
            else:
                return
        except Exception as e:
            print(f"failed.\n*** {e} ***")
            return

        print(f"done. (id={image['id']})")
        return image


    def parse_args(self, raw_args):
        parser = argparse.ArgumentParser(raw_args)
        parser.add_argument(
            "targets",
            metavar="target",
            nargs="+",
            help="directory, filepath, or url to upload"
        )
        parser.add_argument(
            "-t", "--title",
            dest="title",
            metavar="title",
            help="post's title"
        )
        parser.add_argument(
            "-d", "--description",
            dest="description",
            metavar="desc",
            help="post's description"
        )
        parser.add_argument(
            "-a", "--anonymous",
            dest="anon",
            action="store_const", const=True, default=False,
            help="anonymously upload (no imgur account)"
        )
        return parser.parse_args()


    def prompt_args(self):
        print("-- Targets may be a url, filepath, or directory.")
        targets = []
        while True:
            target = input("Target: ")
            if target:
                targets.append(target)
            else:
                break

        title = input("Title: ")
        description = input("Description: ")
        anon = (input("Anonymous (y/n): ") == "y")
        print("")

        return argparse.Namespace(targets=targets, title=title,
                description=description, anon=anon)


    def run(self, raw_args):
        self.initialize_client()

        if raw_args:
            interactive = False
            args = self.parse_args(raw_args)
        else:
            interactive = True
            args = self.prompt_args()

        if not args.anon:
            self.authorize_user()

        self.create_album(args.targets, args.title, args.description)

        print(self.client.credits)

        if interactive:
            input("press enter to exit...")