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}' )
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
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)
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
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}" )
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
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')
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!')
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')
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
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." )
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