suno-easy 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fred
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,216 @@
1
+ Metadata-Version: 2.4
2
+ Name: suno-easy
3
+ Version: 0.1.0
4
+ Summary: A lightweight, modern, and fully-typed Python SDK for the Suno AI API (sunoapi.org)
5
+ Author-email: Fred <frederic.dymko@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Onnonoka/suno-easy
8
+ Project-URL: Documentation, https://github.com/Onnonoka/suno-easy#readme
9
+ Project-URL: Repository, https://github.com/Onnonoka/suno-easy.git
10
+ Project-URL: Issues, https://github.com/Onnonoka/suno-easy/issues
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: requests>=2.25.0
20
+ Dynamic: license-file
21
+
22
+ # suno-easy 🎵
23
+
24
+ > [!IMPORTANT]
25
+ > **Disclaimer**: This is an unofficial, community-driven Python SDK wrapper for the Suno API (`sunoapi.org`). It is not affiliated with, endorsed, sponsored, or supported by Suno, Inc. or the official Suno AI platform.
26
+
27
+ `suno-easy` is a lightweight, modern, and fully-typed Python SDK for the Suno AI API ([sunoapi.org](https://docs.sunoapi.org/)).
28
+
29
+ It provides an intuitive, object-oriented interface to generate music, write lyrics, create voice personas, separate audio stems, and generate MIDI notes from audio files.
30
+
31
+ ---
32
+
33
+ ## Features
34
+
35
+ - **Clean Namespace Organization**: Resources are grouped logically (`client.music`, `client.lyrics`, `client.audio`, `client.persona`).
36
+ - **Fully Typed**: Rich python dataclasses for responses (`Song`, `Lyrics`, `SeparatedStems`, `MIDIData`, `CoverImage`).
37
+ - **Smart Polling**: Methods can either block and return the processed result (`wait=True`) or instantly return a `taskId` for asynchronous workflows (`wait=False`).
38
+ - **Built-in Downloads**: Download audio tracks, cover images, and isolated stems with built-in streaming helpers.
39
+ - **Robust Error Handling**: Distinct exceptions for HTTP failures (`SunoAPIError`) and generation failures (`TaskFailed`).
40
+
41
+ ---
42
+
43
+ ## Repository Structure
44
+
45
+ ```text
46
+ suno-easy/
47
+ ├── suno_easy/ # Core SDK library source code
48
+ │ ├── __init__.py # Exposed client, models, and exceptions
49
+ │ ├── client.py # Main SunoClient orchestrator
50
+ │ ├── models.py # Strongly typed dataclasses representing API payloads
51
+ │ ├── audio.py # Audio processing sub-resource (stems, MIDI, covers)
52
+ │ ├── music.py # Music generation and extension sub-resource
53
+ │ ├── lyrics.py # Lyrics generation sub-resource
54
+ │ ├── persona.py # Voice/style persona sub-resource
55
+ │ ├── exceptions.py # SDK custom exception classes
56
+ │ └── utils.py # Internal utility and polling helpers
57
+ ├── tests/ # Test suite
58
+ │ ├── __init__.py
59
+ │ └── test_client.py # Mocked HTTP interface unit tests
60
+ ├── examples/ # Basic usage examples
61
+ │ └── quickstart.py # Quickstart example script
62
+ ├── pyproject.toml # PEP 621 compliant project packaging configuration
63
+ ├── requirements.txt # Runtime dependencies
64
+ ├── requirements-dev.txt# Development and testing requirements
65
+ ├── LICENSE # MIT License file
66
+ └── README.md # Project documentation
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Installation
72
+
73
+ This SDK requires `requests`. You can install the package directly from source:
74
+
75
+ ```bash
76
+ pip install .
77
+ ```
78
+
79
+ Or for development (editable mode):
80
+
81
+ ```bash
82
+ pip install -e .
83
+ ```
84
+
85
+ ---
86
+
87
+ ## Quickstart
88
+
89
+ ### 1. Initialize the Client
90
+
91
+ ```python
92
+ from suno_easy import SunoClient
93
+
94
+ client = SunoClient(api_key="your_suno_api_key_here")
95
+ ```
96
+
97
+ ### 2. Generate Music
98
+
99
+ Generate a track in custom mode (requires prompt, style, and title). By default, this blocks until the songs are generated (usually 2-3 minutes) and returns a list containing two song variations.
100
+
101
+ ```python
102
+ songs = client.music.generate(
103
+ prompt="A peaceful acoustic guitar melody with soft strings",
104
+ style="Folk, Acoustic",
105
+ title="Morning Breeze",
106
+ instrumental=True
107
+ )
108
+
109
+ for song in songs:
110
+ print(f"Song generated: {song.title} (ID: {song.id})")
111
+ print(f"Audio URL: {song.audio_url}")
112
+
113
+ # Download the track and its cover image
114
+ song.download(f"{song.title}.mp3")
115
+ song.download_image(f"{song.title}.jpg")
116
+ ```
117
+
118
+ ### 3. Generate Lyrics
119
+
120
+ Create AI-generated lyrics structure markers like `[Verse]` or `[Chorus]`.
121
+
122
+ ```python
123
+ lyrics_list = client.lyrics.generate(prompt="a song about embarking on a journey to Mars")
124
+
125
+ for lyrics in lyrics_list:
126
+ print(f"Title Idea: {lyrics.title}")
127
+ print(lyrics.text)
128
+ ```
129
+
130
+ ### 4. Separate Vocals (Stem Separation)
131
+
132
+ Separate an existing song task into vocals and instrumental tracks. Supports 2-stem (`separate_vocal`) and up to 12-stem (`split_stem`) separation.
133
+
134
+ ```python
135
+ stems = client.audio.separate_vocals(
136
+ task_id="original_music_task_id",
137
+ mode="separate_vocal" # or "split_stem"
138
+ )
139
+
140
+ print(f"Vocal URL: {stems.vocal_url}")
141
+ print(f"Instrumental URL: {stems.instrumental_url}")
142
+
143
+ # Download isolated files
144
+ stems.download_vocal("vocals.mp3")
145
+ stems.download_instrumental("instrumental.mp3")
146
+ ```
147
+
148
+ ### 5. Convert Audio to MIDI
149
+
150
+ Convert separated audio tracks into MIDI note structures.
151
+
152
+ ```python
153
+ midi_data = client.audio.generate_midi(task_id="vocal_removal_task_id")
154
+
155
+ print(f"MIDI Generation State: {midi_data.state}")
156
+ for instrument in midi_data.instruments:
157
+ print(f"Instrument: {instrument.name}")
158
+ for note in instrument.notes[:5]: # Print first 5 notes
159
+ print(f" Note pitch: {note.pitch}, start: {note.start}s, end: {note.end}s")
160
+ ```
161
+
162
+ ---
163
+
164
+ ## Asynchronous Workflows (Webhooks & Background Tasks)
165
+
166
+ If you don't want the methods to block your program execution, set `wait=False`. The client will instantly return the `taskId` string. You can then poll later or receive webhook callbacks on your server.
167
+
168
+ ```python
169
+ # Starts music generation and returns instantly
170
+ task_id = client.music.generate(
171
+ prompt="Lo-fi hip hop beat for studying",
172
+ style="Lo-Fi",
173
+ title="Study Session",
174
+ wait=False,
175
+ callback_url="https://yourdomain.com/webhook"
176
+ )
177
+
178
+ print(f"Music generation started. Task ID: {task_id}")
179
+
180
+ # Manually retrieve info later
181
+ task_info = client.music.get_task_info(task_id)
182
+ print(f"Status: {task_info.get('status')}")
183
+ ```
184
+
185
+ ---
186
+
187
+ ## API Reference
188
+
189
+ ### `client.music`
190
+ * `generate(...) -> list[Song] | str`: Generates songs from prompts.
191
+ * `extend(...) -> list[Song] | str`: Extends an existing song from a timestamp.
192
+ * `generate_instrumental(...) -> list[Song] | str`: Generates instrumentals.
193
+ * `remaster(music_id, ...) -> list[Song] | str`: Improves the quality of a song.
194
+
195
+ ### `client.lyrics`
196
+ * `generate(prompt, ...) -> list[Lyrics] | str`: Generates lyrics.
197
+ * `get(task_id) -> list[Lyrics]`: Retrieves lyrics from a completed task.
198
+
199
+ ### `client.audio`
200
+ * `cover(upload_url, style, title, ...) -> list[Song] | str`: Applies a style cover to an uploaded audio.
201
+ * `extend(upload_url, continue_at, prompt, ...) -> list[Song] | str`: Extends an uploaded audio track.
202
+ * `separate_vocals(task_id, mode, ...) -> SeparatedStems | str`: Split vocals and instrumentation.
203
+ * `get_separated_stems(task_id) -> SeparatedStems`: Retrieves separated stems.
204
+ * `generate_midi(task_id, ...) -> MIDIData | str`: Converts audio stems to MIDI notes.
205
+ * `get_midi(task_id) -> MIDIData`: Retrieves MIDI notes.
206
+ * `add_vocals(upload_url, prompt, ...) -> list[Song] | str`: Adds vocals to an instrumental track.
207
+ * `add_instrumental(upload_url, title, tags, ...) -> list[Song] | str`: Adds backing instruments to vocals.
208
+
209
+ ### `client.persona`
210
+ * `create(music_id, name) -> dict`: Creates a voice/style persona from a track.
211
+
212
+ ---
213
+
214
+ ## License
215
+
216
+ This project is licensed under the MIT License.
@@ -0,0 +1,195 @@
1
+ # suno-easy 🎵
2
+
3
+ > [!IMPORTANT]
4
+ > **Disclaimer**: This is an unofficial, community-driven Python SDK wrapper for the Suno API (`sunoapi.org`). It is not affiliated with, endorsed, sponsored, or supported by Suno, Inc. or the official Suno AI platform.
5
+
6
+ `suno-easy` is a lightweight, modern, and fully-typed Python SDK for the Suno AI API ([sunoapi.org](https://docs.sunoapi.org/)).
7
+
8
+ It provides an intuitive, object-oriented interface to generate music, write lyrics, create voice personas, separate audio stems, and generate MIDI notes from audio files.
9
+
10
+ ---
11
+
12
+ ## Features
13
+
14
+ - **Clean Namespace Organization**: Resources are grouped logically (`client.music`, `client.lyrics`, `client.audio`, `client.persona`).
15
+ - **Fully Typed**: Rich python dataclasses for responses (`Song`, `Lyrics`, `SeparatedStems`, `MIDIData`, `CoverImage`).
16
+ - **Smart Polling**: Methods can either block and return the processed result (`wait=True`) or instantly return a `taskId` for asynchronous workflows (`wait=False`).
17
+ - **Built-in Downloads**: Download audio tracks, cover images, and isolated stems with built-in streaming helpers.
18
+ - **Robust Error Handling**: Distinct exceptions for HTTP failures (`SunoAPIError`) and generation failures (`TaskFailed`).
19
+
20
+ ---
21
+
22
+ ## Repository Structure
23
+
24
+ ```text
25
+ suno-easy/
26
+ ├── suno_easy/ # Core SDK library source code
27
+ │ ├── __init__.py # Exposed client, models, and exceptions
28
+ │ ├── client.py # Main SunoClient orchestrator
29
+ │ ├── models.py # Strongly typed dataclasses representing API payloads
30
+ │ ├── audio.py # Audio processing sub-resource (stems, MIDI, covers)
31
+ │ ├── music.py # Music generation and extension sub-resource
32
+ │ ├── lyrics.py # Lyrics generation sub-resource
33
+ │ ├── persona.py # Voice/style persona sub-resource
34
+ │ ├── exceptions.py # SDK custom exception classes
35
+ │ └── utils.py # Internal utility and polling helpers
36
+ ├── tests/ # Test suite
37
+ │ ├── __init__.py
38
+ │ └── test_client.py # Mocked HTTP interface unit tests
39
+ ├── examples/ # Basic usage examples
40
+ │ └── quickstart.py # Quickstart example script
41
+ ├── pyproject.toml # PEP 621 compliant project packaging configuration
42
+ ├── requirements.txt # Runtime dependencies
43
+ ├── requirements-dev.txt# Development and testing requirements
44
+ ├── LICENSE # MIT License file
45
+ └── README.md # Project documentation
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Installation
51
+
52
+ This SDK requires `requests`. You can install the package directly from source:
53
+
54
+ ```bash
55
+ pip install .
56
+ ```
57
+
58
+ Or for development (editable mode):
59
+
60
+ ```bash
61
+ pip install -e .
62
+ ```
63
+
64
+ ---
65
+
66
+ ## Quickstart
67
+
68
+ ### 1. Initialize the Client
69
+
70
+ ```python
71
+ from suno_easy import SunoClient
72
+
73
+ client = SunoClient(api_key="your_suno_api_key_here")
74
+ ```
75
+
76
+ ### 2. Generate Music
77
+
78
+ Generate a track in custom mode (requires prompt, style, and title). By default, this blocks until the songs are generated (usually 2-3 minutes) and returns a list containing two song variations.
79
+
80
+ ```python
81
+ songs = client.music.generate(
82
+ prompt="A peaceful acoustic guitar melody with soft strings",
83
+ style="Folk, Acoustic",
84
+ title="Morning Breeze",
85
+ instrumental=True
86
+ )
87
+
88
+ for song in songs:
89
+ print(f"Song generated: {song.title} (ID: {song.id})")
90
+ print(f"Audio URL: {song.audio_url}")
91
+
92
+ # Download the track and its cover image
93
+ song.download(f"{song.title}.mp3")
94
+ song.download_image(f"{song.title}.jpg")
95
+ ```
96
+
97
+ ### 3. Generate Lyrics
98
+
99
+ Create AI-generated lyrics structure markers like `[Verse]` or `[Chorus]`.
100
+
101
+ ```python
102
+ lyrics_list = client.lyrics.generate(prompt="a song about embarking on a journey to Mars")
103
+
104
+ for lyrics in lyrics_list:
105
+ print(f"Title Idea: {lyrics.title}")
106
+ print(lyrics.text)
107
+ ```
108
+
109
+ ### 4. Separate Vocals (Stem Separation)
110
+
111
+ Separate an existing song task into vocals and instrumental tracks. Supports 2-stem (`separate_vocal`) and up to 12-stem (`split_stem`) separation.
112
+
113
+ ```python
114
+ stems = client.audio.separate_vocals(
115
+ task_id="original_music_task_id",
116
+ mode="separate_vocal" # or "split_stem"
117
+ )
118
+
119
+ print(f"Vocal URL: {stems.vocal_url}")
120
+ print(f"Instrumental URL: {stems.instrumental_url}")
121
+
122
+ # Download isolated files
123
+ stems.download_vocal("vocals.mp3")
124
+ stems.download_instrumental("instrumental.mp3")
125
+ ```
126
+
127
+ ### 5. Convert Audio to MIDI
128
+
129
+ Convert separated audio tracks into MIDI note structures.
130
+
131
+ ```python
132
+ midi_data = client.audio.generate_midi(task_id="vocal_removal_task_id")
133
+
134
+ print(f"MIDI Generation State: {midi_data.state}")
135
+ for instrument in midi_data.instruments:
136
+ print(f"Instrument: {instrument.name}")
137
+ for note in instrument.notes[:5]: # Print first 5 notes
138
+ print(f" Note pitch: {note.pitch}, start: {note.start}s, end: {note.end}s")
139
+ ```
140
+
141
+ ---
142
+
143
+ ## Asynchronous Workflows (Webhooks & Background Tasks)
144
+
145
+ If you don't want the methods to block your program execution, set `wait=False`. The client will instantly return the `taskId` string. You can then poll later or receive webhook callbacks on your server.
146
+
147
+ ```python
148
+ # Starts music generation and returns instantly
149
+ task_id = client.music.generate(
150
+ prompt="Lo-fi hip hop beat for studying",
151
+ style="Lo-Fi",
152
+ title="Study Session",
153
+ wait=False,
154
+ callback_url="https://yourdomain.com/webhook"
155
+ )
156
+
157
+ print(f"Music generation started. Task ID: {task_id}")
158
+
159
+ # Manually retrieve info later
160
+ task_info = client.music.get_task_info(task_id)
161
+ print(f"Status: {task_info.get('status')}")
162
+ ```
163
+
164
+ ---
165
+
166
+ ## API Reference
167
+
168
+ ### `client.music`
169
+ * `generate(...) -> list[Song] | str`: Generates songs from prompts.
170
+ * `extend(...) -> list[Song] | str`: Extends an existing song from a timestamp.
171
+ * `generate_instrumental(...) -> list[Song] | str`: Generates instrumentals.
172
+ * `remaster(music_id, ...) -> list[Song] | str`: Improves the quality of a song.
173
+
174
+ ### `client.lyrics`
175
+ * `generate(prompt, ...) -> list[Lyrics] | str`: Generates lyrics.
176
+ * `get(task_id) -> list[Lyrics]`: Retrieves lyrics from a completed task.
177
+
178
+ ### `client.audio`
179
+ * `cover(upload_url, style, title, ...) -> list[Song] | str`: Applies a style cover to an uploaded audio.
180
+ * `extend(upload_url, continue_at, prompt, ...) -> list[Song] | str`: Extends an uploaded audio track.
181
+ * `separate_vocals(task_id, mode, ...) -> SeparatedStems | str`: Split vocals and instrumentation.
182
+ * `get_separated_stems(task_id) -> SeparatedStems`: Retrieves separated stems.
183
+ * `generate_midi(task_id, ...) -> MIDIData | str`: Converts audio stems to MIDI notes.
184
+ * `get_midi(task_id) -> MIDIData`: Retrieves MIDI notes.
185
+ * `add_vocals(upload_url, prompt, ...) -> list[Song] | str`: Adds vocals to an instrumental track.
186
+ * `add_instrumental(upload_url, title, tags, ...) -> list[Song] | str`: Adds backing instruments to vocals.
187
+
188
+ ### `client.persona`
189
+ * `create(music_id, name) -> dict`: Creates a voice/style persona from a track.
190
+
191
+ ---
192
+
193
+ ## License
194
+
195
+ This project is licensed under the MIT License.
@@ -0,0 +1,33 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "suno-easy"
7
+ version = "0.1.0"
8
+ description = "A lightweight, modern, and fully-typed Python SDK for the Suno AI API (sunoapi.org)"
9
+ readme = "README.md"
10
+ authors = [
11
+ { name = "Fred", email = "frederic.dymko@gmail.com" }
12
+ ]
13
+ license = { text = "MIT" }
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ "Intended Audience :: Developers",
19
+ "Topic :: Software Development :: Libraries :: Python Modules",
20
+ ]
21
+ requires-python = ">=3.8"
22
+ dependencies = [
23
+ "requests>=2.25.0",
24
+ ]
25
+
26
+ [project.urls]
27
+ Homepage = "https://github.com/Onnonoka/suno-easy"
28
+ Documentation = "https://github.com/Onnonoka/suno-easy#readme"
29
+ Repository = "https://github.com/Onnonoka/suno-easy.git"
30
+ Issues = "https://github.com/Onnonoka/suno-easy/issues"
31
+
32
+ [tool.setuptools]
33
+ packages = ["suno_easy"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,25 @@
1
+ from .client import SunoClient
2
+ from .models import (
3
+ Song,
4
+ Lyrics,
5
+ CoverImage,
6
+ SeparatedStems,
7
+ MIDIData,
8
+ MIDINote,
9
+ MIDIInstrument,
10
+ )
11
+ from .exceptions import SunoError, TaskFailed, SunoAPIError
12
+
13
+ __all__ = [
14
+ "SunoClient",
15
+ "Song",
16
+ "Lyrics",
17
+ "CoverImage",
18
+ "SeparatedStems",
19
+ "MIDIData",
20
+ "MIDINote",
21
+ "MIDIInstrument",
22
+ "SunoError",
23
+ "TaskFailed",
24
+ "SunoAPIError",
25
+ ]