Metadata-Version: 2.2
Name: gaanaclient
Version: 1.0.0
Summary: Python API client for the Unofficial Gaana Music API
Author: xylen-py
Project-URL: Homepage, https://github.com/xylen-py/GaanaClient
Project-URL: Repository, https://github.com/xylen-py/GaanaClient
Project-URL: Issues, https://github.com/xylen-py/GaanaClient/issues
Project-URL: API, https://github.com/xylen-py/gaana-plugin-api
Keywords: gaana,music,api,client,streaming,indian-music
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Sound/Audio
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28.0
Requires-Dist: aiohttp>=3.8.0

# Gaana

[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://python.org)
[![aiohttp](https://img.shields.io/badge/aiohttp-3.8+-blue.svg)](https://docs.aiohttp.org)
[![requests](https://img.shields.io/badge/requests-2.28+-blue.svg)](https://requests.readthedocs.io)

Python API client for the [Unofficial Gaana Music API](https://github.com/xylen-py/gaana-plugin-api). Full-featured sync and async support with typed models for all endpoints.

> **Educational & Research Purpose Only**: This project is created solely for educational and research purposes. Use responsibly and respect Gaana's terms of service.

---

## Installation

```bash
pip install gaanaclient
```

Or install from source:

```bash
git clone https://github.com/xylen-py/GaanaClient.git
cd GaanaClient
pip install .
```

**Dependencies**: `requests` (sync), `aiohttp` (async)

---

## Quick Start

### Sync Client

```python
from gaana import GaanaClient

client = GaanaClient()

result = client.search("Tum Hi Ho")
for song in result.songs:
    print(f"{song.title} - {song.artists} ({song.duration}s)")

song = client.get_song("tum-hi-ho")
print(song.title, song.isrc, song.duration)

album = client.get_album("aashiqui-2")
for track in album:
    print(track.title)

stream = client.get_stream(song.track_id, quality="high")
print(stream.hlsUrl, stream.durationMs)

client.close()
```

### Async Client

```python
import asyncio
from gaana import AsyncGaanaClient

async def main():
    async with AsyncGaanaClient() as client:
        result = await client.search("Kesariya")
        for song in result.songs:
            print(f"{song.title} - {song.artists}")

        charts = await client.get_charts(limit=5)
        for chart in charts:
            print(f"{chart.title} - {chart.play_count} plays")

asyncio.run(main())
```

### Custom Base URL

```python
client = GaanaClient(base_url="https://your-api.vercel.app/api", timeout=30)
```

### Context Manager

```python
with GaanaClient() as client:
    song = client.get_song("tum-hi-ho")
    print(song)
```

---

## API Reference

### Search Methods

| Method | Parameters | Returns |
|---|---|---|
| `search(query, limit=10)` | `query`: search string, `limit`: 1-25 | `SearchResult` |
| `search_songs(query, limit=10)` | Same as above | `List[Song]` |
| `search_albums(query, limit=10)` | Same as above | `List[Album]` |
| `search_playlists(query, limit=10)` | Same as above | `List[Playlist]` |
| `search_artists(query, limit=10)` | Same as above | `List[Artist]` |

### Resource Methods

Each resource supports 3 access patterns: auto-detect (seokey or URL), explicit URL, explicit seokey.

| Method | Parameters | Returns |
|---|---|---|
| `get_song(identifier)` | Seokey or full Gaana URL | `Song` |
| `get_song_by_url(url)` | Full Gaana URL | `Song` |
| `get_song_by_seokey(seokey)` | Seokey string | `Song` |
| `get_album(identifier)` | Seokey or full Gaana URL | `Album` |
| `get_album_by_url(url)` | Full Gaana URL | `Album` |
| `get_album_by_seokey(seokey)` | Seokey string | `Album` |
| `get_playlist(identifier)` | Seokey or full Gaana URL | `Playlist` |
| `get_playlist_by_url(url)` | Full Gaana URL | `Playlist` |
| `get_playlist_by_seokey(seokey)` | Seokey string | `Playlist` |
| `get_artist(identifier)` | Seokey or full Gaana URL | `Artist` |
| `get_artist_by_url(url)` | Full Gaana URL | `Artist` |
| `get_artist_by_seokey(seokey)` | Seokey string | `Artist` |

### Browse & Stream Methods

| Method | Parameters | Returns |
|---|---|---|
| `get_stream(track_id, quality="high")` | `track_id`: numeric ID, `quality`: `low`/`medium`/`high` | `StreamInfo` |
| `get_trending(language="hi", limit=20)` | `language`: ISO code, `limit`: count | `TrendingResult` |
| `get_charts(limit=20)` | `limit`: count | `ChartResult` |
| `get_new_releases(language="hi")` | `language`: ISO code | `NewReleasesResult` |
| `health()` | None | `HealthStatus` |

---

## Models Reference

### Song

| Field | Type | Description |
|---|---|---|
| `seokey` | `str` | URL-friendly identifier |
| `track_id` | `str` | Numeric track ID |
| `title` | `str` | Track title |
| `artists` | `str` | Comma-separated artist names |
| `album` | `str` | Album title |
| `album_id` | `str` | Album ID |
| `album_seokey` | `str` | Album seokey |
| `duration` | `int` | Duration in seconds |
| `language` | `str` | Language code |
| `is_explicit` | `bool` | Explicit content flag |
| `isrc` | `str` | International Standard Recording Code |
| `artworkUrl` | `str` | High-res artwork URL |
| `song_url` | `str` | Full Gaana URL |
| `album_url` | `str` | Album page URL |
| `artist_seokeys` | `str` | Comma-separated artist seokeys |
| `artist_ids` | `str` | Comma-separated artist IDs |
| `media_urls` | `List[Dict]` | Decrypted stream URLs (from detail endpoint) |
| **Properties** | | |
| `url` | `str` | Gaana URL (computed) |
| `artist_list` | `List[str]` | Artists as list |
| `duration_ms` | `int` | Duration in milliseconds |
| `identifier` | `str` | track_id or seokey |

### Album

| Field | Type | Description |
|---|---|---|
| `seokey`, `album_id`, `title`, `artists` | `str` | Basic info |
| `artist_seokeys`, `artist_ids` | `str` | Artist identifiers |
| `duration` | `int` | Total duration in seconds |
| `is_explicit` | `bool` | Explicit flag |
| `language`, `label` | `str` | Language and record label |
| `track_count` | `int` | Number of tracks |
| `release_date` | `str` | Release date |
| `play_count`, `favorite_count` | `int` | Engagement metrics |
| `artworkUrl`, `album_url` | `str` | URLs |
| `tracks` | `List[Song]` | Album tracks |

Albums are **iterable**: `for track in album:` and support `len(album)`.

### Playlist

| Field | Type | Description |
|---|---|---|
| `title`, `playlist_id`, `seokey` | `str` | Basic info |
| `artworkUrl` | `str` | Artwork URL |
| `description` | `str` | Playlist description |
| `author` | `str` | Creator name |
| `trackcount` | `int` | Track count |
| `favorite_count` | `str` | Favorites |
| `language` | `str` | Language |
| `created_on`, `modified_on` | `str` | Timestamps |
| `playlist_url` | `str` | Full URL |
| `tracks` | `List[Song]` | Playlist tracks |

Playlists are **iterable**: `for track in playlist:` and support `len(playlist)`.

### Artist

| Field | Type | Description |
|---|---|---|
| `artist_id`, `seokey`, `name` | `str` | Basic info |
| `artwork` | `str` | Artist image URL |
| `artist_url` | `str` | Gaana profile URL |
| `top_tracks` | `List[Song]` | Top tracks |

Artists are **iterable**: `for track in artist:` and support `len(artist)`.

### StreamInfo

| Field | Type | Description |
|---|---|---|
| `quality` | `str` | `low`/`medium`/`high` |
| `bitRate` | `str` | Bitrate (e.g., `128`) |
| `hlsUrl` | `str` | HLS playlist URL |
| `url` | `str` | Direct first segment URL |
| `initUrl` | `str` | Initialization segment URL |
| `segments` | `List[StreamSegment]` | All segments with URLs and durations |
| `durationMs` | `int` | Total duration in milliseconds |
| `format` | `str` | Format (e.g., `ts`, `m4s`) |
| `duration_seconds` | `float` | Duration in seconds (computed) |
| `segment_count` | `int` | Number of segments (computed) |
| `segment_urls` | `List[str]` | All segment URLs (computed) |

### Chart

| Field | Type | Description |
|---|---|---|
| `seokey`, `playlist_id`, `title` | `str` | Basic info |
| `language` | `str` | Language |
| `favorite_count` | `int` | Favorites |
| `is_explicit` | `bool` | Explicit flag |
| `play_count` | `int` | Total plays |
| `artworkUrl`, `playlist_url` | `str` | URLs |

### Other Models

**SearchResult** - `songs`, `albums`, `playlists`, `artists`, `success`, `timestamp`, `total`, `is_empty`

**TrendingResult** - `tracks`, `count`, `success`, `timestamp`, `is_empty` (iterable)

**ChartResult** - `charts`, `count`, `success`, `timestamp`, `is_empty` (iterable)

**NewReleasesResult** - `tracks`, `albums`, `success`, `timestamp`, `total`, `is_empty`

**HealthStatus** - `status`, `uptime`, `environment`, `timestamp`, `is_healthy` (bool-convertible)

---

## Exceptions

| Exception | Trigger | Attributes |
|---|---|---|
| `GaanaError` | Base exception for all errors | `message` |
| `GaanaAPIError` | HTTP 4xx/5xx responses | `status_code`, `message` |
| `GaanaNotFoundError` | Resource not found (404) | `message` |
| `GaanaRateLimitError` | Rate limited (429) | `message` |
| `GaanaConnectionError` | Network/timeout failures | `message` |

```python
from gaana import GaanaClient, GaanaNotFoundError, GaanaAPIError

client = GaanaClient()
try:
    song = client.get_song("nonexistent-song")
except GaanaNotFoundError:
    print("Song not found")
except GaanaAPIError as e:
    print(f"API error: {e.status_code}")
```

---

## Utilities

```python
from gaana import extract_seokey, extract_type, is_gaana_url
from gaana import VALID_LANGUAGES, VALID_QUALITIES

extract_seokey("https://gaana.com/song/tum-hi-ho")       # "tum-hi-ho"
extract_type("https://gaana.com/album/aashiqui-2")        # "album"
is_gaana_url("https://gaana.com/song/tum-hi-ho")          # True

VALID_QUALITIES   # ("low", "medium", "high")
VALID_LANGUAGES   # ("hi", "en", "pa", "ta", "te", "mr", "gu", "bn", ...)
```

---

## Test Results

<details>
<summary><b>Search</b> — search("Tum Hi Ho", limit=3)</summary>

```
9 results returned

  Tum Hi Ho | Mithoon, Arijit Singh | 261s | INS181303031
  Tum Hi Ho Bandhu | Kavita Seth, Pritam, Neeraj Sridhar | 283s | GBSGZ12200008
  Tum Hi Ho-Rehnuma | Shreya Ghoshal, Armaan Malik | 260s | INS181900547
```

</details>

<details>
<summary><b>Get Song</b> — get_song("tum-hi-ho")</summary>

```
title:    Tum Hi Ho
artists:  Gurbani Bhatia
duration: 263s
isrc:     INS181305577
album:    Magical Fingers
track_id: 1511279
```

</details>

<details>
<summary><b>Get Song by URL</b> — get_song("https://gaana.com/song/tum-hi-ho")</summary>

```
title:    Tum Hi Ho
artists:  Gurbani Bhatia
duration: 263s
```

</details>

<details>
<summary><b>Get Album</b> — get_album("aashiqui-2")</summary>

```
title:        Aashiqui 2
artists:      Arijit Singh, Ankit Tiwari, Palak Muchhal, Shreya Ghoshal...
tracks:       11
label:        T-Series
release_date: 2013-04-06

Tracks:
  Tum Hi Ho | 261s
  Chahun Main Ya Naa | 304s
  Sunn Raha Hai | 314s
  ...
```

</details>

<details>
<summary><b>Get Playlist</b> — get_playlist("gaana-dj-hindi-top-50-1")</summary>

```
title:  Hindi Top 50
author: Gaana
tracks: 50

Tracks:
  Gehra Hua (From "Dhurandhar") | Shashwat Sachdev, Arijit Singh...
  Shararat | Shashwat Sachdev, Madhubanti Bagchi, Jasmine Sandlas
  ...
```

</details>

<details>
<summary><b>Get Artist</b> — get_artist("arijit-singh")</summary>

```
name:       Arijit Singh
artist_id:  52767
top_tracks: 20

Top Tracks:
  Rang De Tu Mohe Gerua (Holi Hai) | 110s
  Pyaar Hota Kayi Baar Hai Tech House Remix | 212s
  Samjhawan | 269s
  ...
```

</details>

<details>
<summary><b>Get Stream</b> — get_stream("29797868", quality="high")</summary>

```
quality:    high
bitRate:    128
durationMs: 191705
format:     ts
segments:   33
hlsUrl:     https://vodhlsgaana-ebw.akamaized.net/hls/23/3076323/29797868...
```

</details>

<details>
<summary><b>New Releases</b> — get_new_releases(language="hi")</summary>

```
tracks: 16
albums: 24

Tracks:
  Main Hoon (From "Battle Of Galwan") | Ayaan Lall, Shreya Ghoshal...
  5-7 | Karan Aujla, MXRCI
  ...
```

</details>

<details>
<summary><b>Health</b> — health()</summary>

```
status:      ok
uptime:      121.02s
environment: production
```

</details>

---

## Supported Languages

| Code | Language | Code | Language |
|---|---|---|---|
| `hi` | Hindi | `ta` | Tamil |
| `en` | English | `te` | Telugu |
| `pa` | Punjabi | `mr` | Marathi |
| `gu` | Gujarati | `bn` | Bengali |
| `kn` | Kannada | `ml` | Malayalam |
| `ur` | Urdu | `as` | Assamese |
| `rj` | Rajasthani | `or` | Odia |
| `bh` | Bhojpuri | | |

---

## License

MIT
