runapi-suno 0.3.0__tar.gz → 0.3.2__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.
Files changed (37) hide show
  1. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/PKG-INFO +7 -7
  2. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/README.md +3 -3
  3. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/pyproject.toml +4 -4
  4. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/client.py +6 -0
  5. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/contract_gen.py +313 -12
  6. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/__init__.py +6 -0
  7. runapi_suno-0.3.2/src/runapi/suno/resources/add_samples.py +11 -0
  8. runapi_suno-0.3.2/src/runapi/suno/resources/audio_actions.py +14 -0
  9. runapi_suno-0.3.2/src/runapi/suno/resources/remaster_audio.py +5 -0
  10. runapi_suno-0.3.2/src/runapi/suno/resources/stitch_audio.py +5 -0
  11. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/tests/test_client.py +31 -1
  12. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/__init__.py +0 -0
  13. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/_validators.py +0 -0
  14. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/py.typed +0 -0
  15. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/add_instrumental.py +0 -0
  16. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/add_vocals.py +0 -0
  17. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/blend_lyrics.py +0 -0
  18. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/boost_style.py +0 -0
  19. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/check_voice.py +0 -0
  20. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/convert_audio.py +0 -0
  21. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/cover_audio.py +0 -0
  22. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/create_mashup.py +0 -0
  23. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/extend_music.py +0 -0
  24. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/generate_artwork.py +0 -0
  25. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/generate_lyrics.py +0 -0
  26. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/generate_midi.py +0 -0
  27. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/generate_persona.py +0 -0
  28. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/generate_voice.py +0 -0
  29. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/get_timestamped_lyrics.py +0 -0
  30. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/regenerate_validation_phrase.py +0 -0
  31. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/replace_section.py +0 -0
  32. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/separate_audio_stems.py +0 -0
  33. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/text_to_music.py +0 -0
  34. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/text_to_sound.py +0 -0
  35. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/visualize_music.py +0 -0
  36. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/resources/voice_to_validation_phrase.py +0 -0
  37. {runapi_suno-0.3.0 → runapi_suno-0.3.2}/src/runapi/suno/types.py +0 -0
@@ -1,25 +1,25 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runapi-suno
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: RunAPI Suno SDK for text-to-music, lyric generation and blending, cover audio, music extension, stem separation, voice validation phrase, custom voice, and related audio workflows in JavaScript, Python, Ruby, Go, Java, and PHP
5
5
  Project-URL: Homepage, https://runapi.ai/models/suno
6
- Project-URL: Documentation, https://runapi.ai/docs#sdk-suno
6
+ Project-URL: Documentation, https://runapi.ai/docs/resources/sdks
7
7
  Project-URL: Source, https://github.com/runapi-ai/suno-sdk
8
8
  Project-URL: Issues, https://github.com/runapi-ai/suno-sdk/issues
9
9
  Project-URL: Changelog, https://github.com/runapi-ai/suno-sdk/blob/main/CHANGELOG.md
10
- Project-URL: Release Notes, https://github.com/runapi-ai/suno-sdk/releases/tag/python%2Fv0.3.0
10
+ Project-URL: Release Notes, https://github.com/runapi-ai/suno-sdk/releases/tag/python%2Fv0.3.2
11
11
  Author-email: RunAPI <contact@runapi.ai>
12
12
  License-Expression: Apache-2.0
13
13
  Keywords: api,audio-generation,golang,gradle,java,maven,music-api,music-generation,python,ruby,runapi,runapi-ai,sdk,suno,suno-ai-api,typescript
14
14
  Requires-Python: >=3.9
15
- Requires-Dist: runapi-core>=0.3.0
15
+ Requires-Dist: runapi-core>=0.3.6
16
16
  Description-Content-Type: text/markdown
17
17
 
18
18
  # Suno API Python SDK for RunAPI
19
19
 
20
20
  The Suno Python SDK is the language-specific package for Suno on RunAPI. Use this package for song generation, lyrics, vocals, extension, and audio transformation workflows when your application needs request bodies, task status lookup, and consistent RunAPI errors in Python.
21
21
 
