def _create_folder_structure(self):
        '''
        Creates the gallery folder structure by copying all the gallery templates
        and moving all images and videos to the
        photos subfolder.
        We can't use `simplegallery.gallery-init.create_gallery_folder_structure`
        because there is no possibility to set
        another public folder
        '''
        # Copy the public and templates folder
        spg_common.log("Copying gallery template files...")
        shutil.copytree(Path(
            pkg_resources.resource_filename("simplegallery",
                                            "data/templates")),
                        self.gallery_path / 'templates',
                        dirs_exist_ok=True)
        shutil.copytree(Path(
            pkg_resources.resource_filename("simplegallery", "data/public")),
                        self.public_gallery_dir,
                        dirs_exist_ok=True)

        photos_dir = self.public_gallery_dir / 'images' / 'photos'
        if not photos_dir.exists():
            photos_dir.mkdir(parents=True)
        spg_common.log(
            f'Moving all photos and videos to {_pltostr(photos_dir)}..')

        for path in self.image_source.iterdir():
            basename_lower = _pltostr(path).lower()
            if (basename_lower.endswith(".jpg")
                    or basename_lower.endswith(".jpeg")
                    or basename_lower.endswith(".gif")
                    or basename_lower.endswith(".mp4")
                    or basename_lower.endswith(".png")):
                shutil.copy(path, photos_dir / path.name)
    def upload_gallery(self, location, gallery_path):
        """
        Upload the gallery to the specified location
        :param location: S3 bucket where the gallery should be uploaded
        :param gallery_path: path to the root of the public files of the gallery
        """
        # Add s3 protocol if needed
        if not location.startswith('s3://'):
            location = 's3://' + location

        # Add trailing / if needed
        if not location.endswith('/'):
            location += '/'

        # Build and execute the AWS S3 sync command
        aws_command = [
            'aws', 's3', 'sync', gallery_path, location, '--exclude',
            '.DS_Store'
        ]

        spg_common.log(f'Uploading to AWS S3 at {location}')
        process = subprocess.run(aws_command)

        if process.returncode != 0:
            raise spg_common.SPGException('Could not sync with AWS S3')

        # Compute HTTP URL and display success message
        url = location.replace('s3://', 'http://') + 'index.html'
        spg_common.log(
            f'Upload finished successfully! You can access your gallery at: {url}'
        )
Exemple #3
0
def create_gallery_folder_structure(gallery_root):
    """
    Creates the gallery folder structure by copying all the gallery templates and moving all images and videos to the
    photos subfolder
    :param gallery_root: Path to the gallery root
    """

    # Copy the public and templates folder
    spg_common.log('Copying gallery template files...')
    copy_tree(
        pkg_resources.resource_filename('simplegallery', 'data/templates'),
        os.path.join(gallery_root, 'templates'))
    copy_tree(pkg_resources.resource_filename('simplegallery', 'data/public'),
              os.path.join(gallery_root, 'public'))

    # Move all images and videos to the correct subfolder under public
    photos_dir = os.path.join(gallery_root, 'public', 'images', 'photos')
    spg_common.log(f'Moving all photos and videos to {photos_dir}...')

    for path in glob.glob(os.path.join(gallery_root, '*')):
        basename_lower = os.path.basename(path).lower()
        if basename_lower.endswith('.jpg') or basename_lower.endswith(
                '.jpeg') or basename_lower.endswith(
                    '.gif') or basename_lower.endswith('.mp4'):
            shutil.move(path, os.path.join(photos_dir, os.path.basename(path)))
