functionality for handling male and female recordings of words
This commit is contained in:
parent
a91ae1b1f3
commit
d2a1d03640
|
@ -9,6 +9,7 @@ import ExtraEntryInfo from "../components/ExtraEntryInfo";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { Types as T, InlinePs } from "@lingdocs/ps-react";
|
import { Types as T, InlinePs } from "@lingdocs/ps-react";
|
||||||
import playStorageAudio from "./PlayStorageAudio";
|
import playStorageAudio from "./PlayStorageAudio";
|
||||||
|
import { getRecordedGenders } from "../lib/recorded-genders";
|
||||||
|
|
||||||
function Entry({
|
function Entry({
|
||||||
entry,
|
entry,
|
||||||
|
@ -22,11 +23,12 @@ function Entry({
|
||||||
isolateEntry?: (ts: number) => void;
|
isolateEntry?: (ts: number) => void;
|
||||||
admin: boolean;
|
admin: boolean;
|
||||||
}) {
|
}) {
|
||||||
function handlePlayStorageAudio(
|
const gendersRecorded = getRecordedGenders(entry);
|
||||||
e: React.MouseEvent<HTMLElement, MouseEvent>
|
function handlePlayStorageAudio(gender: T.Gender) {
|
||||||
) {
|
return (e: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
playStorageAudio(entry.ts, entry.p, () => null);
|
playStorageAudio(entry.ts, gender, entry.p, () => null);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -43,13 +45,14 @@ function Entry({
|
||||||
{` `}
|
{` `}
|
||||||
{/* Can't figure out why but the <em> here can't be empty */}
|
{/* Can't figure out why but the <em> here can't be empty */}
|
||||||
<em>{entry.c || "\u00A0"}</em>
|
<em>{entry.c || "\u00A0"}</em>
|
||||||
{entry.a && !nonClickable && (
|
{!nonClickable &&
|
||||||
<i
|
gendersRecorded.map((gender) => (
|
||||||
onClick={handlePlayStorageAudio}
|
<i
|
||||||
className="clickable ml-2 fas fa-volume-down px-1"
|
onClick={handlePlayStorageAudio(gender)}
|
||||||
title="play audio"
|
className="clickable ml-2 fas fa-volume-down px-1"
|
||||||
/>
|
title="play audio"
|
||||||
)}
|
/>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<ExtraEntryInfo entry={entry} textOptions={textOptions} />
|
<ExtraEntryInfo entry={entry} textOptions={textOptions} />
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Types as T, InlinePs } from "@lingdocs/ps-react";
|
import { Types as T, InlinePs } from "@lingdocs/ps-react";
|
||||||
import { getAudioPath } from "./PlayStorageAudio";
|
import { getAudioPath } from "./PlayStorageAudio";
|
||||||
import ReactGA from "react-ga4";
|
import ReactGA from "react-ga4";
|
||||||
|
import { getRecordedGenders } from "../lib/recorded-genders";
|
||||||
|
|
||||||
export function EntryAudioDisplay({
|
export function EntryAudioDisplay({
|
||||||
entry,
|
entry,
|
||||||
|
@ -9,23 +10,46 @@ export function EntryAudioDisplay({
|
||||||
entry: T.DictionaryEntry;
|
entry: T.DictionaryEntry;
|
||||||
opts: T.TextOptions;
|
opts: T.TextOptions;
|
||||||
}) {
|
}) {
|
||||||
const audioPath = getAudioPath(entry.ts);
|
if (!entry.a) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="mb-4">
|
||||||
|
{getRecordedGenders(entry).map((gender) => (
|
||||||
|
<EntryRecording entry={entry} opts={opts} gender={gender} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function EntryRecording({
|
||||||
|
entry,
|
||||||
|
opts,
|
||||||
|
gender,
|
||||||
|
}: {
|
||||||
|
entry: T.DictionaryEntry;
|
||||||
|
opts: T.TextOptions;
|
||||||
|
gender: T.Gender;
|
||||||
|
}) {
|
||||||
|
const audioPath = getAudioPath(entry.ts, gender);
|
||||||
if (!entry.a) {
|
if (!entry.a) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
function handlePlay() {
|
function handlePlay() {
|
||||||
ReactGA.event({
|
ReactGA.event({
|
||||||
category: "sounds",
|
category: "sounds",
|
||||||
action: `play ${entry.p} - ${entry.ts}`,
|
action: `play ${entry.p} - ${entry.ts} ${gender}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDownload() {
|
function handleDownload() {
|
||||||
ReactGA.event({
|
ReactGA.event({
|
||||||
category: "sounds",
|
category: "sounds",
|
||||||
action: `download ${entry.p} - ${entry.ts}`,
|
action: `download ${entry.p} - ${entry.ts} ${gender}`,
|
||||||
});
|
});
|
||||||
const documentName = `${entry.p}-${entry.ts}.mp3`;
|
const documentName = `${entry.p}-${entry.ts}-${
|
||||||
|
gender === "masc" ? "m" : "f"
|
||||||
|
}.mp3`;
|
||||||
|
|
||||||
fetch(audioPath)
|
fetch(audioPath)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
@ -45,10 +69,15 @@ export function EntryAudioDisplay({
|
||||||
<figure>
|
<figure>
|
||||||
<figcaption className="mb-2 pl-2">
|
<figcaption className="mb-2 pl-2">
|
||||||
<div style={{ display: "none" }}>
|
<div style={{ display: "none" }}>
|
||||||
Listen to <InlinePs opts={opts} ps={{ p: entry.p, f: entry.f }} />
|
Listen to <InlinePs opts={opts} ps={{ p: entry.p, f: entry.f }} />:
|
||||||
|
{` `}
|
||||||
|
{gender === "masc" ? "Male" : "Female"} recording
|
||||||
</div>
|
</div>
|
||||||
</figcaption>
|
</figcaption>
|
||||||
<div className="d-flex align-items-center">
|
<div className="d-flex align-items-center">
|
||||||
|
<div className="mr-2" style={{ width: "1rem" }}>
|
||||||
|
{gender === "masc" ? "M" : "F"}
|
||||||
|
</div>
|
||||||
<audio
|
<audio
|
||||||
controls
|
controls
|
||||||
controlsList="nofullscreen"
|
controlsList="nofullscreen"
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
import ReactGA from "react-ga4";
|
import ReactGA from "react-ga4";
|
||||||
|
import { Types as T } from "@lingdocs/ps-react";
|
||||||
|
|
||||||
export function getAudioPath(ts: number): string {
|
export function getAudioPath(ts: number, gender: T.Gender): string {
|
||||||
return `https://storage.lingdocs.com/audio/${ts}.mp3`;
|
return `https://storage.lingdocs.com/audio/${ts}${
|
||||||
|
gender === "fem" ? "f" : ""
|
||||||
|
}.mp3`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function playStorageAudio(
|
export default function playStorageAudio(
|
||||||
ts: number,
|
ts: number,
|
||||||
|
gender: T.Gender,
|
||||||
p: string,
|
p: string,
|
||||||
callback: () => void
|
callback: () => void
|
||||||
) {
|
) {
|
||||||
|
@ -14,7 +18,7 @@ export default function playStorageAudio(
|
||||||
category: "sounds",
|
category: "sounds",
|
||||||
action: `quick play ${p} - ${ts}`,
|
action: `quick play ${p} - ${ts}`,
|
||||||
});
|
});
|
||||||
let audio = new Audio(getAudioPath(ts));
|
let audio = new Audio(getAudioPath(ts, gender));
|
||||||
audio.addEventListener("ended", () => {
|
audio.addEventListener("ended", () => {
|
||||||
callback();
|
callback();
|
||||||
audio.remove();
|
audio.remove();
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { Types as T } from "@lingdocs/ps-react";
|
||||||
|
|
||||||
|
export function getRecordedGenders(entry: T.DictionaryEntry): T.Gender[] {
|
||||||
|
return entry.a === 1
|
||||||
|
? ["masc"]
|
||||||
|
: entry.a === 2
|
||||||
|
? ["fem"]
|
||||||
|
: entry.a === 3
|
||||||
|
? ["masc", "fem"]
|
||||||
|
: [];
|
||||||
|
}
|
|
@ -58,7 +58,8 @@ registerRoute(
|
||||||
registerRoute(
|
registerRoute(
|
||||||
// Add in any other file extensions or routing criteria as needed.
|
// Add in any other file extensions or routing criteria as needed.
|
||||||
({ url }) =>
|
({ url }) =>
|
||||||
url.origin === self.location.origin && ([".png", ".woff2", "woff"].some(ending => url.pathname.endsWith(ending)))
|
url.origin === self.location.origin &&
|
||||||
|
[".png", ".woff2", "woff"].some((ending) => url.pathname.endsWith(ending)),
|
||||||
// Customize this strategy as needed, e.g., by changing to CacheFirst.
|
// Customize this strategy as needed, e.g., by changing to CacheFirst.
|
||||||
new StaleWhileRevalidate({
|
new StaleWhileRevalidate({
|
||||||
cacheName: "images",
|
cacheName: "images",
|
||||||
|
|
Loading…
Reference in New Issue