Name | lyriq JSON |
Version |
1.2.0
JSON |
| download |
home_page | None |
Summary | A lightweight Python library designed to effortlessly fetch song lyrics. |
upload_time | 2025-07-15 12:37:24 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.9 |
license | None |
keywords |
lyrics
music
synchronization
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# Lyriq
A lightweight Python library designed to effortlessly fetch and display song lyrics, with support for synchronized lyrics and an accompanying CLI tool.
[](https://pypi.org/project/lyriq/)
[](https://pypi.org/project/lyriq/)
[](https://github.com/tn3w/lyriq/blob/main/LICENSE)
## Features
- Fetch lyrics from the LRCLib API
- Support for both plain and synchronized lyrics
- Built-in caching to reduce API calls
- CLI tool with synchronized lyrics playback
- Support for saving/loading lyrics in JSON and plain text formats
- Colorful terminal output with synchronized highlighting
## Installation
### From PyPI
```bash
pip install lyriq
```
### Development Installation
```bash
git clone https://github.com/tn3w/lyriq.git
cd lyriq
pip install -e ".[dev]"
```
## Usage
### Basic Usage
```python
import sys
from lyriq import get_lyrics
lyrics = get_lyrics("Circles", "Post Malone")
if not lyrics:
print("No lyrics found for 'Circles' by Post Malone")
sys.exit(0)
print(f"ID: {lyrics.id}")
print(f"Name: {lyrics.name}")
print(f"Track: {lyrics.track_name}")
print(f"Artist: {lyrics.artist_name}")
print(f"Album: {lyrics.album_name}")
print(f"Duration: {lyrics.duration} seconds")
print(f"Instrumental: {'Yes' if lyrics.synced_lyrics else 'No'}")
print("\nPlain Lyrics:")
print("-" * 40)
print(lyrics.plain_lyrics)
print("\nSynchronized Lyrics (timestamp: lyric):")
print("-" * 40)
for timestamp, line in sorted(lyrics.lyrics.items()):
print(f"[{timestamp}] {line}")
print("-" * 40)
```
### Fetch by ID
```python
from lyriq import get_lyrics_by_id
# Fetch lyrics by ID
lyrics = get_lyrics_by_id("449") # ID for "Circles" by Post Malone
if lyrics:
print(f"Found: {lyrics.track_name} by {lyrics.artist_name}")
```
### Convert to Plain Text
```python
from lyriq import to_plain_lyrics, get_lyrics
lyrics = get_lyrics("Circles", "Post Malone")
plain_text = to_plain_lyrics(lyrics)
print(plain_text)
```
### Search for Lyrics
```python
from lyriq import search_lyrics
# Search by general query
results = search_lyrics(q="Circles Post Malone")
# Or search by song and artist name
results = search_lyrics(song_name="Circles", artist_name="Post Malone")
if results:
print(f"Found {len(results)} results:")
for i, lyrics in enumerate(results[:3]): # Display first 3 results
print(f"{i+1}. {lyrics.track_name} by {lyrics.artist_name} ({lyrics.album_name})")
else:
print("No results found")
```
### Save and Load Lyrics
```python
from lyriq import get_lyrics
# Fetch and save lyrics
lyrics = get_lyrics("Circles", "Post Malone")
# Save to plain text file
lyrics.to_plain_file("circles.txt")
# Save to JSON file
lyrics.to_json_file("circles.json")
# Load from JSON file
loaded_lyrics = lyrics.from_json_file("circles.json")
```
## Command Line Interface
The library comes with a command-line interface for quick access to lyrics with synchronized lyrics playback:
```
usage: lyriq [-h] [-v] [--id ID] [--duration [DURATION]] [--search [SEARCH]] [--search-index SEARCH_INDEX]
[--none-char NONE_CHAR] [--no-info] [--plain] [--file FILE] [--file-format {plain,json}] [--load LOAD]
[song_name] [artist_name] [album_name]
Fetch and display song lyrics
positional arguments:
song_name Name of the song (optional)
artist_name Name of the artist (optional)
album_name Name of the album (optional)
options:
-h, --help show this help message and exit
-v, --version show version message and exit
--id ID ID of the song
--duration [DURATION]
Duration of the song (optional)
--search [SEARCH] Search for lyrics by song name and artist name. Optionally provide a search query.
--search-index SEARCH_INDEX
Select search result at specified index directly (1-based)
--none-char NONE_CHAR
Character to use for empty lines
--no-info Do not display track information
--plain Display only plain lyrics
--file FILE File to save lyrics to and exit
--file-format {plain,json}
Format to save lyrics to
--load LOAD Load lyrics from file
```
### Usage Examples
```bash
# Basic usage
lyriq "Circles" "Post Malone"
# With album name (optional)
lyriq "Circles" "Post Malone" "Hollywood's Bleeding"
# With duration (optional)
lyriq "Circles" "Post Malone" --duration 210
# Fetch lyrics by ID
lyriq --id 449
# Custom character for empty lines
lyriq "Circles" "Post Malone" --none-char "*"
# Display no track information
lyriq "Circles" "Post Malone" --no-info
# Display only plain lyrics
lyriq "Circles" "Post Malone" --plain
# Save lyrics to file and exit
lyriq "Circles" "Post Malone" --file Circles-Post-Malone.txt
# Save lyrics to JSON file and exit
lyriq "Circles" "Post Malone" --file Circles-Post-Malone.json --file-format json
# Load lyrics from file
lyriq --load Circles-Post-Malone.json
# Search for lyrics using song name and artist name fields with interactive UI
lyriq "Circles" "Post Malone" --search
# Search with general query
lyriq --search "Circles Post Malone"
# Search and select result at specific index
lyriq --search "Circles Post Malone" --search-index 1
```
### CLI Features
- Display song metadata with colored highlighting of differences
- Synchronized lyrics playback (if available)
- Interactive controls:
- Press `SPACE` (or custom character): Play/Pause
- Press `←` / `→` arrows: Rewind/Fast-forward by 5 seconds
- Press `r`: Toggle repeat
- Press `q`: Quit
- Interactive search UI:
- Navigate results with `↑` / `↓` arrow keys
- Select with `Enter` or number keys `1-9`
- Pagination with 4 results per page
- Shows synchronized lyrics availability with color indicators
## API Reference
### Main Functions
#### `get_lyrics(song_name, artist_name, album_name=None, duration=None, none_char="♪")`
Fetches lyrics for a song by artist name and song name.
- **Parameters**:
- `song_name`: Name of the song
- `artist_name`: Name of the artist
- `album_name`: (Optional) Album name to improve search accuracy
- `duration`: (Optional) Duration of the song in seconds
- `none_char`: Character to use for empty lines in synchronized lyrics
- **Returns**: A `Lyrics` object if found, `None` otherwise
#### `get_lyrics_by_id(lyrics_id, none_char="♪")`
Fetches lyrics for a song by its LRCLib ID.
- **Parameters**:
- `lyrics_id`: The LRCLib ID of the song
- `none_char`: Character to use for empty lines in synchronized lyrics
- **Returns**: A `Lyrics` object if found, `None` otherwise
#### `search_lyrics(q=None, song_name=None, artist_name=None, album_name=None, none_char="♪")`
Searches for lyrics by query or song/artist information.
- **Parameters**:
- `q`: General search query string
- `song_name`: Optional song name for searching
- `artist_name`: Optional artist name for searching
- `album_name`: Optional album name for better matching
- `none_char`: Character to use for empty lines in synchronized lyrics
- **Returns**: A list of `Lyrics` objects if found, `None` otherwise
#### `to_plain_lyrics(lyrics, none_char="♪")`
Converts a `Lyrics` object or lyrics dictionary to plain text.
- **Parameters**:
- `lyrics`: A `Lyrics` object or dictionary containing lyrics data
- `none_char`: Character to use for empty lines
- **Returns**: Plain text lyrics as a string
#### `request_challenge()`
Requests a cryptographic challenge from the API for generating a publish token.
- **Returns**: A tuple containing `(prefix, target)` for the proof-of-work challenge
- **Raises**: `LyriqError` if the API returns an error
#### `verify_nonce(result_bytes, target_bytes)`
Verifies if a nonce satisfies the target requirement for the proof-of-work challenge.
- **Parameters**:
- `result_bytes`: The hashed result as bytes
- `target_bytes`: The target as bytes
- **Returns**: `True` if the nonce satisfies the target, `False` otherwise
#### `generate_publish_token(prefix, target)`
Generates a valid publish token by solving a proof-of-work challenge.
- **Parameters**:
- `prefix`: The prefix string provided by the challenge
- `target`: The target string in hexadecimal format provided by the challenge
- **Returns**: A valid publish token in the format `{prefix}:{nonce}`
- **Raises**: `LyriqError` if there is an error with the token generation
#### `publish_lyrics(track_name, artist_name, album_name, duration, plain_lyrics="", synced_lyrics="")`
Publishes lyrics to the LRCLIB API.
- **Parameters**:
- `track_name`: Name of the track
- `artist_name`: Name of the artist
- `album_name`: Name of the album
- `duration`: Duration of the track in seconds
- `plain_lyrics`: Plain text lyrics (optional)
- `synced_lyrics`: Synchronized lyrics (optional)
- **Returns**: `True` if the publish was successful, `False` otherwise
- **Raises**: `LyriqError` if there is an error publishing the lyrics
### Lyrics Class
#### Properties
- `lyrics`: Dictionary mapping timestamps to lyric lines
- `synced_lyrics`: Raw synchronized lyrics string
- `plain_lyrics`: Plain lyrics string
- `id`: LRCLib ID of the song
- `name`: Name of the song
- `track_name`: Name of the track
- `artist_name`: Name of the artist
- `album_name`: Name of the album
- `duration`: Duration of the song in seconds
- `instrumental`: Whether the song is instrumental (True/False)
#### Methods
##### `from_dict(data, none_char="♪")`
Create a `Lyrics` instance from a dictionary.
- **Parameters**:
- `data`: Raw lyrics data dictionary from the API
- `none_char`: Character to use for empty lines
- **Returns**: A new `Lyrics` instance
##### `to_dict()`
Convert the `Lyrics` instance to a dictionary.
- **Returns**: Dictionary representation of the lyrics
##### `to_plain_file(file_path)`
Write the lyrics to a plain text file.
- **Parameters**:
- `file_path`: Path to the output file
##### `to_json_file(file_path)`
Write the lyrics to a JSON file.
- **Parameters**:
- `file_path`: Path to the output file
##### `from_json_file(file_path, none_char="♪")`
Read lyrics from a JSON file.
- **Parameters**:
- `file_path`: Path to the JSON file
- `none_char`: Character to use for empty lines
- **Returns**: A new `Lyrics` instance
## Examples
See the examples directory for practical usage examples:
- `examples/basic_usage.py` - Basic usage of the library
- `examples/fetch_by_id.py` - Fetching lyrics by ID
- `examples/search_lyrics.py` - Searching for lyrics
- `examples/synced_lyrics.py` - Working with synchronized lyrics
- `examples/format_conversion.py` - Converting between formats
- `examples/publishing_lyrics.py` - Publishing lyrics to the API
## Development
### Project Structure
```
lyriq/
├── .github/
│ ├── workflows/
│ │ ├── python-tests.yml
│ │ └── python-publish.yml
├── environment.yml # Environment file
├── examples/ # Example files demonstrating usage
│ ├── basic_usage.py
│ ├── fetch_by_id.py
│ ├── search_lyrics.py
│ ├── synced_lyrics.py
│ ├── format_conversion.py
│ └── publishing_lyrics.py
├── lyriq/
│ ├── __init__.py # Package exports
│ ├── __main__.py # CLI entry point
│ ├── lyriq.py # Core functionality
│ ├── cli.py # Command line interface
│ └── cache/ # Auto-generated cache directory
│ ├── lyrics.json # Lyrics cache
│ └── search.json # Search cache
├── tests/
│ ├── __init__.py
│ └── test_lyriq.py # Test suite
├── pyproject.toml # Project configuration
├── setup.py # Setup script
├── main.py # Example usage
├── README.md # This file
├── LICENSE # License file
└── .gitignore # Git ignore file
```
### Running Tests
```bash
# Install development dependencies
pip install -e ".[dev]"
# Run the test suite
pytest
# Run with coverage report
pytest --cov=lyriq --cov-report=term-missing
```
### Adding Features
1. Make changes to the core functionality in `lyriq.py`
2. Add appropriate tests in `test_lyriq.py`
3. Update documentation in docstrings and README.md
4. Run tests to ensure everything works
## Technical Details
### API
Lyriq uses the LRCLib API (https://lrclib.net/api) to fetch lyrics data. The API provides both synchronized and plain lyrics.
### Caching
To reduce API calls and improve performance, Lyriq caches all retrieved lyrics in JSON files located in the cache directory:
```
<package_location>/cache/
```
The cache is thread-safe and automatically writes to disk when new lyrics are added.
### Synchronized Lyrics Format
Synchronized lyrics are stored in LRC format with timestamps in the format `[MM:SS.ms]`. The CLI tool interprets these timestamps to display the lyrics at the right moment during playback.
## License
Apache 2.0 License - See LICENSE file for details.
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Raw data
{
"_id": null,
"home_page": null,
"name": "lyriq",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "lyrics, music, synchronization",
"author": null,
"author_email": "TN3W <tn3w@protonmail.com>",
"download_url": "https://files.pythonhosted.org/packages/3d/41/7793aeda2a31115b30f8543f6901e043367a7675dc90d32ae68bc52db681/lyriq-1.2.0.tar.gz",
"platform": null,
"description": "# Lyriq\n\nA lightweight Python library designed to effortlessly fetch and display song lyrics, with support for synchronized lyrics and an accompanying CLI tool.\n\n[](https://pypi.org/project/lyriq/)\n[](https://pypi.org/project/lyriq/)\n[](https://github.com/tn3w/lyriq/blob/main/LICENSE)\n\n## Features\n\n- Fetch lyrics from the LRCLib API\n- Support for both plain and synchronized lyrics\n- Built-in caching to reduce API calls\n- CLI tool with synchronized lyrics playback\n- Support for saving/loading lyrics in JSON and plain text formats\n- Colorful terminal output with synchronized highlighting\n\n## Installation\n\n### From PyPI\n\n```bash\npip install lyriq\n```\n\n### Development Installation\n\n```bash\ngit clone https://github.com/tn3w/lyriq.git\ncd lyriq\npip install -e \".[dev]\"\n```\n\n## Usage\n\n### Basic Usage\n\n```python\nimport sys\nfrom lyriq import get_lyrics\n\nlyrics = get_lyrics(\"Circles\", \"Post Malone\")\nif not lyrics:\n print(\"No lyrics found for 'Circles' by Post Malone\")\n sys.exit(0)\n\nprint(f\"ID: {lyrics.id}\")\nprint(f\"Name: {lyrics.name}\")\nprint(f\"Track: {lyrics.track_name}\")\nprint(f\"Artist: {lyrics.artist_name}\")\nprint(f\"Album: {lyrics.album_name}\")\nprint(f\"Duration: {lyrics.duration} seconds\")\nprint(f\"Instrumental: {'Yes' if lyrics.synced_lyrics else 'No'}\")\nprint(\"\\nPlain Lyrics:\")\nprint(\"-\" * 40)\nprint(lyrics.plain_lyrics)\nprint(\"\\nSynchronized Lyrics (timestamp: lyric):\")\nprint(\"-\" * 40)\n\nfor timestamp, line in sorted(lyrics.lyrics.items()):\n print(f\"[{timestamp}] {line}\")\n\nprint(\"-\" * 40)\n```\n\n### Fetch by ID\n\n```python\nfrom lyriq import get_lyrics_by_id\n\n# Fetch lyrics by ID\nlyrics = get_lyrics_by_id(\"449\") # ID for \"Circles\" by Post Malone\n\nif lyrics:\n print(f\"Found: {lyrics.track_name} by {lyrics.artist_name}\")\n```\n\n### Convert to Plain Text\n\n```python\nfrom lyriq import to_plain_lyrics, get_lyrics\n\nlyrics = get_lyrics(\"Circles\", \"Post Malone\")\nplain_text = to_plain_lyrics(lyrics)\nprint(plain_text)\n```\n\n### Search for Lyrics\n\n```python\nfrom lyriq import search_lyrics\n\n# Search by general query\nresults = search_lyrics(q=\"Circles Post Malone\")\n\n# Or search by song and artist name\nresults = search_lyrics(song_name=\"Circles\", artist_name=\"Post Malone\")\n\nif results:\n print(f\"Found {len(results)} results:\")\n for i, lyrics in enumerate(results[:3]): # Display first 3 results\n print(f\"{i+1}. {lyrics.track_name} by {lyrics.artist_name} ({lyrics.album_name})\")\nelse:\n print(\"No results found\")\n```\n\n### Save and Load Lyrics\n\n```python\nfrom lyriq import get_lyrics\n\n# Fetch and save lyrics\nlyrics = get_lyrics(\"Circles\", \"Post Malone\")\n\n# Save to plain text file\nlyrics.to_plain_file(\"circles.txt\")\n\n# Save to JSON file\nlyrics.to_json_file(\"circles.json\")\n\n# Load from JSON file\nloaded_lyrics = lyrics.from_json_file(\"circles.json\")\n```\n\n## Command Line Interface\n\nThe library comes with a command-line interface for quick access to lyrics with synchronized lyrics playback:\n```\nusage: lyriq [-h] [-v] [--id ID] [--duration [DURATION]] [--search [SEARCH]] [--search-index SEARCH_INDEX]\n [--none-char NONE_CHAR] [--no-info] [--plain] [--file FILE] [--file-format {plain,json}] [--load LOAD]\n [song_name] [artist_name] [album_name]\n\nFetch and display song lyrics\n\npositional arguments:\n song_name Name of the song (optional)\n artist_name Name of the artist (optional)\n album_name Name of the album (optional)\n\noptions:\n -h, --help show this help message and exit\n -v, --version show version message and exit\n --id ID ID of the song\n --duration [DURATION]\n Duration of the song (optional)\n --search [SEARCH] Search for lyrics by song name and artist name. Optionally provide a search query.\n --search-index SEARCH_INDEX\n Select search result at specified index directly (1-based)\n --none-char NONE_CHAR\n Character to use for empty lines\n --no-info Do not display track information\n --plain Display only plain lyrics\n --file FILE File to save lyrics to and exit\n --file-format {plain,json}\n Format to save lyrics to\n --load LOAD Load lyrics from file\n```\n\n### Usage Examples\n\n```bash\n# Basic usage\nlyriq \"Circles\" \"Post Malone\"\n\n# With album name (optional)\nlyriq \"Circles\" \"Post Malone\" \"Hollywood's Bleeding\"\n\n# With duration (optional)\nlyriq \"Circles\" \"Post Malone\" --duration 210\n\n# Fetch lyrics by ID\nlyriq --id 449\n\n# Custom character for empty lines\nlyriq \"Circles\" \"Post Malone\" --none-char \"*\"\n\n# Display no track information\nlyriq \"Circles\" \"Post Malone\" --no-info\n\n# Display only plain lyrics\nlyriq \"Circles\" \"Post Malone\" --plain\n\n# Save lyrics to file and exit\nlyriq \"Circles\" \"Post Malone\" --file Circles-Post-Malone.txt\n\n# Save lyrics to JSON file and exit\nlyriq \"Circles\" \"Post Malone\" --file Circles-Post-Malone.json --file-format json\n\n# Load lyrics from file\nlyriq --load Circles-Post-Malone.json\n\n# Search for lyrics using song name and artist name fields with interactive UI\nlyriq \"Circles\" \"Post Malone\" --search\n\n# Search with general query\nlyriq --search \"Circles Post Malone\"\n\n# Search and select result at specific index\nlyriq --search \"Circles Post Malone\" --search-index 1\n```\n\n### CLI Features\n\n- Display song metadata with colored highlighting of differences\n- Synchronized lyrics playback (if available)\n- Interactive controls:\n - Press `SPACE` (or custom character): Play/Pause\n - Press `\u2190` / `\u2192` arrows: Rewind/Fast-forward by 5 seconds\n - Press `r`: Toggle repeat\n - Press `q`: Quit\n- Interactive search UI:\n - Navigate results with `\u2191` / `\u2193` arrow keys\n - Select with `Enter` or number keys `1-9`\n - Pagination with 4 results per page\n - Shows synchronized lyrics availability with color indicators\n\n## API Reference\n\n### Main Functions\n\n#### `get_lyrics(song_name, artist_name, album_name=None, duration=None, none_char=\"\u266a\")`\n\nFetches lyrics for a song by artist name and song name.\n\n- **Parameters**:\n - `song_name`: Name of the song\n - `artist_name`: Name of the artist\n - `album_name`: (Optional) Album name to improve search accuracy\n - `duration`: (Optional) Duration of the song in seconds\n - `none_char`: Character to use for empty lines in synchronized lyrics\n- **Returns**: A `Lyrics` object if found, `None` otherwise\n\n#### `get_lyrics_by_id(lyrics_id, none_char=\"\u266a\")`\n\nFetches lyrics for a song by its LRCLib ID.\n\n- **Parameters**:\n - `lyrics_id`: The LRCLib ID of the song\n - `none_char`: Character to use for empty lines in synchronized lyrics\n- **Returns**: A `Lyrics` object if found, `None` otherwise\n\n#### `search_lyrics(q=None, song_name=None, artist_name=None, album_name=None, none_char=\"\u266a\")`\n\nSearches for lyrics by query or song/artist information.\n\n- **Parameters**:\n - `q`: General search query string\n - `song_name`: Optional song name for searching\n - `artist_name`: Optional artist name for searching\n - `album_name`: Optional album name for better matching\n - `none_char`: Character to use for empty lines in synchronized lyrics\n- **Returns**: A list of `Lyrics` objects if found, `None` otherwise\n\n#### `to_plain_lyrics(lyrics, none_char=\"\u266a\")`\n\nConverts a `Lyrics` object or lyrics dictionary to plain text.\n\n- **Parameters**:\n - `lyrics`: A `Lyrics` object or dictionary containing lyrics data\n - `none_char`: Character to use for empty lines\n- **Returns**: Plain text lyrics as a string\n\n#### `request_challenge()`\n\nRequests a cryptographic challenge from the API for generating a publish token.\n\n- **Returns**: A tuple containing `(prefix, target)` for the proof-of-work challenge\n- **Raises**: `LyriqError` if the API returns an error\n\n#### `verify_nonce(result_bytes, target_bytes)`\n\nVerifies if a nonce satisfies the target requirement for the proof-of-work challenge.\n\n- **Parameters**:\n - `result_bytes`: The hashed result as bytes\n - `target_bytes`: The target as bytes\n- **Returns**: `True` if the nonce satisfies the target, `False` otherwise\n\n#### `generate_publish_token(prefix, target)`\n\nGenerates a valid publish token by solving a proof-of-work challenge.\n\n- **Parameters**:\n - `prefix`: The prefix string provided by the challenge\n - `target`: The target string in hexadecimal format provided by the challenge\n- **Returns**: A valid publish token in the format `{prefix}:{nonce}`\n- **Raises**: `LyriqError` if there is an error with the token generation\n\n#### `publish_lyrics(track_name, artist_name, album_name, duration, plain_lyrics=\"\", synced_lyrics=\"\")`\n\nPublishes lyrics to the LRCLIB API.\n\n- **Parameters**:\n - `track_name`: Name of the track\n - `artist_name`: Name of the artist\n - `album_name`: Name of the album\n - `duration`: Duration of the track in seconds\n - `plain_lyrics`: Plain text lyrics (optional)\n - `synced_lyrics`: Synchronized lyrics (optional)\n- **Returns**: `True` if the publish was successful, `False` otherwise\n- **Raises**: `LyriqError` if there is an error publishing the lyrics\n\n### Lyrics Class\n\n#### Properties\n\n- `lyrics`: Dictionary mapping timestamps to lyric lines\n- `synced_lyrics`: Raw synchronized lyrics string\n- `plain_lyrics`: Plain lyrics string\n- `id`: LRCLib ID of the song\n- `name`: Name of the song\n- `track_name`: Name of the track\n- `artist_name`: Name of the artist\n- `album_name`: Name of the album\n- `duration`: Duration of the song in seconds\n- `instrumental`: Whether the song is instrumental (True/False)\n\n#### Methods\n\n##### `from_dict(data, none_char=\"\u266a\")`\n\nCreate a `Lyrics` instance from a dictionary.\n\n- **Parameters**:\n - `data`: Raw lyrics data dictionary from the API\n - `none_char`: Character to use for empty lines\n- **Returns**: A new `Lyrics` instance\n\n##### `to_dict()`\n\nConvert the `Lyrics` instance to a dictionary.\n\n- **Returns**: Dictionary representation of the lyrics\n\n##### `to_plain_file(file_path)`\n\nWrite the lyrics to a plain text file.\n\n- **Parameters**:\n - `file_path`: Path to the output file\n\n##### `to_json_file(file_path)`\n\nWrite the lyrics to a JSON file.\n\n- **Parameters**:\n - `file_path`: Path to the output file\n\n##### `from_json_file(file_path, none_char=\"\u266a\")`\n\nRead lyrics from a JSON file.\n\n- **Parameters**:\n - `file_path`: Path to the JSON file\n - `none_char`: Character to use for empty lines\n- **Returns**: A new `Lyrics` instance\n\n## Examples\n\nSee the examples directory for practical usage examples:\n\n- `examples/basic_usage.py` - Basic usage of the library\n- `examples/fetch_by_id.py` - Fetching lyrics by ID\n- `examples/search_lyrics.py` - Searching for lyrics\n- `examples/synced_lyrics.py` - Working with synchronized lyrics\n- `examples/format_conversion.py` - Converting between formats\n- `examples/publishing_lyrics.py` - Publishing lyrics to the API\n\n## Development\n\n### Project Structure\n\n```\nlyriq/\n\u251c\u2500\u2500 .github/\n\u2502 \u251c\u2500\u2500 workflows/\n\u2502 \u2502 \u251c\u2500\u2500 python-tests.yml\n\u2502 \u2502 \u2514\u2500\u2500 python-publish.yml\n\u251c\u2500\u2500 environment.yml # Environment file\n\u251c\u2500\u2500 examples/ # Example files demonstrating usage\n\u2502 \u251c\u2500\u2500 basic_usage.py\n\u2502 \u251c\u2500\u2500 fetch_by_id.py\n\u2502 \u251c\u2500\u2500 search_lyrics.py\n\u2502 \u251c\u2500\u2500 synced_lyrics.py\n\u2502 \u251c\u2500\u2500 format_conversion.py\n\u2502 \u2514\u2500\u2500 publishing_lyrics.py\n\u251c\u2500\u2500 lyriq/\n\u2502 \u251c\u2500\u2500 __init__.py # Package exports\n\u2502 \u251c\u2500\u2500 __main__.py # CLI entry point\n\u2502 \u251c\u2500\u2500 lyriq.py # Core functionality\n\u2502 \u251c\u2500\u2500 cli.py # Command line interface\n\u2502 \u2514\u2500\u2500 cache/ # Auto-generated cache directory\n\u2502 \u251c\u2500\u2500 lyrics.json # Lyrics cache\n\u2502 \u2514\u2500\u2500 search.json # Search cache\n\u251c\u2500\u2500 tests/\n\u2502 \u251c\u2500\u2500 __init__.py\n\u2502 \u2514\u2500\u2500 test_lyriq.py # Test suite\n\u251c\u2500\u2500 pyproject.toml # Project configuration\n\u251c\u2500\u2500 setup.py # Setup script\n\u251c\u2500\u2500 main.py # Example usage\n\u251c\u2500\u2500 README.md # This file\n\u251c\u2500\u2500 LICENSE # License file\n\u2514\u2500\u2500 .gitignore # Git ignore file\n```\n\n### Running Tests\n\n```bash\n# Install development dependencies\npip install -e \".[dev]\"\n\n# Run the test suite\npytest\n\n# Run with coverage report\npytest --cov=lyriq --cov-report=term-missing\n```\n\n### Adding Features\n\n1. Make changes to the core functionality in `lyriq.py`\n2. Add appropriate tests in `test_lyriq.py`\n3. Update documentation in docstrings and README.md\n4. Run tests to ensure everything works\n\n## Technical Details\n\n### API\n\nLyriq uses the LRCLib API (https://lrclib.net/api) to fetch lyrics data. The API provides both synchronized and plain lyrics.\n\n### Caching\n\nTo reduce API calls and improve performance, Lyriq caches all retrieved lyrics in JSON files located in the cache directory:\n\n```\n<package_location>/cache/\n```\n\nThe cache is thread-safe and automatically writes to disk when new lyrics are added.\n\n### Synchronized Lyrics Format\n\nSynchronized lyrics are stored in LRC format with timestamps in the format `[MM:SS.ms]`. The CLI tool interprets these timestamps to display the lyrics at the right moment during playback.\n\n## License\n\nApache 2.0 License - See LICENSE file for details.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n",
"bugtrack_url": null,
"license": null,
"summary": "A lightweight Python library designed to effortlessly fetch song lyrics.",
"version": "1.2.0",
"project_urls": {
"Documentation": "https://github.com/tn3w/lyriq/blob/master/README.md",
"Homepage": "https://github.com/tn3w/lyriq",
"Issues": "https://github.com/tn3w/lyriq/issues",
"Repository": "https://github.com/tn3w/lyriq.git"
},
"split_keywords": [
"lyrics",
" music",
" synchronization"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "a2e4dfc980a037341a578531231744cb707133e49bd0b97edc7d5fd2b05b1baf",
"md5": "0f420d82dc71914cff4af84d02b471d6",
"sha256": "d96207204bce964fb66c46b6c7173ca228a9a7ec43dcc5ca50fecf711663b4c1"
},
"downloads": -1,
"filename": "lyriq-1.2.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "0f420d82dc71914cff4af84d02b471d6",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 20792,
"upload_time": "2025-07-15T12:37:23",
"upload_time_iso_8601": "2025-07-15T12:37:23.350851Z",
"url": "https://files.pythonhosted.org/packages/a2/e4/dfc980a037341a578531231744cb707133e49bd0b97edc7d5fd2b05b1baf/lyriq-1.2.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "3d417793aeda2a31115b30f8543f6901e043367a7675dc90d32ae68bc52db681",
"md5": "257c705e8337f34df5f881754dc1da07",
"sha256": "8d4407d1a6bd5de2330ab7f50185c2fc1736ef5b61d43e2bb3331bcadcf6a71e"
},
"downloads": -1,
"filename": "lyriq-1.2.0.tar.gz",
"has_sig": false,
"md5_digest": "257c705e8337f34df5f881754dc1da07",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 28349,
"upload_time": "2025-07-15T12:37:24",
"upload_time_iso_8601": "2025-07-15T12:37:24.263182Z",
"url": "https://files.pythonhosted.org/packages/3d/41/7793aeda2a31115b30f8543f6901e043367a7675dc90d32ae68bc52db681/lyriq-1.2.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-15 12:37:24",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "tn3w",
"github_project": "lyriq",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "lyriq"
}