Skip to content

Commit

Permalink
feat: add audio player
Browse files Browse the repository at this point in the history
  • Loading branch information
syusui-s committed Jul 7, 2024
1 parent ac179e5 commit ea05c67
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 2 deletions.
42 changes: 42 additions & 0 deletions src/components/event/textNote/AudioDisplay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Component, createSignal, Show } from 'solid-js';

import LazyLoad from '@/components/utils/LazyLoad';
import SafeLink from '@/components/utils/SafeLink';
import { useTranslation } from '@/i18n/useTranslation';

type AudioDisplayProps = {
url: string;
initialHidden: boolean;
};

const AudioDisplay: Component<AudioDisplayProps> = (props) => {
const i18n = useTranslation();
const [hidden, setHidden] = createSignal(props.initialHidden);

return (
<Show
when={!hidden()}
fallback={
<button
class="rounded bg-bg-tertiary p-3 text-xs text-fg-secondary hover:shadow"
onClick={() => setHidden(false)}
>
{i18n.t('post.showAudio')}
</button>
}
>
<LazyLoad fallback={<div class="max-w-full" />}>
{() => (
<SafeLink class="my-2 block" href={props.url}>
{/* eslint-disable-next-line jsx-a11y/media-has-caption */}
<audio src={props.url} controls>
<a href={props.url}>{i18n.t('post.download')}</a>
</audio>
</SafeLink>
)}
</LazyLoad>
</Show>
);
};

export default AudioDisplay;
6 changes: 5 additions & 1 deletion src/components/event/textNote/TextNoteContentDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as Kind from 'nostr-tools/kinds';
// eslint-disable-next-line import/no-cycle
import EventDisplayById from '@/components/event/EventDisplayById';
// import ParameterizedReplaceableEventDisplayById from '@/components/event/ParameterizedReplaceableEventDisplayById';
import AudioDisplay from '@/components/event/textNote/AudioDisplay';
import ImageDisplay from '@/components/event/textNote/ImageDisplay';
import MentionedEventDisplay from '@/components/event/textNote/MentionedEventDisplay';
import MentionedUserDisplay from '@/components/event/textNote/MentionedUserDisplay';
Expand All @@ -15,7 +16,7 @@ import { createRelaysColumn, createSearchColumn } from '@/core/column';
import useConfig from '@/core/useConfig';
import { useRequestCommand } from '@/hooks/useCommandBus';
import { ParsedTextNoteResolvedNode, type ParsedTextNoteResolved } from '@/nostr/parseTextNote';
import { isImageUrl, isVideoUrl, isWebSocketUrl } from '@/utils/url';
import { isImageUrl, isVideoUrl, isAudioUrl, isWebSocketUrl } from '@/utils/url';

export type TextNoteContentDisplayProps = {
parsed: ParsedTextNoteResolved;
Expand Down Expand Up @@ -54,6 +55,9 @@ const TextNoteContentDisplay = (props: TextNoteContentDisplayProps) => {
if (isVideoUrl(item.content)) {
return <VideoDisplay url={item.content} initialHidden={initialHidden()} />;
}
if (isAudioUrl(item.content)) {
return <AudioDisplay url={item.content} initialHidden={initialHidden()} />;
}
if (isWebSocketUrl(item.content)) {
return (
<button
Expand Down
1 change: 1 addition & 0 deletions src/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export default {
failedToDelete: 'Failed to delete',
showImage: 'Show image',
showVideo: 'Show video',
showAudio: 'Show audio player',
showPreview: 'Show preview',
showOverflow: 'Read more',
hideOverflow: 'Hide',
Expand Down
1 change: 1 addition & 0 deletions src/locales/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export default {
failedToDelete: 'すべてのリレーで削除に失敗しました',
showImage: '画像を表示する',
showVideo: '動画を表示する',
showAudio: '音声プレイヤーを表示する',
showPreview: 'プレビューを表示する',
showOverflow: '続きを読む',
hideOverflow: '隠す',
Expand Down
11 changes: 10 additions & 1 deletion src/utils/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,16 @@ export const isImageUrl = (urlString: string): boolean => {
export const isVideoUrl = (urlString: string): boolean => {
try {
const url = new URL(urlString);
return /\.(mpg|mpeg|mp4|avi|mov|webm|ogv)$/i.test(url.pathname);
return /\.(mpg|mpeg|mp4|avi|mov|mkv|webm|ogv)$/i.test(url.pathname);
} catch {
return false;
}
};

export const isAudioUrl = (urlString: string): boolean => {
try {
const url = new URL(urlString);
return /\.(wav|mp3|flac|wma|m4a|aac|ogg|oga|opus)$/i.test(url.pathname);
} catch {
return false;
}
Expand Down

0 comments on commit ea05c67

Please sign in to comment.