extend this script to read Tabs_ files too
```
#!/usr/bin/env python3
import argparse
import os
import struct
import sys
import json
from pathlib import Path
from collections import defaultdict
import datetime
import io

# Constants for command types
K_COMMAND_UPDATE_TAB_NAVIGATION = 6
K_COMMAND_SET_SELECTED_TAB_IN_INDEX = 8
K_COMMAND_SET_TAB_WINDOW = 0
K_COMMAND_SET_TAB_GROUP = 25
K_COMMAND_SET_TAB_GROUP_METADATA2 = 27
K_COMMAND_SET_SELECTED_NAVIGATION_INDEX = 7
K_COMMAND_TAB_CLOSED = 16
K_COMMAND_WINDOW_CLOSED = 17
K_COMMAND_SET_TAB_INDEX_IN_WINDOW = 2
K_COMMAND_SET_ACTIVE_WINDOW = 20
K_COMMAND_LAST_ACTIVE_TIME = 21

MAGIC_HEADER = b"SNSS"

# Data Structures
class Group:
    def __init__(self, high, low, name=""):
        self.high = high
        self.low = low
        self.name = name

class Window:
    def __init__(self, id):
        self.id = id
        self.active_tab_idx = 0
        self.deleted = False
        self.tabs = []

class HistoryItem:
    def __init__(self, idx, url="", title=""):
        self.idx = idx
        self.url = url
        self.title = title

class Tab:
    def __init__(self, id):
        self.id = id
        self.history = []
        self.idx = 0
        self.win = 0
        self.deleted = False
        self.current_history_idx = 0
        self.group = None

class Result:
    def __init__(self):
        self.windows = []

# Helper Functions
def read_uint8(f):
    data = f.read(1)
    if len(data) != 1:
        raise EOFError("Failed to read uint8.")
    return struct.unpack("<B", data)[0]

def read_uint16(f):
    data = f.read(2)
    if len(data) != 2:
        raise EOFError("Failed to read uint16.")
    return struct.unpack("<H", data)[0]

def read_uint32(f):
    data = f.read(4)
    if len(data) != 4:
        raise EOFError("Failed to read uint32.")
    return struct.unpack("<I", data)[0]

def read_uint64(f):
    data = f.read(8)
    if len(data) != 8:
        raise EOFError("Failed to read uint64.")
    return struct.unpack("<Q", data)[0]

def read_string(f):
    sz = read_uint32(f)
    rsz = sz
    if rsz % 4 != 0:
        rsz += 4 - (rsz % 4)
    data = f.read(rsz)
    if len(data) != rsz:
        raise EOFError("Failed to read string.")
    return data[:sz].decode('utf-8', errors='replace')

def read_string16(f):
    sz = read_uint32(f)
    rsz = sz * 2
    if rsz % 4 != 0:
        rsz += 4 - (rsz % 4)
    data = f.read(rsz)
    if len(data) != rsz:
        raise EOFError("Failed to read string16.")
    # Interpret as little-endian UTF-16
    return data[:sz*2].decode('utf-16le', errors='replace')

# Main Parsing Function
def parse_session(file_path):
    tabs = {}
    windows = {}
    groups = {}
    active_window = None

    def get_window(id):
        if id not in windows:
            windows[id] = Window(id)
        return windows[id]

    def get_group(high, low):
        key = f"{high:x}{low:x}"
        if key not in groups:
            groups[key] = Group(high, low)
        return groups[key]

    def get_tab(id):
        if id not in tabs:
            tabs[id] = Tab(id)
        return tabs[id]

    with open(file_path, 'rb') as f:
        # Read and validate magic header
        magic = f.read(4)
        if magic != MAGIC_HEADER:
            raise ValueError("Invalid SNSS file: Incorrect magic header.")

        # Read and validate version
        version = read_uint32(f)
        if version not in [1, 3]:
            raise ValueError(f"Invalid SNSS file: Unsupported version {version}.")

        while True:
            try:
                sz = read_uint16(f) -1
                cmd_type = read_uint8(f)
                payload = f.read(sz)
                if len(payload) != sz:
                    raise EOFError("Incomplete command payload.")
                data = io.BytesIO(payload)

                if cmd_type == K_COMMAND_UPDATE_TAB_NAVIGATION:
                    data_size = read_uint32(data)
                    tab_id = read_uint32(data)
                    hist_idx = read_uint32(data)
                    url = read_string(data)
                    title = read_string16(data)

                    tab = get_tab(tab_id)
                    # Find or create history item
                    item = next((h for h in tab.history if h.idx == hist_idx), None)
                    if not item:
                        item = HistoryItem(hist_idx)
                        tab.history.append(item)
                    item.url = url
                    item.title = title

                elif cmd_type == K_COMMAND_SET_SELECTED_TAB_IN_INDEX:
                    win_id = read_uint32(data)
                    idx = read_uint32(data)
                    win = get_window(win_id)
                    win.active_tab_idx = idx

                elif cmd_type == K_COMMAND_SET_TAB_GROUP_METADATA2:
                    data_size = read_uint32(data)
                    high = read_uint64(data)
                    low = read_uint64(data)
                    name = read_string16(data)
                    group = get_group(high, low)
                    group.name = name

                elif cmd_type == K_COMMAND_SET_TAB_GROUP:
                    tab_id = read_uint32(data)
                    padding = read_uint32(data)  # Struct padding
                    high = read_uint64(data)
                    low = read_uint64(data)
                    tab = get_tab(tab_id)
                    tab.group = get_group(high, low)

                elif cmd_type == K_COMMAND_SET_TAB_WINDOW:
                    win_id = read_uint32(data)
                    tab_id = read_uint32(data)
                    tab = get_tab(tab_id)
                    tab.win = win_id

                elif cmd_type == K_COMMAND_WINDOW_CLOSED:
                    win_id = read_uint32(data)
                    win = get_window(win_id)
                    win.deleted = True

                elif cmd_type == K_COMMAND_TAB_CLOSED:
                    tab_id = read_uint32(data)
                    tab = get_tab(tab_id)
                    tab.deleted = True

                elif cmd_type == K_COMMAND_SET_TAB_INDEX_IN_WINDOW:
                    tab_id = read_uint32(data)
                    index = read_uint32(data)
                    tab = get_tab(tab_id)
                    tab.idx = index

                elif cmd_type == K_COMMAND_SET_ACTIVE_WINDOW:
                    win_id = read_uint32(data)
                    active_window = get_window(win_id)

                elif cmd_type == K_COMMAND_LAST_ACTIVE_TIME:
                    # Skipping proper implementation as noted in Go code
                    data.read(4 + 8)  # Skip id and time

                elif cmd_type == K_COMMAND_SET_SELECTED_NAVIGATION_INDEX:
                    tab_id = read_uint32(data)
                    idx = read_uint32(data)
                    tab = get_tab(tab_id)
                    tab.current_history_idx = idx

                else:
                    # Unknown command type; skip
                    pass

            except EOFError:
                break

    # Organize tabs into windows
    for tab in tabs.values():
        # Skip tabs without a window
        if tab.win == 0:
            continue
        win = get_window(tab.win)
        win.tabs.append(tab)

    # Sort tabs within windows
    for win in windows.values():
        win.tabs.sort(key=lambda t: t.idx)

    # Prepare Result
    result = Result()
    for win in windows.values():
        window_obj = {
            "active": (win == active_window),
            "deleted": win.deleted,
            "tabs": []
        }
        for idx, tab in enumerate(win.tabs):
            if not tab.deleted:
                is_active = (idx == win.active_tab_idx)
            else:
                is_active = False
            tab_obj = {
                "active": is_active,
                "history": [{"url": h.url, "title": h.title} for h in sorted(tab.history, key=lambda x: x.idx)],
                "url": "",
                "title": "",
                "deleted": tab.deleted,
                "group": tab.group.name if tab.group else ""
            }
            # Truncate history to current_history_idx
            for h in sorted(tab.history, key=lambda x: x.idx):
                tab_obj["history"].append({"url": h.url, "title": h.title})
                if h.idx == tab.current_history_idx:
                    tab_obj["url"] = h.url
                    tab_obj["title"] = h.title
                    break
            window_obj["tabs"].append(tab_obj)
        result.windows.append(window_obj)

    return result

# Function to find session files
def find_sessions(path):
    session_files = []

    for root, dirs, files in os.walk(path):
        for file in files:
            if file.startswith("Session_"):
                full_path = os.path.join(root, file)
                session_files.append(full_path)

    return session_files

# Function to handle printf-like formatting
def format_output(format_str, tab, include_history):
    outputs = []
    if include_history:
        for item in tab["history"]:
            s = format_str.replace("%u", item["url"])
            s = s.replace("%g", tab["group"])
            s = s.replace("%t", item["title"])
            s = s.replace("\\n", "\n")
            s = s.replace("\\t", "\t")
            s = s.replace("\\0", "\x00")
            outputs.append(s)
    else:
        s = format_str.replace("%u", tab["url"])
        s = s.replace("%g", tab["group"])
        s = s.replace("%t", tab["title"])
        s = s.replace("\\n", "\n")
        s = s.replace("\\t", "\t")
        s = s.replace("\\0", "\x00")
        outputs.append(s)
    return "".join(outputs)

# Function to write output to a file
def write_output(output_path, data, is_json, pretty):
    with open(output_path, 'w', encoding='utf-8') as f:
        if is_json:
            if pretty:
                json.dump(data, f, indent=2)
            else:
                json.dump(data, f, separators=(',', ':'))
        else:
            f.write(data)

# Function to generate output content based on arguments
def generate_output(result, args):
    if args.json:
        output_data = {
            "windows": result.windows
        }
        return output_data
    elif args.active:
        outputs = []
        for win in result.windows:
            if win["active"]:
                for tab in win["tabs"]:
                    if tab["active"]:
                        outputs.append(format_output(args.printf, tab, args.history))
        return "\n".join(outputs)
    else:
        outputs = []
        for win in result.windows:
            if not win["deleted"] or args.deleted:
                for tab in win["tabs"]:
                    if not tab["deleted"] or args.deleted:
                        outputs.append(format_output(args.printf, tab, args.history))
        return "\n".join(outputs)

# Function to handle a single session file
def handle_single_session(session_file, args):
    try:
        result = parse_session(session_file)
    except Exception as e:
        print(f"Error parsing session file '{session_file}': {e}", file=sys.stderr)
        return

    output_content = generate_output(result, args)

    if args.output:
        output_path = args.output
    else:
        # Default output to stdout
        if args.json:
            if args.pretty:
                print(json.dumps(output_content, indent=2))
            else:
                print(json.dumps(output_content, separators=(',', ':')))
        else:
            print(output_content, end='')
        return

    try:
        write_output(output_path, output_content, args.json, args.pretty)
        print(f"Session '{session_file}' dumped to '{output_path}'.")
    except Exception as e:
        print(f"Error writing to '{output_path}': {e}", file=sys.stderr)

# Function to handle multiple session files
def handle_multiple_sessions(session_files, args):
    if not args.output_dir:
        print("Output directory not specified.", file=sys.stderr)
        return

    output_dir = Path(args.output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)

    for session_file in session_files:
        try:
            result = parse_session(session_file)
        except Exception as e:
            print(f"Error parsing session file '{session_file}': {e}", file=sys.stderr)
            continue

        output_content = generate_output(result, args)

        session_filename = Path(session_file).stem  # e.g., "Session_12345"
        if args.json:
            output_filename = f"{session_filename}.json"
        else:
            output_filename = f"{session_filename}.txt"

        output_path = output_dir / output_filename

        try:
            write_output(output_path, output_content, args.json, args.pretty)
            print(f"Session '{session_file}' dumped to '{output_path}'.")
        except Exception as e:
            print(f"Error writing to '{output_path}': {e}", file=sys.stderr)

# Main Function
def main():
    parser = argparse.ArgumentParser(
        description="Chrome Session Dump - Parses Chrome's session files to extract window and tab information.",
        formatter_class=argparse.RawTextHelpFormatter,
        epilog="""
Example Usage:

1. Dump the latest session to stdout (minimized JSON by default):
   python3 session_dump.py --json

2. Dump the latest session to a pretty-printed JSON file:
   python3 session_dump.py --output latest_session.json --json --pretty

3. Dump multiple session files to a designated folder with minimized JSON:
   python3 session_dump.py /path/to/chrome/session_directory --output-dir /path/to/output_folder --json

4. Dump multiple session files to a designated folder with pretty-printed JSON:
   python3 session_dump.py /path/to/chrome/session_directory --output-dir /path/to/output_folder --json --pretty

5. Dump a specific session file to a text file with custom format:
   python3 session_dump.py /path/to/Session_12345 --output session_12345.txt --printf "Title: %t\nURL: %u\n\n"

6. Include deleted tabs and history in the output:
   python3 session_dump.py --output complete_session.json --json --deleted --history

7. Dump minimized JSON without specifying output file (outputs to stdout):
   python3 session_dump.py --json

8. Dump non-JSON output with custom printf format:
   python3 session_dump.py /path/to/Session_12345 --output session_12345.txt --printf "Title: %t\nURL: %u\n\n"
"""
    )
    parser.add_argument(
        "target",
        nargs="?",
        default=None,
        help="Path to the session file or Chrome directory. Defaults to Chrome's config directory."
    )
    parser.add_argument(
        "--json",
        action="store_true",
        help="Produce JSON formatted output. Includes all tabs with their history and metadata."
    )
    parser.add_argument(
        "--pretty",
        action="store_true",
        help="Pretty-print JSON output with indentation. Use with --json."
    )
    parser.add_argument(
        "--active",
        action="store_true",
        help="Print the currently active tab."
    )
    parser.add_argument(
        "--deleted",
        action="store_true",
        help="Include tabs and windows that have been deleted."
    )
    parser.add_argument(
        "--history",
        action="store_true",
        help="Include the history of each tab in the output."
    )
    parser.add_argument(
        "--printf",
        default="%u\n",
        help="The output format for tabs if --json is not specified. Use %%u for URL, %%g for group, %%t for title. (Default: '%%u\\n')"
    )
    group = parser.add_mutually_exclusive_group()
    group.add_argument(
        "--output",
        type=str,
        help="Specify an output file to dump a single session."
    )
    group.add_argument(
        "--output-dir",
        type=str,
        help="Specify an output directory to dump multiple session files. Each session will be saved as a separate file."
    )

    args = parser.parse_args()

    # Validate arguments
    if args.pretty and not args.json:
        parser.error("--pretty can only be used with --json.")

    # Determine the target path
    if args.target:
        target = Path(os.path.expanduser(args.target))
    else:
        # Default Chrome config directories
        possible_dirs = [
            Path.home() / ".config" / "chromium",
            Path.home() / ".config" / "google-chrome",
            Path.home() / ".config" / "chrome"
        ]
        target = next((d for d in possible_dirs if d.exists()), None)
        if not target:
            print("Default Chrome config directories not found. Please specify a session file or Chrome directory.", file=sys.stderr)
            sys.exit(1)

    # If target is a directory, find all session files
    if target.is_dir():
        session_files = find_sessions(str(target))
        if not session_files:
            print("No session files found in the specified directory.", file=sys.stderr)
            sys.exit(1)
        if args.output_dir:
            handle_multiple_sessions(session_files, args)
        else:
            # If output_dir not specified, default to dumping the latest session
            latest_session = max(session_files, key=lambda x: os.path.getmtime(x))
            handle_single_session(latest_session, args)
    else:
        # Assume target is a session file
        handle_single_session(str(target), args)

if __name__ == "__main__":
    main()
```