Display a Google Drive directory structure as an ASCII tree via Python

Sometimes folder structures can be confusing, and getting a clear pictures can be challenging. This Python script lists all files and folders within a specified root folder, representing the structure of the folders with ASCII art.

It makes it practical and versatile working with directory structures, providing a clear and easy-to-interpret representation of the folder hierarchy.

Prerequisites

To run the script successfully, you will need the following prerequisites:

  1. Create a new Google Project
  2. Enable the Drive API
  3. Create an OAuth consent screen
  4. Create OAuth 2.0 Client IDs – Desktop App
  5. Download the JSON file
  6. Setup Python
    $ sudo apt install python3-pip
    $ pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

Further information can be found in the Python quickstart guide from Google.

In order to run the script, simply rename the JSON file you’ve downloaded to “credentials.json” and position it within the script’s directory. If necessary, you can also specify the “folder_id” variable with the folder ID where you wish to initiate the process. The default setting for this variable is “root.”

Script

import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

# Define the Google Drive API scopes for accessing files and folders
# If modifying these scopes, delete the file token.json
SCOPES = ['https://www.googleapis.com/auth/drive']
TOKEN_PATH = 'token.json'
CREDENTIALS_PATH = 'credentials.json'

# Mapping of MIME types to file extensions for Google files
GOOGLE_FILE_EXTENSIONS = {
    'application/vnd.google-apps.document': '.gdoc',
    'application/vnd.google-apps.spreadsheet': '.gsheet',
    'application/vnd.google-apps.presentation': '.gslides',
    'application/vnd.google-apps.script': '.gs',
    'application/vnd.google-apps.map': '.gmap',
    'application/vnd.google-apps.form': '.gform',
    'application/vnd.google-apps.drawing': '.gdraw',
    'application/vnd.google-apps.jam': '.gjam',
    # Add more mappings as needed
}

def get_credentials():
    # Gets user credentials or prompts for authorization if needed
    # Try to load existing credentials from 'token.json'
    creds = Credentials.from_authorized_user_file(TOKEN_PATH, SCOPES) if os.path.exists(TOKEN_PATH) else None

    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            # Refresh the credentials if they have expired
            creds.refresh(Request())
        else:
            # If no valid credentials exist, initiate the OAuth flow to obtain them
            flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_PATH, SCOPES)
            creds = flow.run_local_server(port=0)

        # Save the credentials for future runs
        with open(TOKEN_PATH, 'w') as token_file:
            token_file.write(creds.to_json())

    return creds

def list_files_and_folders(drive_service, folder_id, indent=""):
    # Lists files and folders recursively starting from the specified folder ID in ascending order
    try:
        # Query the Google Drive API for files and folders within the specified folder
        results = drive_service.files().list(
            pageSize=1000, # The number of files returned in each API request
            q=f"'{folder_id}' in parents and trashed=false",  # Exclude items in the trash
            fields="nextPageToken, files(id, name, mimeType)",
            includeItemsFromAllDrives=True,  # Include items from all drives
            supportsAllDrives=True  # Supports querying items from all drives
        ).execute()
        items = results.get('files', [])

        if not items:
            # If no items are found, print a message
            print(indent + "No files or folders found.")
        else:
            # Sort the items in ascending order by name
            items.sort(key=lambda x: x['name'].lower())
            for item in items:
                if item['mimeType'] == 'application/vnd.google-apps.folder':
                    # If the item is a folder, print its name with proper indentation
                    print(indent + "└─ " + item['name'])
                    # Recursively list files and folders within this folder
                    list_files_and_folders(drive_service, item['id'], indent + "    ")
                else:
                    # If the item is not a folder, print its name with proper indentation
                    if item['mimeType'].startswith('application/vnd.google-apps.'):
                        # Check if the item is a Google file and append the extension to the name
                        file_extension = GOOGLE_FILE_EXTENSIONS.get(item['mimeType'], '')
                        print(indent + "├─ " + item['name'] + file_extension)
                    else:
                        # For non-Google files, print the name as is
                        print(indent + "├─ " + item['name'])

    except HttpError as error:
        # Handle any HTTP errors that occur during the API request
        print(f"An error occurred: {error}")

def main():
    # Main function to list files and folders recursively from the root folder
    # Get user credentials to access Google Drive
    creds = get_credentials()
    # Create a service to interact with the Google Drive API
    service = build('drive', 'v3', credentials=creds)
    
    # Define the root folder ID to start listing files and folders
    folder_id = 'root'
    print(f"Root Folder ID: {folder_id}")
    list_files_and_folders(service, folder_id)

if __name__ == '__main__':
    main()
Python ASCII Tree Output
Visualization of a folder tree formatted in ASCII.
asterix Written by:

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *