# Payas Player — Documentation

> Privacy-first audio & video player · Playlist · Visualizer · Browser transcoding · No server · Open Source  
> Developer: **Saman Wijesinghe** · License: MIT

---

## Table of Contents

1. [Project Overview](#1-project-overview)
2. [Quick Start](#2-quick-start)
3. [Interface Layout](#3-interface-layout)
4. [Playback Controls](#4-playback-controls)
5. [Supported Formats](#5-supported-formats)
6. [Playlist Management](#6-playlist-management)
7. [Audio Visualizer](#7-audio-visualizer)
8. [FFmpeg Transcoding](#8-ffmpeg-transcoding)
9. [Keyboard Shortcuts](#9-keyboard-shortcuts)
10. [Settings Reference](#10-settings-reference)
11. [Storage & Data](#11-storage--data)
12. [Architecture & Code Structure](#12-architecture--code-structure)
13. [JavaScript API Reference](#13-javascript-api-reference)
14. [License](#14-license)

---

## 1. Project Overview

**Payas Player** is a fully client-side audio and video player that runs entirely in your browser — no server, no account, no build step. Open `payas-player.html` directly, drop in your media files, and play. Unsupported formats are transcoded on-the-fly in the browser using **FFmpeg.wasm**.

### Key Facts

| Property | Value |
|---|---|
| Entry point | `payas-player.html` |
| Stack | HTML5 · CSS3 · Vanilla JS (ES2022) |
| Dependencies | Bootstrap 5.3.3 · Font Awesome 6.5.2 · FFmpeg.wasm 0.11.6 · Google Fonts |
| Storage | `localStorage` (theme + volume) |
| Audio formats | MP3 · M4A · AAC · WAV · FLAC · OGG · OPUS · ALAC · AIFF · WMA |
| Video formats | MP4 · MKV · MOV · WebM · AVI · WMV · TS · 3GP · HEVC · H264 |
| Transcoding | AVI · WMV → MP4 via FFmpeg.wasm (on demand) |
| Export | None (player only) |
| Themes | Light · Dark |

### Design Language

Payas Player follows the **Payas design system** shared across all Payas web tools. Same colour tokens, typography, and component patterns.

---

## 2. Quick Start

No build or server required. Open the file directly:

```bash
# Option 1 — open directly
xdg-open payas-player.html          # Linux
open payas-player.html              # macOS
start payas-player.html             # Windows

# Option 2 — serve locally
python3 -m http.server 8080
# Then visit http://localhost:8080/payas-player.html
```

**Load media** by clicking **Open** in the title bar, or **drag and drop** audio/video files onto the drop zone. Playback begins automatically when a track is loaded.

---

## 3. Interface Layout

```
┌─ Title Bar ──────────────────────────────────────────────────┐
│ [▶ Logo] [Open] [Clear] [Settings] [About] [License] [🌙]    │
├─ Body ───────────────────────────────────────────────────────┤
│  Playlist Sidebar (260px)  │  Media Area                     │
│  [+ Add] [Clear All]       │  (Drop Zone / Video / Audio Art)│
│  [Track 1  MP3  3:12  ✕]  │  Audio: spinning art, metadata  │
│  [Track 2  FLAC 5:47  ✕]  │  Video: full-width video player │
│  [Track 3  MP4  1:22  ✕]  │  Unsupported: error message     │
│  …                         │  Transcoding: progress bar      │
├─ Controls Bar ───────────────────────────────────────────────┤
│  ◀──────────────── seek ──────────────▶  0:00 / 3:12        │
│  [Now Playing: Track name · format]                          │
│  [⇄ Shuffle] [⏮] [⏹] [⏯ PLAY] [⏭] [↻ Repeat]  [vol 🔊] [speed▼] │
└──────────────────────────────────────────────────────────────┘
```

### Title Bar

| Control | Action |
|---|---|
| Open | Open audio/video files via file picker (`Ctrl+O`) |
| Clear | Empty the entire playlist |
| Settings | Open the settings panel |
| About | Version and project info |
| License | MIT licence text |
| Theme toggle (🌙) | Switch light / dark mode |

### Media Area

| State | Display |
|---|---|
| Empty | Drop zone with accepted format badges |
| Audio playing | Spinning album-art disc, track title, metadata |
| Video playing | Full-width `<video>` element |
| Transcoding | Progress bar with percentage complete |
| Unsupported | Error message with format name |

---

## 4. Playback Controls

### Seek Bar

The seek bar spans the full width of the controls area.

| Interaction | Result |
|---|---|
| Click a position | Seek to that time |
| Drag the handle | Scrub through the track |
| Buffering indicator | Shows downloaded portion of the file |
| Time display | Current time / total duration (HH:MM:SS) |

### Main Control Buttons

| Button | Key | Description |
|---|---|---|
| Shuffle | `X` | Toggle random playback order |
| Previous | `Shift+←` | Go to the previous track |
| Stop | `S` | Stop playback and reset to start |
| Play / Pause | `Space` | Play or pause the current track |
| Next | `Shift+→` | Advance to the next track |
| Repeat | `R` | Cycle: Off → Repeat One → Repeat All |

### Volume & Speed

| Control | Key | Description |
|---|---|---|
| Volume slider | `↑` / `↓` | Adjust volume (0–100%) |
| Mute toggle | `M` | Toggle mute on/off |
| Speed dropdown | — | Set playback speed: 0.5× / 0.75× / 1× / 1.25× / 1.5× / 2× |

### Seek Shortcuts

| Shortcut | Action |
|---|---|
| `←` | Rewind 5 seconds |
| `→` | Forward 5 seconds |
| `J` | Rewind 10 seconds |
| `L` | Forward 10 seconds |

---

## 5. Supported Formats

### Audio

| Format | Extension(s) | Notes |
|---|---|---|
| MP3 | `.mp3` | Natively supported |
| AAC / M4A | `.aac`, `.m4a` | Natively supported |
| WAV | `.wav` | Natively supported |
| FLAC | `.flac` | Natively supported in modern browsers |
| OGG / OGA | `.ogg`, `.oga` | Natively supported |
| Opus | `.opus` | Natively supported |
| ALAC | `.alac` | Support varies by browser |
| AIFF / AIF | `.aiff`, `.aif` | Support varies by browser |
| WMA | `.wma` | Transcoded via FFmpeg.wasm |

### Video

| Format | Extension(s) | Notes |
|---|---|---|
| MP4 (H.264) | `.mp4`, `.m4v` | Natively supported |
| WebM | `.webm`, `.ogv` | Natively supported |
| MKV | `.mkv` | Support varies by browser |
| MOV | `.mov` | Support varies by browser |
| AVI | `.avi` | Transcoded via FFmpeg.wasm |
| WMV | `.wmv` | Transcoded via FFmpeg.wasm |
| MPEG-TS | `.ts`, `.mts` | Support varies by browser |
| 3GP | `.3gp`, `.3g2` | Support varies by browser |
| HEVC / H.265 | `.hevc`, `.h265` | Support varies by browser |

> Formats marked "varies by browser" may play directly in Chrome/Edge but require transcoding in Firefox or Safari.

---

## 6. Playlist Management

### Adding Files

- Click **Open** in the title bar (`Ctrl+O`)
- Drag and drop files onto the drop zone in the media area
- Multiple files can be added at once; they are appended to the current playlist

### Playlist Sidebar

Each track entry shows:
- Format icon and colour-coded format badge (e.g. `MP3`, `FLAC`, `MP4`)
- Track name (filename without extension)
- Duration (probed automatically after loading)
- Remove button (✕)

Click any track to load and begin playing it immediately.

### Playback Order

| Mode | Behaviour |
|---|---|
| Normal | Tracks play sequentially |
| Shuffle (`X`) | Each next track is chosen randomly |
| Repeat One (`R` once) | Current track loops indefinitely |
| Repeat All (`R` twice) | Playlist loops from the beginning |

---

## 7. Audio Visualizer

When audio is playing, an optional **frequency visualizer** is drawn below the album art using the **Web Audio API**.

- Real-time FFT frequency analysis
- Drawn on an HTML `<canvas>` (500×72 px)
- Colour matches the current accent theme
- Toggle on/off in Settings → Visualization

The visualizer connects to the `<audio>` element via an `AnalyserNode`. It is lazy — initialized only when audio first plays, keeping the UI lightweight for video playback.

---

## 8. FFmpeg Transcoding

Payas Player uses **FFmpeg.wasm 0.11.6** for client-side format conversion. FFmpeg is **not loaded at startup** — it is fetched from CDN on demand the first time an unsupported file is opened, keeping initial load time low.

### Transcoding Flow

1. An unsupported format (AVI, WMV, etc.) is added to the playlist.
2. The media area shows a transcoding progress view with a percentage bar.
3. FFmpeg.wasm converts the file to MP4 in memory.
4. The converted blob is loaded into the `<video>` element and playback begins.
5. The converted data is not written to disk.

### Transcoding Progress View

```
Converting: track-name.avi
[████████████░░░░░░░░] 64%
```

---

## 9. Keyboard Shortcuts

| Shortcut | Action |
|---|---|
| `Space` | Play / Pause |
| `S` | Stop |
| `Shift+←` | Previous track |
| `Shift+→` | Next track |
| `←` | Rewind 5 seconds |
| `→` | Forward 5 seconds |
| `J` | Rewind 10 seconds |
| `L` | Forward 10 seconds |
| `↑` | Volume up |
| `↓` | Volume down |
| `M` | Toggle mute |
| `F` | Toggle video fullscreen |
| `R` | Cycle repeat mode |
| `X` | Toggle shuffle |
| `Ctrl+P` | Toggle playlist sidebar |
| `Ctrl+O` | Open files |

---

## 10. Settings Reference

Open via **Settings** in the title bar.

### Appearance

| Setting | Options | Default |
|---|---|---|
| Theme | Light / Dark | Light |

### Playback

| Setting | Options | Default |
|---|---|---|
| Default volume | 0–100% (slider) | 80% |
| Remember volume | Toggle on/off | On |

### Visualization

| Setting | Options | Default |
|---|---|---|
| Audio visualizer | Toggle on/off | On |

### Keyboard Shortcuts

Opens a modal listing all keyboard shortcuts. No editable settings.

---

## 11. Storage & Data

### localStorage Keys

| Key | Contents |
|---|---|
| `pp-theme` | `"light"` or `"dark"` |
| `pp-vol` | Last volume value (0–100) |

> The playlist is **not persisted** between sessions. Files must be re-opened each time.

---

## 12. Architecture & Code Structure

Payas Player is a **single HTML file** — no bundler, no framework, no server.

```
payas-player.html
├── <style>          CSS custom properties, layout, controls, seek bar, visualizer
├── <body>
│   ├── Title Bar    Open, clear, settings, theme
│   ├── Body Row
│   │   ├── Sidebar  Playlist with track list
│   │   └── Media    Drop zone / video / audio art / transcode view
│   └── Controls Bar Seek, play/pause, shuffle, repeat, volume, speed
└── <script>         All application logic (vanilla JS)
    ├── Playlist         addFiles, renderPlaylist, removeTrack, clearAll
    ├── Playback         loadTrack, togglePlay, prevTrack, nextTrack, onEnded
    ├── Seek             onTimeUpdate, onProgress, seekTo
    ├── Shuffle/Repeat   toggleShuffle, cycleRepeat, pickNext
    ├── Volume/Speed     setVolume, toggleMute, setSpeed
    ├── Fullscreen       toggleFullscreen (video)
    ├── Visualizer       initAndDrawViz (Web Audio API AnalyserNode)
    ├── Transcoding      getFFmpeg (lazy load), transcodeFile
    ├── Duration probe   probeDuration (temporary Audio element)
    ├── Theme            setTheme, loadSettings, saveSettings
    └── Keyboard         global keydown handler
```

---

## 13. JavaScript API Reference

All functions are in global scope within the single HTML file.

### Playlist

```js
addFiles(files)         // Process FileList — add tracks, probe durations
renderPlaylist()        // Redraw playlist sidebar from tracks array
removeTrack(idx)        // Remove track at index; manage active index
clearAll()              // Empty playlist, reset UI to drop-zone state
probeDuration(idx)      // Create temp Audio to measure track length
```

### Playback

```js
loadTrack(idx, autoplay)  // Set media src, update Now Playing, optionally autoplay
togglePlay()              // Play if paused, pause if playing
prevTrack()               // Load the previous track (respects shuffle)
nextTrack()               // Load the next track (respects shuffle/repeat)
onEnded()                 // Called when a track finishes; handles repeat/next
```

### Seek & Time

```js
onTimeUpdate()    // Update seek bar position and time display
onProgress()      // Update buffered portion indicator on seek bar
seekTo(fraction)  // Seek to position 0.0–1.0 of total duration
```

### Mode Toggles

```js
toggleShuffle()   // Enable / disable random track selection
cycleRepeat()     // Advance repeat state: 0 (off) → 1 (one) → 2 (all)
```

### Volume & Speed

```js
setVolume(val)    // Set volume 0–100, update slider and localStorage
toggleMute()      // Toggle mute on/off
setSpeed(val)     // Set playback rate (0.5 – 2.0)
```

### Visualizer

```js
initAndDrawViz()  // Connect AnalyserNode to audio element; start rAF draw loop
```

### Transcoding

```js
getFFmpeg()         // Lazy-load FFmpeg.wasm from CDN (returns Promise)
transcodeFile(file) // Convert file to MP4 blob using FFmpeg.wasm
```

### Settings & Theme

```js
setTheme(dark)      // true = dark, false = light; writes to localStorage
loadSettings()      // Read theme and volume from localStorage
saveSettings()      // Write current volume to localStorage
```

---

## 14. License

MIT License

Copyright © Saman Wijesinghe

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
