Skip to content

Commit

Permalink
feat(music): original music video link
Browse files Browse the repository at this point in the history
  • Loading branch information
dnaroma committed Apr 6, 2024
1 parent a401c72 commit 627432d
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 30 deletions.
57 changes: 57 additions & 0 deletions src/components/blocks/EmbedVideoPlayer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { Fragment, useEffect, useState } from "react";

const MusicVideoPlayer: React.FC<{
videoUrl: string;
}> = (props) => {
const [isYtbVideo, setIsYtbVideo] = useState(false);
const [ytbVideoId, setYtbVideoId] = useState("");

const [isNicoVideo, setIsNicoVideo] = useState(false);
const [nicoVideoId, setNicoVideoId] = useState("");

useEffect(() => {
if (props.videoUrl.includes("youtube.com")) {
setIsYtbVideo(true);
setYtbVideoId(
new URLSearchParams(new URL(props.videoUrl).search).get("v") || ""
);
} else if (props.videoUrl.includes("youtu.be")) {
setIsYtbVideo(true);
setYtbVideoId(new URL(props.videoUrl).pathname.split("/")[1] || "");
} else if (props.videoUrl.includes("nicovideo.jp")) {
setIsNicoVideo(true);
setNicoVideoId(
new URL(props.videoUrl).pathname.split("/")[2].split("?")[0] || ""
);
}
}, [props.videoUrl]);

return (
<Fragment>
{isYtbVideo && (
<iframe
width="100%"
height="485"
src={`https://www.youtube.com/embed/${ytbVideoId}`}
title="YouTube video player"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
style={{ border: "none" }}
></iframe>
)}
{isNicoVideo && (
<iframe
width="100%"
height="485"
src={`https://embed.nicovideo.jp/watch/${nicoVideoId}?autoplay=0`}
title="niconico"
allowFullScreen
allow="encrypted-media *;"
style={{ border: "none" }}
></iframe>
)}
</Fragment>
);
};

