Search code examples
pythonservice-accountspresentationgoogle-slides-apigoogle-slides

Replacing google slides images using slides api


I have the following scripts to update the images in google slides, it works fine but sometimes it gives me 400 error, service account has a write permission to the drive/images and the presentation

image_mappings = {
    "id_in_presenation": "name_of_the_image",
    "id_in_presenation1": "name_of_the_image1",
}

# listing .png files 
def get_png_files(drive_folder_id, drive_service):
    query = f"'{drive_folder_id}' in parents and mimeType='image/png'"
    results = drive_service.files().list(q=query, supportsAllDrives=True, fields="files(id, name, webViewLink, webContentLink)").execute()
    drive_png_files = results.get('files', [])
    print('drive_png_files', drive_png_files)
    return drive_png_files`


# updating images in slides

def update_images_in_slides(drive_png_files, slides_service, presentation_id):
    """
    Updates images in a Google Slides presentation.

    Args:
    drive_png_files: A list of .png files from Google Drive.
    slides_service: The authenticated Google Slides service object.
    presentation_id: The ID of the presentation to update.
    """

    requests = []
    for slide_image_id, new_image_name in info.image_mappings.items():
        drive_file = next((item for item in drive_png_files if item['name'] == new_image_name), None)
        if drive_file:
            requests.append({
                'replaceImage': {
                    'imageObjectId': slide_image_id,
                    'imageReplaceMethod': 'CENTER_INSIDE',
                    'url': f'https://drive.google.com/uc?id={drive_file["id"]}'
                }
            })
    if requests:
        body = {'requests': requests}
        try:
            response = slides_service.presentations().batchUpdate(presentationId=presentation_id, body=body).execute()
            time.sleep(10)
            print(f"\nUpdated the slide: {response}")
        except Exception as exc:
            raise ValueError(f"Failed to update the presentation.") from exc

gave editor and writer access permission to the service account for the drives, images, presentation did not help


Solution

  • From your question, I guessed the following issues.

    1. Image files that are not publicly shared might be included.
    2. Image files that are over the maximum image size might be included. Ref

    When these issues occur, an error of the status code 400 occurs. But, unfortunately, I cannot know your actual error message from your question. When my guess was correct, how about the following modification?

    Modified script:

    In this modification, your function update_images_in_slides is modified.

    In order to use Drive API, drive_service is added to the last argument. Please be careful about this.

    def update_images_in_slides(drive_png_files, slides_service, presentation_id, drive_service):
        """
        Updates images in a Google Slides presentation.
    
        Args:
        drive_png_files: A list of .png files from Google Drive.
        slides_service: The authenticated Google Slides service object.
        presentation_id: The ID of the presentation to update.
        """
    
        # Images are publicly shared for inserting to Slide.
        batch1 = drive_service.new_batch_http_request()
        for e in drive_png_files:
            batch1.add(drive_service.permissions().create(fileId=e["id"], body={"type": "anyone", "role": "reader"}, supportsAllDrives=True))
        batch1.execute()
    
        requests = []
        for slide_image_id, new_image_name in info.image_mappings.items():
            drive_file = next((item for item in drive_png_files if item['name'] == new_image_name), None)
            if drive_file:
                requests.append({
                    'replaceImage': {
                        'imageObjectId': slide_image_id,
                        'imageReplaceMethod': 'CENTER_INSIDE',
                        # 'url': f'https://drive.google.com/uc?id={drive_file["id"]}'
                        'url': f'https://drive.google.com/thumbnail?sz=w1000&id={drive_file["id"]}'
                    }
                })
        if requests:
            body = {'requests': requests}
            try:
                response = slides_service.presentations().batchUpdate(presentationId=presentation_id, body=body).execute()
                time.sleep(10)
                print(f"\nUpdated the slide: {response}")
            except Exception as exc:
                raise ValueError(f"Failed to update the presentation.") from exc
    
        # Permission of publicly shared images is removed.
        batch2 = drive_service.new_batch_http_request()
        for e in drive_png_files:
            batch2.add(drive_service.permissions().delete(fileId=e["id"], permissionId="anyoneWithLink", supportsAllDrives=True))
        batch2.execute()
    
    • When I tested this modified script, I confirmed that the script worked without errors.

    Note:

    • This modified script supposes that your values of drive_png_files, slides_service, presentation_id, drive_service and info.image_mappings are valid values. Please be careful about this.

    • In this modification, the following flow is used.

      1. Image files are publicly shared.
      2. Put the publicly shared images on Slide.
      3. Permissions of public sharing are removed.
    • I cannot know your current scopes. So, when an error is related to the scopes, please add a scope of https://www.googleapis.com/auth/drive to your current scope, and test it again. Please be careful about this.

    • If the image sizes of all images are varied sizes, I guess that 'url': f'https://drive.google.com/uc?id={drive_file["id"]}' might be able to be used.

    Reference