Skip to content

Commit 2f468be

Browse files
authored
feature: rust rewrite & gui (#54)
* feat: rust rewrite * fix: scroll by notes * fix: remove unused logs * feat: update check and style changes * fix: few improvements * fix: image scraping issues * move files to appropriate directory * feat: about popup * feat: gh workflow * fix: adjust gh runner description * fix: modify NSIS installer
1 parent 6df4b7f commit 2f468be

267 files changed

Lines changed: 23234 additions & 1293 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.codex/AGENTS.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
## Xiaomi Note Exporter (Tauri + Vue)
2+
3+
### Purpose
4+
5+
- Desktop app that exports Xiaomi/Mi Cloud notes to Markdown, with optional image downloads.
6+
- Supports browsing past export sessions, viewing/editing exported files, and converting Markdown exports to JSON.
7+
8+
### Tech Stack
9+
10+
- Frontend: Vue 3 + TypeScript + Vite, Pinia, Vue Router (hash).
11+
- UI: Tailwind CSS v4, shadcn-vue components, md-editor-v3.
12+
- Backend: Tauri v2 (Rust), SQLite (rusqlite), reqwest, chrono.
13+
14+
### How It Works (High Level)
15+
16+
1. User starts an export from the Export view.
17+
2. Tauri opens a Mi Cloud auth window and injects a scraping script.
18+
3. Scraper reports progress/events back to the UI via Tauri events.
19+
4. Notes are written to Markdown (split files or one combined file) and images saved optionally.
20+
5. Session metadata is stored in SQLite for history and viewer features.
21+
22+
### Frontend Structure
23+
24+
- App shell: [src/App.vue](src/App.vue)
25+
- Renders AppHeader/AppSidebar and RouterView.
26+
- Initializes export event listeners on mount.
27+
- Routing: [src/router/index.ts](src/router/index.ts)
28+
- Routes: Export, History, Converter, Viewer, Settings.
29+
- API bridge: [src/lib/api.ts](src/lib/api.ts)
30+
- Invokes Tauri commands (export, sessions, files, settings, updates, converter).
31+
- State stores:
32+
- Export: [src/stores/export.ts](src/stores/export.ts) (progress, events, logs).
33+
- Sessions: [src/stores/sessions.ts](src/stores/sessions.ts) (history list).
34+
- Settings: [src/stores/settings.ts](src/stores/settings.ts) (theme, default export dir).
35+
- Views:
36+
- Export: [src/views/export-view.vue](src/views/export-view.vue)
37+
- History: [src/views/history-view.vue](src/views/history-view.vue)
38+
- Viewer: [src/views/viewer-view.vue](src/views/viewer-view.vue)
39+
- Converter: [src/views/converter-view.vue](src/views/converter-view.vue)
40+
- Settings: [src/views/settings-view.vue](src/views/settings-view.vue)
41+
42+
### Backend Structure (Tauri)
43+
44+
- Entry point: [src-tauri/src/main.rs](src-tauri/src/main.rs)
45+
- App bootstrap: [src-tauri/src/lib.rs](src-tauri/src/lib.rs)
46+
- Creates app data dirs, sessions DB, settings file.
47+
- Registers commands and plugins (dialog, opener).
48+
- State: [src-tauri/src/state.rs](src-tauri/src/state.rs)
49+
- Tracks current export session and metadata.
50+
- Models: [src-tauri/src/models.rs](src-tauri/src/models.rs)
51+
- Session, settings, event payloads, file entries.
52+
53+
### Tauri Commands (JS invoke names)
54+
55+
- Export flow: `start_export`, `cancel_export`, `report_export_total`, `append_scraped_note`,
56+
`finish_scrape`, `fail_scrape`, `download_scrape_image`.
57+
- Files: `read_export_file`, `write_export_file`, `list_export_files`, `open_in_explorer`.
58+
- Sessions: `get_sessions`, `get_session`, `delete_session`.
59+
- Converter: `convert_to_json`.
60+
- Settings: `get_app_settings`, `update_app_settings`.
61+
- Updates: `check_latest_release_version`.
62+
63+
### Tauri Events Emitted to Frontend
64+
65+
- `export:progress` (ExportProgressEvent)
66+
- `export:complete` (ExportCompleteEvent)
67+
- `export:error` (ExportErrorEvent)
68+
69+
### Export Details
70+
71+
- Output paths are timestamped:
72+
- Split mode: folder `exported_notes_<stamp>/` with note files.
73+
- Single file mode: `exported_notes_<stamp>.md`.
74+
- Optional images saved to `images_<stamp>/` or `exported_notes_<stamp>/images/`.
75+
- Supported image hosts are allowlisted in Rust (Mi Cloud domains only).
76+
77+
### Data Storage
78+
79+
- SQLite DB at app data dir: `sessions.db`.
80+
- Settings JSON at app data dir: `settings.json`.
81+
- Migrations: [src-tauri/src/db/migrations.rs](src-tauri/src/db/migrations.rs).
82+
83+
### Markdown Formatting
84+
85+
- Notes are written via [src-tauri/src/services/markdown.rs](src-tauri/src/services/markdown.rs).
86+
- Title falls back to "Untitled Note".
87+
- Created date is appended as `*Created at: dd/MM/YYYY HH:mm*`.
88+
89+
### Converter
90+
91+
- Converts exported Markdown into JSON via `convert_to_json` (Rust service).
92+
- UI surface in [src/views/converter-view.vue](src/views/converter-view.vue).
93+
94+
### Build and Run
95+
96+
- Frontend dev: `npm run dev`
97+
- Frontend build: `npm run build`
98+
- Tauri dev: `npm run tauri dev`
99+
- Tauri build: `npm run tauri build`
100+
101+
### Key Config Files
102+
103+
- Vite: [vite.config.ts](vite.config.ts)
104+
- Tauri: [src-tauri/tauri.conf.json](src-tauri/tauri.conf.json)
105+
- Package deps: [package.json](package.json)
106+
- Rust deps: [src-tauri/Cargo.toml](src-tauri/Cargo.toml)
107+
108+
### Notes for Contributors
109+
110+
- Export workflow depends on the embedded scraper script: [src-tauri/src/services/scripts/scraper.js](src-tauri/src/services/scripts/scraper.js)
111+
- Theme is applied from settings on boot in [src/stores/settings.ts](src/stores/settings.ts).
112+
- Viewer uses `md-editor-v3` and writes edits back via `write_export_file`.
113+
- MCP server: use the shadcn-vue MCP server to lookup component docs/props since these components are used across the app.

.github/workflows/publish.yml

Lines changed: 100 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,78 +9,134 @@ on:
99
workflow_dispatch:
1010
inputs:
1111
version:
12-
description: "Version number (e.g., 1.0.0)"
12+
description: "Version number (e.g., 2.0.0)"
1313
required: true
1414
type: string
15+
platform:
16+
description: "Platform to ship"
17+
required: true
18+
type: choice
19+
options:
20+
- windows
21+
- linux
22+
- macos
1523

1624
jobs:
17-
build-and-test:
18-
runs-on: windows-latest
25+
build-installers:
26+
name: Build installer (${{ inputs.platform }})
27+
runs-on: ${{ inputs.platform == 'windows' && 'windows-latest' || inputs.platform == 'linux' && 'ubuntu-24.04' || 'macos-15' }}
1928
steps:
20-
- uses: actions/checkout@v3
29+
- uses: actions/checkout@v4
2130

22-
- name: Setup .NET
23-
uses: actions/setup-dotnet@v2
31+
- name: Install Linux dependencies
32+
if: inputs.platform == 'linux'
33+
run: |
34+
sudo apt-get update
35+
sudo apt-get install -y \
36+
libwebkit2gtk-4.1-dev \
37+
libappindicator3-dev \
38+
librsvg2-dev \
39+
patchelf
40+
41+
- name: Setup Node.js
42+
uses: actions/setup-node@v4
2443
with:
25-
dotnet-version: 8.0.x
26-
27-
- name: Restore dependencies
28-
run: dotnet restore
29-
30-
- name: Build
31-
run: dotnet build --no-restore
44+
node-version: lts/*
45+
cache: npm
3246

33-
- name: Test
34-
run: dotnet test --no-build --verbosity normal
47+
- name: Install Rust stable
48+
if: inputs.platform != 'macos'
49+
uses: dtolnay/rust-toolchain@stable
3550

36-
publish:
37-
runs-on: windows-latest
38-
needs: build-and-test
39-
steps:
40-
- uses: actions/checkout@v3
41-
42-
- name: Setup .NET
43-
uses: actions/setup-dotnet@v2
51+
- name: Install Rust stable (macOS Apple Silicon target)
52+
if: inputs.platform == 'macos'
53+
uses: dtolnay/rust-toolchain@stable
4454
with:
45-
dotnet-version: 8.0.x
55+
targets: aarch64-apple-darwin
4656

47-
- name: Restore dependencies
48-
run: dotnet restore
57+
- name: Rust cache
58+
uses: swatinem/rust-cache@v2.8.2
59+
with:
60+
workspaces: ./src-tauri -> target
4961

50-
- name: Publish
51-
run: dotnet publish -c Release -p:PublishProfile=FolderProfile -p:PublishDir=${{ github.workspace }}/publish
62+
- name: Install frontend dependencies
63+
run: npm ci
5264

53-
- name: Upload publish artifact
54-
uses: actions/upload-artifact@v6
65+
- name: Build Tauri installer (Windows NSIS only)
66+
if: inputs.platform == 'windows'
67+
uses: tauri-apps/tauri-action@v0.6.1
68+
env:
69+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5570
with:
56-
name: publish-folder
57-
path: ${{ github.workspace }}/publish
71+
uploadWorkflowArtifacts: true
72+
args: --bundles nsis
73+
74+
- name: Build Tauri installer
75+
if: inputs.platform != 'windows'
76+
uses: tauri-apps/tauri-action@v0.6.1
77+
env:
78+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
79+
with:
80+
uploadWorkflowArtifacts: true
5881

5982
create-release:
6083
runs-on: windows-latest
61-
needs: publish
84+
needs: build-installers
6285
steps:
63-
- name: Download publish artifact
64-
uses: actions/download-artifact@v6
86+
- name: Download build artifacts
87+
uses: actions/download-artifact@v7
6588
with:
66-
name: publish-folder
67-
path: ${{ github.workspace }}/publish
89+
path: ${{ github.workspace }}/release-assets
6890

69-
- name: Create ZIP file
70-
run: |
71-
Compress-Archive -Path ./publish/* -DestinationPath ./release-win-x86.zip -Force
91+
- name: Collect installer artifacts
92+
id: collect-installers
7293
shell: pwsh
94+
run: |
95+
$root = Join-Path $env:GITHUB_WORKSPACE "release-assets"
96+
$platform = "${{ inputs.platform }}"
97+
$patterns = switch ($platform) {
98+
"windows" { @("*.exe") }
99+
"linux" { @("*.deb", "*.rpm", "*.AppImage") }
100+
"macos" { @("*.dmg", "*.pkg", "*.app.tar.gz") }
101+
default { @() }
102+
}
103+
104+
if ($patterns.Count -eq 0) {
105+
throw "Unsupported platform selection: $platform"
106+
}
107+
108+
$files = foreach ($pattern in $patterns) {
109+
Get-ChildItem -Path $root -Recurse -File -Filter $pattern -ErrorAction SilentlyContinue
110+
}
111+
112+
$files = $files | Sort-Object -Property FullName -Unique
113+
114+
if (-not $files -or $files.Count -eq 0) {
115+
throw "No installer artifacts found under $root for platform $platform."
116+
}
117+
118+
$artifactList = ($files | ForEach-Object { $_.FullName }) -join ","
119+
$attestationSubjects = ($files | ForEach-Object { $_.FullName }) -join "`n"
120+
121+
"artifacts=$artifactList" >> $env:GITHUB_OUTPUT
122+
"subject_path<<EOF" >> $env:GITHUB_OUTPUT
123+
$attestationSubjects >> $env:GITHUB_OUTPUT
124+
"EOF" >> $env:GITHUB_OUTPUT
73125
74126
- name: Attest release artifact
75-
uses: actions/attest-build-provenance@v3.1.0
127+
uses: actions/attest-build-provenance@v3.2.0
76128
with:
77-
subject-path: ./release-win-x86.zip
129+
subject-path: ${{ steps.collect-installers.outputs.subject_path }}
78130

79131
- name: Create Draft Release
80-
uses: ncipollo/release-action@v1
132+
uses: ncipollo/release-action@v1.20.0
81133
with:
134+
commit: ${{ github.sha }}
82135
tag: v${{ inputs.version }}
83136
name: Release v${{ inputs.version }}
137+
allowUpdates: true
138+
updateOnlyUnreleased: true
139+
replacesArtifacts: true
84140
draft: true
85-
artifacts: ./release-win-x86.zip
141+
artifacts: ${{ steps.collect-installers.outputs.artifacts }}
86142
token: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
1-
.git
2-
.vs/
3-
xiaomiNoteExporter/bin
4-
xiaomiNoteExporter/obj
5-
xiaomiNoteExporter.Gui/
6-
*.user
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
25+
26+
.vs/

.vscode/extensions.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"recommendations": [
3+
"Vue.volar",
4+
"tauri-apps.tauri-vscode",
5+
"rust-lang.rust-analyzer"
6+
]
7+
}

0 commit comments

Comments
 (0)