22
- This README is the Python package guide inside the public `suno-sdk` repository. For the repository overview, start at `../README.md`; for model details, use https://runapi.ai/models/suno; for API reference, use https://runapi.ai/docs#suno; for SDK docs, use https://runapi.ai/docs#sdk-suno.
22
+ This README is the Python package guide inside the public `suno-sdk` repository. For the repository overview, start at `../README.md`; for model details, use https://runapi.ai/models/suno; for API reference, use https://runapi.ai/docs/api/suno/text-to-music; for SDK docs, use https://runapi.ai/docs/resources/sdks.
23
23
 
24
24
  ## Install
25
25
 
@@ -76,8 +76,8 @@ Pass parameters as keyword arguments and catch the `runapi.suno` error classes w
76
76
  ## Links
77
77
 
78
78
  - Model page: https://runapi.ai/models/suno
79
- - SDK docs: https://runapi.ai/docs#sdk-suno
80
- - Product docs: https://runapi.ai/docs#suno
79
+ - SDK docs: https://runapi.ai/docs/resources/sdks
80
+ - Product docs: https://runapi.ai/docs/api/suno/text-to-music
81
81
  - Pricing and rate limits: https://runapi.ai/models/suno/v4
82
82
  - Provider comparison: https://runapi.ai/providers/suno
83
83
  - Full catalog: https://runapi.ai/models
@@ -2,7 +2,7 @@
2
2
 
3
3
  The Suno Python SDK is the language-specific package for Suno on RunAPI. Use this package for song generation, lyrics, vocals, extension, and audio transformation workflows when your application needs request bodies, task status lookup, and consistent RunAPI errors in Python.
4
4
 
5
- This README is the Python package guide inside the public `suno-sdk` repository. For the repository overview, start at `../README.md`; for model details, use https://runapi.ai/models/suno; for API reference, use https://runapi.ai/docs#suno; for SDK docs, use https://runapi.ai/docs#sdk-suno.
5
+ This README is the Python package guide inside the public `suno-sdk` repository. For the repository overview, start at `../README.md`; for model details, use https://runapi.ai/models/suno; for API reference, use https://runapi.ai/docs/api/suno/text-to-music; for SDK docs, use https://runapi.ai/docs/resources/sdks.
6
6
 
7
7
  ## Install
8
8
 
@@ -59,8 +59,8 @@ Pass parameters as keyword arguments and catch the `runapi.suno` error classes w
59
59
  ## Links
60
60
 
61
61
  - Model page: https://runapi.ai/models/suno
62
- - SDK docs: https://runapi.ai/docs#sdk-suno
63
- - Product docs: https://runapi.ai/docs#suno
62
+ - SDK docs: https://runapi.ai/docs/resources/sdks
63
+ - Product docs: https://runapi.ai/docs/api/suno/text-to-music
64
64
  - Pricing and rate limits: https://runapi.ai/models/suno/v4
65
65
  - Provider comparison: https://runapi.ai/providers/suno
66
66
  - Full catalog: https://runapi.ai/models
@@ -4,22 +4,22 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "runapi-suno"
7
- version = "0.3.0"
7
+ version = "0.3.2"
8
8
  description = "RunAPI Suno SDK for text-to-music, lyric generation and blending, cover audio, music extension, stem separation, voice validation phrase, custom voice, and related audio workflows in JavaScript, Python, Ruby, Go, Java, and PHP"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
11
11
  license = "Apache-2.0"
12
12
  authors = [{ name = "RunAPI", email = "contact@runapi.ai" }]
13
13
  keywords = ["runapi", "runapi-ai", "suno", "api", "sdk", "typescript", "python", "ruby", "golang", "java", "maven", "gradle", "music-generation", "audio-generation", "music-api", "suno-ai-api"]
14
- dependencies = ["runapi-core>=0.3.0"]
14
+ dependencies = ["runapi-core>=0.3.6"]
15
15
 
16
16
  [project.urls]
17
17
  Homepage = "https://runapi.ai/models/suno"
18
- Documentation = "https://runapi.ai/docs#sdk-suno"
18
+ Documentation = "https://runapi.ai/docs/resources/sdks"
19
19
  Source = "https://github.com/runapi-ai/suno-sdk"