def deploy_to_netlify(zip_file_path, token, site_id):
    """
    Deploys the gallery to Netlify using the Deploy API
    :param zip_file_path: path to the zip file containing the gallery's files
    :param token: OAuth 2.0 authentication token
    :param site_id: ID of the Netlify site (optional - if no ID is provided, a new site will be created)
    :return: URL to the site where the gallery was uploaded
    """
    # Read the content of the ZIP file
    with open(zip_file_path, 'rb') as zip_in:
        gallery_data = zip_in.read()

    sites_url = 'https://api.netlify.com/api/v1/sites' + (f'/{site_id}'
                                                          if site_id else '')
    headers = {
        'Authorization': f'Bearer {token}',
        'Content-Type': 'application/zip'
    }

    spg_common.log('Uploading gallery to Netlify...')

    if site_id:
        response_string = requests.put(sites_url,
                                       headers=headers,
                                       data=gallery_data)
    else:
        response_string = requests.post(sites_url,
                                        headers=headers,
                                        data=gallery_data)

    response = json.loads(response_string.text)

    return f'https://{response.get("subdomain")}.netlify.com'
    def create_thumbnails(self, force=False):
        """
        Checks if every image has an existing thumbnail and generates it if not (or if forced by the user)
        :param force: Forces generation of thumbnails if set to true
        """

        # Multiply the thumbnail size by the factor to generate larger thumbnails to improve quality on retina displays
        thumbnail_height = self.gallery_config[
            'thumbnail_height'] * FilesGalleryLogic.THUMBNAIL_SIZE_FACTOR
        thumbnails_path = self.gallery_config['thumbnails_path']

        photos = glob.glob(
            os.path.join(self.gallery_config['images_path'], '*.*'))

        if not photos:
            raise spg_common.SPGException(
                f'No photos could be found under {self.gallery_config["images_path"]}'
            )

        count_thumbnails_created = 0
        for photo in photos:
            thumbnail_path = get_thumbnail_name(thumbnails_path, photo)

            # Check if the thumbnail should be generated. This happens if one of the following applies:
            # - Forced by the user with -f
            # - No thumbnail for this image
            # - The thumbnail image size doesn't correspond to the specified size
            if force or not os.path.exists(
                    thumbnail_path) or not check_correct_thumbnail_size(
                        thumbnail_path, thumbnail_height):
                spg_media.create_thumbnail(photo, thumbnail_path,
                                           thumbnail_height)
                count_thumbnails_created += 1

        spg_common.log(f'New thumbnails generated: {count_thumbnails_created}')
def create_gallery_folder_structure(gallery_root):
    """
    Creates the gallery folder structure by copying all the gallery templates and moving all images and videos to the
    photos subfolder
    :param gallery_root: Path to the gallery root
    """

    # Copy the public and templates folder
    spg_common.log("Copying gallery template files...")
    copy_tree(
        pkg_resources.resource_filename("simplegallery", "data/templates"),
        os.path.join(gallery_root, "templates"),
    )
    copy_tree(
        pkg_resources.resource_filename("simplegallery", "data/public"),
        os.path.join(gallery_root, "public"),
    )

    # Move all images and videos to the correct subfolder under public
    photos_dir = os.path.join(gallery_root, "public", "images", "photos")
    spg_common.log(f"Moving all photos and videos to {photos_dir}...")

    for path in glob.glob(os.path.join(gallery_root, "*")):
        basename_lower = os.path.basename(path).lower()
        if (basename_lower.endswith(".jpg") or basename_lower.endswith(".jpeg")
                or basename_lower.endswith(".gif")
                or basename_lower.endswith(".mp4")
                or basename_lower.endswith(".png")):
            shutil.move(path, os.path.join(photos_dir, os.path.basename(path)))
    def _create_gallery_json(self):
        ''' Build the gallery config '''

        gallery_config = dict(
            images_data_file=_pltostr(self.gallery_path / 'images_data.json'),
            public_path=_pltostr(self.public_gallery_dir),
            templates_path=_pltostr(self.gallery_path / 'templates'),
            images_path=_pltostr(self.public_gallery_dir / 'images' /
                                 'photos'),
            thumbnails_path=_pltostr(self.public_gallery_dir / 'images' /
                                     'thumbnails'),
            thumbnail_height=160,
            title=self.name,
            description=self.description,
            background_photo=self.background_photo,
            background_photo_offset=self.background_photo_offset,
            url=self.url,
        )

        self.gallery_config_path.write_text(
            json.dumps(gallery_config, indent=4, separators=(",", ": ")))

        spg_common.log("Gallery config stored in gallery.json")

        return True
