@imgly/plugin-soundstripe-web 0.1.0 → 0.1.1
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.
- package/README.md +34 -5
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +3 -3
- package/dist/plugin.d.ts +1 -1
- package/dist/refresh-audio-uris.d.ts +7 -3
- package/dist/soundstripe-asset-source.d.ts +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,21 +104,45 @@ You can also manually trigger a refresh using the exported utility function:
|
|
|
104
104
|
import { refreshSoundstripeAudioURIs } from '@imgly/plugin-soundstripe-web';
|
|
105
105
|
|
|
106
106
|
// Manually refresh all Soundstripe audio URIs in the current scene
|
|
107
|
-
await refreshSoundstripeAudioURIs(
|
|
107
|
+
await refreshSoundstripeAudioURIs(cesdk.engine, { apiKey });
|
|
108
|
+
|
|
109
|
+
// Or when using a proxy server
|
|
110
|
+
await refreshSoundstripeAudioURIs(cesdk.engine, { baseUrl: 'https://your-proxy.com' });
|
|
108
111
|
```
|
|
109
112
|
|
|
110
113
|
## Configuration
|
|
111
114
|
|
|
112
115
|
### Plugin Configuration
|
|
113
116
|
|
|
117
|
+
The plugin can be configured in two ways depending on your setup:
|
|
118
|
+
|
|
119
|
+
#### Option 1: Direct API Access (Development)
|
|
114
120
|
```typescript
|
|
115
121
|
import SoundstripePlugin from '@imgly/plugin-soundstripe-web';
|
|
116
122
|
|
|
117
123
|
await cesdk.addPlugin(SoundstripePlugin({
|
|
118
|
-
apiKey: 'your-soundstripe-api-key'
|
|
124
|
+
apiKey: 'your-soundstripe-api-key' // Your Soundstripe API key
|
|
119
125
|
}))
|
|
120
126
|
```
|
|
121
127
|
|
|
128
|
+
#### Option 2: Proxy Server (Production - Recommended)
|
|
129
|
+
```typescript
|
|
130
|
+
import SoundstripePlugin from '@imgly/plugin-soundstripe-web';
|
|
131
|
+
|
|
132
|
+
await cesdk.addPlugin(SoundstripePlugin({
|
|
133
|
+
baseUrl: 'https://your-proxy-server.com' // Your proxy server URL
|
|
134
|
+
}))
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### Configuration Parameters
|
|
138
|
+
|
|
139
|
+
| Parameter | Type | Required | Description |
|
|
140
|
+
|-----------|------|----------|-------------|
|
|
141
|
+
| `apiKey` | `string` | Conditional | Your Soundstripe API key. Required when using direct API access (Option 1). |
|
|
142
|
+
| `baseUrl` | `string` | Conditional | Your proxy server base URL. Required when using proxy server (Option 2). |
|
|
143
|
+
|
|
144
|
+
**Note:** Either `apiKey` or `baseUrl` must be provided. You cannot omit both parameters.
|
|
145
|
+
|
|
122
146
|
### Proxy Configuration Example
|
|
123
147
|
|
|
124
148
|
For production environments, configure your proxy server to handle Soundstripe API requests:
|
|
@@ -148,18 +172,23 @@ Then modify the plugin to use your proxy endpoint instead of direct API calls.
|
|
|
148
172
|
Creates a new Soundstripe plugin instance.
|
|
149
173
|
|
|
150
174
|
#### Parameters
|
|
151
|
-
- `configuration.apiKey` (string,
|
|
175
|
+
- `configuration.apiKey` (string, optional): Your Soundstripe API key. Required when using direct API access.
|
|
176
|
+
- `configuration.baseUrl` (string, optional): Your proxy server base URL. Required when using proxy server.
|
|
177
|
+
|
|
178
|
+
**Note:** Either `apiKey` or `baseUrl` must be provided.
|
|
152
179
|
|
|
153
180
|
#### Returns
|
|
154
181
|
A plugin object compatible with CE.SDK's plugin system
|
|
155
182
|
|
|
156
|
-
### `refreshSoundstripeAudioURIs(
|
|
183
|
+
### `refreshSoundstripeAudioURIs(engine, config)`
|
|
157
184
|
|
|
158
185
|
Manually refreshes all Soundstripe audio URIs in the current scene.
|
|
159
186
|
|
|
160
187
|
#### Parameters
|
|
161
|
-
- `apiKey` (string, required): Your Soundstripe API key
|
|
162
188
|
- `engine` (CreativeEngine, required): The CE.SDK engine instance
|
|
189
|
+
- `config` (object, optional): Configuration object with the following properties:
|
|
190
|
+
- `apiKey` (string, optional): Your Soundstripe API key. Optional when using proxy server.
|
|
191
|
+
- `baseUrl` (string, optional): Your proxy server base URL
|
|
163
192
|
|
|
164
193
|
#### Returns
|
|
165
194
|
Promise<void>
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var A="@imgly/plugin-soundstripe-web";var P={assets:[],currentPage:1,nextPage:void 0,total:0};function b(r,c){let{apiKey:n,baseUrl:a}=c,l=async(e,t,i)=>{let d=a||"https://api.soundstripe.com",s=new URL(`${d}/v1/songs`);e&&s.searchParams.set("filter[q]",e),t&&s.searchParams.set("page[number]",t.toString()),i&&s.searchParams.set("page[size]",i.toString());let m={Accept:"application/vnd.api+json","Content-Type":"application/vnd.api+json"};n&&(console.warn("Using direct Soundstripe API access, this is not recommended for production use. Instead, consider using a proxy server."),m.Authorization=`Bearer ${n}`);let p=await fetch(s.toString(),{headers:m});if(!p.ok)throw new Error(`Soundstripe API error: ${p.status} ${p.statusText}`);return p.json()},o=(e,t)=>{let i=t.find(s=>s.type==="audio_files"&&s.id===e.relationships.audio_files.data[0]?.id);if(!i?.attributes.versions?.mp3)return;let d=t.find(s=>s.type==="artists"&&s.id===e.relationships.artists.data[0]?.id);return{id:e.id,label:e.attributes.title,meta:{mimeType:"audio/mp3",uri:i.attributes.versions.mp3,thumbUri:d?.attributes?.image,previewUri:i.attributes.versions.mp3,filename:e.attributes.title,blockType:"//ly.img.ubq/audio",duration:i.attributes.duration.toString()},credits:d?.attributes?.name?{name:d.attributes.name}:void 0}},f=(e,t,i)=>e<Math.ceil(i/t)?e+1:void 0;return{id:"ly.img.audio.soundstripe",credits:{name:"Soundstripe",url:"https://soundstripe.com/"},license:{name:"Soundstripe",url:"https://www.soundstripe.com/music-licensing"},applyAsset:async e=>{let t=await r.asset.defaultApplyAsset(e);if(t)return r.block.setMetadata(t,"ly.img.audio.soundstripe.songId",e.id),t},applyAssetToBlock:async(e,t)=>{await r.asset.defaultApplyAssetToBlock(e,t),r.block.setMetadata(t,"ly.img.audio.soundstripe.songId",e.id)},async findAssets(e){try{let t=await l(e.query,e.page,e.perPage);return{assets:t.data.map(s=>o(s,t.included)).filter(s=>s!==void 0),currentPage:e.page,nextPage:f(e.page,e.perPage,t.links.meta.total_count),total:t.links.meta.total_count}}catch{return P}}}}var y=b;async function g(r,c={}){let{apiKey:n,baseUrl:a}=c,l=async o=>{let f=a||"https://api.soundstripe.com",u=new URL(`${f}/v1/songs/${o}`),e={Accept:"application/vnd.api+json","Content-Type":"application/vnd.api+json"};n&&(console.warn("Using direct Soundstripe API access for refresh, this is not recommended for production use. Instead, consider using a proxy server."),e.Authorization=`Bearer ${n}`);let t=await fetch(u.toString(),{headers:e});if(!t.ok)throw new Error(`Soundstripe API error: ${t.status} ${t.statusText}`);return t.json()};try{if(r.scene.get()===null)return;let f=r.block.findByType("audio");await Promise.allSettled(f.map(async u=>{let e=r.block.getString(u,"audio/fileURI");if(e&&e.includes("soundstripe.com"))try{let i=r.block.getMetadata(u,"ly.img.audio.soundstripe.songId");if(!i){console.warn(`No metadata found for Soundstripe audio block ${u}`);return}let s=await l(i),p=s.included.find(S=>S.type==="audio_files"&&S.id===s.data.relationships.audio_files.data[0]?.id)?.attributes.versions?.mp3;p&&p!==e&&r.block.setString(u,"audio/fileURI",p)}catch(i){console.warn(`Failed to refresh URI for Soundstripe audio block ${u}:`,i)}}))}catch(o){console.warn("Failed to refresh Soundstripe audio URIs:",o)}}var h=r=>{let{apiKey:c,baseUrl:n}=r;if(!c&&!n)throw new Error("Soundstripe Plugin: Either apiKey or baseUrl must be provided");return{async initialize({engine:a,cesdk:l}){try{let o=y(a,{apiKey:c,baseUrl:n});a.asset.addSource(o),a.scene.onActiveChanged(()=>{g(a,{apiKey:c,baseUrl:n})}),l&&l.setTranslations({en:{[`libraries.${o.id}.label`]:"Soundstripe"}})}catch(o){throw console.error("\u{1F3B5} Soundstripe Plugin: Initialization failed:",o),o}}}};var U=r=>({name:A,version:"0.1.1",...h(r)}),$=U;export{$ as default,g as refreshSoundstripeAudioURIs};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/constants.ts", "../src/soundstripe-asset-source.ts", "../src/refresh-audio-uris.ts", "../src/plugin.ts", "../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["export const PLUGIN_ID = '@imgly/plugin-soundstripe-web';\n", "import {\n AssetQueryData,\n AssetResult,\n AssetsQueryResult,\n AssetSource,\n CreativeEngine\n} from '@cesdk/cesdk-js';\nimport {\n SoundstripeApiResponse,\n SoundstripeSong,\n SoundstripeArtist,\n SoundstripeAudioFile\n} from './types';\nimport { refreshSoundstripeAudioURIs } from './refresh-audio-uris';\n\nconst EMPTY_RESULT: AssetsQueryResult = {\n assets: [],\n currentPage: 1,\n nextPage: undefined,\n total: 0\n};\n\nfunction createSoundstripeSource(\n apiKey: string,\n engine: CreativeEngine,\n baseUrl?: string\n): AssetSource {\n const fetchSoundstripeAssets = async (\n query?: string,\n page?: number,\n perPage?: number\n ): Promise<SoundstripeApiResponse> => {\n const apiBaseUrl = baseUrl || 'https://api.soundstripe.com';\n const url = new URL(`${apiBaseUrl}/v1/songs`);\n\n if (query) url.searchParams.set('filter[q]', query);\n if (page) url.searchParams.set('page[number]', page.toString());\n if (perPage) url.searchParams.set('page[size]', perPage.toString());\n\n const response = await fetch(url.toString(), {\n headers: {\n Accept: 'application/vnd.api+json',\n 'Content-Type': 'application/vnd.api+json',\n Authorization: `Bearer ${apiKey}`\n }\n });\n\n if (!response.ok) {\n throw new Error(\n `Soundstripe API error: ${response.status} ${response.statusText}`\n );\n }\n\n return response.json();\n };\n\n const formatAsset = (\n audio: SoundstripeSong,\n relationships: Array<SoundstripeArtist | SoundstripeAudioFile>\n ): AssetResult | undefined => {\n const audioFile = relationships.find(\n (item): item is SoundstripeAudioFile =>\n item.type === 'audio_files' &&\n item.id === audio.relationships.audio_files.data[0]?.id\n );\n\n if (!audioFile?.attributes.versions?.mp3) {\n return undefined;\n }\n\n const firstAuthor = relationships.find(\n (item): item is SoundstripeArtist =>\n item.type === 'artists' &&\n item.id === audio.relationships.artists.data[0]?.id\n );\n\n return {\n id: audio.id,\n label: audio.attributes.title,\n meta: {\n mimeType: 'audio/mp3',\n uri: audioFile.attributes.versions.mp3,\n thumbUri: firstAuthor?.attributes?.image,\n previewUri: audioFile.attributes.versions.mp3,\n filename: audio.attributes.title,\n blockType: '//ly.img.ubq/audio',\n duration: audioFile.attributes.duration.toString()\n },\n credits: firstAuthor?.attributes?.name\n ? {\n name: firstAuthor.attributes.name\n }\n : undefined\n };\n };\n\n const calculateNextPage = (\n page: number,\n pageSize: number,\n resultCount: number\n ) => {\n const hasNextPage = page < Math.ceil(resultCount / pageSize);\n return hasNextPage ? page + 1 : undefined;\n };\n\n const SoundstripeSource: AssetSource = {\n id: 'ly.img.audio.soundstripe',\n credits: {\n name: 'Soundstripe',\n url: 'https://soundstripe.com/'\n },\n license: {\n name: 'Soundstripe',\n url: 'https://www.soundstripe.com/music-licensing'\n },\n applyAsset: async (assetResult) => {\n const blockId = await engine.asset.defaultApplyAsset(assetResult);\n if (!blockId) return;\n engine.block.setMetadata(\n blockId,\n 'ly.img.audio.soundstripe.songId',\n assetResult.id\n );\n return blockId;\n },\n applyAssetToBlock: async (assetResult, blockId) => {\n await engine.asset.defaultApplyAssetToBlock(assetResult, blockId);\n engine.block.setMetadata(\n blockId,\n 'ly.img.audio.soundstripe.songId',\n assetResult.id\n );\n },\n async findAssets(queryData: AssetQueryData): Promise<AssetsQueryResult> {\n try {\n const response = await fetchSoundstripeAssets(\n queryData.query,\n queryData.page,\n queryData.perPage\n );\n\n const assets = response.data\n .map((song) => formatAsset(song, response.included))\n .filter((asset): asset is AssetResult => asset !== undefined);\n\n const result = {\n assets,\n currentPage: queryData.page,\n nextPage: calculateNextPage(\n queryData.page,\n queryData.perPage,\n response.links.meta.total_count\n ),\n total: response.links.meta.total_count\n };\n\n return result;\n } catch (error) {\n return EMPTY_RESULT;\n }\n }\n };\n\n return SoundstripeSource;\n}\n\nexport default createSoundstripeSource;\n", "import { CreativeEngine } from '@cesdk/cesdk-js';\nimport { SoundstripeSingleAssetResponse, SoundstripeAudioFile } from './types';\n\n/**\n * Refreshes expired Soundstripe audio URIs in the current scene\n * @param apiKey - Your Soundstripe API key\n * @param engine - The CESDK engine instance\n * @param baseUrl - Optional base URL for proxy server\n */\nexport async function refreshSoundstripeAudioURIs(\n apiKey: string,\n engine: CreativeEngine,\n baseUrl?: string\n): Promise<void> {\n const fetchSoundstripeSong = async (\n songId: string\n ): Promise<SoundstripeSingleAssetResponse> => {\n const apiBaseUrl = baseUrl || 'https://api.soundstripe.com';\n const url = new URL(`${apiBaseUrl}/v1/songs/${songId}`);\n\n const response = await fetch(url.toString(), {\n headers: {\n Accept: 'application/vnd.api+json',\n 'Content-Type': 'application/vnd.api+json',\n Authorization: `Bearer ${apiKey}`\n }\n });\n\n if (!response.ok) {\n throw new Error(\n `Soundstripe API error: ${response.status} ${response.statusText}`\n );\n }\n\n return response.json();\n };\n\n try {\n const scene = engine.scene.get();\n if (scene === null) {\n return;\n }\n\n const audioBlocks = engine.block.findByType('audio');\n\n await Promise.allSettled(\n audioBlocks.map(async (blockId) => {\n const oldUri = engine.block.getString(blockId, 'audio/fileURI');\n const isSoundStripe = oldUri && oldUri.includes('soundstripe.com');\n if (!isSoundStripe) {\n return;\n }\n try {\n const metadata = engine.block.getMetadata(\n blockId,\n 'ly.img.audio.soundstripe.songId'\n );\n if (!metadata) {\n console.warn(\n `No metadata found for Soundstripe audio block ${blockId}`\n );\n return;\n }\n\n const songId = metadata;\n const response = await fetchSoundstripeSong(songId);\n\n const audioFile = response.included.find(\n (item): item is SoundstripeAudioFile =>\n item.type === 'audio_files' &&\n item.id === response.data.relationships.audio_files.data[0]?.id\n );\n const newUri = audioFile?.attributes.versions?.mp3;\n\n if (newUri && newUri !== oldUri) {\n engine.block.setString(blockId, 'audio/fileURI', newUri);\n }\n } catch (error) {\n console.warn(\n `Failed to refresh URI for Soundstripe audio block ${blockId}:`,\n error\n );\n }\n })\n );\n } catch (error) {\n console.warn('Failed to refresh Soundstripe audio URIs:', error);\n }\n}\n", "import { CreativeEngine, type EditorPlugin } from '@cesdk/cesdk-js';\nimport createSoundstripeSource from './soundstripe-asset-source';\nimport { refreshSoundstripeAudioURIs } from './refresh-audio-uris';\n\nexport const SoundstripePlugin = (\n pluginConfiguration: SoundstripePluginConfiguration\n): Omit<EditorPlugin, 'name' | 'version'> => {\n const { apiKey, baseUrl } = pluginConfiguration;\n\n return {\n async initialize({ engine, cesdk }) {\n try {\n const soundstripeSource = createSoundstripeSource(\n apiKey,\n engine as CreativeEngine,\n baseUrl\n );\n engine.asset.addSource(soundstripeSource);\n\n // Refresh all soundstripe urls when a scene is loaded\n engine.scene.onActiveChanged(() => {\n refreshSoundstripeAudioURIs(apiKey, engine as CreativeEngine, baseUrl);\n });\n if (cesdk) {\n cesdk.setTranslations({\n en: {\n [`libraries.${soundstripeSource.id}.label`]: 'Soundstripe'\n }\n });\n }\n } catch (error) {\n console.error('\uD83C\uDFB5 Soundstripe Plugin: Initialization failed:', error);\n throw error;\n }\n }\n };\n};\n\nexport interface SoundstripePluginConfiguration {\n apiKey: string;\n baseUrl?: string; // Optional base URL for proxy server\n}\n", "import { PLUGIN_ID } from './constants';\nimport {\n SoundstripePlugin,\n type SoundstripePluginConfiguration\n} from './plugin';\n\nconst Plugin = (pluginConfiguration: SoundstripePluginConfiguration) => ({\n name: PLUGIN_ID,\n version: PLUGIN_VERSION,\n ...SoundstripePlugin(pluginConfiguration)\n});\n\nexport default Plugin;\nexport type { SoundstripePluginConfiguration };\nexport { refreshSoundstripeAudioURIs } from './refresh-audio-uris';\n"],
|
|
5
|
-
"mappings": "AAAO,IAAMA,EAAY,gCCezB,IAAMC,EAAkC,CACtC,OAAQ,CAAC,EACT,YAAa,EACb,SAAU,OACV,MAAO,CACT,
|
|
6
|
-
"names": ["PLUGIN_ID", "EMPTY_RESULT", "createSoundstripeSource", "
|
|
4
|
+
"sourcesContent": ["export const PLUGIN_ID = '@imgly/plugin-soundstripe-web';\n", "import {\n AssetQueryData,\n AssetResult,\n AssetsQueryResult,\n AssetSource,\n CreativeEngine\n} from '@cesdk/cesdk-js';\nimport {\n SoundstripeApiResponse,\n SoundstripeSong,\n SoundstripeArtist,\n SoundstripeAudioFile\n} from './types';\nimport { refreshSoundstripeAudioURIs } from './refresh-audio-uris';\n\nconst EMPTY_RESULT: AssetsQueryResult = {\n assets: [],\n currentPage: 1,\n nextPage: undefined,\n total: 0\n};\n\ninterface SoundstripeSourceConfig {\n apiKey?: string;\n baseUrl?: string;\n}\n\nfunction createSoundstripeSource(\n engine: CreativeEngine,\n config: SoundstripeSourceConfig\n): AssetSource {\n const { apiKey, baseUrl } = config;\n const fetchSoundstripeAssets = async (\n query?: string,\n page?: number,\n perPage?: number\n ): Promise<SoundstripeApiResponse> => {\n const apiBaseUrl = baseUrl || 'https://api.soundstripe.com';\n const url = new URL(`${apiBaseUrl}/v1/songs`);\n\n if (query) url.searchParams.set('filter[q]', query);\n if (page) url.searchParams.set('page[number]', page.toString());\n if (perPage) url.searchParams.set('page[size]', perPage.toString());\n\n const headers: Record<string, string> = {\n Accept: 'application/vnd.api+json',\n 'Content-Type': 'application/vnd.api+json'\n };\n\n // Only add Authorization header if apiKey is provided (not needed for proxy)\n if (apiKey) {\n console.warn(\n 'Using direct Soundstripe API access, this is not recommended for production use. Instead, consider using a proxy server.'\n );\n headers.Authorization = `Bearer ${apiKey}`;\n }\n\n const response = await fetch(url.toString(), { headers });\n\n if (!response.ok) {\n throw new Error(\n `Soundstripe API error: ${response.status} ${response.statusText}`\n );\n }\n\n return response.json();\n };\n\n const formatAsset = (\n audio: SoundstripeSong,\n relationships: Array<SoundstripeArtist | SoundstripeAudioFile>\n ): AssetResult | undefined => {\n const audioFile = relationships.find(\n (item): item is SoundstripeAudioFile =>\n item.type === 'audio_files' &&\n item.id === audio.relationships.audio_files.data[0]?.id\n );\n\n if (!audioFile?.attributes.versions?.mp3) {\n return undefined;\n }\n\n const firstAuthor = relationships.find(\n (item): item is SoundstripeArtist =>\n item.type === 'artists' &&\n item.id === audio.relationships.artists.data[0]?.id\n );\n\n return {\n id: audio.id,\n label: audio.attributes.title,\n meta: {\n mimeType: 'audio/mp3',\n uri: audioFile.attributes.versions.mp3,\n thumbUri: firstAuthor?.attributes?.image,\n previewUri: audioFile.attributes.versions.mp3,\n filename: audio.attributes.title,\n blockType: '//ly.img.ubq/audio',\n duration: audioFile.attributes.duration.toString()\n },\n credits: firstAuthor?.attributes?.name\n ? {\n name: firstAuthor.attributes.name\n }\n : undefined\n };\n };\n\n const calculateNextPage = (\n page: number,\n pageSize: number,\n resultCount: number\n ) => {\n const hasNextPage = page < Math.ceil(resultCount / pageSize);\n return hasNextPage ? page + 1 : undefined;\n };\n\n const SoundstripeSource: AssetSource = {\n id: 'ly.img.audio.soundstripe',\n credits: {\n name: 'Soundstripe',\n url: 'https://soundstripe.com/'\n },\n license: {\n name: 'Soundstripe',\n url: 'https://www.soundstripe.com/music-licensing'\n },\n applyAsset: async (assetResult) => {\n const blockId = await engine.asset.defaultApplyAsset(assetResult);\n if (!blockId) return;\n engine.block.setMetadata(\n blockId,\n 'ly.img.audio.soundstripe.songId',\n assetResult.id\n );\n return blockId;\n },\n applyAssetToBlock: async (assetResult, blockId) => {\n await engine.asset.defaultApplyAssetToBlock(assetResult, blockId);\n engine.block.setMetadata(\n blockId,\n 'ly.img.audio.soundstripe.songId',\n assetResult.id\n );\n },\n async findAssets(queryData: AssetQueryData): Promise<AssetsQueryResult> {\n try {\n const response = await fetchSoundstripeAssets(\n queryData.query,\n queryData.page,\n queryData.perPage\n );\n\n const assets = response.data\n .map((song) => formatAsset(song, response.included))\n .filter((asset): asset is AssetResult => asset !== undefined);\n\n const result = {\n assets,\n currentPage: queryData.page,\n nextPage: calculateNextPage(\n queryData.page,\n queryData.perPage,\n response.links.meta.total_count\n ),\n total: response.links.meta.total_count\n };\n\n return result;\n } catch (error) {\n return EMPTY_RESULT;\n }\n }\n };\n\n return SoundstripeSource;\n}\n\nexport default createSoundstripeSource;\n", "import { CreativeEngine } from '@cesdk/cesdk-js';\nimport { SoundstripeSingleAssetResponse, SoundstripeAudioFile } from './types';\n\ninterface RefreshAudioConfig {\n apiKey?: string;\n baseUrl?: string;\n}\n\n/**\n * Refreshes expired Soundstripe audio URIs in the current scene\n * @param engine - The CESDK engine instance\n * @param config - Configuration object with apiKey and baseUrl\n */\nexport async function refreshSoundstripeAudioURIs(\n engine: CreativeEngine,\n config: RefreshAudioConfig = {}\n): Promise<void> {\n const { apiKey, baseUrl } = config;\n const fetchSoundstripeSong = async (\n songId: string\n ): Promise<SoundstripeSingleAssetResponse> => {\n const apiBaseUrl = baseUrl || 'https://api.soundstripe.com';\n const url = new URL(`${apiBaseUrl}/v1/songs/${songId}`);\n\n const headers: Record<string, string> = {\n Accept: 'application/vnd.api+json',\n 'Content-Type': 'application/vnd.api+json'\n };\n\n // Only add Authorization header if apiKey is provided (not needed for proxy)\n if (apiKey) {\n console.warn(\n 'Using direct Soundstripe API access for refresh, this is not recommended for production use. Instead, consider using a proxy server.'\n );\n headers.Authorization = `Bearer ${apiKey}`;\n }\n\n const response = await fetch(url.toString(), { headers });\n\n if (!response.ok) {\n throw new Error(\n `Soundstripe API error: ${response.status} ${response.statusText}`\n );\n }\n\n return response.json();\n };\n\n try {\n const scene = engine.scene.get();\n if (scene === null) {\n return;\n }\n\n const audioBlocks = engine.block.findByType('audio');\n\n await Promise.allSettled(\n audioBlocks.map(async (blockId) => {\n const oldUri = engine.block.getString(blockId, 'audio/fileURI');\n const isSoundStripe = oldUri && oldUri.includes('soundstripe.com');\n if (!isSoundStripe) {\n return;\n }\n try {\n const metadata = engine.block.getMetadata(\n blockId,\n 'ly.img.audio.soundstripe.songId'\n );\n if (!metadata) {\n console.warn(\n `No metadata found for Soundstripe audio block ${blockId}`\n );\n return;\n }\n\n const songId = metadata;\n const response = await fetchSoundstripeSong(songId);\n\n const audioFile = response.included.find(\n (item): item is SoundstripeAudioFile =>\n item.type === 'audio_files' &&\n item.id === response.data.relationships.audio_files.data[0]?.id\n );\n const newUri = audioFile?.attributes.versions?.mp3;\n\n if (newUri && newUri !== oldUri) {\n engine.block.setString(blockId, 'audio/fileURI', newUri);\n }\n } catch (error) {\n console.warn(\n `Failed to refresh URI for Soundstripe audio block ${blockId}:`,\n error\n );\n }\n })\n );\n } catch (error) {\n console.warn('Failed to refresh Soundstripe audio URIs:', error);\n }\n}\n", "import { CreativeEngine, type EditorPlugin } from '@cesdk/cesdk-js';\nimport createSoundstripeSource from './soundstripe-asset-source';\nimport { refreshSoundstripeAudioURIs } from './refresh-audio-uris';\n\nexport const SoundstripePlugin = (\n pluginConfiguration: SoundstripePluginConfiguration\n): Omit<EditorPlugin, 'name' | 'version'> => {\n const { apiKey, baseUrl } = pluginConfiguration;\n\n // Validate configuration: either apiKey (for direct API) or baseUrl (for proxy) must be provided\n if (!apiKey && !baseUrl) {\n throw new Error('Soundstripe Plugin: Either apiKey or baseUrl must be provided');\n }\n\n return {\n async initialize({ engine, cesdk }) {\n try {\n const soundstripeSource = createSoundstripeSource(\n engine as CreativeEngine,\n { apiKey, baseUrl }\n );\n engine.asset.addSource(soundstripeSource);\n\n // Refresh all soundstripe urls when a scene is loaded\n engine.scene.onActiveChanged(() => {\n refreshSoundstripeAudioURIs(engine as CreativeEngine, { apiKey, baseUrl });\n });\n if (cesdk) {\n cesdk.setTranslations({\n en: {\n [`libraries.${soundstripeSource.id}.label`]: 'Soundstripe'\n }\n });\n }\n } catch (error) {\n console.error('\uD83C\uDFB5 Soundstripe Plugin: Initialization failed:', error);\n throw error;\n }\n }\n };\n};\n\nexport interface SoundstripePluginConfiguration {\n apiKey?: string; // Optional API key (required when using direct API access)\n baseUrl?: string; // Optional base URL for proxy server (required when using proxy)\n}\n", "import { PLUGIN_ID } from './constants';\nimport {\n SoundstripePlugin,\n type SoundstripePluginConfiguration\n} from './plugin';\n\nconst Plugin = (pluginConfiguration: SoundstripePluginConfiguration) => ({\n name: PLUGIN_ID,\n version: PLUGIN_VERSION,\n ...SoundstripePlugin(pluginConfiguration)\n});\n\nexport default Plugin;\nexport type { SoundstripePluginConfiguration };\nexport { refreshSoundstripeAudioURIs } from './refresh-audio-uris';\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["PLUGIN_ID", "EMPTY_RESULT", "createSoundstripeSource", "engine", "config", "apiKey", "baseUrl", "fetchSoundstripeAssets", "query", "page", "perPage", "apiBaseUrl", "url", "headers", "response", "formatAsset", "audio", "relationships", "audioFile", "item", "firstAuthor", "calculateNextPage", "pageSize", "resultCount", "assetResult", "blockId", "queryData", "song", "asset", "soundstripe_asset_source_default", "refreshSoundstripeAudioURIs", "engine", "config", "apiKey", "baseUrl", "fetchSoundstripeSong", "songId", "apiBaseUrl", "url", "headers", "response", "audioBlocks", "blockId", "oldUri", "metadata", "newUri", "item", "error", "SoundstripePlugin", "pluginConfiguration", "apiKey", "baseUrl", "engine", "cesdk", "soundstripeSource", "soundstripe_asset_source_default", "refreshSoundstripeAudioURIs", "error", "Plugin", "pluginConfiguration", "PLUGIN_ID", "SoundstripePlugin", "src_default"]
|
|
7
7
|
}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type EditorPlugin } from '@cesdk/cesdk-js';
|
|
2
2
|
export declare const SoundstripePlugin: (pluginConfiguration: SoundstripePluginConfiguration) => Omit<EditorPlugin, "name" | "version">;
|
|
3
3
|
export interface SoundstripePluginConfiguration {
|
|
4
|
-
apiKey
|
|
4
|
+
apiKey?: string;
|
|
5
5
|
baseUrl?: string;
|
|
6
6
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { CreativeEngine } from '@cesdk/cesdk-js';
|
|
2
|
+
interface RefreshAudioConfig {
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
}
|
|
2
6
|
/**
|
|
3
7
|
* Refreshes expired Soundstripe audio URIs in the current scene
|
|
4
|
-
* @param apiKey - Your Soundstripe API key
|
|
5
8
|
* @param engine - The CESDK engine instance
|
|
6
|
-
* @param
|
|
9
|
+
* @param config - Configuration object with apiKey and baseUrl
|
|
7
10
|
*/
|
|
8
|
-
export declare function refreshSoundstripeAudioURIs(
|
|
11
|
+
export declare function refreshSoundstripeAudioURIs(engine: CreativeEngine, config?: RefreshAudioConfig): Promise<void>;
|
|
12
|
+
export {};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import { AssetSource, CreativeEngine } from '@cesdk/cesdk-js';
|
|
2
|
-
|
|
2
|
+
interface SoundstripeSourceConfig {
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
}
|
|
6
|
+
declare function createSoundstripeSource(engine: CreativeEngine, config: SoundstripeSourceConfig): AssetSource;
|
|
3
7
|
export default createSoundstripeSource;
|