Add banner, logging, statistics and preparing detection

This commit is contained in:
csd4ni3l
2025-06-14 15:55:48 +02:00
parent 2a4987c581
commit c25d934f3c
2 changed files with 76 additions and 18 deletions

90
main.py
View File

@@ -1,4 +1,4 @@
import os, time, argparse, re import os, time, argparse, re, sys, logging
from selenium.webdriver import Chrome, ChromeService from selenium.webdriver import Chrome, ChromeService
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.options import Options
@@ -7,6 +7,19 @@ from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support import expected_conditions as EC
from zipfile import ZipFile from zipfile import ZipFile
BANNER = """
██████ ██████ ██████ ██
██ ██ ██ ██ ██ ██
██ ███ ██████ █████ ██ ██ ██
██ ██ ██ ██ ██ ██
██████ ██ ██████ ███████
gp-dl — Google Photos Downloader
Download full-res albums using Selenium
Author: csd4ni3l | GitHub: https://github.com/csd4ni3l
"""
def parse_args(): def parse_args():
parser = argparse.ArgumentParser(description="Download full-res images from a Google Photos album using Selenium.") parser = argparse.ArgumentParser(description="Download full-res images from a Google Photos album using Selenium.")
parser.add_argument("--album-urls", nargs="+", required=True, help="Google Photos album URL") parser.add_argument("--album-urls", nargs="+", required=True, help="Google Photos album URL")
@@ -44,66 +57,111 @@ def find_zip_file():
if file.endswith(".zip"): if file.endswith(".zip"):
return file return file
def find_crdownload_file():
for file in os.listdir("gp_temp"):
if file.endswith(".crdownload"):
return file
def configure_logging():
logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=logging.DEBUG)
for logger_to_disable in ["selenium", "urllib3"]:
logging.getLogger(logger_to_disable).propagate = False
logging.getLogger(logger_to_disable).disabled = True
def main(): def main():
args = parse_args() args = parse_args()
driver = setup_driver(profile_dir=args.profile_dir, headless=args.headless) driver = setup_driver(profile_dir=args.profile_dir, headless=args.headless)
if not os.path.exists("gp_temp") or not os.path.isdir("gp_temp"):
logging.info("Creating gp_temp directory to temporarily store the downloaded zip files.")
os.makedirs("gp_temp", exist_ok=True) os.makedirs("gp_temp", exist_ok=True)
if not os.path.exists(args.output_dir) or not os.path.isdir(args.output_dir): if not os.path.exists(args.output_dir) or not os.path.isdir(args.output_dir):
print("ERROR: Invalid output directory.") logging.fatal("Invalid output directory. Please supply a valid and existing directory.")
return return
failed_album_count = 0
successful_album_count = 0
total_albums = len(args.album_urls)
all_start = time.perf_counter()
album_times = []
for album_url in args.album_urls: for album_url in args.album_urls:
album_start = time.perf_counter()
if re.match(r'^https?://photos\.app\.goo\.gl/[A-Za-z0-9]+$', album_url) is None: if re.match(r'^https?://photos\.app\.goo\.gl/[A-Za-z0-9]+$', album_url) is None:
print(f"Invalid album URL: {album_url}") logging.error(f"Invalid album URL: {album_url}")
logging.info("Continuing with next album URL.")
failed_album_count += 1
continue continue
print(f"Opening {album_url}") logging.info(f"Now downloading {album_url}")
driver.get(album_url) driver.get(album_url)
print("Waiting for menu button...") logging.debug("Waiting for menu button...")
try: try:
menu_button = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@aria-label="More options"]'))) menu_button = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@aria-label="More options"]')))
except TimeoutException: except TimeoutException:
print("ERROR: Could not find more options button in time.") logging.error("Could not find more options button in time.")
print("Continuing with next album.") logging.info("Continuing with next album URL.")
failed_album_count += 1
continue continue
print("Clicking menu button...") logging.debug("Clicking menu button...")
menu_button.click() menu_button.click()
print("Waiting for download all button...") logging.debug("Waiting for download all button...")
try: try:
download_all_button = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@aria-label="Download all"]'))) download_all_button = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@aria-label="Download all"]')))
except TimeoutException: except TimeoutException:
print("ERROR: Could not find download all button in time.") logging.error("Could not find download all button in time.")
print("Continuing with next album.") logging.info("Continuing with next album.")
failed_album_count += 1
continue continue
print("Clicking the download all button...") logging.debug("Clicking the download all button...")
download_all_button.click() download_all_button.click()
print("Waiting for a zip file to land in gp_temp...") logging.debug("Waiting for Google to prepare the file...")
crdownload_file = None
while not crdownload_file:
crdownload_file = find_crdownload_file()
time.sleep(0.1)
logging.debug("Waiting for the download to finish...")
zip_file = None zip_file = None
while not zip_file: while not zip_file:
zip_file = find_zip_file() zip_file = find_zip_file()
time.sleep(0.1) time.sleep(0.1)
print(f"Zip file downloaded, extracting to {args.output_dir}") logging.debug(f"Zip file downloaded, extracting to {args.output_dir}")
with ZipFile(f"gp_temp/{zip_file}") as opened_file: with ZipFile(f"gp_temp/{zip_file}") as opened_file:
opened_file.extractall(args.output_dir) opened_file.extractall(args.output_dir)
print("Deleting zip file...") logging.debug("Deleting zip file...")
os.remove(f"gp_temp/{zip_file}") os.remove(f"gp_temp/{zip_file}")
print(f"Succesfully extracted to {args.output_dir}") logging.info(f"Succesfully extracted zip file to {args.output_dir}")
successful_album_count += 1
album_times.append(time.perf_counter() - album_start)
logging.debug("Removing gp_temp directory.")
os.removedirs("gp_temp") os.removedirs("gp_temp")
print("\n===== DOWNLOAD STATISTICS =====")
print(f"Total albums given: {total_albums}")
print(f"Successfully downloaded: {successful_album_count}")
print(f"Failed downloads: {failed_album_count}")
print(f"Average time taken per album: {sum(album_times) / len(album_times):.2f} seconds")
print(f"Total time taken: {time.perf_counter() - all_start:.2f} seconds")
print("================================")
driver.quit() driver.quit()
if __name__ == '__main__': if __name__ == '__main__':
print(BANNER)
configure_logging()
main() main()

2
uv.lock generated
View File

@@ -38,7 +38,7 @@ wheels = [
] ]
[[package]] [[package]]
name = "gp-downloader" name = "gp-dl"
version = "0.1.0" version = "0.1.0"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [