litemm 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. litemm-0.1.0/.gitignore +15 -0
  2. litemm-0.1.0/.python-version +1 -0
  3. litemm-0.1.0/PKG-INFO +356 -0
  4. litemm-0.1.0/README.md +333 -0
  5. litemm-0.1.0/package-lock.json +119 -0
  6. litemm-0.1.0/package.json +8 -0
  7. litemm-0.1.0/pyproject.toml +54 -0
  8. litemm-0.1.0/src/mm/__init__.py +9 -0
  9. litemm-0.1.0/src/mm/_version.py +34 -0
  10. litemm-0.1.0/src/mm/cli/__init__.py +82 -0
  11. litemm-0.1.0/src/mm/cli/_utils.py +210 -0
  12. litemm-0.1.0/src/mm/cli/config_cmd.py +53 -0
  13. litemm-0.1.0/src/mm/cli/db/__init__.py +127 -0
  14. litemm-0.1.0/src/mm/cli/db/clean.py +71 -0
  15. litemm-0.1.0/src/mm/cli/db/stats.py +310 -0
  16. litemm-0.1.0/src/mm/cli/db/sync.py +108 -0
  17. litemm-0.1.0/src/mm/cli/dedup.py +55 -0
  18. litemm-0.1.0/src/mm/cli/geo.py +61 -0
  19. litemm-0.1.0/src/mm/cli/importer.py +104 -0
  20. litemm-0.1.0/src/mm/cli/info.py +63 -0
  21. litemm-0.1.0/src/mm/cli/init.py +64 -0
  22. litemm-0.1.0/src/mm/cli/search.py +94 -0
  23. litemm-0.1.0/src/mm/cli/server.py +56 -0
  24. litemm-0.1.0/src/mm/config.py +208 -0
  25. litemm-0.1.0/src/mm/core/__init__.py +1 -0
  26. litemm-0.1.0/src/mm/core/dedup.py +44 -0
  27. litemm-0.1.0/src/mm/core/embeddings.py +143 -0
  28. litemm-0.1.0/src/mm/core/geocoding.py +427 -0
  29. litemm-0.1.0/src/mm/core/importer.py +138 -0
  30. litemm-0.1.0/src/mm/core/metadata.py +318 -0
  31. litemm-0.1.0/src/mm/core/scanner.py +155 -0
  32. litemm-0.1.0/src/mm/core/tagger.py +144 -0
  33. litemm-0.1.0/src/mm/core/thumbnail.py +275 -0
  34. litemm-0.1.0/src/mm/db/__init__.py +5 -0
  35. litemm-0.1.0/src/mm/db/_seed.py +170 -0
  36. litemm-0.1.0/src/mm/db/async_repository.py +68 -0
  37. litemm-0.1.0/src/mm/db/dto.py +76 -0
  38. litemm-0.1.0/src/mm/db/helpers.py +126 -0
  39. litemm-0.1.0/src/mm/db/mixins/__init__.py +11 -0
  40. litemm-0.1.0/src/mm/db/mixins/_albums.py +98 -0
  41. litemm-0.1.0/src/mm/db/mixins/_cli.py +275 -0
  42. litemm-0.1.0/src/mm/db/mixins/_config.py +53 -0
  43. litemm-0.1.0/src/mm/db/mixins/_media.py +240 -0
  44. litemm-0.1.0/src/mm/db/mixins/_metadata.py +63 -0
  45. litemm-0.1.0/src/mm/db/mixins/_smart_albums.py +185 -0
  46. litemm-0.1.0/src/mm/db/mixins/_stats.py +393 -0
  47. litemm-0.1.0/src/mm/db/mixins/_tags.py +110 -0
  48. litemm-0.1.0/src/mm/db/mixins/_users.py +85 -0
  49. litemm-0.1.0/src/mm/db/models.py +228 -0
  50. litemm-0.1.0/src/mm/db/sync_repo.py +41 -0
  51. litemm-0.1.0/src/mm/db/vector_store.py +102 -0
  52. litemm-0.1.0/src/mm/server/__init__.py +0 -0
  53. litemm-0.1.0/src/mm/server/app.py +105 -0
  54. litemm-0.1.0/src/mm/server/dependencies.py +140 -0
  55. litemm-0.1.0/src/mm/server/routers/albums.py +81 -0
  56. litemm-0.1.0/src/mm/server/routers/auth.py +98 -0
  57. litemm-0.1.0/src/mm/server/routers/batch.py +56 -0
  58. litemm-0.1.0/src/mm/server/routers/library.py +136 -0
  59. litemm-0.1.0/src/mm/server/routers/media.py +318 -0
  60. litemm-0.1.0/src/mm/server/routers/smart_albums.py +124 -0
  61. litemm-0.1.0/src/mm/server/routers/stats.py +63 -0
  62. litemm-0.1.0/src/mm/server/routers/tags.py +44 -0
  63. litemm-0.1.0/src/mm/server/routers/users.py +59 -0
  64. litemm-0.1.0/src/mm/server/schemas.py +203 -0
  65. litemm-0.1.0/src/mm/server/smart_albums.py +447 -0
  66. litemm-0.1.0/src/mm/server/utils.py +94 -0
  67. litemm-0.1.0/tests/conftest.py +21 -0
  68. litemm-0.1.0/tests/test_dedup.py +77 -0
  69. litemm-0.1.0/tests/test_repository.py +77 -0
  70. litemm-0.1.0/tests/test_scanner.py +40 -0
  71. litemm-0.1.0/uv.lock +2411 -0
  72. litemm-0.1.0/web/.gitignore +24 -0
  73. litemm-0.1.0/web/README.md +73 -0
  74. litemm-0.1.0/web/eslint.config.js +23 -0
  75. litemm-0.1.0/web/index.html +18 -0
  76. litemm-0.1.0/web/package-lock.json +4545 -0
  77. litemm-0.1.0/web/package.json +42 -0
  78. litemm-0.1.0/web/public/vite.svg +1 -0
  79. litemm-0.1.0/web/src/App.tsx +38 -0
  80. litemm-0.1.0/web/src/api/client.ts +28 -0
  81. litemm-0.1.0/web/src/api/types.ts +136 -0
  82. litemm-0.1.0/web/src/components/album-card.tsx +67 -0
  83. litemm-0.1.0/web/src/components/auth-image.tsx +43 -0
  84. litemm-0.1.0/web/src/components/bottom-bar.tsx +333 -0
  85. litemm-0.1.0/web/src/components/floating-search-bar.tsx +640 -0
  86. litemm-0.1.0/web/src/components/gallery/gallery-grid.tsx +54 -0
  87. litemm-0.1.0/web/src/components/gallery/index.ts +4 -0
  88. litemm-0.1.0/web/src/components/gallery/justified-gallery.tsx +120 -0
  89. litemm-0.1.0/web/src/components/gallery/media-tile.tsx +177 -0
  90. litemm-0.1.0/web/src/components/media-detail/index.ts +2 -0
  91. litemm-0.1.0/web/src/components/media-detail/info-dialog.tsx +546 -0
  92. litemm-0.1.0/web/src/components/media-detail/media-detail-panel.tsx +216 -0
  93. litemm-0.1.0/web/src/components/media-detail.tsx +3 -0
  94. litemm-0.1.0/web/src/components/menu-dropdown.tsx +327 -0
  95. litemm-0.1.0/web/src/components/ui/button.tsx +42 -0
  96. litemm-0.1.0/web/src/components/ui/card.tsx +23 -0
  97. litemm-0.1.0/web/src/components/ui/input.tsx +20 -0
  98. litemm-0.1.0/web/src/components/ui/scroll-area.tsx +46 -0
  99. litemm-0.1.0/web/src/components/ui/select.tsx +20 -0
  100. litemm-0.1.0/web/src/components/ui/star-rating.tsx +41 -0
  101. litemm-0.1.0/web/src/hooks/use-detail-panel.ts +45 -0
  102. litemm-0.1.0/web/src/hooks/use-infinite-scroll.ts +33 -0
  103. litemm-0.1.0/web/src/hooks/use-pinch-zoom.ts +61 -0
  104. litemm-0.1.0/web/src/index.css +81 -0
  105. litemm-0.1.0/web/src/layouts/app-layout.tsx +565 -0
  106. litemm-0.1.0/web/src/lib/format.ts +105 -0
  107. litemm-0.1.0/web/src/lib/icons.ts +33 -0
  108. litemm-0.1.0/web/src/lib/media-url.ts +33 -0
  109. litemm-0.1.0/web/src/lib/utils.ts +6 -0
  110. litemm-0.1.0/web/src/main.tsx +12 -0
  111. litemm-0.1.0/web/src/pages/albums.tsx +487 -0
  112. litemm-0.1.0/web/src/pages/dashboard.tsx +81 -0
  113. litemm-0.1.0/web/src/pages/login.tsx +68 -0
  114. litemm-0.1.0/web/src/pages/media-library.tsx +648 -0
  115. litemm-0.1.0/web/src/pages/profile.tsx +46 -0
  116. litemm-0.1.0/web/src/pages/settings.tsx +343 -0
  117. litemm-0.1.0/web/src/stores/album-section.ts +22 -0
  118. litemm-0.1.0/web/src/stores/auth.ts +62 -0
  119. litemm-0.1.0/web/src/stores/media.ts +219 -0
  120. litemm-0.1.0/web/src/stores/theme.ts +354 -0
  121. litemm-0.1.0/web/tsconfig.app.json +40 -0
  122. litemm-0.1.0/web/tsconfig.json +7 -0
  123. litemm-0.1.0/web/tsconfig.node.json +26 -0
  124. litemm-0.1.0/web/vite.config.ts +38 -0