Exemple #8
0
    def check_location(self, location):
        """
        Checks if the location is empty or not
        :param location: S3 bucket where the gallery should be uploaded
        :return: True if the location is not empty, False otherwise
        """
        if not location:
            spg_common.log("Location cannot be empty when uploading to AWS")

        return bool(location)
Exemple #9
0
def check_if_gallery_creation_possible(gallery_root):
    """
    Checks if a gallery can be created in the specified folder
    :param gallery_root: Root of the new gallery
    :return: True if a new gallery can be created and false otherwise
    """

    # Check if the path exists
    if not os.path.exists(gallery_root):
        spg_common.log(
            f'The specified gallery path does not exist: {gallery_root}.')
        return False

    return True
    def gallery_build(self, force_thumbnail_regeneration=False):
        '''
        Build the gallery (create thumbnails)

        Args:
            force_thumbnail_regeneration (bool, optional):
                Force to re-generate all thumbnails. Defaults to False.

        Raises:
            RuntimeError: will be raised if there is any error

        Returns:
            bool: returns True if everything worked fine
        '''

        gallery_config_path = _pltostr(self.gallery_config_path)
        gallery_config = spg_common.read_gallery_config(gallery_config_path)

        if not gallery_config:
            spg_common.log(
                f"Cannot load the gallery.json file ({gallery_config_path})!")
            ### TODO: Implement Error Handling
            raise RuntimeError

        # Get the gallery logic
        gallery_logic = get_gallery_logic(gallery_config)

        spg_common.log(f"Generating thumbnails for {self.name}...")
        gallery_logic.create_thumbnails(force_thumbnail_regeneration)

        spg_common.log(
            f"Generating the images_data.json file for {self.name}...")
        gallery_logic.create_images_data_file()

        spg_common.log(f"Creating the index.html for {self.name}...")
        gallery_build.build_html(gallery_config)

        spg_common.log(
            f"The gallery {self.name} was built successfully. Open {self.public_gallery_dir}"
        )

        return True
    def gallery_init(self):
        '''
        Build up the gallery structure.

        Raises:
            RuntimeError: if there is any description

        Returns:
            bool: returns True if everything worked fine
        '''

        # create galaxy json
        if not self._create_gallery_json():
            ### TODO: Implement Error Handling
            raise RuntimeError(f'create gallery json failed for {self.name}')

        # create folder structure
        spg_common.log(f"Creating Photo Gallery {self.name}...")
        self._create_folder_structure()
        spg_common.log(f"Photo Gallery {self.name} initialized successfully!")

        return True
Exemple #12
0
    def upload_gallery(self, location, gallery_path):
        """
        Upload the gallery to the specified location
        :param location: S3 bucket where the gallery should be uploaded
        :param gallery_path: path to the root of the public files of the gallery
        """
        # Add s3 protocol if needed
        if not location.startswith("s3://"):
            location = "s3://" + location

        # Add trailing / if needed
        if not location.endswith("/"):
            location += "/"

        # Build and execute the AWS S3 sync command
        aws_command = [
            "aws",
            "s3",
            "sync",
            gallery_path,
            location,
            "--exclude",
            ".DS_Store",
        ]

        spg_common.log(f"Uploading to AWS S3 at {location}")
        process = subprocess.run(aws_command)

        if process.returncode != 0:
            raise spg_common.SPGException("Could not sync with AWS S3")

        # Compute HTTP URL and display success message
        url = location.replace("s3://", "http://") + "index.html"
        spg_common.log(
            f"Upload finished successfully! You can access your gallery at: {url}"
        )