export default MusicVideoPlayer;
2 changes: 1 addition & 1 deletion src/components/blocks/SekaiGameNews.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function InfoInternal(props: { onClick: () => void }) {
function InfoInternalDialog(props: {
url: string;
open: boolean;
onClose: (event: {}, reason: "backdropClick" | "escapeKeyDown") => void;
onClose: (event: unknown, reason: "backdropClick" | "escapeKeyDown") => void;
title: string;
}) {
return (
Expand Down
109 changes: 80 additions & 29 deletions src/pages/music/MusicDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Switch,
Link,
Box,
IconButton,
} from "@mui/material";
import { Alert } from "@mui/material";
import { TabContext, TabPanel } from "@mui/lab";
Expand All @@ -26,6 +27,7 @@ import {
IMusicTagInfo,
IMusicVocalInfo,
IOutCharaProfile,
IMusicOriginal,
} from "../../types.d";
import { getRemoteAssetURL, useCachedData, useMusicTagName } from "../../utils";
import { charaIcons } from "../../utils/resources";
Expand Down Expand Up @@ -55,6 +57,7 @@ import TypographyHeader from "../../components/styled/TypographyHeader";
import ContainerContent from "../../components/styled/ContainerContent";
import PaperContainer from "../../components/styled/PaperContainer";
import GridOut from "../../components/styled/GridOut";
import EmbedVideoPlayer from "../../components/blocks/EmbedVideoPlayer";

const MusicDetail: React.FC<unknown> = observer(() => {
const { t } = useTranslation();
Expand All @@ -81,6 +84,7 @@ const MusicDetail: React.FC<unknown> = observer(() => {
const [danceMembers] = useCachedData<IMusicDanceMembers>("musicDanceMembers");
const [musicAchievements] =
useCachedData<IMusicAchievement>("musicAchievements");
const [musicOriginals] = useCachedData<IMusicOriginal>("musicOriginals");

const { musicId } = useParams<{ musicId: string }>();

Expand All @@ -91,6 +95,7 @@ const MusicDetail: React.FC<unknown> = observer(() => {
const [musicVocalTypes, setMusicVocalTypes] = useState<string[]>([]);
const [musicDanceMember, setMusicDanceMember] =
useState<IMusicDanceMembers>();
const [musicOriginal, setMusicOriginal] = useState<IMusicOriginal>();
const [selectedPreviewVocalType, setSelectedPreviewVocalType] =
useState<number>(0);
const [selectedVocalType, setSelectedVocalType] = useState<number>(0);
Expand Down Expand Up @@ -165,6 +170,14 @@ const MusicDetail: React.FC<unknown> = observer(() => {
}
}, [difficulties]);

useEffect(() => {
if (musicOriginals) {
setMusicOriginal(
musicOriginals.find((elem) => elem.musicId === Number(musicId))
);
}
}, [musicOriginals, musicId]);

useEffect(() => {
if (music && musicVocal && musicVocal[selectedPreviewVocalType]) {
if ([420, 445, 453, 459, 464, 10001, 10002].includes(music.id)) {
Expand Down Expand Up @@ -441,23 +454,39 @@ const MusicDetail: React.FC<unknown> = observer(() => {
<Alert severity="warning">
<Trans i18nKey="music:alert[0]" components={{ b: <b /> }} />
</Alert>
<Grid container justifyContent="center">
<Grid item xs={12} sm={6}>
<div
onClick={() => {
setActiveIdx(0);
setVisible(true);
}}
>
<Box
component={Image}
src={musicJacket}
bgColor=""
sx={{ cursor: "pointer" }}
/>
</div>
{["original", "mv_2d"].includes(vocalPreviewVal) &&
musicVocalTypes.length &&
musicVocal.length &&
longMusicPlaybackURL ? (
<MusicVideoPlayer
audioPath={longMusicPlaybackURL}
videoPath={musicVideoURL}
onPlay={() => setVocalDisabled(true)}
onPause={() => setVocalDisabled(false)}
onEnded={() => setVocalDisabled(false)}
/>
) : ["original_video"].includes(vocalPreviewVal) &&
musicOriginal?.videoLink ? (
<EmbedVideoPlayer videoUrl={musicOriginal.videoLink} />
) : (
<Grid container justifyContent="center">
<Grid item xs={12} sm={6}>
<div
onClick={() => {
setActiveIdx(0);
setVisible(true);
}}
>
<Box
component={Image}
src={musicJacket}
bgColor=""
sx={{ cursor: "pointer" }}
/>
</div>
</Grid>
</Grid>
</Grid>
)}
<PaperContainer>
<Grid container direction="column" spacing={1}>
<Grid
Expand Down Expand Up @@ -518,6 +547,14 @@ const MusicDetail: React.FC<unknown> = observer(() => {
}
/>
))}
{!!musicOriginal && (
<FormControlLabel
value="original_video"
control={<Radio color="primary"></Radio>}
label={t("music:vocalTab.original_video") as string}
labelPlacement="end"
/>
)}
</RadioGroup>
</Grid>
</Grid>
Expand Down Expand Up @@ -611,19 +648,6 @@ const MusicDetail: React.FC<unknown> = observer(() => {
offset={trimSilence ? music.fillerSec : 0}
/>
)}
{["original", "mv_2d"].includes(vocalPreviewVal) &&
musicVocalTypes.length &&
musicVocal.length &&
longMusicPlaybackURL && (
<MusicVideoPlayer
audioPath={longMusicPlaybackURL}
videoPath={musicVideoURL}
onPlay={() => setVocalDisabled(true)}
onPause={() => setVocalDisabled(false)}
onEnded={() => setVocalDisabled(false)}
/>
)}

<GridOut container direction="column">
<Grid
container
Expand Down Expand Up @@ -817,6 +841,33 @@ const MusicDetail: React.FC<unknown> = observer(() => {
</Typography>
</Grid>
<Divider style={{ margin: "1% 0" }} />
{!!musicOriginal && (
<Fragment>
<Grid
container
direction="row"
wrap="nowrap"
justifyContent="space-between"
alignItems="center"
>
<Typography variant="subtitle1" style={{ fontWeight: 600 }}>
{t("music:vocalTab.original_video")}
</Typography>
<Typography>
<IconButton
component="a"
href={musicOriginal.videoLink}
target="_blank"
size="small"
color="inherit"
>
<OpenInNew />
</IconButton>
</Typography>
</Grid>
<Divider style={{ margin: "1% 0" }} />
</Fragment>
)}
</GridOut>
</ContainerContent>
<TypographyHeader>
Expand Down
6 changes: 6 additions & 0 deletions src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1563,3 +1563,9 @@ interface ICompactResourceBoxDetailENUM {
resourceBoxPurpose: string[];
resourceType: string[];
}

export interface IMusicOriginal {
id: number;
musicId: number;
videoLink: string;
}
2 changes: 2 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import {
ICompactResourceBox,
ICompactResourceBoxDetail,
IGachaTicket,
IMusicOriginal,
} from "./../types.d";
import { useAssetI18n, useCharaName } from "./i18n";
import { useLocation } from "react-router-dom";
Expand Down Expand Up @@ -154,6 +155,7 @@ export function useCachedData<
| IMasterLessonReward
| IEventMusic
| IGachaTicket
| IMusicOriginal
>(name: string): [T[] | undefined, boolean, any] {
// const [cached, cachedRef, setCached] = useRefState<T[]>([]);
const { region } = useRootStore();
Expand Down

0 comments on commit 627432d

Please sign in to comment.