@@ -0,0 +1,15 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+ src/mm/_version.py
9
+ node_modules/
10
+ .vite/
11
+ /ssd
12
+
13
+ # Virtual environments
14
+ .venv
15
+ *.db
@@ -0,0 +1 @@
1
+ 3.10
litemm-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,356 @@
1
+ Metadata-Version: 2.4
2
+ Name: litemm
3
+ Version: 0.1.0
4
+ Summary: Media Manager & Visualizer
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: aiosqlite>=0.22.1
7
+ Requires-Dist: click>=8.3.1
8
+ Requires-Dist: fastapi[standard]>=0.115
9
+ Requires-Dist: lunar-python>=1.4.8
10
+ Requires-Dist: numpy>=1.24
11
+ Requires-Dist: peewee-aio>=2.2.2
12
+ Requires-Dist: peewee-async>=1.2.1
13
+ Requires-Dist: peewee>=3.19.0
14
+ Requires-Dist: pillow-heif>=0.18
15
+ Requires-Dist: pillow>=10.0
16
+ Requires-Dist: pyyaml>=6.0
17
+ Requires-Dist: rawpy>=0.26.1
18
+ Provides-Extra: clip
19
+ Requires-Dist: open-clip-torch>=2.24; extra == 'clip'
20
+ Requires-Dist: pillow>=10.0; extra == 'clip'
21
+ Requires-Dist: torch>=2.0; extra == 'clip'
22
+ Description-Content-Type: text/markdown
23
+
24
+ <div align="center">
25
+
26
+ # 📸 MM — Universal Organizer for Media
27
+
28
+ **A self-hosted, AI-powered media library manager for photos, videos, and audio.**
29
+
30
+ Scan, tag, search, deduplicate, and browse your media collection with a beautiful web UI.
31
+
32
+ [![GitHub Stars](https://img.shields.io/github/stars/HSPK/mm?style=for-the-badge&logo=github&color=f4c542)](https://github.com/HSPK/mm/stargazers)
33
+ [![GitHub Forks](https://img.shields.io/github/forks/HSPK/mm?style=for-the-badge&logo=github&color=blue)](https://github.com/HSPK/mm/network/members)
34
+ [![GitHub Issues](https://img.shields.io/github/issues/HSPK/mm?style=for-the-badge&logo=github&color=orange)](https://github.com/HSPK/mm/issues)
35
+ [![GitHub Last Commit](https://img.shields.io/github/last-commit/HSPK/mm?style=for-the-badge&logo=github)](https://github.com/HSPK/mm/commits)
36
+ [![GitHub License](https://img.shields.io/github/license/HSPK/mm?style=for-the-badge)](https://github.com/HSPK/mm/blob/main/LICENSE)
37
+ [![Python](https://img.shields.io/badge/Python-3.10+-3776AB?style=for-the-badge&logo=python&logoColor=white)](https://python.org)
38
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://typescriptlang.org)
39
+ [![FastAPI](https://img.shields.io/badge/FastAPI-0.115+-009688?style=for-the-badge&logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com)
40
+ [![React](https://img.shields.io/badge/React-19-61DAFB?style=for-the-badge&logo=react&logoColor=black)](https://react.dev)
41
+
42
+ ---
43
+
44
+ [Features](#-features) · [Quick Start](#-quick-start) · [Installation](#-installation) · [Usage](#-usage) · [Web UI](#-web-ui) · [API](#-api) · [Contributing](#-contributing)
45
+
46
+ </div>
47
+
48
+ ---
49
+
50
+ ## ✨ Features
51
+
52
+ <table>
53
+ <tr>
54
+ <td width="50%">
55
+
56
+ ### 🔍 Smart Scanning
57
+ - Recursive media discovery with parallel processing
58
+ - SHA-256 hashing for integrity & deduplication
59
+ - EXIF, video, and audio metadata extraction
60
+ - Support for RAW, HEIC/HEIF, and 30+ formats
61
+
62
+ </td>
63
+ <td width="50%">
64
+
65
+ ### 🤖 AI-Powered
66
+ - CLIP-based image embeddings (ViT-B-32)
67
+ - Natural language image search ("sunset over ocean")
68
+ - Zero-shot auto-tagging (~36 categories)
69
+ - Visual similarity search
70
+
71
+ </td>
72
+ </tr>
73
+ <tr>
74
+ <td>
75
+
76
+ ### 🌍 Offline Geocoding
77
+ - Reverse geocoding from GPS EXIF data
78
+ - GeoNames cities15000 dataset (no API keys needed)
79
+ - Chinese province/city name support
80
+ - Chinese lunar & solar festival detection
81
+
82
+ </td>
83
+ <td>
84
+
85
+ ### 🖼️ Beautiful Web UI
86
+ - Responsive gallery with justified layout
87
+ - Pinch-to-zoom thumbnail resizing
88
+ - Infinite scroll with date grouping
89
+ - Detail panel with full metadata & map
90
+
91
+ </td>
92
+ </tr>
93
+ <tr>
94
+ <td>
95
+
96
+ ### 📁 Library Management
97
+ - Manual & smart albums (auto-generated)
98
+ - Star ratings, tags, batch operations
99
+ - Template-based file import & organization
100
+ - Multi-library support with runtime switching
101
+
102
+ </td>
103
+ <td>
104
+
105
+ ### ⚡ Performance
106
+ - SQLite-backed (zero config, portable)
107
+ - WebP thumbnail caching (4 sizes) with ETag
108
+ - Async API server (FastAPI + Uvicorn)
109
+ - Background CLIP processing
110
+
111
+ </td>
112
+ </tr>
113
+ </table>
114
+
115
+ ## 🏗️ Architecture
116
+
117
+ ```
118
+ ┌──────────────────────────────────────────────────────────────┐
119
+ │ Web UI (React) │
120
+ │ React 19 · TailwindCSS · Zustand · Vite │
121
+ └──────────────────┬───────────────────────────────────────────┘
122
+ │ REST API
123
+ ┌──────────────────▼───────────────────────────────────────────┐
124
+ │ FastAPI Server │
125
+ │ Auth · Media · Albums · Smart Albums · Tags · Stats │
126
+ └──────────────────┬───────────────────────────────────────────┘
127
+
128
+ ┌──────────────────▼───────────────────────────────────────────┐
129
+ │ Core Engines │
130
+ │ Scanner · Metadata · Embeddings · Tagger · Geocoding · ... │
131
+ └──────────────────┬───────────────────────────────────────────┘
132
+
133
+ ┌──────────────────▼───────────────────────────────────────────┐
134
+ │ SQLite (Peewee ORM / aiosqlite) │
135
+ │ Media · Metadata · Tags · Embeddings · Albums │
136
+ └──────────────────────────────────────────────────────────────┘
137
+ ```
138
+
139
+ ## 🚀 Quick Start
140
+
141
+ ```bash
142
+ # Install with uv (recommended)
143
+ uv pip install -e .
144
+
145
+ # Create a new library (interactive)
146
+ mm init ~/Photos
147
+
148
+ # Start the web server
149
+ mm server
150
+ # → Open http://localhost:8000
151
+ ```
152
+
153
+ ## 📦 Installation
154
+
155
+ ### Prerequisites
156
+
157
+ - **Python 3.10+**
158
+ - **[uv](https://docs.astral.sh/uv/)** (recommended) or pip
159
+ - **exiftool** — for EXIF metadata extraction
160
+ - **ffmpeg** / **ffprobe** — for video/audio metadata & thumbnails
161
+
162
+ ```bash
163
+ # macOS
164
+ brew install exiftool ffmpeg
165
+
166
+ # Ubuntu / Debian
167
+ sudo apt install libimage-exiftool-perl ffmpeg
168
+ ```
169
+
170
+ ### Install mm
171
+
172
+ ```bash
173
+ # Clone the repository
174
+ git clone https://github.com/HSPK/mm.git
175
+ cd mm
176
+
177
+ # Install with uv
178
+ uv pip install -e .
179
+
180
+ # (Optional) Install CLIP support for AI features
181
+ uv pip install -e ".[clip]"
182
+ ```
183
+
184
+ ### Build the Frontend
185
+
186
+ ```bash
187
+ cd web
188
+ npm install
189
+ npm run build
190
+ cd ..
191
+ ```
192
+
193
+ ## 📖 Usage
194
+
195
+ ### CLI Commands
196
+
197
+ | Command | Description |
198
+ |---|---|
199
+ | `mm init [dir]` | Create or open a media library (interactive setup) |
200
+ | `mm server [dir]` | Start the web UI server |
201
+ | `mm import <source>` | Import media files into the active library |
202
+ | `mm search` | Search by text, image, or tags (requires CLIP) |
203
+ | `mm dedup` | Find and remove duplicate media files by hash |
204
+ | `mm info <file>` | Show detailed file metadata |
205
+ | `mm config [key] [value]` | Get or set library config values |
206
+ | `mm geo update` | Offline reverse geocode GPS-tagged media |
207
+ | `mm db list` | List all registered databases |
208
+ | `mm db set <n>` | Switch the active database |
209
+ | `mm db add <path>` | Register an existing database file |
210
+ | `mm db rm <n>` | Unregister a database (optionally delete) |
211
+ | `mm db stats` | Show detailed library statistics |
212
+ | `mm db clean` | Remove entries for files no longer on disk |
213
+ | `mm db sync <dir>` | Clean stale entries and re-scan changed files |
214
+
215
+ ### Library Setup
216
+
217
+ ```bash
218
+ # Create a new library interactively
219
+ mm init ~/Photos
220
+
221
+ # View all config values
222
+ mm config
223
+
224
+ # Set the import template
225
+ mm config import_template "{year}/{year}-{month:02d}-{day:02d}/{original_name}{ext}"
226
+
227
+ # Sync database with disk (remove stale + re-scan)
228
+ mm db sync ~/Photos
229
+
230
+ # Parallel sync with 8 workers
231
+ mm db sync ~/Photos -j 8
232
+ ```
233
+
234
+ ### Searching
235
+
236
+ ```bash
237
+ # Semantic search by text (requires CLIP)
238
+ mm search --text "sunset at the beach"
239
+
240
+ # Search by image similarity
241
+ mm search --image ~/Photos/reference.jpg --top-k 20
242
+
243
+ # Filter by tags
244
+ mm search --tag landscape --tag nature
245
+ ```
246
+
247
+ ### Deduplication
248
+
249
+ ```bash
250
+ # Find and remove duplicate media files (by hash)
251
+ mm dedup
252
+ ```
253
+
254
+ ### Importing & Organizing
255
+
256
+ ```bash
257
+ # Import from SD card (copies into library using configured template)
258
+ mm import ~/DCIM
259
+
260
+ # Move instead of copy
261
+ mm import ~/DCIM --move
262
+ ```
263
+
264
+ ### Web Server
265
+
266
+ ```bash
267
+ # Start on default port (8000)
268
+ mm server
269
+
270
+ # Specify library directory
271
+ mm server ~/Photos
272
+
273
+ # Custom host and port
274
+ mm server -h 0.0.0.0 -p 9000
275
+
276
+ # Development mode with auto-reload
277
+ mm server --reload
278
+ ```
279
+
280
+ ## 🌐 Web UI
281
+
282
+ The web interface provides a full-featured media browser:
283
+
284
+ - **Library** — Browse all media with infinite scroll, date grouping, and adjustable thumbnail sizes
285
+ - **Albums** — Smart albums auto-generated by tag, camera, year, festival, and location
286
+ - **Search** — Quick filtering and semantic search
287
+ - **Detail View** — Full metadata, EXIF info, location, tags, and star ratings
288
+ - **Batch Operations** — Multi-select for bulk tagging, rating, and deletion
289
+ - **Settings** — Theme switching (light/dark), library management
290
+ - **Auth** — User accounts with token-based authentication
291
+
292
+ ## 🔌 API
293
+
294
+ mm exposes a comprehensive REST API at `/api/`:
295
+
296
+ | Endpoint | Description |
297
+ |---|---|
298
+ | `/api/auth/*` | Authentication (login, setup, logout) |
299
+ | `/api/media` | Media CRUD, thumbnails, file streaming |
300
+ | `/api/batch/*` | Bulk operations (tags, ratings, delete) |
301
+ | `/api/albums/*` | Album management |
302
+ | `/api/smart-albums/*` | Smart album definitions & resolution |
303
+ | `/api/tags` | Tag CRUD with usage counts |
304
+ | `/api/stats` | Library statistics & timeline |
305
+ | `/api/library` | Multi-library switching |
306
+ | `/api/users` | User management (admin) |
307
+
308
+ Interactive API docs available at **`/docs`** (Swagger UI) when the server is running.
309
+
310
+ ## 🛠️ Tech Stack
311
+
312
+ | Component | Technology |
313
+ |---|---|
314
+ | **Backend** | Python 3.10+, FastAPI, Peewee ORM, SQLite |
315
+ | **AI/ML** | OpenCLIP (ViT-B-32), PyTorch |
316
+ | **Frontend** | React 19, TypeScript, TailwindCSS, Vite |
317
+ | **State** | Zustand |
318
+ | **UI Kit** | shadcn/ui, Radix UI, Lucide Icons |
319
+ | **Media** | Pillow, pillow-heif, rawpy, exiftool, ffmpeg |
320
+ | **Geocoding** | GeoNames (offline), lunar-python |
321
+
322
+ ## 🤝 Contributing
323
+
324
+ Contributions are welcome! Here's how to get started:
325
+
326
+ ```bash
327
+ # Clone and install in dev mode
328
+ git clone https://github.com/HSPK/mm.git
329
+ cd mm
330
+ uv pip install -e ".[clip]"
331
+
332
+ # Install dev dependencies
333
+ uv pip install -e ".[dev]"
334
+
335
+ # Run tests
336
+ pytest
337
+
338
+ # Start frontend dev server
339
+ cd web && npm install && npm run dev
340
+ ```
341
+
342
+ Please open an issue first to discuss what you would like to change.
343
+
344
+ ## 📄 License
345
+
346
+ This project is open source. See the [LICENSE](LICENSE) file for details.
347
+
348
+ ---
349
+
350
+ <div align="center">
351
+
352
+ **If you find mm useful, please consider giving it a ⭐!**
353
+
354
+ [![Star History Chart](https://api.star-history.com/svg?repos=HSPK/mm&type=Date)](https://star-history.com/#HSPK/mm&Date)
355
+
356
+ </div>
litemm-0.1.0/README.md ADDED
@@ -0,0 +1,333 @@
1
+ <div align="center">
2
+
3
+ # 📸 MM — Universal Organizer for Media
4
+
5
+ **A self-hosted, AI-powered media library manager for photos, videos, and audio.**
6
+
7
+ Scan, tag, search, deduplicate, and browse your media collection with a beautiful web UI.
8
+
9
+ [![GitHub Stars](https://img.shields.io/github/stars/HSPK/mm?style=for-the-badge&logo=github&color=f4c542)](https://github.com/HSPK/mm/stargazers)
10
+ [![GitHub Forks](https://img.shields.io/github/forks/HSPK/mm?style=for-the-badge&logo=github&color=blue)](https://github.com/HSPK/mm/network/members)
11
+ [![GitHub Issues](https://img.shields.io/github/issues/HSPK/mm?style=for-the-badge&logo=github&color=orange)](https://github.com/HSPK/mm/issues)
12
+ [![GitHub Last Commit](https://img.shields.io/github/last-commit/HSPK/mm?style=for-the-badge&logo=github)](https://github.com/HSPK/mm/commits)
13
+ [![GitHub License](https://img.shields.io/github/license/HSPK/mm?style=for-the-badge)](https://github.com/HSPK/mm/blob/main/LICENSE)
14
+ [![Python](https://img.shields.io/badge/Python-3.10+-3776AB?style=for-the-badge&logo=python&logoColor=white)](https://python.org)
15
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://typescriptlang.org)
16
+ [![FastAPI](https://img.shields.io/badge/FastAPI-0.115+-009688?style=for-the-badge&logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com)
17
+ [![React](https://img.shields.io/badge/React-19-61DAFB?style=for-the-badge&logo=react&logoColor=black)](https://react.dev)
18
+
19
+ ---
20
+
21
+ [Features](#-features) · [Quick Start](#-quick-start) · [Installation](#-installation) · [Usage](#-usage) · [Web UI](#-web-ui) · [API](#-api) · [Contributing](#-contributing)
22
+
23
+ </div>
24
+
25
+ ---
26
+
27
+ ## ✨ Features
28
+
29
+ <table>
30
+ <tr>
31
+ <td width="50%">
32
+
33
+ ### 🔍 Smart Scanning
34
+ - Recursive media discovery with parallel processing
35
+ - SHA-256 hashing for integrity & deduplication
36
+ - EXIF, video, and audio metadata extraction
37
+ - Support for RAW, HEIC/HEIF, and 30+ formats
38
+
39
+ </td>
40
+ <td width="50%">
41
+
42
+ ### 🤖 AI-Powered
43
+ - CLIP-based image embeddings (ViT-B-32)
44
+ - Natural language image search ("sunset over ocean")
45
+ - Zero-shot auto-tagging (~36 categories)
46
+ - Visual similarity search
47
+
48
+ </td>
49
+ </tr>
50
+ <tr>
51
+ <td>
52
+
53
+ ### 🌍 Offline Geocoding
54
+ - Reverse geocoding from GPS EXIF data
55
+ - GeoNames cities15000 dataset (no API keys needed)
56
+ - Chinese province/city name support
57
+ - Chinese lunar & solar festival detection
58
+
59
+ </td>
60
+ <td>
61
+
62
+ ### 🖼️ Beautiful Web UI
63
+ - Responsive gallery with justified layout
64
+ - Pinch-to-zoom thumbnail resizing
65
+ - Infinite scroll with date grouping
66
+ - Detail panel with full metadata & map
67
+
68
+ </td>
69
+ </tr>
70
+ <tr>
71
+ <td>
72
+
73
+ ### 📁 Library Management
74
+ - Manual & smart albums (auto-generated)
75
+ - Star ratings, tags, batch operations
76
+ - Template-based file import & organization
77
+ - Multi-library support with runtime switching
78
+
79
+ </td>
80
+ <td>
81
+
82
+ ### ⚡ Performance
83
+ - SQLite-backed (zero config, portable)
84
+ - WebP thumbnail caching (4 sizes) with ETag
85
+ - Async API server (FastAPI + Uvicorn)
86
+ - Background CLIP processing
87
+
88
+ </td>
89
+ </tr>
90
+ </table>
91
+
92
+ ## 🏗️ Architecture
93
+
94
+ ```
95
+ ┌──────────────────────────────────────────────────────────────┐
96
+ │ Web UI (React) │
97
+ │ React 19 · TailwindCSS · Zustand · Vite │
98
+ └──────────────────┬───────────────────────────────────────────┘
99
+ │ REST API
100
+ ┌──────────────────▼───────────────────────────────────────────┐
101
+ │ FastAPI Server │
102
+ │ Auth · Media · Albums · Smart Albums · Tags · Stats │
103
+ └──────────────────┬───────────────────────────────────────────┘
104
+
105
+ ┌──────────────────▼───────────────────────────────────────────┐
106
+ │ Core Engines │
107
+ │ Scanner · Metadata · Embeddings · Tagger · Geocoding · ... │
108
+ └──────────────────┬───────────────────────────────────────────┘
109
+
110
+ ┌──────────────────▼───────────────────────────────────────────┐
111
+ │ SQLite (Peewee ORM / aiosqlite) │
112
+ │ Media · Metadata · Tags · Embeddings · Albums │
113
+ └──────────────────────────────────────────────────────────────┘
114
+ ```
115
+
116
+ ## 🚀 Quick Start
117
+
118
+ ```bash
119
+ # Install with uv (recommended)
120
+ uv pip install -e .
121
+
122
+ # Create a new library (interactive)
123
+ mm init ~/Photos
124
+
125
+ # Start the web server
126
+ mm server
127
+ # → Open http://localhost:8000
128
+ ```
129
+
130
+ ## 📦 Installation
131
+
132
+ ### Prerequisites
133
+
134
+ - **Python 3.10+**
135
+ - **[uv](https://docs.astral.sh/uv/)** (recommended) or pip
136
+ - **exiftool** — for EXIF metadata extraction
137
+ - **ffmpeg** / **ffprobe** — for video/audio metadata & thumbnails
138
+
139
+ ```bash
140
+ # macOS
141
+ brew install exiftool ffmpeg
142
+
143
+ # Ubuntu / Debian
144
+ sudo apt install libimage-exiftool-perl ffmpeg
145
+ ```
146
+
147
+ ### Install mm
148
+
149
+ ```bash
150
+ # Clone the repository
151
+ git clone https://github.com/HSPK/mm.git
152
+ cd mm
153
+
154
+ # Install with uv
155
+ uv pip install -e .
156
+
157
+ # (Optional) Install CLIP support for AI features
158
+ uv pip install -e ".[clip]"
159
+ ```
160
+
161
+ ### Build the Frontend
162
+
163
+ ```bash
164
+ cd web
165
+ npm install
166
+ npm run build
167
+ cd ..
168
+ ```
169
+
170
+ ## 📖 Usage
171
+
172
+ ### CLI Commands
173
+
174
+ | Command | Description |
175
+ |---|---|
176
+ | `mm init [dir]` | Create or open a media library (interactive setup) |
177
+ | `mm server [dir]` | Start the web UI server |
178
+ | `mm import <source>` | Import media files into the active library |
179
+ | `mm search` | Search by text, image, or tags (requires CLIP) |
180
+ | `mm dedup` | Find and remove duplicate media files by hash |
181
+ | `mm info <file>` | Show detailed file metadata |
182
+ | `mm config [key] [value]` | Get or set library config values |
183
+ | `mm geo update` | Offline reverse geocode GPS-tagged media |
184
+ | `mm db list` | List all registered databases |
185
+ | `mm db set <n>` | Switch the active database |
186
+ | `mm db add <path>` | Register an existing database file |
187
+ | `mm db rm <n>` | Unregister a database (optionally delete) |
188
+ | `mm db stats` | Show detailed library statistics |
189
+ | `mm db clean` | Remove entries for files no longer on disk |
190
+ | `mm db sync <dir>` | Clean stale entries and re-scan changed files |
191
+
192
+ ### Library Setup
193
+
194
+ ```bash
195
+ # Create a new library interactively
196
+ mm init ~/Photos
197
+
198
+ # View all config values
199
+ mm config
200
+
201
+ # Set the import template
202
+ mm config import_template "{year}/{year}-{month:02d}-{day:02d}/{original_name}{ext}"
203
+
204
+ # Sync database with disk (remove stale + re-scan)
205
+ mm db sync ~/Photos
206
+
207
+ # Parallel sync with 8 workers
208
+ mm db sync ~/Photos -j 8
209
+ ```
210
+
211
+ ### Searching
212
+
213
+ ```bash
214
+ # Semantic search by text (requires CLIP)
215
+ mm search --text "sunset at the beach"
216
+
217
+ # Search by image similarity
218
+ mm search --image ~/Photos/reference.jpg --top-k 20
219
+
220
+ # Filter by tags
221
+ mm search --tag landscape --tag nature
222
+ ```
223
+
224
+ ### Deduplication
225
+
226
+ ```bash
227
+ # Find and remove duplicate media files (by hash)
228
+ mm dedup
229
+ ```
230
+
231
+ ### Importing & Organizing
232
+
233
+ ```bash
234
+ # Import from SD card (copies into library using configured template)
235
+ mm import ~/DCIM
236
+
237
+ # Move instead of copy
238
+ mm import ~/DCIM --move
239
+ ```
240
+
241
+ ### Web Server
242
+
243
+ ```bash
244
+ # Start on default port (8000)
245
+ mm server
246
+
247
+ # Specify library directory
248
+ mm server ~/Photos
249
+
250
+ # Custom host and port
251
+ mm server -h 0.0.0.0 -p 9000
252
+
253
+ # Development mode with auto-reload
254
+ mm server --reload
255
+ ```
256
+
257
+ ## 🌐 Web UI
258
+
259
+ The web interface provides a full-featured media browser:
260
+
261
+ - **Library** — Browse all media with infinite scroll, date grouping, and adjustable thumbnail sizes
262
+ - **Albums** — Smart albums auto-generated by tag, camera, year, festival, and location
263
+ - **Search** — Quick filtering and semantic search
264
+ - **Detail View** — Full metadata, EXIF info, location, tags, and star ratings
265
+ - **Batch Operations** — Multi-select for bulk tagging, rating, and deletion
266
+ - **Settings** — Theme switching (light/dark), library management
267
+ - **Auth** — User accounts with token-based authentication
268
+
269
+ ## 🔌 API
270
+
271
+ mm exposes a comprehensive REST API at `/api/`:
272
+
273
+ | Endpoint | Description |
274
+ |---|---|
275
+ | `/api/auth/*` | Authentication (login, setup, logout) |
276
+ | `/api/media` | Media CRUD, thumbnails, file streaming |
277
+ | `/api/batch/*` | Bulk operations (tags, ratings, delete) |
278
+ | `/api/albums/*` | Album management |
279
+ | `/api/smart-albums/*` | Smart album definitions & resolution |
280
+ | `/api/tags` | Tag CRUD with usage counts |
281
+ | `/api/stats` | Library statistics & timeline |
282
+ | `/api/library` | Multi-library switching |
283
+ | `/api/users` | User management (admin) |
284
+
285
+ Interactive API docs available at **`/docs`** (Swagger UI) when the server is running.
286
+
287
+ ## 🛠️ Tech Stack
288
+
289
+ | Component | Technology |
290
+ |---|---|
291
+ | **Backend** | Python 3.10+, FastAPI, Peewee ORM, SQLite |
292
+ | **AI/ML** | OpenCLIP (ViT-B-32), PyTorch |
293
+ | **Frontend** | React 19, TypeScript, TailwindCSS, Vite |
294
+ | **State** | Zustand |
295
+ | **UI Kit** | shadcn/ui, Radix UI, Lucide Icons |
296
+ | **Media** | Pillow, pillow-heif, rawpy, exiftool, ffmpeg |
297
+ | **Geocoding** | GeoNames (offline), lunar-python |
298
+
299
+ ## 🤝 Contributing
300
+
301
+ Contributions are welcome! Here's how to get started:
302
+
303
+ ```bash
304
+ # Clone and install in dev mode
305
+ git clone https://github.com/HSPK/mm.git
306
+ cd mm
307
+ uv pip install -e ".[clip]"
308
+
309
+ # Install dev dependencies
310
+ uv pip install -e ".[dev]"
311
+
312
+ # Run tests
313
+ pytest
314
+
315
+ # Start frontend dev server
316
+ cd web && npm install && npm run dev
317
+ ```
318
+
319
+ Please open an issue first to discuss what you would like to change.
320
+
321
+ ## 📄 License
322
+
323
+ This project is open source. See the [LICENSE](LICENSE) file for details.
324
+
325
+ ---
326
+
327
+ <div align="center">
328
+
329
+ **If you find mm useful, please consider giving it a ⭐!**
330
+
331
+ [![Star History Chart](https://api.star-history.com/svg?repos=HSPK/mm&type=Date)](https://star-history.com/#HSPK/mm&Date)
332
+
333
+ </div>