Exemple #13
0
def get_gallery_logic(gallery_config):
    """
    Factory function that returns an object of a class derived from BaseGalleryLogic based on the gallery config.
    Supported gallery logics:
    - FilesGalleryLogic - logic for local files gallery
    - OneDriveGallerLogic - logic for shared album from OneDrive
    - GoogleGallerLogic - logic for shared album from Google Photos

    :param gallery_config: gallery config dictionary as read from the gallery.json
    :return: gallery logic object
    """
    if "remote_gallery_type" not in gallery_config:
        return FilesGalleryLogic(gallery_config)
    elif not gallery_config["remote_gallery_type"]:
        return FilesGalleryLogic(gallery_config)
    elif gallery_config["remote_gallery_type"] == "onedrive":
        return OnedriveGalleryLogic(gallery_config)
    elif gallery_config["remote_gallery_type"] == "google":
        return GoogleGalleryLogic(gallery_config)
    else:
        spg_common.log(
            "Unrecognized option for remote_gallery_type. Proceeding as a local gallery."
        )
        return FilesGalleryLogic(gallery_config)
def get_netlify_site_id(location, token):
    """
    Retrieves the ID of a site from the Netlify API
    :param location: name of the Netlify site
    :param token: OAuth 2.0 authentication token
    :return: the site ID if the site exists, None otherwise
    """

    # Check if location invalid
    if location:
        sites_url = 'https://api.netlify.com/api/v1/sites'
        headers = {'Authorization': f'Bearer {token}'}

        response_string = requests.get(sites_url, headers=headers)
        sites = json.loads(response_string.text)

        for site in sites:
            if site['name'] == location or site['url'].endswith(location):
                spg_common.log(f'Found Netlify site: {location}')
                return site['id']
    else:
        spg_common.log(
            f'Cannot find Netlify site {location}. Creating new site...')
        return None
Exemple #15
0
def get_gallery_type(remote_link):
    """
    Get the type of a remote gallery based on the provided link
    :param remote_link: Link to a shared album
    :return: remote gallery type
    """

    if "onedrive.live.com/" in remote_link or "1drv.ms/" in remote_link:
        return "onedrive"
    elif "photos.app.goo.gl/" in remote_link or "photos.google.com" in remote_link:
        return "google"
    elif "amazon.com/photos/" in remote_link:
        spg_common.log("Amazon is not currently supported as a remote gallery")
        return ""
    elif "share.icloud.com/" in remote_link:
        spg_common.log("iCloud is not currently supported as a remote gallery")
        return ""
    elif "www.dropbox.com/" in remote_link:
        spg_common.log("Dropbox is not currently supported as a remote gallery")
        return ""
    else:
        return ""
def get_gallery_type(remote_link):
    """
    Get the type of a remote gallery based on the provided link
    :param remote_link: Link to a shared album
    :return: remote gallery type
    """

    if 'onedrive.live.com/' in remote_link or '1drv.ms/' in remote_link:
        return 'onedrive'
    elif 'photos.app.goo.gl/' in remote_link or 'photos.google.com' in remote_link:
        return 'google'
    elif 'amazon.com/photos/' in remote_link:
        spg_common.log('Amazon is not currently supported as a remote gallery')
        return ''
    elif 'share.icloud.com/' in remote_link:
        spg_common.log('iCloud is not currently supported as a remote gallery')
        return ''
    elif 'www.dropbox.com/' in remote_link:
        spg_common.log(
            'Dropbox is not currently supported as a remote gallery')
        return ''
    else:
        return ''
    def upload_gallery(self, location, gallery_path):
        """
        Upload the gallery to the specified location
        :param location: Netlify site where the gallery should be uploaded
        :param gallery_path: path to the root of the public files of the gallery
        """
        # Create a zip file for the gallery
        spg_common.log('Creating ZIP file of the gallery...')
        zip_file_path = os.path.join(tempfile.gettempdir(),
                                     'simple_photo_gallery.zip')
        create_website_zip(gallery_path, zip_file_path)
        spg_common.log('Gallery ZIP file created!')

        # Start the HTTP server that handles OAuth authentication at Netlify
        httpd = SimplePhotoGalleryHTTPServer(
            ('localhost', 8080), SimplePhotoGalleryHTTPRequestHandler)

        # Get the authorization token
        token = self.get_authorization_token(httpd)

        # Check if the website already exists and get its ID
        site_id = get_netlify_site_id(location, token)

        # Deploy the website
        gallery_url = deploy_to_netlify(zip_file_path, token, site_id)

        # Delete the zip file
        os.remove(zip_file_path)

        # Open the Netlify gallery if successful
        if gallery_url:
            spg_common.log(f'Gallery uploaded successfully to:\n{gallery_url}')
            webbrowser.open(gallery_url)
        else:
            raise spg_common.SPGException(
                f'Something went wrong while uploading to Netlify')
