Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ If you have any questions, please contact [hello@listennotes.com](hello@listenno
- [`fetchPodcastsByDomain`](#fetchpodcastsbydomain) — `GET /podcasts/domains/{domain_name}`
- [`createPlaylist`](#createplaylist) — `POST /playlists`
- [`updatePlaylist`](#updateplaylist) — `PUT /playlists/{id}`
- [`deletePlaylist`](#deleteplaylist) — `DELETE /playlists/{id}`
- [`addPlaylistItem`](#addplaylistitem) — `POST /playlists/{id}/items`
- [`deletePlaylistItem`](#deleteplaylistitem) — `DELETE /playlists/{id}/items/{item_id}`
- [`updatePlaylistItemNotes`](#updateplaylistitemnotes) — `PUT /playlists/{id}/items/{item_id}`
Expand Down Expand Up @@ -783,6 +784,31 @@ client.updatePlaylist({

[Full API documentation](https://www.listennotes.com/api/docs/#put-api-v2-playlists-id)

### deletePlaylist

Delete a playlist.

`DELETE /playlists/{id}`

Permanently delete a playlist, including all episode and podcast references saved in this specific playlist and their notes. The actual episodes and podcasts remain in the Listen Notes podcast database.

**Warning: Deletion cannot be undone. Once deleted, the playlist is gone, regardless of how many episodes or podcasts it contains. You, the developer, are responsible for adding a confirmation step in your app's UI before calling this endpoint to prevent accidental deletion.**

Only playlists owned by your admin API account can be modified; contributor membership does not grant write access.

```javascript
const { Client } = require('podcast-api');
const client = Client({ apiKey: process.env.LISTEN_API_KEY || null });

client.deletePlaylist({
"id": "m1pe7z60bsw"
})
.then((response) => console.log(response.data))
.catch((error) => console.error(error));
```

[Full API documentation](https://www.listennotes.com/api/docs/#delete-api-v2-playlists-id)

### addPlaylistItem

Add an episode or podcast to a playlist.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "podcast-api",
"version": "3.0.2",
"version": "3.1.0",
"description": "JavaScript bindings for the Listen Notes Podcast API",
"main": "src/PodcastApiClient.js",
"scripts": {
Expand Down
3 changes: 3 additions & 0 deletions src/PodcastApiMethods.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 20 additions & 1 deletion src/api-contract.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"schema_version": 1,
"version": "3.0.2",
"version": "3.1.0",
"operations": [
{
"operationId": "search",
Expand Down Expand Up @@ -815,6 +815,25 @@
"summary": "Update playlist metadata.",
"description": "Update any subset of name, description, visibility, and type. Omitted fields remain unchanged; at least one field is required. Switching to private rotates the playlist RSS secret. Type selects the saved default view (episode_list or podcast_list) and the returned listennotes_url; changing it preserves all existing episodes and podcasts.\n\nOnly playlists owned by your admin API account can be modified; contributor membership does not grant write access."
},
{
"operationId": "deletePlaylist",
"func": "deletePlaylist",
"available_from": "3.1.0",
"method": "DELETE",
"path": "/playlists/{id}",
"parameters": [
{
"name": "id",
"in": "path",
"required": true
}
],
"example_params": {
"id": "m1pe7z60bsw"
},
"summary": "Delete a playlist.",
"description": "Permanently delete a playlist, including all episode and podcast references saved in this specific playlist and their notes. The actual episodes and podcasts remain in the Listen Notes podcast database.\n\n**Warning: Deletion cannot be undone. Once deleted, the playlist is gone, regardless of how many episodes or podcasts it contains. You, the developer, are responsible for adding a confirmation step in your app's UI before calling this endpoint to prevent accidental deletion.**\n\nOnly playlists owned by your admin API account can be modified; contributor membership does not grant write access."
},
{
"operationId": "addPlaylistItem",
"func": "addPlaylistItem",
Expand Down
9 changes: 7 additions & 2 deletions tests/TestsLib.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,14 @@ const runTests = ({ createClient, reset, calls, setStatus }) => {
expect(calls()[0].body).toBe('description=');
});

test('missing nested identifiers fail before any request', () => {
test.each([
['deletePlaylist', undefined, 'id'],
['deletePlaylist', { id: '' }, 'id'],
['deletePlaylist', { id: null }, 'id'],
['deletePlaylistItem', { id: 'abc' }, 'item_id'],
])('%s rejects missing path identifiers in %p before any request', (method, params, name) => {
const client = createClient();
expect(() => client.deletePlaylistItem({ id: 'abc' })).toThrow('Missing path parameter: item_id');
expect(() => client[method](params)).toThrow(`Missing path parameter: ${name}`);
expect(calls()).toHaveLength(0);
});

Expand Down
8 changes: 8 additions & 0 deletions tests/integration/MockApiTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ const runIntegrationTests = ({ createClient, calls, reset }) => {
expect(calls()[0].body).toBeFalsy();
});

test('delete a playlist', async () => {
const response = await client.deletePlaylist({ id: PLAYLIST_ID });
const payload = responseData(response, 'DELETE', `/playlists/${PLAYLIST_ID}`);
expect(payload).toEqual({ id: PLAYLIST_ID, deleted: true });
expect(new URL(calls()[0].url).search).toBe('');
expect(calls()[0].body).toBeFalsy();
});

test('missing routes preserve the HTTP 404 error', async () => {
await expect(client.httpClient._get('/sdk-integration-missing-route', {})).rejects.toMatchObject({
response: { status: 404 },
Expand Down
Loading