Skip to content

Latest commit

 

History

History
1340 lines (423 loc) · 22.8 KB

File metadata and controls

1340 lines (423 loc) · 22.8 KB
Error in user YAML: (<unknown>): mapping values are not allowed in this context at line 25 column 42
---



\# Brave Bookmark Exporter – Product Requirements Document (Python Version)



\## 1. Overview



\### 1.1 Product Name (Working)



\*\*Brave Bookmark Exporter\*\*



\### 1.2 Summary



Brave Bookmark Exporter is a Windows 11 desktop application that reads Brave browser bookmarks and exports them as standard Windows Internet Shortcut files (`.url`) into a user-selected folder. The application preserves the bookmark folder hierarchy by mirroring it as a directory structure under the export root.



The app is intended for users who want to:



\* Back up their bookmarks as discrete files.

\* Organize bookmarks as regular files/folders in Explorer.

\* Use bookmarks across tools and workflows that rely on filesystem access.



\### 1.3 Target Platform \& Tech Stack



\* \*\*OS:\*\* Windows 11 (64-bit)

\* \*\*Runtime:\*\* Python 3.11+ (CPython)

\* \*\*Language:\*\* Python

\* \*\*UI Framework:\*\* Qt for Python (PySide6)

\* \*\*Packaging:\*\* Standalone Windows executable using PyInstaller (or similar)



---


## 2. Goals & Non-Goals

### 2.1 Goals

1. **Export Brave bookmarks into .url files**

  * Each bookmark becomes a Windows Internet Shortcut (.url) file.

  * Each shortcut contains a valid URL that opens in the default browser.

2. **Preserve bookmark folder structure**

  * Bookmark folders map to real directories.

  * Nested bookmark folders are exported as nested directories under the chosen output folder.

3. **Flexible export scope**

  * Export **all bookmarks** for a selected Brave profile.

  * Export **specific bookmark folders**.

  * Export **individual bookmarks**.

4. **Safe, non-destructive behavior**

  * Read-only access to Brave data.

  * Never modifies or deletes any files inside Brave’s profile directories.

5. **Usable GUI for non-technical users**

  * Simple, understandable interface:

  * Select profile.

  * View bookmarks tree.

  * Select export target(s).

  * Choose output folder.

  * Run export with feedback and status.

6. **Robust export behavior**

  * Handle:

  * Large numbers of bookmarks.

  * Invalid filenames.

  * Duplicate names.

  * Long paths (with graceful degradation).

### 2.2 Non-Goals (for v1)

* Synchronizing exported shortcuts back into Brave.

* Bi-directional sync between bookmarks and filesystem.

* Editing bookmarks inside the app.

* Exporting favicons or setting custom icons on .url files.

* Supporting non-Brave browsers (Chrome, Edge, etc.) in v1.

* Providing cloud sync or online backup.

* Providing a CLI by default (CLI is a possible future enhancement).


## 3. Users & Use Cases

### 3.1 Primary User Personas

1. **Power User / Knowledge Worker**

2. **Backup-Focused User**

3. **Automation-Oriented User (Secondary)**

(Same descriptions as original PRD – intent unchanged.)

### 3.2 Key Use Cases

1. **Export all bookmarks from Brave**

2. **Export a specific bookmark folder**

3. **Export a small curated set of bookmarks**

4. **Repeat exports** with overwrite / skip / unique-name options.

(Behavior identical to original PRD.)


## 4. Functional Requirements

### 4.1 Profile Detection & Selection

**FR-1**: The application shall detect the default Brave user data directory using known standard paths for Windows (e.g., LOCALAPPDATA\\BraveSoftware\\Brave-Browser\\User Data).

**FR-2**: The application shall scan for existing Brave profiles, including at least:

* Default

* Profile 1

* Profile 2

* Any additional profile directories following Brave’s naming pattern.

**FR-3**: For each profile directory, the application shall check if a Bookmarks file exists.

**FR-4**: The application shall present the list of profiles with:

* Human-readable display name (e.g., *Default*, *Profile 1*).

* Internally tracked profile path.

**FR-5**: The user shall be able to manually specify a custom Brave profile root path if automatic detection fails (e.g., portable Brave installs), using a “Browse…” dialog.


### 4.2 Bookmark File Handling

**FR-6**: The app shall read Brave’s Bookmarks file as JSON (using Python’s json module or equivalent).

**FR-7**: To avoid file locking and concurrency issues, the application **should**:

* Copy the Bookmarks file to a temporary location.

* Parse the copy instead of reading the file in-place.

**FR-8**: If the Bookmarks file cannot be read or parsed:

* The app shall display a clear error message.

* No export operation shall proceed.


### 4.3 Bookmark Tree Parsing

**FR-9**: The application shall parse the Bookmarks JSON into an internal tree representation that includes:

* Folder nodes.

* Bookmark (URL) nodes.

* Root containers (bookmark\_bar, other, mobile).

**FR-10**: Each parsed node shall have:

* A name.

* A type (folder or bookmark).

* A stable identifier (copied from Brave’s id).

* A reference to its parent folder (except root containers).

* A RootKind that indicates the top-level root it belongs to:

  * Bookmark Bar

  * Other Bookmarks

  * Mobile Bookmarks

  * Unknown (for any non-standard roots)

**FR-11**: The internal model shall maintain the original order of children as specified by Brave.


### 4.4 UI: Bookmark Tree Visualization & Selection

**FR-12**: The main window shall display a tree view (Qt QTreeView or QTreeWidget) that represents the bookmark folder structure, including all roots.

**FR-13**: Folder nodes shall be visually distinguishable (e.g., folder icon) from bookmark nodes (e.g., link icon).

**FR-14**: The TreeView shall support:

* Expanding/collapsing folders.

* Selecting nodes for export (via checkboxes).

**FR-15**: The TreeView selection mechanism shall support:

* Selecting entire folders for export.

* Selecting individual bookmarks for export.

* Configurable behavior: selecting a folder can optionally imply all children.

**FR-16**: There shall be an “Export scope” control:

* Option A: Export all bookmarks in the profile.

* Option B: Export only selected folders/bookmarks.

**FR-17**: If “Export all bookmarks” is chosen, the TreeView selection state does not affect the export, but remains visible.


### 4.5 Output Folder & Path Mapping

**FR-18**: The user shall be able to select an **Output Root Folder** using a standard Windows folder picker dialog (QFileDialog).

**FR-19**: For each folder node being exported, the application shall create a corresponding directory under the output root, preserving the hierarchy.

**FR-20**: The app shall provide a setting:

* “[ ] Include full path from top-level root”

  * If enabled: folder paths include top-level roots (Bookmarks Bar, Other Bookmarks, etc.).

  * If disabled: the selected folder(s) are treated as roots in the exported tree.

**FR-21**: For each bookmark node being exported, the app shall compute:

* A relative directory path based on its folder ancestors.

* A filename (without extension) derived from the bookmark title, sanitized.


### 4.6 File Naming, Sanitization & Duplicates

**FR-22**: Bookmark names must be sanitized to valid Windows filenames:

* Remove or replace invalid characters: \\ / : \* ? " < > |.

* Trim trailing spaces and periods.

* Limit length to a configurable maximum (e.g., 120 characters).

**FR-23**: The file extension for all exported bookmarks shall be .url.

**FR-24**: If a file with the same path already exists, the app shall support **three** behaviors, controlled via options:

* **Overwrite**: Replace the existing file.

* **Skip**: Do not re-export this bookmark.

* **Create unique name**: Append a suffix like (2), (3) etc. until an unused filename is found.

**FR-24a**: The user shall be able to choose the behavior via a UI option (e.g., radio buttons).

**Default behavior:** **Create unique name**.


### 4.7 .url File Contents

**FR-25**: Each exported bookmark file shall conform to the basic Windows Internet Shortcut INI-like format:

\[InternetShortcut]

URL=<bookmark\_url>

**FR-26**: The app shall write valid UTF-8 text files.

**FR-27**: If the URL is missing or clearly invalid (e.g., empty string), the bookmark shall be skipped and logged as an error for the result summary.


### 4.8 Export Process & Progress Feedback

**FR-28**: When the user clicks “Export”, the application shall:

* Validate all required inputs (profile, output folder, options).

* Build the list of bookmarks to export.

* Run the export operation on a background worker (e.g., Python QThread or concurrent.futures thread) to keep the UI responsive.

**FR-29**: The app shall display a progress indicator during export:

* Progress bar showing percentage complete or current/total bookmarks.

* Status text (e.g., “Exporting bookmark X of Y”).

**FR-30**: On completion, the app shall show a summary:

* Total bookmarks processed.

* Total bookmarks successfully exported.

* Total folders created.

* Count of skipped items (invalid URL, existing file, etc.).

* Count of errors.

**FR-31**: The summary shall be viewable in the UI and optionally:

* Copied to clipboard.

* Saved as a text log file.


### 4.9 Error Handling & Reporting

**FR-32**: For file system errors (e.g., permission denied, disk full), the app shall:

* Log the specific error for that node.

* Continue with remaining nodes where possible.

* Indicate clearly in the final summary that not all items were exported.

**FR-33**: For malformed JSON or corrupt Bookmarks file:

* The app shall stop processing and display an error message suggesting:

  * Checking Brave installation.

  * Re-running Brave Sync, etc.

**FR-34**: If the output root path is invalid or not writable:

* The app shall present a blocking error and prevent export start.


### 4.10 Settings & Persistence

**FR-35**: The app shall persist user settings to a config file under the user’s %APPDATA% directory (e.g., via a simple JSON or INI file), including:

* Last selected Brave profile.

* Last used output folder.

* Export options (include root path, overwrite/skip/unique-name, etc.).

* Any custom root-folder renaming (see below).

**FR-36**: On startup, the app shall restore settings and pre-select previously used options where possible.

**FR-37**: If a previously selected profile no longer exists, the app should fall back gracefully to the default profile or prompt the user to choose a new one.


### 4.11 Root Folder Naming / Renaming

**FR-38**: The app shall allow the user to **optionally rename** the three main root folders when exporting:

* Bookmarks Bar

* Other Bookmarks

* Mobile Bookmarks

**FR-39**: The UI shall expose simple text fields or a dialog to map:

* Original root name → Exported root folder name.

**FR-40**: If no custom name is provided, default to Brave’s original root name.


## 5. Non-Functional Requirements

### 5.1 Performance

**NFR-1**: The app should handle at least:

* 10,000 bookmarks and folders within ~5–10 seconds of export under typical SSD conditions, assuming a local profile.

**NFR-2**: The UI should remain responsive during export (no blocking of main Qt event loop).

### 5.2 Reliability

**NFR-3**: Export should be idempotent under “Skip existing” and deterministic under “Overwrite” or “Create unique name”.

**NFR-4**: Partial failures should be tolerated; the app should export what it can and report any failures.

### 5.3 Security & Privacy

**NFR-5**: The app shall not transmit any bookmark data off-device.

**NFR-6**: No external network calls are required for v1 (purely local).

### 5.4 Usability

**NFR-7**: Users should be able to:

* Run the installer or unpack a zip.

* Complete a basic “export all bookmarks” workflow within 1–2 minutes on first use.

**NFR-8**: Errors and warnings should be written in clear, non-technical language where possible.

### 5.5 Maintainability & Extensibility

**NFR-9**: The core logic (parsing and export) should be separated into a Python package/module, distinct from the Qt UI, enabling:

* Unit testing (e.g., with pytest).

* Future CLI wrapper or additional UIs (e.g., TUI or web UI).

**NFR-10**: The app should be structured so that supporting other Chromium-based browsers (Chrome, Edge) is straightforward in a future release (e.g., pluggable “browser provider” abstraction).