Exemple #18
0
def main():
    """
    Initializes a new Simple Photo Gallery in a specified folder
    """

    # Parse the arguments
    args = parse_args()

    # Get the gallery root from the arguments
    gallery_root = args.path

    # Check if a gallery can be created at this location
    if not check_if_gallery_creation_possible(gallery_root):
        sys.exit(1)

    # Check if the specified gallery root already contains a gallery
    if check_if_gallery_already_exists(gallery_root):
        if not args.force:
            spg_common.log(
                'A Simple Photo Gallery already exists at the specified location. Set the --force parameter '
                'if you want to overwrite it.')
            sys.exit(0)
        else:
            spg_common.log(
                'A Simple Photo Gallery already exists at the specified location, but will be overwritten.'
            )
    spg_common.log('Creating a Simple Photo Gallery...')

    # Create the gallery json file
    try:
        if not args.keep_gallery_config:
            create_gallery_json(gallery_root, args.remote_link)
    except spg_common.SPGException as exception:
        spg_common.log(exception.message)
        sys.exit(1)
    except Exception as exception:
        spg_common.log(
            f'Something went wrong while creating the gallery.json file: {str(exception)}'
        )
        sys.exit(1)

    # Copy the template files to the gallery root
    try:
        create_gallery_folder_structure(gallery_root)
    except Exception as exception:
        spg_common.log(
            f'Something went wrong while generating the gallery structure: {str(exception)}'
        )
        sys.exit(1)

    spg_common.log('Simple Photo Gallery initialized successfully!')
Exemple #19
0
def create_gallery_json(gallery_root, remote_link):
    """
    Creates a new gallery.json file, based on settings specified by the user
    :param gallery_root: Path to the gallery root
    :param remote_link: Optional link to a remote shared album containing the photos for the gallery
    """

    spg_common.log('Creating the gallery config...')
    spg_common.log(
        'You can answer the following questions in order to set some important gallery properties. You can '
        'also just press Enter to leave the default and change it later in the gallery.json file.'
    )

    # Initialize the gallery config with the main gallery paths
    gallery_config = dict(
        images_data_file=os.path.join(gallery_root, 'images_data.json'),
        public_path=os.path.join(gallery_root, 'public'),
        templates_path=os.path.join(gallery_root, 'templates'),
        images_path=os.path.join(gallery_root, 'public', 'images', 'photos'),
        thumbnails_path=os.path.join(gallery_root, 'public', 'images',
                                     'thumbnails'),
        thumbnail_height=160,
    )

    # Initialize remote gallery configuration
    if remote_link:
        remote_gallery_type = gallery_logic.get_gallery_type(remote_link)

        if not remote_gallery_type:
            raise spg_common.SPGException(
                'Cannot initialize remote gallery - please check the provided link.'
            )
        else:
            gallery_config['remote_gallery_type'] = remote_gallery_type
            gallery_config['remote_link'] = remote_link

    # Set configuration defaults
    default_title = 'My Gallery'
    default_description = 'Default description of my gallery'

    # Ask the user for the title
    gallery_config['title'] = input(
        f'What is the title of your gallery? (default: "{default_title}")\n'
    ) or default_title

    # Ask the user for the description
    gallery_config['description'] = input(
        f'What is the description of your gallery? (default: "{default_description}")\n'
    ) or default_description

    # Ask the user for the background image
    gallery_config['background_photo'] = input(
        f'Which image should be used as background for the header? (default: "")\n'
    )

    # Ask the user for the site URL
    gallery_config['url'] = input(
        f'What is your site URL? This is only needed to better show links to your galleries on social media (default: "")\n'
    )

    # Set the default background offset right after the background image
    gallery_config['background_photo_offset'] = 30

    # Save the configuration to a file
    gallery_config_path = os.path.join(gallery_root, 'gallery.json')
    with open(gallery_config_path, 'w', encoding='utf-8') as out:
        json.dump(gallery_config, out, indent=4, separators=(',', ': '))

    spg_common.log('Gallery config stored in gallery.json')
