plexmix 0.2.7__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.
- plexmix-0.2.7/PKG-INFO +708 -0
- plexmix-0.2.7/README.md +674 -0
- plexmix-0.2.7/pyproject.toml +65 -0
- plexmix-0.2.7/src/plexmix/__init__.py +22 -0
- plexmix-0.2.7/src/plexmix/ai/__init__.py +58 -0
- plexmix-0.2.7/src/plexmix/ai/base.py +115 -0
- plexmix-0.2.7/src/plexmix/ai/claude_provider.py +50 -0
- plexmix-0.2.7/src/plexmix/ai/cohere_provider.py +50 -0
- plexmix-0.2.7/src/plexmix/ai/gemini_provider.py +120 -0
- plexmix-0.2.7/src/plexmix/ai/openai_provider.py +50 -0
- plexmix-0.2.7/src/plexmix/ai/tag_generator.py +305 -0
- plexmix-0.2.7/src/plexmix/cli/__init__.py +0 -0
- plexmix-0.2.7/src/plexmix/cli/main.py +1282 -0
- plexmix-0.2.7/src/plexmix/config/__init__.py +0 -0
- plexmix-0.2.7/src/plexmix/config/credentials.py +81 -0
- plexmix-0.2.7/src/plexmix/config/settings.py +134 -0
- plexmix-0.2.7/src/plexmix/database/__init__.py +0 -0
- plexmix-0.2.7/src/plexmix/database/models.py +167 -0
- plexmix-0.2.7/src/plexmix/database/recovery.py +145 -0
- plexmix-0.2.7/src/plexmix/database/sqlite_manager.py +762 -0
- plexmix-0.2.7/src/plexmix/database/vector_index.py +169 -0
- plexmix-0.2.7/src/plexmix/playlist/__init__.py +0 -0
- plexmix-0.2.7/src/plexmix/playlist/generator.py +250 -0
- plexmix-0.2.7/src/plexmix/plex/__init__.py +0 -0
- plexmix-0.2.7/src/plexmix/plex/client.py +290 -0
- plexmix-0.2.7/src/plexmix/plex/sync.py +631 -0
- plexmix-0.2.7/src/plexmix/ui/__init__.py +0 -0
- plexmix-0.2.7/src/plexmix/ui/app.py +33 -0
- plexmix-0.2.7/src/plexmix/ui/components/__init__.py +0 -0
- plexmix-0.2.7/src/plexmix/ui/components/error.py +145 -0
- plexmix-0.2.7/src/plexmix/ui/components/loading.py +127 -0
- plexmix-0.2.7/src/plexmix/ui/components/navbar.py +77 -0
- plexmix-0.2.7/src/plexmix/ui/components/progress_modal.py +31 -0
- plexmix-0.2.7/src/plexmix/ui/components/toast.py +35 -0
- plexmix-0.2.7/src/plexmix/ui/components/track_table.py +60 -0
- plexmix-0.2.7/src/plexmix/ui/pages/__init__.py +0 -0
- plexmix-0.2.7/src/plexmix/ui/pages/dashboard.py +114 -0
- plexmix-0.2.7/src/plexmix/ui/pages/generator.py +317 -0
- plexmix-0.2.7/src/plexmix/ui/pages/history.py +426 -0
- plexmix-0.2.7/src/plexmix/ui/pages/index.py +19 -0
- plexmix-0.2.7/src/plexmix/ui/pages/library.py +237 -0
- plexmix-0.2.7/src/plexmix/ui/pages/settings.py +256 -0
- plexmix-0.2.7/src/plexmix/ui/pages/tagging.py +324 -0
- plexmix-0.2.7/src/plexmix/ui/states/__init__.py +0 -0
- plexmix-0.2.7/src/plexmix/ui/states/app_state.py +123 -0
- plexmix-0.2.7/src/plexmix/ui/states/dashboard_state.py +59 -0
- plexmix-0.2.7/src/plexmix/ui/states/generator_state.py +316 -0
- plexmix-0.2.7/src/plexmix/ui/states/history_state.py +356 -0
- plexmix-0.2.7/src/plexmix/ui/states/library_state.py +367 -0
- plexmix-0.2.7/src/plexmix/ui/states/settings_state.py +333 -0
- plexmix-0.2.7/src/plexmix/ui/states/tagging_state.py +322 -0
- plexmix-0.2.7/src/plexmix/ui/utils/__init__.py +0 -0
- plexmix-0.2.7/src/plexmix/ui/utils/validation.py +186 -0
- plexmix-0.2.7/src/plexmix/utils/__init__.py +0 -0
- plexmix-0.2.7/src/plexmix/utils/embeddings.py +345 -0
- plexmix-0.2.7/src/plexmix/utils/logging.py +64 -0
plexmix-0.2.7/PKG-INFO
ADDED
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: plexmix
|
|
3
|
+
Version: 0.2.7
|
|
4
|
+
Summary: AI-powered Plex playlist generator using mood-based queries
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: Anthony Izzo
|
|
7
|
+
Requires-Python: >=3.10,<4.0
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Provides-Extra: ui
|
|
16
|
+
Requires-Dist: anthropic (>=0.8.0,<0.9.0)
|
|
17
|
+
Requires-Dist: click (==8.1.7)
|
|
18
|
+
Requires-Dist: faiss-cpu (>=1.7.4,<2.0.0)
|
|
19
|
+
Requires-Dist: google-generativeai (>=0.3.0,<0.4.0)
|
|
20
|
+
Requires-Dist: keyring (>=24.3.0,<25.0.0)
|
|
21
|
+
Requires-Dist: numpy (>=1.26.0,<2.0.0)
|
|
22
|
+
Requires-Dist: openai (>=1.6.0,<2.0.0)
|
|
23
|
+
Requires-Dist: plexapi (>=4.15.0,<5.0.0)
|
|
24
|
+
Requires-Dist: pydantic (>=2.5.0,<3.0.0)
|
|
25
|
+
Requires-Dist: pydantic-settings (>=2.1.0,<3.0.0)
|
|
26
|
+
Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
|
|
27
|
+
Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
|
|
28
|
+
Requires-Dist: reflex (>=0.6.0,<0.7.0) ; extra == "ui"
|
|
29
|
+
Requires-Dist: rich (>=13.7.0,<14.0.0)
|
|
30
|
+
Requires-Dist: sentence-transformers (>=2.2.0,<3.0.0)
|
|
31
|
+
Requires-Dist: typer (>=0.12.0,<0.13.0)
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
<div align="center">
|
|
35
|
+
<img src="logo.png" alt="PlexMix Logo" width="300"/>
|
|
36
|
+
|
|
37
|
+
# PlexMix
|
|
38
|
+
|
|
39
|
+
[](https://opensource.org/licenses/MIT)
|
|
40
|
+
[](https://badge.fury.io/py/plexmix)
|
|
41
|
+
[](https://www.python.org/downloads/)
|
|
42
|
+
|
|
43
|
+
**AI-powered Plex playlist generator using mood-based queries**
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
PlexMix syncs your Plex music library to a local SQLite database, generates semantic embeddings for tracks, and uses AI to create personalized playlists based on mood descriptions.
|
|
47
|
+
|
|
48
|
+
## Features
|
|
49
|
+
|
|
50
|
+
- ✨ **Simple Setup** - Only requires a Google API key to get started
|
|
51
|
+
- 🎵 **Smart Sync** - Syncs Plex music library with incremental updates
|
|
52
|
+
- 🤖 **AI-Powered** - Uses Google Gemini, OpenAI GPT, or Anthropic Claude
|
|
53
|
+
- 🏷️ **AI Tagging** - Automatically generates tags, environments, and instruments for tracks
|
|
54
|
+
- 🔍 **Semantic Search** - FAISS vector similarity search for intelligent track matching
|
|
55
|
+
- 🎨 **Mood-Based** - Generate playlists from natural language descriptions
|
|
56
|
+
- ⚡ **Fast** - Local database with optimized indexes and full-text search
|
|
57
|
+
- 🎯 **Flexible** - Filter by genre, year, rating, artist, environment, and instrument
|
|
58
|
+
- 🛡️ **Resilient** - Automatic database recovery if deleted or corrupted
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
### Option 1: Command Line Interface (Recommended)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Install from PyPI
|
|
66
|
+
pip install plexmix
|
|
67
|
+
|
|
68
|
+
# Run setup wizard
|
|
69
|
+
plexmix config init
|
|
70
|
+
|
|
71
|
+
# Sync your Plex library (incremental, generates embeddings automatically)
|
|
72
|
+
plexmix sync
|
|
73
|
+
|
|
74
|
+
# Generate AI tags for tracks (enhances search quality)
|
|
75
|
+
plexmix tags generate
|
|
76
|
+
|
|
77
|
+
# Create a playlist
|
|
78
|
+
plexmix create "upbeat morning energy"
|
|
79
|
+
|
|
80
|
+
# With filters
|
|
81
|
+
plexmix create "chill evening vibes" --genre jazz --year-min 2010 --limit 30
|
|
82
|
+
|
|
83
|
+
# Filter by environment and instrument
|
|
84
|
+
plexmix create "focus music" --environment study --instrument piano
|
|
85
|
+
|
|
86
|
+
# Use alternative AI provider
|
|
87
|
+
plexmix create "workout motivation" --provider openai
|
|
88
|
+
|
|
89
|
+
# If you encounter issues (e.g., "0 candidate tracks")
|
|
90
|
+
plexmix doctor
|
|
91
|
+
|
|
92
|
+
# Regenerate all tags and embeddings from scratch (WARNING: destructive)
|
|
93
|
+
plexmix sync regenerate
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Option 2: Web User Interface (Alpha)
|
|
97
|
+
|
|
98
|
+
> **Note:** The Web UI is currently in Alpha status. The CLI is the recommended way to interact with PlexMix for production use.
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Install with UI extras
|
|
102
|
+
pip install "plexmix[ui]"
|
|
103
|
+
|
|
104
|
+
# Or if using poetry
|
|
105
|
+
poetry install -E ui
|
|
106
|
+
|
|
107
|
+
# Launch the web UI
|
|
108
|
+
plexmix ui
|
|
109
|
+
|
|
110
|
+
# Optional: Specify host and port
|
|
111
|
+
plexmix ui --host 0.0.0.0 --port 8000
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Then open your browser to `http://localhost:3000`
|
|
115
|
+
|
|
116
|
+
#### Screenshots
|
|
117
|
+
|
|
118
|
+
<div align="center">
|
|
119
|
+
<img src="docs/screenshots/dashboard-light.png" alt="Dashboard - Light Mode" width="45%"/>
|
|
120
|
+
<img src="docs/screenshots/dashboard-dark.png" alt="Dashboard - Dark Mode" width="45%"/>
|
|
121
|
+
<p><em>Dashboard with configuration status and library statistics</em></p>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div align="center">
|
|
125
|
+
<img src="docs/screenshots/generator.png" alt="Playlist Generator" width="90%"/>
|
|
126
|
+
<p><em>AI-powered playlist generator with mood-based queries</em></p>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<div align="center">
|
|
130
|
+
<img src="docs/screenshots/library.png" alt="Library Manager" width="90%"/>
|
|
131
|
+
<p><em>Browse and manage your music library with advanced filtering</em></p>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<div align="center">
|
|
135
|
+
<img src="docs/screenshots/settings.png" alt="Settings" width="90%"/>
|
|
136
|
+
<p><em>Configure Plex, AI providers, and embeddings</em></p>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
#### Web UI Features
|
|
140
|
+
|
|
141
|
+
The web interface provides a modern, intuitive way to interact with PlexMix:
|
|
142
|
+
|
|
143
|
+
- **📊 Dashboard** - Overview of library stats, configuration status, and quick actions
|
|
144
|
+
- **⚙️ Settings** - Configure Plex, AI providers, and embeddings with real-time validation
|
|
145
|
+
- **📚 Library Manager** - Browse, search, and sync your music library with live progress tracking
|
|
146
|
+
- **🎵 Playlist Generator** - Create mood-based playlists with advanced filters and instant preview
|
|
147
|
+
- **🏷️ AI Tagging** - Batch generate tags for tracks with progress monitoring
|
|
148
|
+
- **📜 Playlist History** - View, export, and manage all generated playlists
|
|
149
|
+
|
|
150
|
+
#### Key UI Features
|
|
151
|
+
|
|
152
|
+
- **🌓 Dark/Light Mode** - Toggle between themes with automatic logo switching
|
|
153
|
+
- **Real-time Progress** - Live updates for sync, tagging, and generation operations
|
|
154
|
+
- **Form Validation** - Instant feedback on configuration settings
|
|
155
|
+
- **Loading States** - Skeleton screens and spinners for smooth UX
|
|
156
|
+
- **Error Handling** - User-friendly error messages with recovery options
|
|
157
|
+
- **Responsive Design** - Works on desktop and tablet devices
|
|
158
|
+
|
|
159
|
+
## Installation
|
|
160
|
+
|
|
161
|
+
### From PyPI (Recommended)
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
pip install plexmix
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### From Source
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
git clone https://github.com/izzoa/plexmix.git
|
|
171
|
+
cd plexmix
|
|
172
|
+
poetry install
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Configuration
|
|
176
|
+
|
|
177
|
+
PlexMix uses **Google Gemini by default** for both AI playlist generation and embeddings, requiring only a **single API key**!
|
|
178
|
+
|
|
179
|
+
### Required
|
|
180
|
+
|
|
181
|
+
- **Plex Server**: URL and authentication token
|
|
182
|
+
- **Google API Key**: For Gemini AI and embeddings ([Get one here](https://makersuite.google.com/app/apikey))
|
|
183
|
+
|
|
184
|
+
### Optional Alternative Providers
|
|
185
|
+
|
|
186
|
+
- **OpenAI API Key**: For GPT models and text-embedding-3-small
|
|
187
|
+
- **Anthropic API Key**: For Claude models (AI only, no embeddings)
|
|
188
|
+
- **Cohere API Key**: For Command R7B and Embed v4 models
|
|
189
|
+
- **Local Embeddings**: sentence-transformers (free, offline, no API key needed)
|
|
190
|
+
|
|
191
|
+
### Getting a Plex Token
|
|
192
|
+
|
|
193
|
+
1. Open Plex Web App
|
|
194
|
+
2. Play any media item
|
|
195
|
+
3. Click the three dots (...) → Get Info
|
|
196
|
+
4. View XML
|
|
197
|
+
5. Copy the `X-Plex-Token` from the URL
|
|
198
|
+
|
|
199
|
+
## Usage
|
|
200
|
+
|
|
201
|
+
### Configuration Commands
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
# Interactive setup wizard
|
|
205
|
+
plexmix config init
|
|
206
|
+
|
|
207
|
+
# Test Plex server connection
|
|
208
|
+
plexmix config test
|
|
209
|
+
|
|
210
|
+
# Show current configuration
|
|
211
|
+
plexmix config show
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Troubleshooting Connection Issues:**
|
|
215
|
+
|
|
216
|
+
If you get a "400 Bad Request" error when connecting to Plex:
|
|
217
|
+
|
|
218
|
+
1. **Check your Plex token** - Make sure there are no extra spaces when copying
|
|
219
|
+
2. **Try HTTPS** - Use `https://` instead of `http://` if your server requires secure connections
|
|
220
|
+
3. **Verify the URL** - Ensure the server address and port (default: 32400) are correct
|
|
221
|
+
4. **Check server settings** - In Plex Server settings, look for network/authentication requirements
|
|
222
|
+
5. **Test the connection** - Run `plexmix config test` to diagnose the issue
|
|
223
|
+
|
|
224
|
+
**Common Plex Server URLs:**
|
|
225
|
+
- Local: `http://localhost:32400`
|
|
226
|
+
- Remote: `http://192.168.1.X:32400` (replace X with your server's IP)
|
|
227
|
+
- Secure: `https://your-server:32400`
|
|
228
|
+
|
|
229
|
+
### Sync Commands
|
|
230
|
+
|
|
231
|
+
PlexMix offers three sync modes:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
# Incremental sync (default) - Only syncs new/changed/deleted tracks
|
|
235
|
+
plexmix sync
|
|
236
|
+
|
|
237
|
+
# Same as above, but explicit
|
|
238
|
+
plexmix sync incremental
|
|
239
|
+
|
|
240
|
+
# Regenerate everything from scratch (WARNING: Deletes ALL tags and embeddings)
|
|
241
|
+
plexmix sync regenerate
|
|
242
|
+
|
|
243
|
+
# Legacy alias for incremental sync
|
|
244
|
+
plexmix sync full
|
|
245
|
+
|
|
246
|
+
# Sync without embeddings (faster, but you'll need to generate them later)
|
|
247
|
+
plexmix sync --no-embeddings
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Sync Mode Comparison:**
|
|
251
|
+
|
|
252
|
+
| Mode | Tracks | Tags | Embeddings | Use Case |
|
|
253
|
+
|------|--------|------|------------|----------|
|
|
254
|
+
| `incremental` (default) | ✅ Syncs changes only | ✅ Preserves existing | ✅ Preserves existing | Regular updates, new tracks added |
|
|
255
|
+
| `full` (alias) | ✅ Syncs changes only | ✅ Preserves existing | ✅ Preserves existing | Same as incremental (kept for compatibility) |
|
|
256
|
+
| `regenerate` | ✅ Syncs everything | ⚠️ **DELETES ALL** | ⚠️ **DELETES ALL** | Starting fresh, fixing corrupt data |
|
|
257
|
+
|
|
258
|
+
**When to use each:**
|
|
259
|
+
- **`plexmix sync`** → Default for daily use, adding new music
|
|
260
|
+
- **`plexmix sync regenerate`** → When you want to completely regenerate all AI data (tags, embeddings)
|
|
261
|
+
|
|
262
|
+
### Database Health Check
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
# Diagnose and fix database issues
|
|
266
|
+
plexmix doctor
|
|
267
|
+
|
|
268
|
+
# Force regenerate all tags and embeddings (DEPRECATED: use 'plexmix sync regenerate' instead)
|
|
269
|
+
plexmix doctor --force
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**What does `plexmix doctor` do?**
|
|
273
|
+
- Detects orphaned embeddings (embeddings that reference deleted tracks)
|
|
274
|
+
- Shows database health status (track count, embeddings, orphans)
|
|
275
|
+
- Interactively removes orphaned data
|
|
276
|
+
- Regenerates missing embeddings
|
|
277
|
+
- Rebuilds vector index
|
|
278
|
+
|
|
279
|
+
**When to use:**
|
|
280
|
+
- After "No tracks found matching criteria" errors
|
|
281
|
+
- When playlist generation finds 0 candidates
|
|
282
|
+
- After database corruption or manual track deletion
|
|
283
|
+
- Periodic maintenance to keep database healthy
|
|
284
|
+
|
|
285
|
+
**Note:** For complete regeneration of all tags and embeddings, use `plexmix sync regenerate` instead of `doctor --force`
|
|
286
|
+
|
|
287
|
+
### Database Management
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
# Show database information and statistics
|
|
291
|
+
plexmix db info
|
|
292
|
+
|
|
293
|
+
# Reset database and embeddings (with automatic backup)
|
|
294
|
+
plexmix db reset
|
|
295
|
+
|
|
296
|
+
# Reset without backup (not recommended)
|
|
297
|
+
plexmix db reset --no-backup
|
|
298
|
+
|
|
299
|
+
# Skip confirmation prompt
|
|
300
|
+
plexmix db reset --force
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**What gets deleted:**
|
|
304
|
+
- SQLite database (`~/.plexmix/plexmix.db`)
|
|
305
|
+
- FAISS embeddings index (`~/.plexmix/embeddings.index`)
|
|
306
|
+
- All synced music metadata
|
|
307
|
+
- User-applied tags (moods, environments, instruments)
|
|
308
|
+
- Playlist history
|
|
309
|
+
- AI-generated embeddings
|
|
310
|
+
|
|
311
|
+
**What gets preserved:**
|
|
312
|
+
- Your music files on Plex server (unchanged)
|
|
313
|
+
- Plex server metadata (unchanged)
|
|
314
|
+
- PlexMix configuration (`.env`, `config.yaml`)
|
|
315
|
+
- API keys
|
|
316
|
+
|
|
317
|
+
**When to use:**
|
|
318
|
+
- Complete fresh start
|
|
319
|
+
- Switching embedding providers
|
|
320
|
+
- Database corruption that `doctor` can't fix
|
|
321
|
+
- Testing or development
|
|
322
|
+
|
|
323
|
+
**After reset:**
|
|
324
|
+
1. Run `plexmix sync` to re-sync your library
|
|
325
|
+
2. (Optional) Run `plexmix tags generate` to re-tag tracks
|
|
326
|
+
|
|
327
|
+
By default, a timestamped backup is created in `~/.plexmix/backups/` before deletion.
|
|
328
|
+
|
|
329
|
+
**Database Command Reference:**
|
|
330
|
+
|
|
331
|
+
| Command | Purpose | When to Use |
|
|
332
|
+
|---------|---------|-------------|
|
|
333
|
+
| `plexmix db info` | Show database stats | Check database health, view track/embedding counts |
|
|
334
|
+
| `plexmix db reset` | Delete and reset database | Fresh start, switching providers, unfixable corruption |
|
|
335
|
+
| `plexmix sync` | Incremental sync | Regular updates, new tracks |
|
|
336
|
+
| `plexmix sync regenerate` | Regenerate all data | Regenerate tags/embeddings, fix data quality |
|
|
337
|
+
| `plexmix doctor` | Fix orphaned data | After errors, periodic maintenance |
|
|
338
|
+
|
|
339
|
+
### Tag Generation
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
# Generate AI tags for all untagged tracks
|
|
343
|
+
plexmix tags generate
|
|
344
|
+
|
|
345
|
+
# Use alternative AI provider
|
|
346
|
+
plexmix tags generate --provider openai
|
|
347
|
+
|
|
348
|
+
# Skip embedding regeneration (faster, but tags won't be in search)
|
|
349
|
+
plexmix tags generate --no-regenerate-embeddings
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Embedding Generation
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
# Generate embeddings for tracks without them
|
|
356
|
+
plexmix embeddings generate
|
|
357
|
+
|
|
358
|
+
# Regenerate all embeddings from scratch
|
|
359
|
+
plexmix embeddings generate --regenerate
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**What are tags?**
|
|
363
|
+
AI-generated metadata (per track) that enhances semantic search:
|
|
364
|
+
- **Tags** (3-5): Mood descriptors like energetic, melancholic, upbeat, chill, intense
|
|
365
|
+
- **Environments** (1-3): Best-fit contexts like work, study, focus, relax, party, workout, sleep, driving, social
|
|
366
|
+
- **Instruments** (1-3): Most prominent instruments like piano, guitar, saxophone, drums, bass, synth, vocals, strings
|
|
367
|
+
|
|
368
|
+
All metadata is automatically included in embeddings for more accurate mood-based playlist generation.
|
|
369
|
+
|
|
370
|
+
### Playlist Generation
|
|
371
|
+
|
|
372
|
+
```bash
|
|
373
|
+
# Basic playlist (prompts for track count)
|
|
374
|
+
plexmix create "happy upbeat summer vibes"
|
|
375
|
+
|
|
376
|
+
# Specify track count
|
|
377
|
+
plexmix create "rainy day melancholy" --limit 25
|
|
378
|
+
|
|
379
|
+
# Filter by genre
|
|
380
|
+
plexmix create "energetic workout" --genre rock --limit 40
|
|
381
|
+
|
|
382
|
+
# Filter by year range
|
|
383
|
+
plexmix create "90s nostalgia" --year-min 1990 --year-max 1999
|
|
384
|
+
|
|
385
|
+
# Filter by environment (work, study, focus, relax, party, workout, sleep, driving, social)
|
|
386
|
+
plexmix create "workout energy" --environment workout
|
|
387
|
+
|
|
388
|
+
# Filter by instrument (piano, guitar, saxophone, drums, etc.)
|
|
389
|
+
plexmix create "piano jazz" --instrument piano
|
|
390
|
+
|
|
391
|
+
# Use specific AI provider
|
|
392
|
+
plexmix create "chill study session" --provider claude
|
|
393
|
+
|
|
394
|
+
# Custom playlist name
|
|
395
|
+
plexmix create "morning coffee" --name "Perfect Morning Mix"
|
|
396
|
+
|
|
397
|
+
# Adjust candidate pool multiplier (default: 25x playlist length)
|
|
398
|
+
plexmix create "diverse mix" --limit 20 --pool-multiplier 50
|
|
399
|
+
|
|
400
|
+
# Don't create in Plex (save locally only)
|
|
401
|
+
plexmix create "test playlist" --no-create-in-plex
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
## Architecture
|
|
405
|
+
|
|
406
|
+
PlexMix uses a multi-stage pipeline for intelligent playlist generation:
|
|
407
|
+
|
|
408
|
+
1. **AI Tagging** (One-time setup) → Tracks receive:
|
|
409
|
+
- 3-5 descriptive tags (mood, energy, tempo, emotion)
|
|
410
|
+
- 1-3 environments (work, study, focus, relax, party, workout, sleep, driving, social)
|
|
411
|
+
- 1-3 instruments (piano, guitar, saxophone, drums, bass, synth, vocals, strings, etc.)
|
|
412
|
+
|
|
413
|
+
2. **Playlist Generation Pipeline**:
|
|
414
|
+
- **SQL Filters** → Apply optional filters (genre, year, rating, artist, environment, instrument)
|
|
415
|
+
- **Candidate Pool** → Search using FAISS vector similarity (default: 25x playlist length)
|
|
416
|
+
- **Diversity Selection** → Apply algorithmic diversity rules:
|
|
417
|
+
- Max 3 tracks per artist
|
|
418
|
+
- Max 2 tracks per album
|
|
419
|
+
- No duplicate track/artist combinations
|
|
420
|
+
- **Final Playlist** → Return curated, diverse track list
|
|
421
|
+
|
|
422
|
+
### Technology Stack
|
|
423
|
+
|
|
424
|
+
- **Language**: Python 3.10+
|
|
425
|
+
- **CLI**: Typer with Rich console output
|
|
426
|
+
- **Database**: SQLite with FTS5 full-text search
|
|
427
|
+
- **Vector Search**: FAISS (CPU) with cosine similarity
|
|
428
|
+
- **AI Providers**: Google Gemini (default), OpenAI GPT, Anthropic Claude, Cohere
|
|
429
|
+
- **Embeddings**: Google Gemini (3072d), OpenAI (1536d), Local (384-768d)
|
|
430
|
+
- **Plex Integration**: PlexAPI
|
|
431
|
+
|
|
432
|
+
### Project Structure
|
|
433
|
+
|
|
434
|
+
```
|
|
435
|
+
plexmix/
|
|
436
|
+
├── src/plexmix/
|
|
437
|
+
│ ├── ai/ # AI provider implementations
|
|
438
|
+
│ │ ├── base.py # Abstract base class
|
|
439
|
+
│ │ ├── gemini_provider.py
|
|
440
|
+
│ │ ├── openai_provider.py
|
|
441
|
+
│ │ ├── claude_provider.py
|
|
442
|
+
│ │ └── tag_generator.py # AI-based tag generation
|
|
443
|
+
│ ├── cli/ # Command-line interface
|
|
444
|
+
│ │ └── main.py # Typer CLI app
|
|
445
|
+
│ ├── config/ # Configuration management
|
|
446
|
+
│ │ ├── settings.py # Pydantic settings
|
|
447
|
+
│ │ └── credentials.py # Keyring integration
|
|
448
|
+
│ ├── database/ # Database layer
|
|
449
|
+
│ │ ├── models.py # Pydantic models
|
|
450
|
+
│ │ ├── sqlite_manager.py # SQLite CRUD
|
|
451
|
+
│ │ └── vector_index.py # FAISS index
|
|
452
|
+
│ ├── plex/ # Plex integration
|
|
453
|
+
│ │ ├── client.py # PlexAPI wrapper
|
|
454
|
+
│ │ └── sync.py # Sync engine
|
|
455
|
+
│ ├── playlist/ # Playlist generation
|
|
456
|
+
│ │ └── generator.py # Core generation logic
|
|
457
|
+
│ ├── ui/ # Web UI (Reflex)
|
|
458
|
+
│ │ ├── app.py # Main Reflex app
|
|
459
|
+
│ │ ├── pages/ # UI pages
|
|
460
|
+
│ │ ├── states/ # State management
|
|
461
|
+
│ │ ├── components/ # Reusable components
|
|
462
|
+
│ │ └── utils/ # UI utilities
|
|
463
|
+
│ └── utils/ # Utilities
|
|
464
|
+
│ ├── embeddings.py # Embedding providers
|
|
465
|
+
│ └── logging.py # Logging setup
|
|
466
|
+
└── tests/ # Test suite
|
|
467
|
+
└── ui/ # UI tests
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
## Database Schema
|
|
471
|
+
|
|
472
|
+
PlexMix stores all music metadata locally:
|
|
473
|
+
|
|
474
|
+
- **artists**: Artist information
|
|
475
|
+
- **albums**: Album details with artist relationships
|
|
476
|
+
- **tracks**: Track metadata with full-text search, AI-generated tags (3-5), environments (1-3), and instruments (1-3)
|
|
477
|
+
- **embeddings**: Vector embeddings for semantic search (includes all AI-generated metadata)
|
|
478
|
+
- **playlists**: Generated playlist metadata
|
|
479
|
+
- **sync_history**: Synchronization audit log
|
|
480
|
+
|
|
481
|
+
## AI Provider Comparison
|
|
482
|
+
|
|
483
|
+
| Provider | Model | Context Window | Default Temp | Speed | Quality | Cost | Best For |
|
|
484
|
+
|----------|-------|----------------|--------------|-------|---------|------|----------|
|
|
485
|
+
| **Google Gemini** ⭐ | gemini-2.5-flash | 1M tokens | 0.7 | ⚡⚡⚡ Fast | ⭐⭐⭐⭐ Excellent | 💰 Low | General use, RAG, large contexts |
|
|
486
|
+
| OpenAI | gpt-5-mini | 400K tokens | 0.7 | ⚡⚡ Moderate | ⭐⭐⭐⭐⭐ Outstanding | 💰💰 Medium | High-quality responses, reasoning |
|
|
487
|
+
| OpenAI | gpt-5-nano | 400K tokens | 0.7 | ⚡⚡⚡ Fast | ⭐⭐⭐⭐ Excellent | 💰 Low | Speed-optimized, efficient |
|
|
488
|
+
| Cohere | command-r7b-12-2024 | 128K tokens | 0.3 | ⚡⚡⚡ Fast | ⭐⭐⭐⭐ Excellent | 💰 Low | RAG, tool use, agents |
|
|
489
|
+
| Cohere | command-r-plus-08-2024 | 128K tokens | 0.3 | ⚡⚡ Moderate | ⭐⭐⭐⭐⭐ Outstanding | 💰💰 Medium | Multilingual, complex tasks |
|
|
490
|
+
| Cohere | command-r-08-2024 | 128K tokens | 0.3 | ⚡⚡⚡ Fast | ⭐⭐⭐⭐ Excellent | 💰 Low | Balanced performance |
|
|
491
|
+
| Anthropic | claude-sonnet-4-5 | 200K tokens | 0.7 | ⚡⚡ Moderate | ⭐⭐⭐⭐⭐ Outstanding | 💰💰💰 High | Advanced reasoning, analysis |
|
|
492
|
+
| Anthropic | claude-3-5-haiku-20241022 | 200K tokens | 0.7 | ⚡⚡⚡ Fast | ⭐⭐⭐⭐ Excellent | 💰 Low | Fast responses, efficiency |
|
|
493
|
+
|
|
494
|
+
**Legend:**
|
|
495
|
+
- ⭐ Default/recommended option
|
|
496
|
+
- Speed: ⚡ Slow, ⚡⚡ Moderate, ⚡⚡⚡ Fast
|
|
497
|
+
- Quality: ⭐ Basic → ⭐⭐⭐⭐⭐ Outstanding
|
|
498
|
+
- Cost: 💰 Low, 💰💰 Medium, 💰💰💰 High
|
|
499
|
+
|
|
500
|
+
## Embedding Provider Comparison
|
|
501
|
+
|
|
502
|
+
| Provider | Model | Dimensions | Quality | Speed | Cost | API Key | Best For |
|
|
503
|
+
|----------|-------|------------|---------|-------|------|---------|----------|
|
|
504
|
+
| **Google Gemini** ⭐ | gemini-embedding-001 | 3072 | ⭐⭐⭐⭐⭐ Outstanding | ⚡⚡ Moderate | 💰 Low | Required | High-dimensional, accurate semantic search |
|
|
505
|
+
| OpenAI | text-embedding-3-small | 1536 | ⭐⭐⭐⭐ Excellent | ⚡⚡⚡ Fast | 💰💰 Medium | Required | Balanced performance, OpenAI ecosystem |
|
|
506
|
+
| Cohere | embed-v4 | 256/512/1024/1536 | ⭐⭐⭐⭐ Excellent | ⚡⚡⚡ Fast | 💰 Low | Required | Flexible dimensions (Matryoshka), multimodal |
|
|
507
|
+
| Local | all-MiniLM-L6-v2 | 384 | ⭐⭐⭐ Good | ⚡⚡⚡ Fast | 💰 Free | None | Offline use, privacy, no API costs |
|
|
508
|
+
|
|
509
|
+
**Key Features:**
|
|
510
|
+
- **Gemini**: Highest dimensions (3072d) for maximum semantic precision
|
|
511
|
+
- **OpenAI**: Industry standard, excellent ecosystem integration
|
|
512
|
+
- **Cohere**: Configurable dimensions (256/512/1024/1536), supports images with v4
|
|
513
|
+
- **Local**: Completely free, offline, private, no internet required
|
|
514
|
+
|
|
515
|
+
**Dimension Trade-offs:**
|
|
516
|
+
- Higher dimensions = Better semantic understanding but larger storage
|
|
517
|
+
- Lower dimensions = Faster search but slightly less accurate
|
|
518
|
+
- Cohere's Matryoshka embeddings allow dynamic dimension selection
|
|
519
|
+
|
|
520
|
+
## Development
|
|
521
|
+
|
|
522
|
+
### Setup Development Environment
|
|
523
|
+
|
|
524
|
+
```bash
|
|
525
|
+
# Clone repository
|
|
526
|
+
git clone https://github.com/izzoa/plexmix.git
|
|
527
|
+
cd plexmix
|
|
528
|
+
|
|
529
|
+
# Install with development dependencies
|
|
530
|
+
poetry install
|
|
531
|
+
|
|
532
|
+
# Run tests
|
|
533
|
+
poetry run pytest
|
|
534
|
+
|
|
535
|
+
# Format code
|
|
536
|
+
poetry run black src/
|
|
537
|
+
|
|
538
|
+
# Lint
|
|
539
|
+
poetry run ruff src/
|
|
540
|
+
|
|
541
|
+
# Type check
|
|
542
|
+
poetry run mypy src/
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
### Running Tests
|
|
546
|
+
|
|
547
|
+
```bash
|
|
548
|
+
poetry run pytest
|
|
549
|
+
poetry run pytest --cov=plexmix --cov-report=html
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
## Troubleshooting
|
|
553
|
+
|
|
554
|
+
### "No music libraries found"
|
|
555
|
+
- Ensure your Plex server has a music library
|
|
556
|
+
- Verify your Plex token is correct
|
|
557
|
+
- Check server URL is accessible
|
|
558
|
+
|
|
559
|
+
### "Failed to generate embeddings"
|
|
560
|
+
- Verify API keys are configured correctly
|
|
561
|
+
- Check internet connection
|
|
562
|
+
- Try local embeddings: `--embedding-provider local`
|
|
563
|
+
|
|
564
|
+
### "No tracks found matching criteria"
|
|
565
|
+
- **First, try:** `plexmix doctor` to check for database issues
|
|
566
|
+
- Ensure library is synced: `plexmix sync`
|
|
567
|
+
- Check filters aren't too restrictive
|
|
568
|
+
- Verify embeddings were generated
|
|
569
|
+
|
|
570
|
+
### "0 candidate tracks" or "No orphaned embeddings"
|
|
571
|
+
- This usually means embeddings reference old track IDs
|
|
572
|
+
- **Solution:** Run `plexmix doctor` to detect and fix orphaned embeddings
|
|
573
|
+
- The doctor will clean up orphaned data and regenerate embeddings
|
|
574
|
+
|
|
575
|
+
### Performance Tips
|
|
576
|
+
|
|
577
|
+
- Use local embeddings for faster offline operation
|
|
578
|
+
- Run sync during off-peak hours for large libraries
|
|
579
|
+
- Adjust candidate pool multiplier based on library size (default: 25x playlist length)
|
|
580
|
+
- Smaller libraries: Use lower multiplier (10-15x) for faster generation
|
|
581
|
+
- Larger libraries: Use higher multiplier (30-50x) for better diversity
|
|
582
|
+
- Use filters to narrow search space
|
|
583
|
+
|
|
584
|
+
## FAQ
|
|
585
|
+
|
|
586
|
+
### How does PlexMix work?
|
|
587
|
+
|
|
588
|
+
PlexMix syncs your Plex music library to a local SQLite database, generates AI-powered tags (mood, instruments, environments) for each track, creates semantic embeddings, and uses vector similarity search combined with LLM intelligence to generate playlists from natural language mood descriptions.
|
|
589
|
+
|
|
590
|
+
### Do I need an API key?
|
|
591
|
+
|
|
592
|
+
Yes, but only one! Google Gemini is the default provider for both AI and embeddings. You can get a free API key at [Google AI Studio](https://makersuite.google.com/app/apikey). Alternative providers (OpenAI, Anthropic, local embeddings) are optional.
|
|
593
|
+
|
|
594
|
+
### How much does it cost to run?
|
|
595
|
+
|
|
596
|
+
**Google Gemini (default)**:
|
|
597
|
+
- Embedding generation: ~$0.10-0.30 for 10,000 tracks (one-time)
|
|
598
|
+
- Tag generation: ~$0.20-0.50 for 10,000 tracks (one-time)
|
|
599
|
+
- Playlist creation: ~$0.01 per playlist (ongoing)
|
|
600
|
+
|
|
601
|
+
**Alternatives**:
|
|
602
|
+
- Local embeddings are completely free (no API key needed)
|
|
603
|
+
- OpenAI and Anthropic have similar costs
|
|
604
|
+
|
|
605
|
+
### How long does initial sync take?
|
|
606
|
+
|
|
607
|
+
- **Metadata sync**: 5-15 minutes for 10,000 tracks
|
|
608
|
+
- **Tag generation**: 30-60 minutes for 10,000 tracks
|
|
609
|
+
- **Embedding generation**: 15-30 minutes for 10,000 tracks
|
|
610
|
+
|
|
611
|
+
Total: ~1-2 hours for a large library. You can interrupt and resume at any time.
|
|
612
|
+
|
|
613
|
+
### Can I use this without internet?
|
|
614
|
+
|
|
615
|
+
Partially. After initial sync and tag/embedding generation, you can:
|
|
616
|
+
- ✅ Browse your database offline
|
|
617
|
+
- ✅ Use local embeddings (no API needed)
|
|
618
|
+
- ❌ Generate new playlists (requires AI API)
|
|
619
|
+
- ❌ Generate tags for new tracks (requires AI API)
|
|
620
|
+
|
|
621
|
+
### What's the difference between tags, environments, and instruments?
|
|
622
|
+
|
|
623
|
+
- **Tags** (3-5): Mood and vibe descriptors like "energetic", "melancholic", "upbeat", "chill"
|
|
624
|
+
- **Environments** (1-3): Best contexts for listening like "work", "study", "workout", "party"
|
|
625
|
+
- **Instruments** (1-3): Most prominent instruments like "piano", "guitar", "saxophone", "drums"
|
|
626
|
+
|
|
627
|
+
All three are automatically generated by AI and improve playlist quality.
|
|
628
|
+
|
|
629
|
+
### Why am I getting "0 candidate tracks"?
|
|
630
|
+
|
|
631
|
+
This usually means:
|
|
632
|
+
1. **No embeddings generated**: Run `plexmix embeddings generate`
|
|
633
|
+
2. **Database out of sync**: Run `plexmix doctor` to fix
|
|
634
|
+
3. **Filters too restrictive**: Remove some filters and try again
|
|
635
|
+
4. **Empty library**: Ensure `plexmix sync` completed successfully
|
|
636
|
+
|
|
637
|
+
### Can I use multiple Plex libraries?
|
|
638
|
+
|
|
639
|
+
Not yet. Currently PlexMix supports one music library at a time. Multi-library support is on the roadmap.
|
|
640
|
+
|
|
641
|
+
### Does this modify my Plex server?
|
|
642
|
+
|
|
643
|
+
Only when creating playlists. PlexMix:
|
|
644
|
+
- ✅ Reads metadata from Plex (read-only)
|
|
645
|
+
- ✅ Creates playlists in Plex (if enabled with `--create-in-plex`)
|
|
646
|
+
- ❌ Does NOT modify tracks, albums, or artists
|
|
647
|
+
- ❌ Does NOT delete anything from Plex
|
|
648
|
+
|
|
649
|
+
### What happens if I delete tracks from Plex?
|
|
650
|
+
|
|
651
|
+
Run `plexmix sync` to update your local database. The incremental sync will:
|
|
652
|
+
- Detect deleted tracks from Plex
|
|
653
|
+
- Remove them from the database
|
|
654
|
+
- Clean up orphaned embeddings
|
|
655
|
+
- Update the vector index
|
|
656
|
+
|
|
657
|
+
Or use `plexmix doctor` to clean up orphaned data.
|
|
658
|
+
|
|
659
|
+
### Can I backup my database?
|
|
660
|
+
|
|
661
|
+
Yes! Your database is stored at `~/.plexmix/plexmix.db`. Simply copy this file and the `~/.plexmix/embeddings.index` file to backup all your data, tags, and embeddings.
|
|
662
|
+
|
|
663
|
+
### How do I update PlexMix?
|
|
664
|
+
|
|
665
|
+
```bash
|
|
666
|
+
pip install --upgrade plexmix
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
After updating, run `plexmix sync --no-embeddings` to apply any database migrations.
|
|
670
|
+
|
|
671
|
+
### Can I contribute?
|
|
672
|
+
|
|
673
|
+
Absolutely! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. We welcome bug reports, feature requests, and pull requests.
|
|
674
|
+
|
|
675
|
+
## Roadmap
|
|
676
|
+
|
|
677
|
+
- [ ] Docker support
|
|
678
|
+
- [ ] Multi-library support
|
|
679
|
+
- [ ] Playlist templates
|
|
680
|
+
- [ ] Smart shuffle and ordering
|
|
681
|
+
- [ ] Export/import playlists (M3U, JSON)
|
|
682
|
+
- [ ] Audio feature analysis integration
|
|
683
|
+
|
|
684
|
+
## Contributing
|
|
685
|
+
|
|
686
|
+
Contributions welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
687
|
+
|
|
688
|
+
1. Fork the repository
|
|
689
|
+
2. Create a feature branch
|
|
690
|
+
3. Make your changes
|
|
691
|
+
4. Add tests
|
|
692
|
+
5. Submit a pull request
|
|
693
|
+
|
|
694
|
+
## License
|
|
695
|
+
|
|
696
|
+
MIT License - see [LICENSE](LICENSE) for details
|
|
697
|
+
|
|
698
|
+
## Acknowledgments
|
|
699
|
+
|
|
700
|
+
- Built with [Typer](https://typer.tiangolo.com/) and [Rich](https://rich.readthedocs.io/)
|
|
701
|
+
- Plex integration via [python-plexapi](https://github.com/pkkid/python-plexapi)
|
|
702
|
+
- Vector search powered by [FAISS](https://github.com/facebookresearch/faiss)
|
|
703
|
+
- AI providers: Google, OpenAI, Anthropic, Cohere
|
|
704
|
+
|
|
705
|
+
---
|
|
706
|
+
|
|
707
|
+
**Made with ❤️ for music lovers**
|
|
708
|
+
|