TC direct access to Edge's Favorites Bar

Here you can propose new features, make suggestions etc.

Moderators: petermad, Stefan2, white, Hacker

Post Reply
User avatar
gezgin35689
Junior Member
Junior Member
Posts: 2
Joined: 2018-06-19, 14:58 UTC

TC direct access to Edge's Favorites Bar

Post by *gezgin35689 »

How hard would it be for TC to access and display the contents of Edge's Favorites Bar directly? By "directly" I mean without starting up Edge first. Ideally, access would be from a button placed on TC's Default Bar and when clicked, the Favorites Bar would be displayed as a tree of folders, subfolders, and icons the same way that Edge does. I think this would be useful because TC is always running on my machine but Edge is only running when I start it, so this would save a step. -- Bob
User avatar
ZoSTeR
Power Member
Power Member
Posts: 1060
Joined: 2004-07-29, 11:00 UTC

Re: TC direct access to Edge's Favorites Bar

Post by *ZoSTeR »

 
This is not quite trivial since the good old IE11 Favorites folder is not used anymore.
The Edge bookmarks consist of a "Bookmarks" JSON file and a "Favicons" SQLite database.
To have a "live" view of those would require a fully-fledged plugin but a workaround would be to export the bookmarks to a folder with .lnk files.
That is what the following PowerShell script does.

Before trying to integrate it into TC make sure it runs on its own.

- Save the script to a new folder e.g. "C:\EdgeBookmarks" as "Export-EdgeBookmarks.ps1".
- Download and extract "sqlite3.exe" into the script folder from https://www.sqlite.org/download.html sqlite-tools-win-x64-xxxxxxx.zip
- Open Windows PowerShell ISE and run the script.

It should recreate the Bookmarks folder structure with .lnk files and the associated fav icons in the script subfolder "Edge_Bookmarks_Export_LNK".

Btw this script could be easily adapted to work with Google Chrome.

Disclaimer: product may contain some vibe coding ;)

Export-EdgeBookmarks.ps1

Code: Select all

# Version 0.1
# Date: 2026-02-06
#
# Download, extract and copy sqlite3.exe into the script folder from:
# https://www.sqlite.org/download.html
# sqlite-tools-win-x64-xxxxxxx.zip

cls

# ================= CONFIG =================
$SqliteExe   = Join-Path $PSScriptRoot "sqlite3.exe"
$EdgeProfile = "Default"
$ExportRoot  = Join-Path $PSScriptRoot "Edge_Bookmarks_Export_LNK"
# =========================================

