{"id":43902972,"url":"https://github.com/ecwilsonaz/mediasage","last_synced_at":"2026-02-21T00:27:34.673Z","repository":{"id":336539457,"uuid":"1149893487","full_name":"ecwilsonaz/mediasage","owner":"ecwilsonaz","description":"Unofficial AI-powered Plex playlist generator with library awareness. Every track it suggests, you actually own.","archived":false,"fork":false,"pushed_at":"2026-02-09T22:38:18.000Z","size":12000,"stargazers_count":31,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-09T23:41:19.944Z","etag":null,"topics":["claude","gemini","llm","music","openai","playlist-generator","plex","plexamp","self-hosted"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ecwilsonaz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-04T16:37:42.000Z","updated_at":"2026-02-09T22:38:21.000Z","dependencies_parsed_at":"2026-02-08T21:00:57.739Z","dependency_job_id":null,"html_url":"https://github.com/ecwilsonaz/mediasage","commit_stats":null,"previous_names":["ecwilsonaz/plexsage","ecwilsonaz/mediasage"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/ecwilsonaz/mediasage","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ecwilsonaz%2Fmediasage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ecwilsonaz%2Fmediasage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ecwilsonaz%2Fmediasage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ecwilsonaz%2Fmediasage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ecwilsonaz","download_url":"https://codeload.github.com/ecwilsonaz/mediasage/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ecwilsonaz%2Fmediasage/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29321276,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-10T20:44:44.282Z","status":"ssl_error","status_checked_at":"2026-02-10T20:44:43.393Z","response_time":65,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["claude","gemini","llm","music","openai","playlist-generator","plex","plexamp","self-hosted"],"created_at":"2026-02-06T19:16:10.865Z","updated_at":"2026-02-21T00:27:34.666Z","avatar_url":"https://github.com/ecwilsonaz.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MediaSage for Plex\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Docker Hub](https://img.shields.io/badge/docker-ecwilson%2Fmediasage-blue)](https://hub.docker.com/r/ecwilson/mediasage)\n[![GHCR](https://img.shields.io/badge/ghcr-ecwilsonaz%2Fmediasage-blue)](https://ghcr.io/ecwilsonaz/mediasage)\n[![Python 3.14+](https://img.shields.io/badge/python-3.14+-blue.svg)](https://www.python.org/downloads/)\n\n**AI-powered playlists and album recommendations for Plex—using only music you actually own.**\n\nMediaSage is a self-hosted web app that creates playlists and recommends albums by combining LLM intelligence with your Plex library. Every suggestion is guaranteed playable because it only considers music you have.\n\n*Sample Generated Playlist:*\n![MediaSage Screenshot](docs/images/screenshot-playlist.png)\n\n*Sample Generated Album Recommendation:*\n![MediaSage Screenshot](docs/images/screenshot-album.png)\n\n*Home Screen:*\n![MediaSage Screenshot](docs/images/screenshot-home.png)\n\n*Playlist Flow:*\n![MediaSage Screenshot](docs/images/screenshot-playlist-start.png)\n\n*Album Flow:*\n![MediaSage Screenshot](docs/images/screenshot-album-start.png)\n\n---\n\n## Quick Start\n\n```bash\ndocker run -d \\\n  --name mediasage \\\n  -p 5765:5765 \\\n  -v mediasage-data:/app/data \\\n  --restart unless-stopped \\\n  ghcr.io/ecwilsonaz/mediasage:latest\n```\n\nOpen **http://localhost:5765** — a setup wizard walks you through connecting Plex, choosing an AI provider, and syncing your library.\n\nYou can also pass credentials as environment variables to skip the wizard. See [Configuration](#configuration) for details.\n\n**Requirements:** Docker, a Plex server with music, a [Plex token](https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/), and an API key from Google, Anthropic, or OpenAI (or a local model via Ollama).\n\n---\n\n## Contents\n\n- [Why MediaSage?](#why-mediasage)\n- [Features](#features)\n- [Installation](#installation)\n- [Configuration](#configuration)\n- [How It Works](#how-it-works)\n- [Development](#development)\n- [API Reference](#api-reference)\n\n---\n\n## Why MediaSage?\n\n**Plex users with personal music libraries have few good options for AI playlists.**\n\nPlexamp's built-in Sonic Sage used ChatGPT to generate playlists, but it was designed around Tidal streaming. The AI recommended tracks from an unlimited catalog, and Tidal made them playable. The \"limit to library\" setting just hid results you didn't own—so if you asked for 25 tracks and only 4 existed in your library, you got a 4-track playlist.\n\nWhen [Tidal integration ended in October 2024](https://forums.plex.tv/t/tidal-integration-with-plex-ending-october-28-2024/885728), Sonic Sage lost its foundation. Generic tools like ChatGPT have the same problem: they recommend from an infinite catalog with no awareness of what you actually own.\n\n**MediaSage inverts the approach:**\n\n| Filter-Last (Sonic Sage, ChatGPT) | Filter-First (MediaSage) |\n|-----------------------------------|-------------------------|\n| AI recommends from infinite catalog | AI only sees your library |\n| Hide missing tracks after | No missing tracks possible |\n| Near-empty playlists | Full playlists, every time |\n\nThe result: every track in every playlist exists in your Plex library and plays immediately.\n\n---\n\n## Features\n\n### Playlist Generation\n\nCreate playlists two ways:\n\n**Describe what you want** — Natural language prompts like:\n- \"Melancholy 90s alternative for a rainy day\"\n- \"Upbeat instrumental jazz for a dinner party\"\n- \"Late night electronic, nothing too aggressive\"\n\n**Start from a song** — Pick a track you love, then explore musical dimensions: mood, era, instrumentation, genre, production style. Select which qualities you want more of.\n\n### Album Recommendations\n\nDescribe a mood or moment, answer two quick questions about your preferences, and get a single perfect album to listen to—with an editorial pitch explaining why it fits.\n\n- **Library mode** — recommends albums you own, ready for instant playback\n- **Discovery mode** — suggests albums you don't own yet, based on your taste profile\n- **Familiarity control** — choose between comfort picks, hidden gems, or rediscoveries\n- **Show Me Another** — regenerate without starting over\n- Primary recommendation with a full write-up, plus two secondary picks\n\n### Smart Filtering\n\nBefore the AI sees anything, you control the pool:\n- **Genres** — Select from your library's actual genre tags\n- **Decades** — Filter by era\n- **Minimum rating** — Only tracks rated 3+, 4+, etc.\n- **Exclude live versions** — Skip concert recordings automatically\n\nReal-time track counts show exactly how your filters narrow results.\n\n### Local Library Cache\n\nMediaSage syncs your Plex library to a local SQLite database. After a one-time sync (~2 min for 18,000 tracks), all library operations—filtering, counting, sending to AI—happen locally in milliseconds instead of waiting on Plex.\n\n- **Setup wizard** walks you through first-run configuration and sync\n- **Footer status** shows track count and last sync time\n- **Auto-refresh** keeps cache current (syncs if \u003e24h stale)\n- **Manual refresh** available anytime\n\n### Multi-Provider Support\n\nBring your own API key—or run locally:\n\n| Provider | Max Tracks | Typical Cost | Best For |\n|----------|------------|--------------|----------|\n| **Google Gemini** | ~18,000 | $0.03 – $0.25 | Large libraries, lowest cost |\n| **Anthropic Claude** | ~3,500 | $0.15 – $0.25 | Nuanced recommendations |\n| **OpenAI GPT** | ~2,300 | $0.05 – $0.10 | Solid all-around |\n| **Ollama** ⚗️ | Varies | Free | Privacy, local inference |\n| **Custom** ⚗️ | Configurable | Free | Self-hosted, OpenAI-compatible APIs |\n\n⚗️ *Local LLM support is experimental. [Report issues](https://github.com/ecwilsonaz/mediasage/issues).*\n\n\u003e **Free option:** Google Gemini offers a free API tier that's more than enough for personal use — no credit card required. See the [Gemini free credit guide](docs/gemini-free-credit-guide.md) for setup instructions and details.\n\nEstimated cost displays before you generate. MediaSage auto-detects your provider based on which key you configure.\n\n### Play and Save\n\n- **Play Now** — send tracks directly to any Plex device for instant playback\n- **Create** a new playlist, **replace** an existing one, or **append** tracks to one\n- Device picker shows all active Plex clients with status indicators\n- Duplicate detection when appending to existing playlists\n- Preview tracks with album art before saving\n- Remove tracks you don't want\n- Rename the playlist\n- See actual token usage and cost\n\n---\n\n## Installation\n\n### Docker Compose (Recommended)\n\n```bash\nmkdir mediasage \u0026\u0026 cd mediasage\ncurl -O https://raw.githubusercontent.com/ecwilsonaz/mediasage/main/docker-compose.yml\ncurl -O https://raw.githubusercontent.com/ecwilsonaz/mediasage/main/.env.example\nmv .env.example .env\n```\n\nEdit `.env`:\n\n```bash\nPLEX_URL=http://your-plex-server:32400\nPLEX_TOKEN=your-plex-token\n\n# Choose ONE provider:\nGEMINI_API_KEY=your-gemini-key\n# ANTHROPIC_API_KEY=sk-ant-your-key\n# OPENAI_API_KEY=sk-your-key\n```\n\nStart:\n\n```bash\ndocker compose up -d\n```\n\n### NAS Platforms\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eSynology (Container Manager)\u003c/strong\u003e\u003c/summary\u003e\n\n**GUI:**\n1. **Container Manager** → **Registry** → Search `ghcr.io/ecwilsonaz/mediasage`\n2. Download `latest` tag\n3. **Container** → **Create**\n4. Port: 5765 → 5765\n5. Add environment variables: `PLEX_URL`, `PLEX_TOKEN`, `GEMINI_API_KEY`\n\n**Docker Compose:**\n```bash\nmkdir -p /volume1/docker/mediasage \u0026\u0026 cd /volume1/docker/mediasage\ncurl -O https://raw.githubusercontent.com/ecwilsonaz/mediasage/main/docker-compose.yml\ncurl -O https://raw.githubusercontent.com/ecwilsonaz/mediasage/main/.env.example\nmv .env.example .env \u0026\u0026 nano .env\n```\nThen in **Container Manager** → **Project** → **Create**, point to `/volume1/docker/mediasage`.\n\n**No Docker?** Some Synology models (especially ARM-based units) don't support Docker/Container Manager. See [Bare Metal](#bare-metal-no-docker) below for running MediaSage directly with Python.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eUnraid\u003c/strong\u003e\u003c/summary\u003e\n\n1. **Docker** → **Add Container**\n2. Repository: `ghcr.io/ecwilsonaz/mediasage:latest`\n3. Port: 5765 → 5765\n4. Add variables: `PLEX_URL`, `PLEX_TOKEN`, `GEMINI_API_KEY`\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eTrueNAS SCALE\u003c/strong\u003e\u003c/summary\u003e\n\n1. **Apps** → **Discover Apps** → **Custom App**\n2. Image: `ghcr.io/ecwilsonaz/mediasage`, Tag: `latest`\n3. Port: 5765\n4. Add environment variables\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003ePortainer\u003c/strong\u003e\u003c/summary\u003e\n\n**Stacks** → **Add Stack**:\n\n```yaml\nservices:\n  mediasage:\n    image: ghcr.io/ecwilsonaz/mediasage:latest\n    ports:\n      - \"5765:5765\"\n    environment:\n      - PLEX_URL=http://your-server:32400\n      - PLEX_TOKEN=your-token\n      - GEMINI_API_KEY=your-key\n    volumes:\n      - ./data:/app/data\n    restart: unless-stopped\n```\n\n\u003c/details\u003e\n\n### Bare Metal (No Docker)\n\nDocker isn't required. MediaSage is Python + FastAPI with no native dependencies, so it runs on any machine with Python 3.11+ — including ARM-based Synology NAS models, Raspberry Pis, or any Linux/macOS/Windows box.\n\n```bash\ngit clone https://github.com/ecwilsonaz/mediasage.git\ncd mediasage\npython -m venv venv\nsource venv/bin/activate\npip install -r requirements.txt\n```\n\nSet your environment variables:\n\n```bash\nexport PLEX_URL=http://your-plex-server:32400\nexport PLEX_TOKEN=your-plex-token\nexport GEMINI_API_KEY=your-gemini-key\n```\n\nStart the server:\n\n```bash\nuvicorn backend.main:app --host 0.0.0.0 --port 5765\n```\n\nAccess at **http://your-machine-ip:5765**.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eRunning as a background service (systemd)\u003c/strong\u003e\u003c/summary\u003e\n\nTo keep MediaSage running after you close your terminal, create a systemd service:\n\n```ini\n# /etc/systemd/system/mediasage.service\n[Unit]\nDescription=MediaSage\nAfter=network.target\n\n[Service]\nType=simple\nUser=your-user\nWorkingDirectory=/path/to/mediasage\nEnvironmentFile=/path/to/mediasage/.env\nExecStart=/path/to/mediasage/venv/bin/uvicorn backend.main:app --host 0.0.0.0 --port 5765\nRestart=on-failure\n\n[Install]\nWantedBy=multi-user.target\n```\n\n```bash\nsudo systemctl enable mediasage\nsudo systemctl start mediasage\n```\n\n\u003c/details\u003e\n\n---\n\n## Configuration\n\n### Environment Variables\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `PLEX_URL` | Yes | Plex server URL (e.g., `http://192.168.1.100:32400`) |\n| `PLEX_TOKEN` | Yes | [Plex authentication token](https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/) |\n| `GEMINI_API_KEY` | One required | Google Gemini API key |\n| `ANTHROPIC_API_KEY` | One required | Anthropic API key |\n| `OPENAI_API_KEY` | One required | OpenAI API key |\n| `LLM_PROVIDER` | No | Force provider: `gemini`, `anthropic`, `openai`, `ollama`, `custom` |\n| `PLEX_MUSIC_LIBRARY` | No | Library name if not \"Music\" |\n| `OLLAMA_URL` | No | Ollama server URL (default: `http://localhost:11434`) |\n| `OLLAMA_CONTEXT_WINDOW` | No | Override detected context window for Ollama (default: 32768) |\n| `CUSTOM_LLM_URL` | No | Custom OpenAI-compatible API base URL |\n| `CUSTOM_LLM_API_KEY` | No | API key for custom provider (if required) |\n| `CUSTOM_CONTEXT_WINDOW` | No | Context window size for custom provider (default: 32768) |\n\n### Web UI Configuration\n\nYou can also configure MediaSage through the **Settings** page in the web UI. Settings entered there are saved to `config.user.yaml` and persist across restarts. Environment variables always take priority over UI-saved settings.\n\n### Advanced: config.yaml\n\nMount a config file for additional options:\n\n```yaml\nplex:\n  music_library: \"Music\"\n\nllm:\n  provider: \"gemini\"\n  model_analysis: \"gemini-2.5-flash\"\n  model_generation: \"gemini-2.5-flash\"\n  smart_generation: false  # true = use smarter model for both (higher quality, ~3-5x cost)\n\ndefaults:\n  track_count: 25\n```\n\n### Model Selection\n\nMediaSage uses a two-model strategy by default:\n\n| Role | Purpose | Models Used |\n|------|---------|-------------|\n| **Analysis** | Interpret prompts, suggest filters, analyze seed tracks | claude-sonnet-4-5 / gpt-4.1 / gemini-2.5-flash |\n| **Generation** | Select tracks from filtered list | claude-haiku-4-5 / gpt-4.1-mini / gemini-2.5-flash |\n\nThis balances quality with cost. Enable `smart_generation: true` to use the analysis model for everything.\n\n### Local LLM Setup (Experimental)\n\nRun MediaSage with local models for privacy and zero API costs.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eOllama\u003c/strong\u003e\u003c/summary\u003e\n\n1. Install [Ollama](https://ollama.ai) and pull a model:\n   ```bash\n   ollama pull llama3:8b\n   ```\n\n2. Configure MediaSage via environment or Settings UI:\n   ```bash\n   LLM_PROVIDER=ollama\n   OLLAMA_URL=http://localhost:11434\n   ```\n\n3. Select your model in Settings → the context window is auto-detected.\n\n**Recommended models:** `llama3:8b`, `qwen3:8b`, `mistral` — models with 8K+ context work best.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCustom OpenAI-Compatible API\u003c/strong\u003e\u003c/summary\u003e\n\nFor LM Studio, text-generation-webui, vLLM, or any OpenAI-compatible server:\n\n1. Start your server with an OpenAI-compatible endpoint\n\n2. Configure in Settings:\n   - **API Base URL:** `http://localhost:5000/v1`\n   - **API Key:** If required by your server\n   - **Model Name:** The model identifier\n   - **Context Window:** Your model's context size\n\n\u003c/details\u003e\n\n**Note:** Local models are slower and may produce less accurate results than cloud providers. A 10-minute timeout is used for generation. Models with larger context windows will support more tracks.\n\n---\n\n## How It Works\n\nMediaSage uses a **filter-first architecture** designed for large libraries (50,000+ tracks):\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│  1. ANALYZE                                                      │\n│     LLM interprets your prompt → suggests genre/decade filters   │\n├─────────────────────────────────────────────────────────────────┤\n│  2. FILTER                                                       │\n│     Plex library narrowed to matching tracks                     │\n│     \"90s Alternative\" → 2,000 tracks                             │\n├─────────────────────────────────────────────────────────────────┤\n│  3. SAMPLE                                                       │\n│     If too large for context, randomly sample                    │\n│     Fits within model's token limits                             │\n├─────────────────────────────────────────────────────────────────┤\n│  4. GENERATE                                                     │\n│     Filtered track list + prompt sent to LLM                     │\n│     LLM selects best matches from available tracks               │\n├─────────────────────────────────────────────────────────────────┤\n│  5. MATCH                                                        │\n│     Fuzzy matching links LLM selections to library               │\n│     Handles minor spelling/formatting differences                │\n├─────────────────────────────────────────────────────────────────┤\n│  6. SAVE                                                         │\n│     Playlist created in Plex                                     │\n│     Ready in Plexamp or any Plex client                          │\n└─────────────────────────────────────────────────────────────────┘\n```\n\nThis ensures every track exists in your library while keeping API costs manageable.\n\n---\n\n## Development\n\n### Local Setup\n\n```bash\ngit clone https://github.com/ecwilsonaz/mediasage.git\ncd mediasage\npython -m venv venv\nsource venv/bin/activate\npip install -r requirements.txt\n\nexport PLEX_URL=http://your-plex-server:32400\nexport PLEX_TOKEN=your-plex-token\nexport GEMINI_API_KEY=your-key\n\nuvicorn backend.main:app --reload --port 5765\n```\n\n### Testing\n\n```bash\npytest tests/ -v\n```\n\n### Tech Stack\n\n- **Backend:** Python 3.11+, FastAPI, python-plexapi, rapidfuzz, httpx\n- **Frontend:** Vanilla HTML/CSS/JS (no build step)\n- **LLM SDKs:** anthropic, openai, google-genai (+ Ollama via REST API)\n- **Deployment:** Docker\n\n---\n\n## API Reference\n\nInteractive documentation available at `/docs` when running.\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/api/health` | GET | Health check |\n| `/api/config` | GET/POST | Get or update configuration |\n| `/api/setup/status` | GET | Onboarding checklist state |\n| `/api/setup/validate-plex` | POST | Validate Plex credentials |\n| `/api/setup/validate-ai` | POST | Validate AI provider credentials |\n| `/api/setup/complete` | POST | Mark setup wizard as complete |\n| `/api/library/stats` | GET | Library statistics |\n| `/api/library/status` | GET | Cache state, track count, sync progress |\n| `/api/library/sync` | POST | Trigger background library sync |\n| `/api/library/search` | GET | Search library tracks |\n| `/api/analyze/prompt` | POST | Analyze natural language prompt |\n| `/api/analyze/track` | POST | Analyze a seed track |\n| `/api/filter/preview` | POST | Preview filtered track list |\n| `/api/generate` | POST | Generate playlist |\n| `/api/generate/stream` | POST | Stream playlist generation (SSE) |\n| `/api/playlist` | POST | Save playlist to Plex |\n| `/api/playlist/update` | POST | Replace or append to a playlist |\n| `/api/recommend/albums/preview` | GET | Preview album candidates for filters |\n| `/api/recommend/analyze-prompt` | POST | Analyze prompt for genre/decade filters |\n| `/api/recommend/questions` | POST | Generate clarifying questions |\n| `/api/recommend/generate` | POST | Generate album recommendations |\n| `/api/recommend/switch-mode` | POST | Switch library/discovery mode |\n| `/api/results` | GET | List saved result history |\n| `/api/results/{id}` | GET/DELETE | Get or delete a saved result |\n| `/api/plex/clients` | GET | List active Plex clients |\n| `/api/plex/playlists` | GET | List existing Plex playlists |\n| `/api/play-queue` | POST | Send tracks to a Plex client |\n| `/api/art/{rating_key}` | GET | Proxy album art from Plex |\n| `/api/ollama/status` | GET | Ollama connection status |\n| `/api/ollama/models` | GET | List available Ollama models |\n| `/api/ollama/model-info` | GET | Get model details (context window) |\n\n---\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fecwilsonaz%2Fmediasage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fecwilsonaz%2Fmediasage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fecwilsonaz%2Fmediasage/lists"}