Exemple #20
0
    def generate_images_data(self, images_data):
        """
        Parse the remote link and extract link to the images and the thumbnails
        :param images_data: Images data dictionary containing the existing metadata of the images and which will be
        updated by this function
        :return updated images data dictionary
        """

        # Get the path to the Firefox webdriver
        webdriver_path = pkg_resources.resource_filename(
            'simplegallery', 'bin/geckodriver')

        # Configure the driver in headless mode
        options = Options()
        options.headless = True
        spg_common.log(f'Starting Firefox webdriver...')
        driver = webdriver.Firefox(options=options,
                                   executable_path=webdriver_path)

        # Load the album page
        spg_common.log(
            f'Loading album from {self.gallery_config["remote_link"]}...')
        driver.get(self.gallery_config["remote_link"])

        # Wait until the page is fully loaded
        loading_start = time.time()
        last_image_count = 0
        while True:
            image_count = len(
                driver.find_elements_by_class_name('od-ImageTile-image'))
            if image_count > 1 and image_count == last_image_count:
                break
            last_image_count = image_count
            if (time.time() - loading_start) > 30:
                raise spg_common.SPGException(
                    'Loading the page took too long.')
            time.sleep(5)

        # Parse all photos
        spg_common.log('Finding photos...')
        photos = driver.find_elements_by_class_name('od-ImageTile-image')

        spg_common.log(f'Photos found: {len(photos)}')
        current_photo = 1
        for photo in photos:
            photo_url = photo.get_attribute('src')
            photo_base_url, photo_name = parse_photo_link(photo_url)
            spg_common.log(
                f'{current_photo}/{len(photos)}\t\tProcessing photo {photo_name}: {photo_url}'
            )
            current_photo += 1

            # Compute photo and thumbnail sizes
            photo_link_max_size = f'{photo_base_url}?psid=1&width=9999&height=9999'
            size = spg_media.get_remote_image_size(photo_link_max_size)
            thumbnail_size = spg_media.get_thumbnail_size(
                size, self.gallery_config['thumbnail_height'])

            # Add the photo to the images_data dict
            images_data[photo_name] = dict(
                description='',
                mtime=time.time(),
                size=size,
                src=f'{photo_base_url}?psid=1&width={size[0]}&height={size[1]}',
                thumbnail=
                f'{photo_base_url}?psid=1&width={thumbnail_size[0]}&height={thumbnail_size[1]}',
                thumbnail_size=thumbnail_size,
                type='image',
            )

        spg_common.log(f'All photos processed!')

        driver.quit()

        return images_data