20
20
  Issues = "https://github.com/runapi-ai/suno-sdk/issues"
21
21
  Changelog = "https://github.com/runapi-ai/suno-sdk/blob/main/CHANGELOG.md"
22
- "Release Notes" = "https://github.com/runapi-ai/suno-sdk/releases/tag/python%2Fv0.3.0"
22
+ "Release Notes" = "https://github.com/runapi-ai/suno-sdk/releases/tag/python%2Fv0.3.2"
23
23
 
24
24
  [tool.hatch.build.targets.wheel]
25
25
  packages = ["src/runapi"]
@@ -8,6 +8,9 @@ from runapi.core import ProviderClient
8
8
 
9
9
  from .resources.add_instrumental import AddInstrumental
10
10
  from .resources.add_vocals import AddVocals
11
+ from .resources.add_samples import AddSamples
12
+ from .resources.remaster_audio import RemasterAudio
13
+ from .resources.stitch_audio import StitchAudio
11
14
  from .resources.boost_style import BoostStyle
12
15
  from .resources.blend_lyrics import BlendLyrics
13
16
  from .resources.check_voice import CheckVoice
@@ -53,6 +56,9 @@ class SunoClient(ProviderClient):
53
56
  self.cover_audio = CoverAudio(http)
54
57
  self.add_instrumental = AddInstrumental(http)
55
58
  self.add_vocals = AddVocals(http)
59
+ self.add_samples = AddSamples(http)
60
+ self.remaster_audio = RemasterAudio(http)
61
+ self.stitch_audio = StitchAudio(http)
56
62
  self.separate_audio_stems = SeparateAudioStems(http)
57
63
  self.generate_midi = GenerateMidi(http)
58
64
  self.convert_audio = ConvertAudio(http)
