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
12 changes: 12 additions & 0 deletions src/API/API.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ import {
duration,
isPaused,
plugin,
volume as volumeStore,
} from "src/store";
import { get } from "svelte/store";
import encodePodnotesURI from "src/utility/encodePodnotesURI";
import { isLocalFile } from "src/utility/isLocalFile";

const clampVolume = (value: number): number =>
Math.min(1, Math.max(0, value));

export class API implements IAPI {
public get podcast(): Episode {
return get(currentEpisode);
Expand All @@ -34,6 +38,14 @@ export class API implements IAPI {
return !get(isPaused);
}

public get volume(): number {
return get(volumeStore);
}

public set volume(value: number) {
volumeStore.set(clampVolume(value));
}

/**
* Gets the current time in the given moment format.
* @param format Moment format.
Expand Down
1 change: 1 addition & 0 deletions src/API/IAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface IAPI {
readonly isPlaying: boolean;
readonly length: number;
currentTime: number;
volume: number;

getPodcastTimeFormatted(format: string, linkify?: boolean): string;

Expand Down
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const DEFAULT_SETTINGS: IPodNotesSettings = {
savedFeeds: {},
podNotes: {},
defaultPlaybackRate: 1,
defaultVolume: 1,
playedEpisodes: {},
favorites: {
...FAVORITES_SETTINGS,
Expand Down
22 changes: 22 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
playlists,
queue,
savedFeeds,
volume,
} from "src/store";
import { Plugin, type WorkspaceLeaf } from "obsidian";
import { API } from "src/API/API";
Expand Down Expand Up @@ -40,6 +41,7 @@ import getContextMenuHandler from "./getContextMenuHandler";
import getUniversalPodcastLink from "./getUniversalPodcastLink";
import type { IconType } from "./types/IconType";
import { TranscriptionService } from "./services/TranscriptionService";
import type { Unsubscriber } from "svelte/store";

export default class PodNotes extends Plugin implements IPodNotes {
public api!: IAPI;
Expand All @@ -65,6 +67,7 @@ export default class PodNotes extends Plugin implements IPodNotes {
[podcastName: string]: DownloadedEpisode[];
}>;
private transcriptionService?: TranscriptionService;
private volumeUnsubscribe?: Unsubscriber;

private maxLayoutReadyAttempts = 10;
private layoutReadyAttempts = 0;
Expand All @@ -84,6 +87,9 @@ export default class PodNotes extends Plugin implements IPodNotes {
if (this.settings.currentEpisode) {
currentEpisode.set(this.settings.currentEpisode);
}
volume.set(
Math.min(1, Math.max(0, this.settings.defaultVolume ?? 1)),
);

this.playedEpisodeController = new EpisodeStatusController(
playedEpisodes,
Expand All @@ -104,6 +110,21 @@ export default class PodNotes extends Plugin implements IPodNotes {
).on();

this.api = new API();
this.volumeUnsubscribe = volume.subscribe((value) => {
const clamped = Math.min(1, Math.max(0, value));

if (clamped !== value) {
volume.set(clamped);
return;
}

if (clamped === this.settings.defaultVolume) {
return;
}

this.settings.defaultVolume = clamped;
void this.saveSettings();
});

this.addCommand({
id: "podnotes-show-leaf",
Expand Down Expand Up @@ -337,6 +358,7 @@ export default class PodNotes extends Plugin implements IPodNotes {
this.localFilesController?.off();
this.downloadedEpisodesController?.off();
this.currentEpisodeController?.off();
this.volumeUnsubscribe?.();
}

async loadSettings() {
Expand Down
1 change: 1 addition & 0 deletions src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type { LocalEpisode } from "src/types/LocalEpisode";
export const plugin = writable<PodNotes>();
export const currentTime = writable<number>(0);
export const duration = writable<number>(0);
export const volume = writable<number>(1);

export const currentEpisode = (() => {
const store = writable<Episode>();
Expand Down
1 change: 1 addition & 0 deletions src/types/IPodNotesSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface IPodNotesSettings {
savedFeeds: { [podcastName: string]: PodcastFeed };
podNotes: { [episodeName: string]: PodNote };
defaultPlaybackRate: number;
defaultVolume: number;
playedEpisodes: { [episodeName: string]: PlayedEpisode };
skipBackwardLength: number;
skipForwardLength: number;
Expand Down
61 changes: 47 additions & 14 deletions src/ui/PodcastView/EpisodePlayer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
currentEpisode,
isPaused,
plugin,
volume,
playedEpisodes,
queue,
playlists,
Expand Down Expand Up @@ -36,9 +37,11 @@

const offBinding = new CircumentForcedTwoWayBinding();
//#endregion
const clampVolume = (value: number): number => Math.min(1, Math.max(0, value));

let isHoveringArtwork: boolean = false;
let isLoading: boolean = true;
let playerVolume: number = 1;

function togglePlayback() {
isPaused.update((value) => !value);
Expand Down Expand Up @@ -84,6 +87,12 @@
offBinding.playbackRate = event.detail.value;
}

function onVolumeChange(event: CustomEvent<{ value: number }>) {
const newVolume = clampVolume(event.detail.value);

volume.set(newVolume);
}

function onMetadataLoaded() {
isLoading = false;

Expand Down Expand Up @@ -125,10 +134,15 @@
srcPromise = getSrc($currentEpisode);
});

const unsubVolume = volume.subscribe((value) => {
playerVolume = clampVolume(value);
});

return () => {
unsub();
unsubDownloadedSource();
unsubCurrentEpisode();
unsubVolume();
};
});

Expand Down Expand Up @@ -223,6 +237,7 @@
bind:currentTime={playerTime}
bind:paused={$isPaused}
bind:playbackRate={offBinding._playbackRate}
bind:volume={playerVolume}
on:ended={onEpisodeEnded}
on:loadedmetadata={onMetadataLoaded}
on:play|preventDefault
Expand Down Expand Up @@ -259,18 +274,29 @@
on:click={$plugin.api.skipForward.bind($plugin.api)}
style={{
margin: "0",
cursor: "pointer",
}}
/>
</div>
cursor: "pointer",
}}
/>
</div>

<div class="playbackrate-container">
<span>{offBinding.playbackRate}x</span>
<Slider
on:change={onPlaybackRateChange}
value={offBinding.playbackRate}
limits={[0.5, 3.5, 0.1]}
/>
<div class="slider-stack">
<div class="volume-container">
<span>Volume: {Math.round(playerVolume * 100)}%</span>
<Slider
on:change={onVolumeChange}
value={playerVolume}
limits={[0, 1, 0.05]}
/>
</div>

<div class="playbackrate-container">
<span>{offBinding.playbackRate}x</span>
<Slider
on:change={onPlaybackRateChange}
value={offBinding.playbackRate}
limits={[0.5, 3.5, 0.1]}
/>
</div>
</div>

<EpisodeList
Expand Down Expand Up @@ -383,12 +409,19 @@
margin-right: 25%;
}

:global(.playbackrate-container) {
:global(.slider-stack) {
display: flex;
flex-direction: column;
gap: 1rem;
margin-top: auto;
margin-bottom: 2.5rem;
}

:global(.playbackrate-container),
:global(.volume-container) {
display: flex;
align-items: center;
justify-content: space-around;
margin-bottom: 2.5rem;
flex-direction: column;
margin-top: auto;
}
</style>
2 changes: 1 addition & 1 deletion src/ui/obsidian/Slider.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
});

function updateSliderAttributes(sldr: SliderComponent) {
if (value) sldr.setValue(value);
if (value !== undefined) sldr.setValue(value);
if (limits) {
if (limits.length === 2) {
sldr.setLimits(limits[0], limits[1], 1);
Expand Down
17 changes: 17 additions & 0 deletions src/ui/settings/PodNotesSettingsTab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export class PodNotesSettingsTab extends PluginSettingTab {
});

this.addDefaultPlaybackRateSetting(settingsContainer);
this.addDefaultVolumeSetting(settingsContainer);
this.addSkipLengthSettings(settingsContainer);
this.addNoteSettings(settingsContainer);
this.addDownloadSettings(settingsContainer);
Expand Down Expand Up @@ -94,6 +95,22 @@ export class PodNotesSettingsTab extends PluginSettingTab {
);
}

private addDefaultVolumeSetting(container: HTMLElement): void {
new Setting(container)
.setName("Default Volume")
.setDesc("Set the default playback volume.")
.addSlider((slider) =>
slider
.setLimits(0, 1, 0.05)
.setValue(this.plugin.settings.defaultVolume)
.onChange((value) => {
this.plugin.settings.defaultVolume = value;
this.plugin.saveSettings();
})
.setDynamicTooltip(),
);
}

private addSkipLengthSettings(container: HTMLElement): void {
new Setting(container)
.setName("Skip backward length (s)")
Expand Down