Exemple #21
0
def create_gallery_json(gallery_root, remote_link, use_defaults=False):
    """
    Creates a new gallery.json file, based on settings specified by the user
    :param gallery_root: Path to the gallery root
    :param remote_link: Optional link to a remote shared album containing the photos for the gallery
    :param use_defaults: If set to True, there will be no questions asked on the console
    """

    spg_common.log("Creating the gallery config...")
    spg_common.log(
        "You can answer the following questions in order to set some important gallery properties. You can "
        "also just press Enter to leave the default and change it later in the gallery.json file."
    )

    # Initialize the gallery config with the main gallery paths
    gallery_config = dict(
        images_data_file=os.path.join(gallery_root, "images_data.json"),
        public_path=os.path.join(gallery_root, "public"),
        templates_path=os.path.join(gallery_root, "templates"),
        images_path=os.path.join(gallery_root, "public", "images", "photos"),
        thumbnails_path=os.path.join(gallery_root, "public", "images",
                                     "thumbnails"),
        thumbnail_height=160,
        title="My Gallery",
        description="Default description of my gallery",
        background_photo="",
        url="",
        background_photo_offset=30,
        disable_captions=False,
    )

    # Initialize remote gallery configuration
    if remote_link:
        remote_gallery_type = gallery_logic.get_gallery_type(remote_link)

        if not remote_gallery_type:
            raise spg_common.SPGException(
                "Cannot initialize remote gallery - please check the provided link."
            )
        else:
            gallery_config["remote_gallery_type"] = remote_gallery_type
            gallery_config["remote_link"] = remote_link

    # Set configuration defaults
    default_title = "My Gallery"
    default_description = "Default description of my gallery"

    # If defaults are not used, ask the user to provide input to some important settings
    if not use_defaults:
        # Ask the user for the title
        gallery_config["title"] = (input(
            f'What is the title of your gallery? (default: "{default_title}")\n'
        ) or gallery_config["title"])

        # Ask the user for the description
        gallery_config["description"] = (input(
            f'What is the description of your gallery? (default: "{default_description}")\n'
        ) or gallery_config["description"])

        # Ask the user for the background image
        gallery_config["background_photo"] = input(
            f'Which image should be used as background for the header? (default: "")\n'
        )

        # Ask the user for the site URL
        gallery_config["url"] = input(
            f'What is your site URL? This is only needed to better show links to your galleries on social media (default: "")\n'
        )

        # Set the default background offset right after the background image
        gallery_config["background_photo_offset"] = 30

    # Save the configuration to a file
    gallery_config_path = os.path.join(gallery_root, "gallery.json")
    with open(gallery_config_path, "w", encoding="utf-8") as out:
        json.dump(gallery_config, out, indent=4, separators=(",", ": "))

    spg_common.log("Gallery config stored in gallery.json")
def main():
    """
    Uploads the gallery to the specified hosting provider
    """

    # Parse the arguments
    args = parse_args()

    # Create the uploader
    try:
        uploader = get_uploader(args.hosting)
    except spg_common.SPGException as exception:
        spg_common.log(exception.message)
        sys.exit(1)
    except Exception as exception:
        spg_common.log(
            f"Something went wrong while preparing the upload: {str(exception)}"
        )
        sys.exit(1)

    # Read the gallery config
    gallery_root = args.path
    gallery_config_path = os.path.join(gallery_root, "gallery.json")
    gallery_config = spg_common.read_gallery_config(gallery_config_path)
    if not gallery_config:
        spg_common.log(f"Cannot load the gallery.json file ({gallery_config_path})!")
        sys.exit(1)

    # Get the location from the command line or from the gallery.json
    location = args.location
    if not location:
        if "remote_location" in gallery_config:
            location = gallery_config["remote_location"]

    # Check if the uploader location is valid
    if not uploader.check_location(location):
        spg_common.log(f"The specified location if not valid for this hosting type.")
        sys.exit(1)

    # Check if the gallery is built
    if not os.path.exists(
        os.path.join(gallery_root, gallery_config["public_path"], "index.html")
    ):
        spg_common.log(
            f"Cannot find index.html. Please build the gallery first with gallery_build.!"
        )
        sys.exit(1)

    # Upload the gallery
    try:
        uploader.upload_gallery(
            location, os.path.join(gallery_root, gallery_config["public_path"])
        )
    except spg_common.SPGException as exception:
        spg_common.log(exception.message)
        sys.exit(1)
    except Exception as exception:
        spg_common.log(
            f"Something went wrong while uploading the gallery: {str(exception)}"
        )
        sys.exit(1)
