Covers all metadata sources from Type 1/2 ELF headers through desktop entries to AppStream XML, with schema, parser, and UI display plans.
6.6 KiB
AppImage Comprehensive Metadata Extraction and Display
Goal
Extract ALL available metadata from AppImage files - from the oldest Type 1 format to the newest Type 2 with AppStream XML - and display it comprehensively in the overview tab of the detail view.
Background: All AppImage Metadata Sources
1. ELF Binary Header (Type 1 and Type 2)
- Magic bytes at offset 8:
AI\x01(Type 1) orAI\x02(Type 2) - Architecture from
e_machineat offset 18
2. Type 1: ISO 9660 Volume Descriptor
- Update info at fixed offset 33651 (512 bytes)
3. Type 2: ELF Sections
.upd_info(1024 bytes) - update transport (zsync, GitHub releases, etc.).sha256_sig(1024 bytes) - GPG digital signature.sig_key(8192 bytes) - public key for signature verification
4. Desktop Entry File (.desktop)
Standard freedesktop fields:
Name,GenericName,Comment,Icon,Exec,CategoriesKeywords,MimeType,StartupWMClass,TerminalActionswith[Desktop Action <name>]sections- AppImage-specific:
X-AppImage-Version,X-AppImage-Name,X-AppImage-Arch
5. AppStream / AppData XML (richest source)
Located at usr/share/metainfo/*.xml or usr/share/appdata/*.xml:
<id>- reverse-DNS identifier<name>- localized app name<summary>- one-line description<description>- full rich-text description<developer>- developer/organization<project_license>- SPDX license<project_group>- umbrella project (GNOME, KDE, etc.)<url type="...">- homepage, bugtracker, donation, help, vcs-browser, contribute<keywords>- search terms<categories>- menu categories<screenshots>- screenshot URLs with captions<releases>- version history with dates and changelogs<content_rating type="oars-1.1">- age rating<provides>- MIME types, binaries, D-Bus interfaces<branding>- theme colors
6. Icons (already handled)
.DirIcon, root-level PNG/SVG,usr/share/icons/hierarchy
7. Digital Signatures (Type 2)
- GPG signature in
.sha256_sigELF section - Verifiable with embedded public key
Approach
Parse everything at analysis time and store in the database (Approach A). This matches the existing architecture where run_background_analysis() populates the DB and the UI reads from AppImageRecord.
Database Schema (Migration v9)
16 new columns on appimages:
| Column | Type | Default | Description |
|---|---|---|---|
appstream_id |
TEXT | NULL | Reverse-DNS ID (e.g. org.kde.krita) |
appstream_description |
TEXT | NULL | Rich description (paragraphs joined with newlines) |
generic_name |
TEXT | NULL | Generic descriptor ("Web Browser") |
license |
TEXT | NULL | SPDX license expression |
homepage_url |
TEXT | NULL | Project website |
bugtracker_url |
TEXT | NULL | Bug reporting URL |
donation_url |
TEXT | NULL | Donation page |
help_url |
TEXT | NULL | Documentation URL |
vcs_url |
TEXT | NULL | Source code URL |
keywords |
TEXT | NULL | Comma-separated keywords |
mime_types |
TEXT | NULL | Semicolon-separated MIME types |
content_rating |
TEXT | NULL | Summarized OARS rating |
project_group |
TEXT | NULL | Umbrella project |
release_history |
TEXT | NULL | JSON array of recent releases |
desktop_actions |
TEXT | NULL | JSON array of desktop actions |
has_signature |
INTEGER | 0 | Whether AppImage has GPG signature |
New Module: AppStream XML Parser
File: src/core/appstream.rs
Uses quick-xml crate (pure Rust, lightweight).
Key types:
AppStreamMetadata
id: Option<String>
name: Option<String>
summary: Option<String>
description: Option<String>
developer: Option<String>
project_license: Option<String>
project_group: Option<String>
urls: HashMap<String, String>
keywords: Vec<String>
categories: Vec<String>
content_rating_summary: Option<String>
releases: Vec<ReleaseInfo>
mime_types: Vec<String>
ReleaseInfo
version: String
date: Option<String>
description: Option<String>
Parser function: parse_appstream_file(path: &Path) -> Option<AppStreamMetadata>
- Walks XML events, extracts all fields
- Strips HTML from
<description>(joins<p>with newlines,<li>with bullets) - Caps releases at 10 most recent
- Summarizes OARS content rating into a single label
Extended Desktop Entry Parsing
Update DesktopEntryFields in inspector.rs:
- Add
generic_name,keywords,mime_types,terminal,actions,x_appimage_name - Parse
[Desktop Action <name>]sections for action names and exec commands
Inspector + Analysis Pipeline
AppImageMetadatastruct gains all new fieldsinspect_appimage()looks for AppStream XML after extraction, parses it, merges into metadata (AppStream takes priority for overlapping fields)run_background_analysis()stores new fields viadb.update_appstream_metadata()- Signature detection: read ELF
.sha256_sigsection, check if non-empty
Overview Tab UI Layout
Groups in order (each only shown when data exists):
About (new)
- App ID, Generic name, Developer, License, Project group
Description (new)
- Full multi-paragraph AppStream description
Links (new)
- Homepage, Bug tracker, Source code, Documentation, Donate
- Each row clickable via
gtk::UriLauncher
Updates (existing, unchanged)
Release History (new)
- Recent releases with version, date, description
- Uses
adw::ExpanderRowfor entries with descriptions
Usage (existing, unchanged)
Capabilities (new)
- Keywords, MIME types, Content rating, Desktop actions
File Information (existing, extended)
- Add "Signature: Signed / Not signed" row
Dependencies
Add to Cargo.toml:
quick-xml = "0.37"
Files Modified
| File | Changes |
|---|---|
Cargo.toml |
Add quick-xml |
src/core/mod.rs |
Add pub mod appstream; |
src/core/appstream.rs |
New - AppStream XML parser |
src/core/database.rs |
Migration v9, new columns, update_appstream_metadata() |
src/core/inspector.rs |
Extended desktop parsing, AppStream integration, signature detection |
src/core/analysis.rs |
Store new metadata fields |
src/ui/detail_view.rs |
Redesigned overview tab with all new groups |
Verification
cargo buildcompiles without errors- AppImages with AppStream XML show full metadata (developer, license, URLs, releases)
- AppImages without AppStream XML still show desktop entry fields (graceful degradation)
- URL links open in browser
- Release history is scrollable/expandable
- Empty groups are hidden
- Re-scanning an app picks up newly available metadata