Skip to content

Commit

Permalink
feat(media): enhance enclosure support with progression tracking and …
Browse files Browse the repository at this point in the history
…improved parsing (wip)
  • Loading branch information
NekoAria committed Nov 16, 2024
1 parent 095f483 commit fb14b65
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 6 deletions.
5 changes: 5 additions & 0 deletions src/apis/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ export const markAllAsRead = async () => {
const currentUser = await getCurrentUser()
return apiClient.put(`/v1/users/${currentUser.id}/mark-all-as-read`)
}

export const saveEnclosureProgression = async (
enclosureId,
progress, // enclosureId: number, progress: number
) => apiClient.put(`/v1/enclosures/${enclosureId}`, { media_progression: progress })
16 changes: 16 additions & 0 deletions src/components/Article/ArticleDetail.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,21 @@ const ArticleDetail = forwardRef((_, ref) => {
const { id: categoryId, title: categoryTitle } = activeContent.feed.category
const { id: feedId, title: feedTitle } = activeContent.feed

const mediaPlayerEnclosure = activeContent.enclosures?.find(
(enclosure) =>
enclosure.url !== "" &&
(enclosure.mime_type.startsWith("video/") || enclosure.mime_type.startsWith("audio/")),
)
const enclosure = mediaPlayerEnclosure || null

const imageEnclosure = activeContent.enclosures?.find(
(enclosure) =>
enclosure.mime_type.toLowerCase().startsWith("image/") ||
/\.(jpg|jpeg|png|gif)$/i.test(enclosure.url),
)

const poster = imageEnclosure?.url || ""

// pretty footnotes
useEffect(() => {
littlefoot()
Expand Down Expand Up @@ -285,6 +300,7 @@ const ArticleDetail = forwardRef((_, ref) => {
"--article-width": articleWidth,
}}
>
{enclosure && <PlyrPlayer enclosure={enclosure} poster={poster} src={enclosure.url} />}
{parsedHtml}
<PhotoSlider
bannerVisible={!isBelowMedium}
Expand Down
26 changes: 26 additions & 0 deletions src/components/ui/PlyrPlayer.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useStore } from "@nanostores/react"
import { useEffect, useRef } from "react"

import { saveEnclosureProgression } from "@/apis"
import { contentState } from "@/store/contentState"
import "plyr/dist/plyr.css"
import "./PlyrPlayer.css"
Expand Down Expand Up @@ -95,6 +96,7 @@ const PlyrPlayer = ({
elementType = "video",
plyrOptions = {},
poster = "",
enclosure = null,
onPlayerInit = () => {},
onError = () => {},
}) => {
Expand All @@ -103,6 +105,7 @@ const PlyrPlayer = ({
const mediaRef = useRef(null)
const playerRef = useRef(null)
const hlsRef = useRef(null)
const lastSavedTimeRef = useRef(0)

useEffect(() => {
if (!src || !activeContent) {
Expand All @@ -127,6 +130,29 @@ const PlyrPlayer = ({
mediaRef.current.src = src
}

if (enclosure) {
playerRef.current.on("loadeddata", () => {
playerRef.current.currentTime = enclosure.media_progression
lastSavedTimeRef.current = enclosure.media_progression
})

const updateProgression = () => {
const { currentTime } = playerRef.current
saveEnclosureProgression(enclosure.id, Math.floor(currentTime))
lastSavedTimeRef.current = currentTime
}

playerRef.current.on("timeupdate", () => {
const { currentTime } = playerRef.current
if (currentTime - lastSavedTimeRef.current >= 10) {
updateProgression()
}
})

playerRef.current.on("pause", updateProgression)
playerRef.current.on("ended", updateProgression)
}

onPlayerInit(playerRef.current)
} catch (error) {
onError({ type: "init", error })
Expand Down
13 changes: 7 additions & 6 deletions src/utils/images.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ export const parseCoverImage = (entry) => {
coverSource = video.getAttribute("poster")
isVideo = true
} else if (entry.enclosures?.[0]) {
const firstEnclosure = entry.enclosures[0]
const isImage =
firstEnclosure.mime_type.toLowerCase().startsWith("image/") ||
/\.(jpg|jpeg|png|gif)$/i.test(firstEnclosure.url)
if (isImage) {
coverSource = firstEnclosure.url
const imageEnclosure = entry.enclosures.find(
(enclosure) =>
enclosure.mime_type.toLowerCase().startsWith("image/") ||
/\.(jpg|jpeg|png|gif)$/i.test(enclosure.url),
)
if (imageEnclosure) {
coverSource = imageEnclosure.url
}
// Youtube thumbnail
isVideo = coverSource?.startsWith("https://i.ytimg.com") ?? false
Expand Down

0 comments on commit fb14b65

Please sign in to comment.