def main():
    """
    Builds the HTML gallery, generating all required files for display (thumbnails, images_data.json and index.html).
    """

    # Parse the arguments
    args = parse_args()

    # Read the gallery config
    gallery_root = args.path
    gallery_config_path = os.path.join(gallery_root, "gallery.json")
    gallery_config = spg_common.read_gallery_config(gallery_config_path)
    if not gallery_config:
        spg_common.log(
            f"Cannot load the gallery.json file ({gallery_config_path})!")
        sys.exit(1)

    spg_common.log("Building the Simple Photo Gallery...")

    # Get the gallery logic
    gallery_logic = get_gallery_logic(gallery_config)

    # Check if thumbnails exist and generate them if needed or if specified by the user
    try:
        spg_common.log("Generating thumbnails...")
        gallery_logic.create_thumbnails(args.force_thumbnails)
    except spg_common.SPGException as exception:
        spg_common.log(exception.message)
        sys.exit(1)
    except Exception as exception:
        spg_common.log(
            f"Something went wrong while generating the thumbnails: {str(exception)}"
        )
        sys.exit(1)

    # Generate the images_data.json
    try:
        spg_common.log("Generating the images_data.json file...")
        gallery_logic.create_images_data_file()
        spg_common.log(
            "The image descriptions are stored in images_data.json. You can edit the file to add more "
            "descriptions and build the gallery again.")
    except spg_common.SPGException as exception:
        spg_common.log(exception.message)
        sys.exit(1)
    except Exception as exception:
        spg_common.log(
            f"Something went wrong while generating the images_data.json file: {str(exception)}"
        )
        sys.exit(1)

    # Build the HTML from the templates
    try:
        spg_common.log("Creating the index.html...")
        build_html(gallery_config)
    except Exception as exception:
        spg_common.log(
            f"Something went wrong while generating the gallery HTML: {str(exception)}"
        )
        sys.exit(1)

    spg_common.log(
        "The gallery was built successfully. Open public/index.html to view it."
    )
Exemple #24
0
    def generate_images_data(self, images_data):
        """
        Parse the remote link and extract link to the images and the thumbnails
        :param images_data: Images data dictionary containing the existing metadata of the images and which will be
        updated by this function
        :return updated images data dictionary
        """

        # Get the path to the Firefox webdriver
        webdriver_path = pkg_resources.resource_filename(
            "simplegallery", "bin/geckodriver")

        # Configure the driver in headless mode
        options = Options()
        options.headless = True
        spg_common.log(f"Starting Firefox webdriver...")
        driver = webdriver.Firefox(options=options,
                                   executable_path=webdriver_path)

        # Load the album page
        spg_common.log(
            f'Loading album from {self.gallery_config["remote_link"]}...')
        driver.get(self.gallery_config["remote_link"])

        # Wait until the page is fully loaded
        loading_start = time.time()
        last_image_count = 0
        while True:
            image_count = len(
                driver.find_elements_by_xpath("//div[@data-latest-bg]"))
            if image_count > 1 and image_count == last_image_count:
                break
            last_image_count = image_count
            if (time.time() - loading_start) > 30:
                raise spg_common.SPGException(
                    "Loading the page took too long.")
            time.sleep(5)

        # Parse all photos
        spg_common.log("Finding photos...")
        photos = driver.find_elements_by_xpath("//div[@data-latest-bg]")

        spg_common.log(f"Photos found: {len(photos)}")
        current_photo = 1
        for photo in photos:
            photo_url = photo.get_attribute("data-latest-bg")
            photo_base_url, photo_name = parse_photo_link(photo_url)
            spg_common.log(
                f"{current_photo}/{len(photos)}\t\tProcessing photo {photo_name}: {photo_url}"
            )
            current_photo += 1

            # Compute photo and thumbnail sizes
            photo_link_max_size = f"{photo_base_url}=w9999-h9999-no"
            size = spg_media.get_remote_image_size(photo_link_max_size)
            thumbnail_size = spg_media.get_thumbnail_size(
                size, self.gallery_config["thumbnail_height"])

            # Add the photo to the images_data dict
            images_data[photo_name] = dict(
                description="",
                mtime=time.time(),
                size=size,
                src=f"{photo_base_url}=w{size[0]}-h{size[1]}-no",
                thumbnail=
                f"{photo_base_url}=w{thumbnail_size[0]}-h{thumbnail_size[1]}-no",
                thumbnail_size=thumbnail_size,
                type="image",
            )

        spg_common.log(f"All photos processed!")

        driver.quit()

        return images_data