**NFR-11**: Code style should follow PEP 8 and be type-annotated (PEP 484) where practical.


## 6. Data Model (Conceptual)

### 6.1 Raw Data Structures (Deserialization Layer)

Modeled as Python dataclasses or plain dicts/lists.

**RawBookmarkFile**

* version: str

* checksum: str

* roots: RawRoots

* meta\_info: dict (optional)

**RawRoots**

* bookmark\_bar: RawFolderNode

* other: RawFolderNode

* mobile: RawFolderNode

* Extra roots map (optional).

**RawNode** (generic node)

* id: str

* name: str

* type: str ("folder" or "url")

* date\_added: str

* guid: str (optional)

* meta\_info: dict (optional)

* url: str (for url type)

* children: list[RawNode] (for folder type)

* date\_modified: str (optional, folders)

### 6.2 Domain Model (Application Logic)

Represented as Python classes / dataclasses.

**BookmarkNode** (abstract)

* id: str

* name: str

* parent: BookmarkFolder | None

* node\_type: enum (Folder, Bookmark)

* root\_kind: enum (BookmarkBar, Other, Mobile, Unknown)

* Computed properties:

  * full\_path\_components: list[str]

  * display\_path: str

**BookmarkFolder** (extends BookmarkNode)

* node\_type = Folder

* children: list[BookmarkNode]

* is\_root\_folder: bool

**BookmarkItem** (extends BookmarkNode)

* node\_type = Bookmark

* url: str

**BraveProfileInfo**

* display\_name: str

* profile\_id: str

* profile\_path: str

* bookmark\_file\_path: str

* bookmark\_roots: BookmarkRootsModel (loaded on demand)

**BookmarkRootsModel**

* bookmark\_bar: BookmarkFolder

* other: BookmarkFolder

* mobile: BookmarkFolder

* all\_roots: list[BookmarkFolder]

### 6.3 Export Model

**ExportOptions**

* output\_root\_path: str

* scope: enum (AllBookmarks, SelectedNodes)

* include\_root\_path: bool

* duplicate\_strategy: enum (Overwrite, Skip, UniqueName)

* max\_file\_name\_length: int (e.g., 120)

* sanitize\_file\_names: bool

* root\_name\_overrides: dict[root_kind → str] (optional)

**ExportTarget**

* node: BookmarkItem

* relative\_folder\_path\_components: list[str]

* file\_name\_without\_extension: str

* resolved\_full\_path: str (final .url path after duplicate handling)

**ExportResult**

* total\_nodes\_considered: int

* total\_bookmarks\_exported: int

* total\_folders\_created: int

* skipped\_invalid\_url: int

* skipped\_existing: int

* errors: list[ExportError]

**ExportError**

* node\_name: str

* url: str

* reason: str

* exception\_details: str (optional)


## 7. UX / UI Flows (Qt/PySide6)

### 7.1 Main Screen Layout (Conceptual)

1. **Header area**

  * App title: “Brave Bookmark Exporter”.

  * Profile selector:

  * QComboBox listing detected Brave profiles by display name.

  * “Browse…” (QPushButton) for custom profile path.

  * “Reload Bookmarks” button.

2. **Left pane: Bookmark Tree**

  * QTreeWidget / QTreeView showing:

  * Bookmarks Bar

  * Other Bookmarks

  * Mobile Bookmarks

  * Checkboxes on each node:

  * Folder or bookmark can be marked for export.

  * Optional search/filter box (QLineEdit) above TreeView.

3. **Right pane: Export Settings**

  * Output folder:

  * QLineEdit for selected path.

  * “Browse…” button.

  * Export scope:

  * Radio buttons:

  * “Export all bookmarks in this profile”

  * “Export only selected folders/bookmarks”

  * Options:

  * “[ ] Include full path from top-level root”

  * Duplicate handling: radio buttons for:

  * Overwrite existing files

  * Skip existing files

  * Create unique names (default)

  * Root-name overrides UI (e.g., button to open a small dialog or inline text fields per root).

  * Buttons:

  * “Export Shortcuts”

  * “Open Output Folder” (enabled after an export)

