Metadata-Version: 2.4
Name: riff-player
Version: 2.0.1
Summary: Terminal media player - play music and video from your terminal
Author: Sapnoneel Barik
License: MIT
Project-URL: Homepage, https://github.com/Sapnoneel/Riff
Project-URL: Repository, https://github.com/Sapnoneel/Riff
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mutagen>=1.47.0
Requires-Dist: yt-dlp>=2024.1.0
Requires-Dist: textual>=0.47.0
Requires-Dist: rich>=13.0.0
Requires-Dist: spotipy>=2.23.0
Requires-Dist: ytmusicapi>=1.3.0
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Dynamic: license-file
Dynamic: requires-python

# 🎵 Riff — Terminal Media Player

<div align="center">

![Python](https://img.shields.io/badge/Python-3.11+-3776AB?style=flat-square&logo=python&logoColor=white)
![PyPI](https://img.shields.io/pypi/v/riff-player?style=flat-square&color=orange&label=PyPI)
![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20Linux%20%7C%20macOS-informational?style=flat-square)
![License](https://img.shields.io/badge/License-MIT-green?style=flat-square)
![Status](https://img.shields.io/badge/Status-Active-brightgreen?style=flat-square)

**Play music and video from your terminal. Local files or the entire internet.**

</div>

---

Riff is a cross-platform terminal media player built in Python. Search your local storage with fuzzy-find, stream from YouTube and 1000+ sites, sync your Spotify and YouTube Music playlists, and save tracks for offline listening — all without ever leaving the terminal.

---

## ✨ Features

| Feature | Description |
|---|---|
| 🎵 **Local Playback** | Searches your Music, Videos, and Downloads folders automatically |
| 🌐 **Internet Streaming** | Powered by yt-dlp — YouTube, SoundCloud, and 1000+ sites |
| 📺 **Video Support** | Stream or play video files from the terminal |
| 🔍 **Fuzzy Search** | Interactive file picker via fzf |
| 🖥️ **TUI Interface** | Beautiful full-screen terminal UI via Textual |
| 💿 **Metadata Display** | Shows title, artist, album from ID3 tags |
| 📋 **Playlists** | Save/load local playlists + import from Spotify, YouTube Music, SoundCloud |
| 🔗 **Account Sync** | Connect your music accounts and mirror your playlists locally |
| 💾 **Offline Cache** | Download tracks as compressed `.opus` files for offline listening |
| ⚙️ **Configurable** | Cache size, sync mode, per-account auto-sync — all user controlled |
| 🪟 **Cross-Platform** | Windows, Linux, and macOS |

---

## 📦 Installation

### Option 1 — pip (recommended)

```bash
pip install riff-player
```

### Option 2 — Clone from source

```bash
git clone https://github.com/Sapnoneel/Riff.git
cd Riff
pip install -r requirements.txt
```

### System dependencies (required)

**Windows (PowerShell):**
```powershell
winget install shinchiro.mpv
winget install fzf
```

**Linux (Ubuntu / Debian):**
```bash
sudo apt install mpv fzf
```

**macOS:**
```bash
brew install mpv fzf
```

### Verify setup

```bash
python riff.py info
```

All dependencies should show green checkmarks.

---

## 🚀 Usage

### Playback

```bash
# Show help
python riff.py

# Play a local file directly
python riff.py play "C:/Music/song.mp3"

# Search your local library (interactive fuzzy picker)
python riff.py search "bohemian rhapsody"

# Search audio files only
python riff.py search "adele" --audio

# Browse your entire media library
python riff.py browse

# Stream audio from YouTube / internet
python riff.py stream "lofi hip hop"
python riff.py stream "https://youtu.be/dQw4w9WgXcQ"

# Stream and save offline in one go
python riff.py stream "lofi hip hop" --save

# Stream video
python riff.py video "big buck bunny"

# Queue and shuffle all search results
python riff.py search "pink floyd" --queue --shuffle

# Launch the full TUI interface
python riff.py tui
```

### Playlists

```bash
# Save a playlist manually
python riff.py playlist save "my-mix"

# Load and play a saved playlist
python riff.py playlist load "my-mix"

# List all saved playlists
python riff.py playlist list

# Import from a music platform
python riff.py playlist fetch spotify "Chill Vibes"
python riff.py playlist fetch ytmusic "liked"
python riff.py playlist fetch soundcloud

# Delete a playlist
python riff.py playlist delete "my-mix"
```

### Account Sync

```bash
# Connect your accounts (one-time setup)
python riff.py account connect spotify
python riff.py account connect ytmusic
python riff.py account connect soundcloud

# View connected accounts
python riff.py account list

# Sync manually
python riff.py account sync spotify
python riff.py account sync all

# Sync and download everything for offline access
python riff.py account sync all --offline

# Toggle auto-sync on startup (per platform)
python riff.py account autosync spotify on
python riff.py account autosync ytmusic off
```

### Offline Cache

```bash
# Save a track for offline listening
python riff.py save "lofi hip hop"
python riff.py save "https://youtu.be/..."

# View cached tracks and space used
python riff.py cache list

# Clear a specific track
python riff.py cache clear "lofi hip hop"

# Clear entire cache
python riff.py cache clear
```

### Configuration

```bash
# View all settings
python riff.py config show

# Set cache size limit
python riff.py config set cache.size_limit_mb 2048

# Set cache mode
python riff.py config set cache.mode ask      # prompt after every stream
python riff.py config set cache.mode always   # silently cache everything
python riff.py config set cache.mode manual   # never auto-cache
python riff.py config set cache.mode smart    # cache frequently played tracks

# Toggle local file scan on startup
python riff.py config set startup.local_scan true
```

---

## ⌨️ Playback Controls

Controls work inside mpv during playback:

| Key | Action |
|-----|--------|
| `Space` | Pause / Resume |
| `←` / `→` | Seek 5 seconds |
| `↑` / `↓` | Seek 1 minute |
| `9` / `0` | Volume down / up |
| `m` | Mute |
| `f` | Toggle fullscreen (video) |
| `q` | Quit |

### TUI Controls

| Key | Action |
|-----|--------|
| `L` | Browse local library |
| `S` | Focus search bar |
| `I` | Stream audio from internet |
| `V` | Stream video from internet |
| `Enter` | Play selected file |
| `Q` | Quit |

---

## 🔗 Account Setup Guides

### Spotify
1. Go to [developer.spotify.com/dashboard](https://developer.spotify.com/dashboard)
2. Create an app
3. Add Redirect URI: `http://127.0.0.1:8888/callback`
4. Copy your **Client ID** and **Client Secret**
5. Run `python riff.py account connect spotify` and paste them in

### YouTube Music
1. Run `python riff.py account connect ytmusic`
2. Follow the browser OAuth flow — credentials are saved automatically

### SoundCloud
1. Open [soundcloud.com](https://soundcloud.com) in your browser
2. Open DevTools → Network tab (`F12`)
3. Reload the page and filter by `api-v2`
4. Click any request → Headers → copy the value after `Authorization: OAuth `
5. Run `python riff.py account connect soundcloud` and paste the token

---

## 🗂️ Project Structure

```
Riff/
├── riff.py                  # Entry point
├── pyproject.toml           # PyPI packaging
├── setup.py
├── requirements.txt
├── riff/
│   ├── __init__.py          # Package metadata (v2.0.0)
│   ├── cli.py               # All commands and argument parsing
│   ├── player.py            # mpv wrapper for local playback
│   ├── search.py            # Local file search + fzf picker
│   ├── stream.py            # Internet streaming via yt-dlp
│   ├── meta.py              # Metadata reader (mutagen)
│   ├── tui.py               # Textual TUI interface
│   ├── utils.py             # Cross-platform helpers
│   ├── config.py            # User config (~/.riff/config.json)
│   ├── cache.py             # Offline cache with LRU eviction
│   ├── playlist.py          # Playlist save/load + platform fetch
│   ├── spotify.py           # Spotify API integration
│   ├── ytmusic.py           # YouTube Music integration
│   ├── soundcloud.py        # SoundCloud integration
│   └── sync.py              # Startup sync orchestrator
└── tests/
```

---

## 🔧 Dependencies

| Package | Version | Purpose |
|---------|---------|---------|
| [mpv](https://mpv.io) | latest | Media engine for audio and video |
| [yt-dlp](https://github.com/yt-dlp/yt-dlp) | ≥ 2024.1.0 | Internet streaming from 1000+ sites |
| [fzf](https://github.com/junegunn/fzf) | latest | Interactive fuzzy file picker |
| [mutagen](https://mutagen.readthedocs.io) | ≥ 1.47.0 | Audio metadata / ID3 tag reading |
| [textual](https://textual.textualize.io) | ≥ 0.47.0 | Full-screen TUI framework |
| [rich](https://rich.readthedocs.io) | ≥ 13.0.0 | Terminal text formatting |
| [spotipy](https://spotipy.readthedocs.io) | ≥ 2.23.0 | Spotify Web API |
| [ytmusicapi](https://ytmusicapi.readthedocs.io) | ≥ 1.3.0 | YouTube Music API |

> **Note:** `mpv` and `fzf` are system binaries installed separately.
> All Python packages install automatically via `pip install riff-player`.

---

## 🖥️ Platform Notes

### Windows
- Use **Windows Terminal** for the best TUI experience
- `mpv` installed via `winget install shinchiro.mpv`
- Video plays in a floating mpv window launched from the terminal
- Run scripts inside the venv: `.venv\Scripts\activate`

### Linux
- Video-in-terminal works best with the **kitty** terminal
- All other terminals fall back to a floating mpv window

### macOS
- Video-in-terminal works with **iTerm2**
- Install dependencies via Homebrew

---

## 🤝 Contributing

Contributions are welcome! Here's how:

1. Fork the repository
2. Create a feature branch: `git checkout -b feature/my-feature`
3. Commit your changes: `git commit -m "Add my feature"`
4. Push to your branch: `git push origin feature/my-feature`
5. Open a Pull Request

Please open an issue first for major changes.

---

## 📄 License

MIT © [Sapnoneel Barik](https://github.com/Sapnoneel)

---

<div align="center">
Made with ♪ and Python
</div>