@@ -6,6 +6,15 @@ CONTRACT = {
6
6
  "model": {
7
7
  "required": True
8
8
  },
9
+ "negative_tags": {
10
+ "required": True
11
+ },
12
+ "tags": {
13
+ "required": True
14
+ },
15
+ "title": {
16
+ "required": True
17
+ },
9
18
  "upload_url": {
10
19
  "required": True
11
20
  },
@@ -17,6 +26,15 @@ CONTRACT = {
17
26
  "model": {
18
27
  "required": True
19
28
  },
29
+ "negative_tags": {
30
+ "required": True
31
+ },
32
+ "tags": {
33
+ "required": True
34
+ },
35
+ "title": {
36
+ "required": True
37
+ },
20
38
  "upload_url": {
21
39
  "required": True
22
40
  },
@@ -28,6 +46,15 @@ CONTRACT = {
28
46
  "model": {
29
47
  "required": True
30
48
  },
49
+ "negative_tags": {
50
+ "required": True
51
+ },
52
+ "tags": {
53
+ "required": True
54
+ },
55
+ "title": {
56
+ "required": True
57
+ },
31
58
  "upload_url": {
32
59
  "required": True
33
60
  },
@@ -37,6 +64,91 @@ CONTRACT = {
37
64
  }
38
65
  }
39
66
  },
67
+ "add-samples": {
68
+ "models": ["suno-v4", "suno-v4.5", "suno-v4.5-plus", "suno-v5", "suno-v5.5"],
69
+ "fields_by_model": {
70
+ "suno-v4": {
71
+ "audio_url": {
72
+ "required": True
73
+ },
74
+ "end_seconds": {
75
+ "required": True,
76
+ "min": 0
77
+ },
78
+ "model": {
79
+ "required": True
80
+ },
81
+ "start_seconds": {
82
+ "required": True,
83
+ "min": 0
84
+ }
85
+ },
86
+ "suno-v4.5": {
87
+ "audio_url": {
88
+ "required": True
89
+ },
90
+ "end_seconds": {
91
+ "required": True,
92
+ "min": 0
93
+ },
94
+ "model": {
95
+ "required": True
96
+ },
97
+ "start_seconds": {
98
+ "required": True,
99
+ "min": 0
100
+ }
101
+ },
102
+ "suno-v4.5-plus": {
103
+ "audio_url": {
104
+ "required": True
105
+ },
106
+ "end_seconds": {
107
+ "required": True,
108
+ "min": 0
109
+ },
110
+ "model": {
111
+ "required": True
112
+ },
113
+ "start_seconds": {
114
+ "required": True,
115
+ "min": 0
116
+ }
117
+ },
118
+ "suno-v5": {
119
+ "audio_url": {
120
+ "required": True
121
+ },
122
+ "end_seconds": {
123
+ "required": True,
124
+ "min": 0
125
+ },
126
+ "model": {
127
+ "required": True
128
+ },
129
+ "start_seconds": {
130
+ "required": True,
131
+ "min": 0
132
+ }
133
+ },
134
+ "suno-v5.5": {
135
+ "audio_url": {
136
+ "required": True
137
+ },
138
+ "end_seconds": {
139
+ "required": True,
140
+ "min": 0
141
+ },
142
+ "model": {
143
+ "required": True
144
+ },
145
+ "start_seconds": {
146
+ "required": True,
147
+ "min": 0
148
+ }
149
+ }
150
+ }
151
+ },
40
152
  "add-vocals": {
41
153
  "models": ["suno-v4.5-plus", "suno-v5"],
42
154
  "fields_by_model": {
@@ -47,6 +159,15 @@ CONTRACT = {
47
159
  "model": {
48
160
  "required": True
49
161
  },
162
+ "negative_tags": {
163
+ "required": True
164
+ },
165
+ "style": {
166
+ "required": True
167
+ },
168
+ "title": {
169
+ "required": True
170
+ },
50
171
  "upload_url": {
51
172
  "required": True
52
173
  },
@@ -61,6 +182,15 @@ CONTRACT = {
61
182
  "model": {
62
183
  "required": True
63
184
  },
185
+ "negative_tags": {
186
+ "required": True
187
+ },
188
+ "style": {
189
+ "required": True
190
+ },
191
+ "title": {
192
+ "required": True
193
+ },
64
194
  "upload_url": {
65
195
  "required": True
66
196
  },
@@ -86,7 +216,11 @@ CONTRACT = {
86
216
  "boost-style": {
87
217
  "models": [],
88
218
  "fields_by_model": {
89
- "_": {}
219
+ "_": {
220
+ "description": {
221
+ "required": True
222
+ }
223
+ }
90
224
  }
91
225
  },
92
226
  "check-voice": {
@@ -102,7 +236,14 @@ CONTRACT = {
102
236
  "convert-audio": {
103
237
  "models": [],
104
238
  "fields_by_model": {
105
- "_": {}
239
+ "_": {
240
+ "audio_id": {
241
+ "required": True
242
+ },
243
+ "task_id": {
244
+ "required": True
245
+ }
246
+ }
106
247
  }
107
248
  },
108
249
  "cover-audio": {
@@ -389,7 +530,8 @@ CONTRACT = {
389
530
  "required": True
390
531
  },
391
532
  "parameter_mode": {
392
- "enum": ["source", "custom"]
533
+ "enum": ["source", "custom"],
534
+ "required": True
393
535
  },
394
536
  "persona_type": {
395
537
  "enum": ["style", "voice"]
@@ -403,7 +545,8 @@ CONTRACT = {
403
545
  "required": True
404
546
  },
405
547
  "parameter_mode": {
406
- "enum": ["source", "custom"]
548
+ "enum": ["source", "custom"],
549
+ "required": True
407
550
  },
408
551
  "persona_type": {
409
552
  "enum": ["style", "voice"]
@@ -417,7 +560,8 @@ CONTRACT = {
417
560
  "required": True
418
561
  },
419
562
  "parameter_mode": {
420
- "enum": ["source", "custom"]
563
+ "enum": ["source", "custom"],
564
+ "required": True
421
565
  },
422
566
  "persona_type": {
423
567
  "enum": ["style", "voice"]
@@ -431,7 +575,8 @@ CONTRACT = {
431
575
  "required": True
432
576
  },
433
577
  "parameter_mode": {
434
- "enum": ["source", "custom"]
578
+ "enum": ["source", "custom"],
579
+ "required": True
435
580
  },
436
581
  "persona_type": {
437
582
  "enum": ["style", "voice"]
@@ -445,7 +590,8 @@ CONTRACT = {
445
590
  "required": True
446
591
  },
447
592
  "parameter_mode": {
448
- "enum": ["source", "custom"]
593
+ "enum": ["source", "custom"],
594
+ "required": True
449
595
  },
450
596
  "persona_type": {
451
597
  "enum": ["style", "voice"]
@@ -459,7 +605,8 @@ CONTRACT = {
459
605
  "required": True
460
606
  },
461
607
  "parameter_mode": {
462
- "enum": ["source", "custom"]
608
+ "enum": ["source", "custom"],
609
+ "required": True
463
610
  },
464
611
  "persona_type": {
465
612
  "enum": ["style", "voice"]
@@ -493,13 +640,30 @@ CONTRACT = {
493
640
  "generate-midi": {
494
641
  "models": [],
495
642
  "fields_by_model": {
496
- "_": {}
643
+ "_": {
644
+ "task_id": {
645
+ "required": True
646
+ }
647
+ }
497
648
  }
498
649
  },
499
650
  "generate-persona": {
500
651
  "models": [],
501
652
  "fields_by_model": {
502
- "_": {}
653
+ "_": {
654
+ "audio_id": {
655
+ "required": True
656
+ },
657
+ "description": {
658
+ "required": True
659
+ },
660
+ "name": {
661
+ "required": True
662
+ },
663
+ "task_id": {
664
+ "required": True
665
+ }
666
+ }
503
667
  }
504
668
  },
505
669
  "generate-voice": {
@@ -521,7 +685,14 @@ CONTRACT = {
521
685
  "get-timestamped-lyrics": {
522
686
  "models": [],
523
687
  "fields_by_model": {
524
- "_": {}
688
+ "_": {
689
+ "audio_id": {
690
+ "required": True
691
+ },
692
+ "task_id": {
693
+ "required": True
694
+ }
695
+ }
525
696
  }
526
697
  },
527
698
  "regenerate-validation-phrase": {
@@ -534,6 +705,66 @@ CONTRACT = {
534
705
  }
535
706
  }
536
707
  },
708
+ "remaster-audio": {
709
+ "models": ["suno-v4", "suno-v4.5", "suno-v4.5-plus", "suno-v5", "suno-v5.5"],
710
+ "fields_by_model": {
711
+ "suno-v4": {
712
+ "audio_id": {
713
+ "required": True
714
+ },
715
+ "model": {
716
+ "required": True
717
+ },
718
+ "source_task_id": {
719
+ "required": True
720
+ }
721
+ },
722
+ "suno-v4.5": {
723
+ "audio_id": {
724
+ "required": True
725
+ },
726
+ "model": {
727
+ "required": True
728
+ },
729
+ "source_task_id": {
730
+ "required": True
731
+ }
732
+ },
733
+ "suno-v4.5-plus": {
734
+ "audio_id": {
735
+ "required": True
736
+ },
737
+ "model": {
738
+ "required": True
739
+ },
740
+ "source_task_id": {
741
+ "required": True
742
+ }
743
+ },
744
+ "suno-v5": {
745
+ "audio_id": {
746
+ "required": True
747
+ },
748
+ "model": {
749
+ "required": True
750
+ },
751
+ "source_task_id": {
752
+ "required": True
753
+ }
754
+ },
755
+ "suno-v5.5": {
756
+ "audio_id": {
757
+ "required": True
758
+ },
759
+ "model": {
760
+ "required": True
761
+ },
762
+ "source_task_id": {
763
+ "required": True
764
+ }
765
+ }
766
+ }
767
+ },
537
768
  "replace-section": {
538
769
  "models": [],
539
770
  "fields_by_model": {
@@ -587,6 +818,66 @@ CONTRACT = {
587
818
  "required": ["stem_name"]
588
819
  }]
589
820
  },
821
+ "stitch-audio": {
822
+ "models": ["suno-v4", "suno-v4.5", "suno-v4.5-plus", "suno-v5", "suno-v5.5"],
823
+ "fields_by_model": {
824
+ "suno-v4": {
825
+ "audio_id": {
826
+ "required": True
827
+ },
828
+ "model": {
829
+ "required": True
830
+ },
831
+ "source_task_id": {
832
+ "required": True
833
+ }
834
+ },
835
+ "suno-v4.5": {
836
+ "audio_id": {
837
+ "required": True
838
+ },
839
+ "model": {
840
+ "required": True
841
+ },
842
+ "source_task_id": {
843
+ "required": True
844
+ }
845
+ },
846
+ "suno-v4.5-plus": {
847
+ "audio_id": {
848
+ "required": True
849
+ },
850
+ "model": {
851
+ "required": True
852
+ },
853
+ "source_task_id": {
854
+ "required": True
855
+ }
856
+ },
857
+ "suno-v5": {
858
+ "audio_id": {
859
+ "required": True
860
+ },
861
+ "model": {
862
+ "required": True
863
+ },
864
+ "source_task_id": {
865
+ "required": True
866
+ }
867
+ },
868
+ "suno-v5.5": {
869
+ "audio_id": {
870
+ "required": True
871
+ },
872
+ "model": {
873
+ "required": True
874
+ },
875
+ "source_task_id": {
876
+ "required": True
877
+ }
878
+ }
879
+ }
880
+ },
590
881
  "text-to-music": {
591
882
  "models": ["suno-v4", "suno-v4.5", "suno-v4.5-all", "suno-v4.5-plus", "suno-v5", "suno-v5.5"],
592
883
  "fields_by_model": {
@@ -755,7 +1046,14 @@ CONTRACT = {
755
1046
  "visualize-music": {
756
1047
  "models": [],
757
1048
  "fields_by_model": {
758
- "_": {}
1049
+ "_": {
1050
+ "audio_id": {
1051
+ "required": True
1052
+ },
1053
+ "task_id": {
1054
+ "required": True
1055
+ }
1056
+ }
759
1057
  }
760
1058
  },
761
1059
  "voice-to-validation-phrase": {
@@ -772,6 +1070,9 @@ CONTRACT = {
772
1070
  "vocal_start_seconds": {
773
1071
  "required": True,
774
1072
  "type": "integer"
1073
+ },
1074
+ "voice_url": {
1075
+ "required": True
775
1076
  }
776
1077
  }
777
1078
  }
@@ -1,5 +1,8 @@
1
1
  from .add_instrumental import AddInstrumental
2
2
  from .add_vocals import AddVocals
3
+ from .add_samples import AddSamples
4
+ from .remaster_audio import RemasterAudio
5
+ from .stitch_audio import StitchAudio
3
6
  from .boost_style import BoostStyle
4
7
  from .blend_lyrics import BlendLyrics
5
8
  from .check_voice import CheckVoice
@@ -28,6 +31,9 @@ __all__ = [
28
31
  "CoverAudio",
29
32
  "AddInstrumental",
30
33
  "AddVocals",
34
+ "AddSamples",
35
+ "RemasterAudio",
36
+ "StitchAudio",
31
37
  "SeparateAudioStems",
32
38
  "GenerateMidi",
33
39
  "ConvertAudio",
@@ -0,0 +1,11 @@
1
+ from .audio_actions import AudioAction
2
+ from runapi.core.errors import ValidationError
3
+
4
+ class AddSamples(AudioAction):
5
+ ENDPOINT = "/api/v1/suno/add_samples"
6
+ ACTION = "add-samples"
7
+
8
+ def create(self, options=None, **params):
9
+ if params.get("end_seconds", 0) <= params.get("start_seconds", 0):
10
+ raise ValidationError("end_seconds must be greater than start_seconds")
11
+ return super().create(options=options, **params)
@@ -0,0 +1,14 @@
1
+ from typing import Any, Dict, Optional
2
+ from runapi.core import Resource, RequestOptions
3
+ from ..contract_gen import CONTRACT
4
+
5
+ class AudioAction(Resource):
6
+ ENDPOINT = ""
7
+ ACTION = ""
8
+ def create(self, options: Optional[RequestOptions] = None, **params: Any) -> Any:
9
+ body = self._compact_params(params); self._validate_contract(CONTRACT[self.ACTION], body)
10
+ return self._request("post", self.ENDPOINT, body=body, options=options)
11
+ def get(self, id: str, options: Optional[RequestOptions] = None) -> Any:
12
+ return self._request("get", f"{self.ENDPOINT}/{id}", options=options)
13
+ def run(self, options: Optional[RequestOptions] = None, **params: Any) -> Any:
14
+ task = self.create(options=options, **params); return self._poll_until_complete(lambda: self.get(task.id, options=options))
@@ -0,0 +1,5 @@
1
+ from .audio_actions import AudioAction
2
+ class RemasterAudio(AudioAction):
3
+ ENDPOINT = "/api/v1/suno/remaster_audio"
4
+ ACTION = "remaster-audio"
5
+ def create(self, options=None, **params): return super().create(options=options, **params)
@@ -0,0 +1,5 @@
1
+ from .audio_actions import AudioAction
2
+ class StitchAudio(AudioAction):
3
+ ENDPOINT = "/api/v1/suno/stitch_audio"
4
+ ACTION = "stitch-audio"
5
+ def create(self, options=None, **params): return super().create(options=options, **params)
@@ -75,6 +75,9 @@ def test_exposes_all_resource_accessors():
75
75
  "cover_audio": R.CoverAudio,
76
76
  "add_instrumental": R.AddInstrumental,
77
77
  "add_vocals": R.AddVocals,
78
+ "stitch_audio": R.StitchAudio,
79
+ "remaster_audio": R.RemasterAudio,
80
+ "add_samples": R.AddSamples,
78
81
  "separate_audio_stems": R.SeparateAudioStems,
79
82
  "generate_midi": R.GenerateMidi,
80
83
  "convert_audio": R.ConvertAudio,
@@ -92,7 +95,7 @@ def test_exposes_all_resource_accessors():
92
95
  "generate_persona": R.GeneratePersona,
93
96
  "boost_style": R.BoostStyle,
94
97
  }
95
- assert len(expected) == 22
98
+ assert len(expected) == 25
96
99
  for name, cls in expected.items():
97
100
  assert isinstance(getattr(client, name), cls), name
98
101
 
@@ -134,6 +137,33 @@ def test_blend_lyrics_posts_flat_lyrics_pair():
134
137
  ]
135
138
 
136
139
 
140
+ def test_audio_actions_post_public_request_shapes():
141
+ fake = FakeHttp()
142
+ client = SunoClient(api_key="k", http_client=fake)
143
+
144
+ client.stitch_audio.create(model="suno-v5", source_task_id="source", audio_id="audio")
145
+ client.remaster_audio.create(model="suno-v5", source_task_id="source", audio_id="audio")
146
+ client.add_samples.create(
147
+ model="suno-v5", audio_url="https://file.runapi.ai/source.mp3", start_seconds=5, end_seconds=20
148
+ )
149
+
150
+ assert fake.calls == [
151
+ ("post", "/api/v1/suno/stitch_audio", {"model": "suno-v5", "source_task_id": "source", "audio_id": "audio"}),
152
+ ("post", "/api/v1/suno/remaster_audio", {"model": "suno-v5", "source_task_id": "source", "audio_id": "audio"}),
153
+ ("post", "/api/v1/suno/add_samples", {
154
+ "model": "suno-v5", "audio_url": "https://file.runapi.ai/source.mp3", "start_seconds": 5, "end_seconds": 20,
155
+ }),
156
+ ]
157
+
158
+
159
+ def test_add_samples_rejects_invalid_window():
160
+ client = SunoClient(api_key="k", http_client=FakeHttp())
161
+ with pytest.raises(ValidationError, match="end_seconds must be greater than start_seconds"):
162
+ client.add_samples.create(
163
+ model="suno-v5", audio_url="https://file.runapi.ai/source.mp3", start_seconds=20, end_seconds=20
164
+ )
165
+
166
+
137
167
  def test_blend_lyrics_requires_both_lyrics_texts():
138
168
  client = SunoClient(api_key="k", http_client=FakeHttp())
139
169