4. **Bottom area: Status & Log**

  * QProgressBar (hidden when idle).

  * Status text label (e.g., “Ready”, “Exporting 30 of 200…”).

  * Collapsible “Details” area for export summary and recent messages/errors (e.g., QTextEdit in read-only mode).


## 8. System Design & Architecture (Python)

### 8.1 High-Level Modules

1. **profiles.py – BraveProfileDetector**

  * Finds Brave user data directories.

  * Enumerates profile folders.

  * Returns BraveProfileInfo instances.

2. **loader.py – BookmarkFileLoader**

  * Given a BraveProfileInfo, locates and copies the Bookmarks file to a temporary path.

  * Reads JSON and deserializes into RawBookmarkFile.

3. **tree\_builder.py – BookmarkTreeBuilder**

  * Transforms RawBookmarkFileBookmarkRootsModel:

  * Instantiates BookmarkFolder and BookmarkItem.

  * Sets parent-child relationships.

  * Assigns RootKind.

4. **exporter.py – BookmarkExporter**

  * Given:

  * BookmarkRootsModel

  * A set of selected nodes and/or scope == AllBookmarks

  * ExportOptions

  * Produces:

  * On disk: directories and .url files.

  * In memory: ExportResult.

5. **settings.py – SettingsManager**

  * Persist and load configuration (JSON or INI) under %APPDATA%.

6. **ui/ package – Qt UI Layer**

  * main\_window.py – MainWindow class.

  * viewmodels.py – View models / adapters.

  * Connects UI events to core functions via signals/slots.

### 8.2 Threading / Concurrency

* **UI Thread**:

  * Runs the Qt event loop.

* **Worker Thread**:

  * Export process (and possibly bookmark loading) runs via QThread or QThreadPool with QRunnable, or concurrent.futures.ThreadPoolExecutor integrated with Qt signals.

* Progress and completion events are signalled back to the main thread safely via Qt signals/slots.


## 9. Risks & Mitigations

**Risk 1**: Brave data file format changes in future.

*Mitigation*: Keep deserialization tolerant, log mismatches clearly.

**Risk 2**: Long path issues on systems where long paths are not enabled.

*Mitigation*: Limit filename component length; detect and log path-too-long errors; warn in summary.

**Risk 3**: Multiple bookmarks with identical names in the same folder.

*Mitigation*: Provide explicit duplicate strategies; default “Create unique name” to avoid data loss.

**Risk 4**: User confusion about “include full path from root” behavior.

*Mitigation*: Provide concise tooltip/description and a small preview example.

**Risk 5**: Python runtime / antivirus false positives on packaged EXE.

*Mitigation*: Sign installer where possible; document that the app is offline/local; consider distributing both raw .py version and packaged EXE.


## 10. Milestones & Phases

### Phase 1 – Core Engine (Python Library)

* Implement:

  * RawBookmarkFile deserialization.

  * BookmarkTreeBuilder.

  * BookmarkExporter with duplicate strategies and root renaming.

* Minimal CLI or script harness for testing.

* Unit tests for parsing and export mapping.

### Phase 2 – Basic Qt UI

* Implement:

  * Profile detection UI.

  * Bookmark TreeView (read-only).

  * Output path selection.

  * “Export All” button.

* Wire up export engine; show basic progress.

### Phase 3 – Full Selection & Options

* Add:

  * Tree node checkboxes (folder + bookmark).

  * Export scope options (all vs selected).

  * Include root path toggle.

  * Duplicate-handling options (overwrite/skip/unique-name; default unique-name).

  * Root renaming UI.

### Phase 4 – Polish & Packaging

* Add:

  * Settings persistence.

  * Improved error messages and summary/log file.

  * Application icon and simple About box.

* Package:

  * Build Windows EXE with PyInstaller.

  * Optionally create an MSI or simple installer.