Simplify setup (#46)

This commit is contained in:
Ollie Taylor
2023-07-13 00:27:14 +01:00
committed by GitHub
parent 29ef65733e
commit d18b0c78d0
68 changed files with 1236 additions and 1470 deletions
+259 -297
View File
@@ -1,242 +1,289 @@
<script>
import { DocsPage } from '$src/layout/page';
import { Highlight } from 'svelte-highlight';
import { Highlight, HighlightSvelte } from 'svelte-highlight';
import lang_ts from 'svelte-highlight/languages/typescript';
import {
load_audio_local,
load_audio_remote,
override_episode_state,
audio_load,
audio_mute,
audio_pause,
audio_play,
audio_seek,
audio_skip,
audio_subscribe,
audio_unload,
audio_unmute,
seconds_to_timestamp,
user_preferences_clear,
user_preferences_set_playback_rate,
user_preferences_set_volume,
user_preferences_subscribe,
user_progress_clear,
user_progress_get,
user_progress_save,
user_progress_subscribe,
} from './code';
</script>
<DocsPage
title="API"
let:Section
let:SectionArticle
let:TableModule
let:TableSchema
>
<Section title="episode_audio">
<!-- methods -->
<h3>Methods</h3>
<DocsPage title="API" let:Section let:SectionArticle let:TableSchema>
<Section title="audio">
<SectionArticle title="audio data">
<TableSchema
rows={[
{
property: 'is_loaded',
type: 'boolean',
description: 'Whether the audio element is loaded or not',
},
{
property: 'is_paused',
type: 'boolean',
description: 'Whether the audio element is paused or not',
},
{
property: 'current_time',
type: 'number',
description:
'The current time of the audio element in seconds',
},
{
property: 'duration',
type: 'number',
description: 'The duration of the audio element in seconds',
},
{
property: 'timestamp_current',
type: 'string',
description:
'The current time of the audio element in timestamp format (hh:mm:ss)',
},
{
property: 'timestamp_end',
type: 'string',
description:
'The end time of the audio element in timestamp format (hh:mm:ss)',
},
]}
/>
</SectionArticle>
<TableModule
rows={[
{
method: '.subscribe()',
description: 'You can subscribe to changes in the audio state.',
},
{
method: '.load(\n src:string, \n details:EpisodeDetails\n)',
description:
'Load a new audio source. This will stop the current audio source and replace it with the new one.',
},
{
method: '.unload()',
description:
'Unload the current audio source. This will stop the current audio source and remove it from the audio state.',
},
{
method: '.play(\n action: "set" | "toggle" = "set"\n)',
description: 'Set or toggle the play state',
},
{
method: '.pause(\n action: "set" | "toggle" = "set"\n)',
description: 'Set or toggle the pause state',
},
{
method: '.mute(\n action: "set" | "toggle" = "set"\n)',
description: 'Set or toggle the mute state',
},
{
method: '.unmute(\n action: "set" | "toggle" = "set"\n)',
description: 'Set or toggle the unmute state',
},
{
method:
'.seek(\n seconds: number, \n from: "from-start" | "from-end" = "from-start"\n)',
description:
'Seek to a specific time in the audio. The `from` parameter determines whether the time is relative to the start or end of the audio.',
},
{
method:
'.skip(\n seconds: number, \n type: "forward" | "backward" = "forward"\n)',
description:
'Skip forward or backward in the audio by a specific number of seconds.',
},
]}
/>
<!-- data -->
<h3>EpisodeState</h3>
<TableSchema
rows={[
{
property: 'will_autoplay',
type: 'boolean',
description: 'Whether episodes will autoplay once loaded.',
},
{
property: 'is_paused',
type: 'boolean',
description: 'Whether the episode is paused.',
},
{
property: 'duration',
type: 'number',
description: 'The duration of the episode in seconds.',
},
{
property: 'src',
type: 'string',
description: 'The source of the episode.',
},
{
property: 'start_at',
type: 'number',
description: 'The starting point of the episode in seconds.',
},
{
property: 'details',
type: 'EpisodeDetails | null',
description:
'The details of the episode or null if there are none.',
},
]}
/>
<SectionArticle title="Load audio source">
<!--
audio.subscribe
audio.load
audio.unload
audio.play
audio.pause
audio.mute
audio.unmute
audio.seek
audio.skip
-->
<SectionArticle title="audio.subscribe">
<p>
All you need to load an episode is a URL to an audio file.
svelte-podcast uses a html audio element under the hood, so any
audio file compatible with the autio element is also compatible with
this package.
Subscribe to specific changes in the audio attributes. This will
return a readable store that you can use to access the attributes.
</p>
<h4>Using a remote file (URL)</h4>
<p>
An <em>audio url</em> could be a URL to an MP3 file from an RSS
feed, like this:
<code>https://media.transistor.fm/27a058c9/27b595e2.mp3</code>. It
could also be a path to a static file on your server.
</p>
<div
class="codeblock not-prose flex flex-col items-stretch gap-2 py-1"
>
<Highlight code={load_audio_remote} language={lang_ts} />
<div class="not-prose codeblock">
<HighlightSvelte code={audio_subscribe} />
</div>
</SectionArticle>
<h4>Using a local file (relative path)</h4>
<SectionArticle title="audio.load">
<p>
If you're using SvelteKit, you can store <em>static files</em> in
the /static directory. When your site is built, everything in the
static directory will be at the root of your site. If you have a
file in <code>/static/episides/episode-01.mp3</code> you could load
it as <code>/episides/episode-01.mp3</code>
Load a new audio source. This will stop the current audio source and
replace it with the new one.
</p>
<div class="not-prose codeblock">
<Highlight code={audio_load} language={lang_ts} />
</div>
</SectionArticle>
<div
class="codeblock not-prose flex flex-col items-stretch gap-2 py-1"
>
<Highlight code={load_audio_local} language={lang_ts} />
<SectionArticle title="audio.unload">
<p>
Unload the current audio source. This will stop the current audio
source and remove it from the audio state.
</p>
<div class="not-prose codeblock">
<Highlight code={audio_unload} language={lang_ts} />
</div>
</SectionArticle>
<SectionArticle title="audio.play">
<p>Set or toggle the play state.</p>
<div class="not-prose codeblock">
<Highlight code={audio_play} language={lang_ts} />
</div>
</SectionArticle>
<SectionArticle title="audio.pause">
<p>Set or toggle the pause state.</p>
<div class="not-prose codeblock">
<Highlight code={audio_pause} language={lang_ts} />
</div>
</SectionArticle>
<SectionArticle title="audio.mute">
<p>Set or toggle the mute state.</p>
<div class="not-prose codeblock">
<Highlight code={audio_mute} language={lang_ts} />
</div>
</SectionArticle>
<SectionArticle title="audio.unmute">
<p>Set or toggle the unmute state.</p>
<div class="not-prose codeblock">
<Highlight code={audio_unmute} language={lang_ts} />
</div>
</SectionArticle>
<SectionArticle title="audio.seek">
<p>
Seek to a specific time in the audio. The `from` parameter
determines whether the time is relative to the start or end of the
audio.
</p>
<div class="not-prose codeblock">
<Highlight code={audio_seek} language={lang_ts} />
</div>
</SectionArticle>
<SectionArticle title="audio.skip">
<p>
Skip forward or backward in the audio by a specific number of
seconds.
</p>
<div class="not-prose codeblock">
<Highlight code={audio_skip} language={lang_ts} />
</div>
</SectionArticle>
</Section>
<Section title="episode_details">
<h3>Methods</h3>
<Section title="user_preferences">
<SectionArticle title="user_preferences data">
<TableSchema
rows={[
{
property: 'playback_rate',
type: 'number',
description: 'The audio player playback rate (speed)',
},
{
property: 'volume',
type: 'number',
description: 'The audio player volume.',
},
]}
/>
</SectionArticle>
<TableModule
rows={[
{
method: '.subscribe() | $episode_details',
description: 'You can subscribe to changes in the audio state.',
},
{
method: '.set(\n data:EpisodeDetails\n)',
description: 'You can set the audio state.',
},
{
method: '.update((\n data:EpisodeDetails) => EpisodeDetails\n)',
description:
'You can update the audio state. This is useful if you want to update the state based on the previous state.',
},
]}
/>
<!--
user_preferences.subscribe
user_preferences.set_playback_rate
user_preferences.set_volume
user_preferences.clear
-->
<SectionArticle title="user_preferences.subscribe">
<p>
Subscribe to changes in the user preferences. This will return a
readable store that you can use to access the user preferences.
</p>
<div class="not-prose codeblock">
<HighlightSvelte code={user_preferences_subscribe} />
</div>
</SectionArticle>
<!-- data -->
<h3>EpisodeState</h3>
<div class="not-prose codeblock">
<Highlight code={`Record<string, unknown>`} language={lang_ts} />
</div>
<p>
Episode state holds the metadata for the current episode. You derermine
the shape of the this data.
</p>
<SectionArticle title="user_preferences.set_playback_rate">
<p>
Set the playback rate. This will update the user preferences and
apply the new playback rate to the audio.
</p>
<div class="not-prose codeblock">
<Highlight
code={user_preferences_set_playback_rate}
language={lang_ts}
/>
</div>
</SectionArticle>
<p>
For complete type safety, we recommend defining this type yourself in a
.d.ts file. In SvelteKit, you should do this in <code>
/src/app.d.ts
</code>.
</p>
<SectionArticle title="user_preferences.set_volume">
<p>
Set the volume. This will update the user preferences and apply the
new volume to the audio.
</p>
<div class="not-prose codeblock">
<Highlight code={user_preferences_set_volume} language={lang_ts} />
</div>
</SectionArticle>
<h4>Override EpisodeState</h4>
<div class="not-prose codeblock">
<Highlight code={override_episode_state} language={lang_ts} />
</div>
<SectionArticle title="user_preferences.clear">
<p>
Clear the user preferences. This will reset the user preferences to
the default values.
</p>
<div class="not-prose codeblock">
<Highlight code={user_preferences_clear} language={lang_ts} />
</div>
</SectionArticle>
</Section>
<!-- episode_progress -->
<Section title="episode_progress">
<!-- methods -->
<h3>Methods</h3>
<TableModule
rows={[
{
method: '.subscribe() | $episode_progress',
description: 'You can subscribe to changes in the audio state.',
},
{
method: '.set(\n data:EpisodeProgress\n)',
description: 'You can set the audio state.',
},
{
method:
'.update(\n (data:EpisodeProgress) => EpisodeProgress\n)',
description:
'You can update the audio state. This is useful if you want to update the state based on the previous state.',
},
]}
/>
<!-- user_progress -->
<Section title="user_progress">
<SectionArticle title="user_progress data">
<p>
User progress is a record where the keys are audio sources, and the
values are timestamps in seconds. Progress is retrieved by matching
the source, and returning the timestamp.
</p>
<!-- data -->
<h3>EpisodeProgress</h3>
<TableSchema
rows={[
{
property: 'current_time',
type: 'number',
description: 'The current time of the episode in seconds.',
},
{
property: 'timestamp',
type: 'string',
description:
"The current time of the episode in the format 'mm:ss'.",
},
{
property: 'has_ended',
type: 'boolean',
description: 'Whether the episode has ended or not.',
},
]}
/>
<div class="not-prose codeblock">
<Highlight code={`Record<string, number>`} language={lang_ts} />
</div>
</SectionArticle>
<!--
* user_progress.subscribe - Subscribes to user progress store
* user_progress.get - Gets user progress for a given audio source
* user_progress.clear - Clears user progress store
* user_progress.save - Saves user progress
-->
<SectionArticle title="user_progress.subscribe">
<p>
Subscribe to changes in the user progress. This will return a
readable store that you can use to access the user progress.
</p>
<div class="not-prose codeblock">
<HighlightSvelte code={user_progress_subscribe} />
</div>
</SectionArticle>
<SectionArticle title="user_progress.get">
<p>
Get the user progress for a given audio source. This will return the
timestamp in seconds.
</p>
<div class="not-prose codeblock">
<Highlight code={user_progress_get} language={lang_ts} />
</div>
</SectionArticle>
<SectionArticle title="user_progress.clear">
<p>
Clear the user progress. This will reset the user progress to the
default values.
</p>
<div class="not-prose codeblock">
<Highlight code={user_progress_clear} language={lang_ts} />
</div>
</SectionArticle>
<SectionArticle title="user_progress.save">
<p>
Save the user progress for a given audio source. This will update
the user progress with the new timestamp.
</p>
<div class="not-prose codeblock">
<Highlight code={user_progress_save} language={lang_ts} />
</div>
</SectionArticle>
</Section>
<!-- seconds_to_timestamp -->
@@ -261,89 +308,4 @@
<Highlight code={seconds_to_timestamp} language={lang_ts} />
</div>
</Section>
<!-- user_preferences -->
<Section title="user_preferences">
<!-- methods -->
<h3>Methods</h3>
<TableModule
rows={[
{
method: '.subscribe() | $episode_audio',
description:
'You can subscribe to changes in the users preferences.',
},
{
method: '.set_playback_rate(\n value:number\n)',
description: 'You can set the users playback rate.',
},
{
method: '.set_volume(\n value:number\n)',
description: 'You can set the users volume.',
},
{
method: '.clear()',
description: 'You can clear the users preferences.',
},
]}
/>
<!-- data -->
<h3>UserPreferences</h3>
<TableSchema
rows={[
{
property: 'playback_rate',
type: 'number',
description: 'The audio player playback rate (speed)',
},
{
property: 'volume',
type: 'number',
description: 'The audio player volume.',
},
]}
/>
</Section>
<!-- user_progress -->
<Section title="user_progress">
<!-- methods -->
<h3>Methods</h3>
<TableModule
rows={[
{
method: '.subscribe() | $episode_progress',
description:
'You can subscribe to changes in the users progress.',
},
{
method: '.get(\n src:string\n): number | undefined',
description:
'You can get the users progress for a given audio source.',
},
{
method: '.save(\n src:string, \n value:number\n)',
description:
'You can save the users progress for a given audio source.',
},
{
method: '.clear()',
description: 'You can clear the users progress.',
},
]}
/>
<!-- data -->
<h3>UserProgress</h3>
<p>
User progress is a record where the keys are audio sources, and the
values are timestamps in seconds. Progress is retrieved by matching the
source, and returning the timestamp.
</p>
<div class="not-prose codeblock">
<Highlight code={`Record<string, number>`} language={lang_ts} />
</div>
</Section>
</DocsPage>
+17
View File
@@ -0,0 +1,17 @@
import { audio } from 'svelte-podcast';
// load a new audio source
audio.load(
// path to audio file
'/episode-377.mp3',
// custom metadata
{
title: 'Supper Club × Rich Harris, Author of Svelte',
guests: ['Rich Harris'],
hosts: ['Wes Bos', 'Scott Tolinski'],
},
// autoplay
true,
);
+9
View File
@@ -0,0 +1,9 @@
import { audio } from 'svelte-podcast';
// mute the current audio source
// do nothing if it's already muted
audio.mute('set');
// mute the current audio if it's unmuted
// unmute the current audio if it's muted
audio.mute('toggle');
+9
View File
@@ -0,0 +1,9 @@
import { audio } from 'svelte-podcast';
// pause the current audio source
// do nothing if it's already paused
audio.pause('set');
// pause the current audio if it's playing
// play the current audio if it's paused
audio.pause('toggle');
+9
View File
@@ -0,0 +1,9 @@
import { audio } from 'svelte-podcast';
// play the current audio source
// do nothing if it's already playing
audio.play('set');
// play the current audio if it's paused
// pause the current audio if it's playing
audio.play('toggle');
+7
View File
@@ -0,0 +1,7 @@
import { audio } from 'svelte-podcast';
// go to 200 seconds from the start
audio.seek(200);
// go to 200 seconds before the end
audio.seek(200, 'from-end');
+7
View File
@@ -0,0 +1,7 @@
import { audio } from 'svelte-podcast';
// skip forward 30 seconds from the current position
audio.skip(30);
// skip backward 30 seconds from the current position
audio.skip(30, 'backward');
@@ -0,0 +1,16 @@
<script>
import { audio } from 'svelte-podcast';
// return the current user preferences
const attributes = $audio;
// or subscribe to changes in the user preferences
audio.subscribe((attr) => {
// do something with the new preferences whenever they change
console.log(attr);
});
</script>
<p>Current timestamp {attributes.timestamp_current}.</p>
<p>{attributes.is_paused ? 'Paused...' : 'Playing!'}.</p>
+4
View File
@@ -0,0 +1,4 @@
import { audio } from 'svelte-podcast';
// unload the current audio source
audio.unload();
+9
View File
@@ -0,0 +1,9 @@
import { audio } from 'svelte-podcast';
// unmute the current audio source
// do nothing if it's already unmuted
audio.unmute('set');
// unmute the current audio if it's muted
// mute the current audio if it's unmuted
audio.unmute('toggle');
+41 -8
View File
@@ -1,15 +1,48 @@
import { format_code } from '../../../layout/helper';
import { default as audio_load_src } from './audio-load.js?raw';
import { default as audio_mute_src } from './audio-mute.js?raw';
import { default as audio_pause_src } from './audio-pause.js?raw';
import { default as audio_play_src } from './audio-play.js?raw';
import { default as audio_seek_src } from './audio-seek.js?raw';
import { default as audio_skip_src } from './audio-skip.js?raw';
import { default as audio_subscribe_src } from './audio-subscribe.svelte?raw';
import { default as audio_unload_src } from './audio-unload.js?raw';
import { default as audio_unmute_src } from './audio-unmute.js?raw';
import { default as load_audio_after_click_src } from './load-audio-after-click.svelte?raw';
import { default as load_audio_after_mount_src } from './load-audio-after-mount.svelte?raw';
import { default as load_audio_local_src } from './load-audio-local?raw';
import { default as load_audio_remote_src } from './load-audio-remote?raw';
import { default as override_episode_state_src } from './override-episode-state?raw';
import { default as seconds_to_timestamp_src } from './seconds-to-timestamp?raw';
const format_code = (/** @type {string} */ code) => code.replaceAll('\t', ' ');
import { default as user_preferences_clear_src } from './user_preferences-clear?raw';
import { default as user_preferences_set_playback_rate_src } from './user_preferences-set_playback_rate?raw';
import { default as user_preferences_set_volume_src } from './user_preferences-set_volume?raw';
import { default as user_preferences_subscribe_src } from './user_preferences-subscribe.svelte?raw';
import { default as user_progress_clear_src } from './user_progress-clear?raw';
import { default as user_progress_get_src } from './user_progress-get?raw';
import { default as user_progress_save_src } from './user_progress-save?raw';
import { default as user_progress_subscribe_src } from './user_progress-subscribe.svelte?raw';
export const load_audio_after_click = format_code(load_audio_after_click_src);
export const load_audio_after_mount = format_code(load_audio_after_mount_src);
export const load_audio_local = format_code(load_audio_local_src);
export const load_audio_remote = format_code(load_audio_remote_src);
export const override_episode_state = format_code(override_episode_state_src);
export const seconds_to_timestamp = format_code(seconds_to_timestamp_src);
export const audio_load = format_code(audio_load_src);
export const audio_play = format_code(audio_play_src);
export const audio_unload = format_code(audio_unload_src);
export const audio_pause = format_code(audio_pause_src);
export const audio_skip = format_code(audio_skip_src);
export const audio_seek = format_code(audio_seek_src);
export const audio_mute = format_code(audio_mute_src);
export const audio_unmute = format_code(audio_unmute_src);
export const user_preferences_clear = format_code(user_preferences_clear_src);
export const user_preferences_set_playback_rate = format_code(
user_preferences_set_playback_rate_src,
);
export const user_preferences_set_volume = format_code(
user_preferences_set_volume_src,
);
export const user_preferences_subscribe = format_code(
user_preferences_subscribe_src,
);
export const audio_subscribe = format_code(audio_subscribe_src);
export const user_progress_clear = format_code(user_progress_clear_src);
export const user_progress_get = format_code(user_progress_get_src);
export const user_progress_save = format_code(user_progress_save_src);
export const user_progress_subscribe = format_code(user_progress_subscribe_src);
@@ -1,11 +1,11 @@
<script>
import { episode_audio } from 'svelte-podcast';
import { audio } from 'svelte-podcast';
</script>
<!-- load the episode on click -->
<button
on:click={() =>
episode_audio.load('/episode-audio.mp3', {
audio.load('/episode-audio.mp3', {
/* optional metadata */
})}
>
@@ -13,4 +13,4 @@
</button>
<!-- unload the episode on click -->
<button on:click={() => episode_audio.unload()}>Unload Episode</button>
<button on:click={() => audio.unload()}>Unload Episode</button>
@@ -1,10 +1,10 @@
<script>
import { onMount } from 'svelte';
import { episode_audio } from 'svelte-podcast';
import { audio } from 'svelte-podcast';
onMount(() => {
// load the episode on mount without any metadata
episode_audio.load('/episode-audio.mp3', {
audio.load('/episode-audio.mp3', {
/* optional metadata */
});
});
-9
View File
@@ -1,9 +0,0 @@
import { episode_audio } from 'svelte-podcast';
episode_audio.load(
// path to file
'/episode-audio.mp3',
// custom metadata
{},
);
-9
View File
@@ -1,9 +0,0 @@
import { episode_audio } from 'svelte-podcast';
episode_audio.load(
// url
'https://media.transistor.fm/27a058c9/27b595e2.mp3',
// custom metadata
{},
);
@@ -1,11 +0,0 @@
// include this in your /src/app.d.ts file
declare module 'svelte-podcast' {
interface EpisodeDetails {
// define your own properties here
title: string;
artwork?: string;
}
}
export {};
+1 -1
View File
@@ -1,4 +1,4 @@
import { seconds_to_timestamp } from 'svelte-podcast';
import { seconds_to_timestamp } from 'svelte-podcast/utility';
// Example
seconds_to_timestamp(5173); // 01:26:13
@@ -0,0 +1,4 @@
import { user_preferences } from '../../../lib/user';
// Clears all user preferences
user_preferences.clear();
@@ -0,0 +1,4 @@
import { user_preferences } from '../../../lib/user';
// Sets the playback speed to 150%
user_preferences.set_playback_rate(1.5);
@@ -0,0 +1,4 @@
import { user_preferences } from '../../../lib/user';
// Sets the volume to 75%
user_preferences.set_volume(0.75);
@@ -0,0 +1,16 @@
<script>
import { user_preferences } from 'svelte-podcast';
// return the current user preferences
const preferences = $user_preferences;
// or subscribe to changes in the user preferences
user_preferences.subscribe((prefs) => {
// do something with the new preferences whenever they change
console.log(prefs);
});
</script>
<p>Listening at {preferences.playback_rate * 100}% speed.</p>
<p>Volume set to {preferences.volume * 100}%.</p>
@@ -0,0 +1,4 @@
import { user_progress } from 'svelte-podcast';
// Clear the user's progress for ALL episodes.
user_progress.clear();
+4
View File
@@ -0,0 +1,4 @@
import { user_progress } from 'svelte-podcast';
// Get the user's progress for a specific episode.
user_progress.get('https://example.com/episodes/1');
@@ -0,0 +1,4 @@
import { user_progress } from 'svelte-podcast';
// Save the user's progress for the current episode.
user_progress.save();
@@ -0,0 +1,16 @@
<script>
import { user_progress } from 'svelte-podcast';
// return the current user progress
const progress = $user_progress;
// or subscribe to changes in the user progress
user_progress.subscribe((prog) => {
// do something with the new progress whenever they change
console.log(prog);
});
</script>
<p>
Listened to {progress['https://example.com/episodes/1']} seconds of episode 1.
</p>