[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

$EdgeDataPath = "$env:LOCALAPPDATA\Microsoft\Edge\User Data\$EdgeProfile"
$LiveBookmarks = Join-Path $EdgeDataPath "Bookmarks"
$LiveFavicons  = Join-Path $EdgeDataPath "Favicons"

foreach ($p in @($SqliteExe, $LiveBookmarks, $LiveFavicons)) {
    if (!(Test-Path $p)) { Write-Error "Missing required file: $p"; exit 1 }
}

# ---- Create export folders ----
New-Item -ItemType Directory -Force -Path $ExportRoot | Out-Null
$IconRoot    = Join-Path $ExportRoot "_icons"
$IconPngRoot = Join-Path $ExportRoot "_icons_png"
New-Item -ItemType Directory -Force -Path $IconRoot | Out-Null
New-Item -ItemType Directory -Force -Path $IconPngRoot | Out-Null

# ================= TEMP COPIES =================
$TempDir = Join-Path $env:TEMP "EdgeBookmarkExport"
New-Item -ItemType Directory -Force -Path $TempDir | Out-Null

$TempBookmarks = Join-Path $TempDir "Bookmarks.json"
$TempFavicons  = Join-Path $TempDir "Favicons.db"

Copy-Item $LiveBookmarks $TempBookmarks -Force
Copy-Item $LiveFavicons  $TempFavicons  -Force

# ================= LOAD BOOKMARKS (UTF-8!) =================
$Bookmarks = Get-Content $TempBookmarks -Raw -Encoding UTF8 | ConvertFrom-Json
$Global:ProcessedDomains = @{}

# ---------------- UTILITY FUNCTIONS ----------------
function Get-Domain($url) { try { ([Uri]$url).Host.ToLower() } catch { "" } }
function Safe-Name($s) { $s -replace '[<>:"/\\|?*]', '_' -replace '^\s+|\s+$','' }

# ---------------- PNG → ICO (minimal ICO writer) ----------------
function Convert-PngToIco {
    param([string]$PngPath, [string]$IcoPath)

    if (-not (Test-Path $PngPath)) { return }

    try {
        $pngBytes = [System.IO.File]::ReadAllBytes($PngPath)
        $fs = [System.IO.File]::Open($IcoPath, [System.IO.FileMode]::Create)

        # ICO header: 6 bytes
        $fs.WriteByte(0); $fs.WriteByte(0) # Reserved
        $fs.WriteByte(1); $fs.WriteByte(0) # Image type (icon)
        $fs.WriteByte(1); $fs.WriteByte(0) # Number of images

        # Directory entry: 16 bytes
        $fs.WriteByte(32)                   # Width
        $fs.WriteByte(32)                   # Height
        $fs.WriteByte(0)                    # Colors
        $fs.WriteByte(0)                    # Reserved
        $fs.WriteByte(1); $fs.WriteByte(0)  # Color planes
        $fs.WriteByte(32); $fs.WriteByte(0) # Bits per pixel
        $size = [BitConverter]::GetBytes($pngBytes.Length)
        $fs.Write($size,0,4)                # Size of image data
        $offset = 6 + 16                    # header + dir entry
        $fs.Write([BitConverter]::GetBytes($offset),0,4) # Offset to image data

        # Write PNG bytes
        $fs.Write($pngBytes,0,$pngBytes.Length)
        $fs.Close()
    } catch {
        Write-Warning "Failed to create ICO: $PngPath"
    }
}

# ---------------- Extract Favicon ----------------
function Extract-Favicon($PageUrl) {
    $domain = Get-Domain $PageUrl
    if ([string]::IsNullOrEmpty($domain)) { Write-Warning "Cannot get domain for $PageUrl"; return $null }
    if ($ProcessedDomains.ContainsKey($domain)) { return $ProcessedDomains[$domain] }

    $PngPath = Join-Path $IconPngRoot ($domain + ".png")
    $IcoPath = Join-Path $IconRoot ($domain + ".ico")

    Write-Host "[DEBUG] Extracting favicon for: $PageUrl → $PngPath"

    $SqlPath = $PngPath -replace '\\','/'
    $SqlScript = @"
SELECT writefile(
    '$SqlPath',
    favicon_bitmaps.image_data
)
FROM icon_mapping
JOIN favicons ON icon_mapping.icon_id = favicons.id
JOIN favicon_bitmaps ON favicon_bitmaps.icon_id = favicons.id
WHERE icon_mapping.page_url LIKE '$PageUrl%'
AND favicon_bitmaps.width = (
    SELECT MAX(width)
    FROM favicon_bitmaps fb2
    WHERE fb2.icon_id = favicons.id
)
LIMIT 1;
"@
    & $SqliteExe $TempFavicons $SqlScript

    if (Test-Path $PngPath) {
        $size = (Get-Item $PngPath).Length
        Write-Host "[DEBUG] PNG extracted ($size bytes)"
        if ($size -gt 0) {
            Convert-PngToIco -PngPath $PngPath -IcoPath $IcoPath
            $ProcessedDomains[$domain] = $IcoPath
            Write-Host "[DEBUG] ICO created: $IcoPath"
            return $IcoPath
        } else {
            Write-Warning "PNG file is empty for $PageUrl"; Remove-Item $PngPath -Force; return $null
        }
    } else {
        Write-Warning "No PNG file created for $PageUrl"; return $null
    }
}

# ---------------- Create .lnk ----------------
function Create-Shortcut {
    param([string]$TargetUrl, [string]$ShortcutPath, [string]$IconPath)
    $WshShell = New-Object -ComObject WScript.Shell
    $Shortcut = $WshShell.CreateShortcut($ShortcutPath)
    $Shortcut.TargetPath = $TargetUrl
    if (![string]::IsNullOrEmpty($IconPath) -and (Test-Path $IconPath)) { $Shortcut.IconLocation = $IconPath }
    $Shortcut.Save()
}

# ---------------- Export Bookmarks ----------------
function Export-BookmarkNode {
    param($Node, $Path)
    foreach ($Child in $Node.children) {
        if ($Child.type -eq "folder") {
            $FolderName = Safe-Name $Child.name
            $NewPath = Join-Path $Path $FolderName
            New-Item -ItemType Directory -Force -Path $NewPath | Out-Null
            Export-BookmarkNode $Child $NewPath
        }
        elseif ($Child.type -eq "url") {
            $Name = Safe-Name $Child.name
            $Url  = $Child.url
            $IconPath = Extract-Favicon $Url
            $LnkFile  = Join-Path $Path "$Name.lnk"
            Create-Shortcut -TargetUrl $Url -ShortcutPath $LnkFile -IconPath $IconPath
        }
    }
}

Export-BookmarkNode $Bookmarks.roots.bookmark_bar $ExportRoot
Export-BookmarkNode $Bookmarks.roots.other        $ExportRoot
Export-BookmarkNode $Bookmarks.roots.synced       $ExportRoot

# ---------------- CLEANUP ----------------
Remove-Item $TempDir -Recurse -Force

Write-Host "[OK] Bookmarks exported successfully."
Write-Host "Export folder: $ExportRoot"
Write-Host "PNG favicons: $IconPngRoot"
Write-Host "ICO icons: $IconRoot"
User avatar
Native2904
Senior Member
Senior Member
Posts: 281
Joined: 2014-01-30, 14:23 UTC
Location: Aachen

Re: TC direct access to Edge's Favorites Bar

Post by *Native2904 »

2 ZoSTeR
Very interesting approach!
I have one question though: when new bookmarks are added, does the script need to be run again each time to pick them up?
Glückauf
#270101 Single user licence.
Total Commander 64-bit – latest version – Windows 11 Pro 24H2
User avatar
ZoSTeR
Power Member
Power Member
Posts: 1060
Joined: 2004-07-29, 11:00 UTC

Re: TC direct access to Edge's Favorites Bar

Post by *ZoSTeR »

Native2904 wrote: 2026-02-06, 21:01 UTC when new bookmarks are added, does the script need to be run again each time to pick them up?
Yes, the script would have to run again. This could be automated with a scheduled task and optimized to only extract new bookmarks or you just put i on a TC button with (run script & cd EdgeBookmarks).
Post Reply