diff --git a/README.md b/README.md
index 1af8129..fe30649 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,6 @@
# Aleph
-Aleph (or Aleph or א or 阿莱夫, ˈɑːlɛf) is a RSS reader & podcast client built for the desktop.
+Aleph (or א or 阿莱夫, ˈɑːlɛf) is an RSS reader & podcast client built for the desktop.
-![Example](https://pbs.twimg.com/media/FOX6Lt8VUAUv9vl?format=jpg&name=medium)
+![Example](https://aleph.chezhe.dev/screenshot.png)
diff --git a/package.json b/package.json
index 16ee8f1..24d3422 100644
--- a/package.json
+++ b/package.json
@@ -12,15 +12,14 @@
"@types/node": "^16.7.13",
"@types/react": "^17.0.20",
"@types/react-dom": "^17.0.9",
- "axios": "^0.26.1",
"dayjs": "^1.11.0",
"fast-xml-parser": "^4.0.7",
"grommet": "^2.21.0",
"grommet-icons": "^4.7.0",
"lodash": "^4.17.21",
"react": "^17.0.2",
- "react-audio-player": "^0.17.0",
"react-dom": "^17.0.2",
+ "react-loading": "^2.0.3",
"react-redux": "^7.2.6",
"react-scripts": "5.0.0",
"styled-components": "^5.3.3",
diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
index 317abdf..26d82e5 100644
--- a/src-tauri/Cargo.lock
+++ b/src-tauri/Cargo.lock
@@ -36,7 +36,7 @@ dependencies = [
[[package]]
name = "aleph"
-version = "0.3.0"
+version = "0.4.0"
dependencies = [
"serde",
"serde_json",
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index 7e5d8c9..5dbcb25 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "aleph"
-version = "0.4.0"
+version = "0.5.0"
description = "A Tauri App"
authors = ["chezhe"]
license = ""
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 54cb993..90e2a10 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -1,7 +1,7 @@
{
"package": {
"productName": "aleph",
- "version": "0.4.0"
+ "version": "0.5.0"
},
"build": {
"distDir": "../build",
diff --git a/src/components/AddFeed.tsx b/src/components/AddFeed.tsx
index 4125e0c..4438c28 100644
--- a/src/components/AddFeed.tsx
+++ b/src/components/AddFeed.tsx
@@ -86,6 +86,7 @@ export default function AddFeed({
type: 'feed/update',
payload: newFeed,
})
+ onClose()
} else {
try {
setIsAdding(true)
diff --git a/src/components/Playing.tsx b/src/components/Playing.tsx
deleted file mode 100644
index db9ec0e..0000000
--- a/src/components/Playing.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import { Box, Button, Image } from 'grommet'
-import { Close } from 'grommet-icons'
-import ReactAudioPlayer from 'react-audio-player'
-import { Episode } from '../types'
-import { stripURL } from '../utils/format'
-
-export default function Playing({
- activeItem,
- playingEp,
- setPlayingEp,
-}: {
- activeItem: Episode | undefined
- playingEp: Episode | undefined
- setPlayingEp: (ep: Episode | undefined) => void
-}) {
- if (
- !playingEp ||
- (playingEp && activeItem && activeItem?.podurl === playingEp?.podurl)
- ) {
- return null
- }
- return (
-
-
- }
- onClick={() => setPlayingEp(undefined)}
- size="small"
- primary
- />
-
-
-
- {
- setPlayingEp(playingEp)
- }}
- />
-
- )
-}
diff --git a/src/components/PodPlayer.tsx b/src/components/PodPlayer.tsx
index 4386da4..dcee4c7 100644
--- a/src/components/PodPlayer.tsx
+++ b/src/components/PodPlayer.tsx
@@ -1,7 +1,69 @@
-import { Box, Button, Image } from 'grommet'
-import ReactAudioPlayer from 'react-audio-player'
+import { Box, Button, RangeInput, Text } from 'grommet'
+import { Pause, Play } from 'grommet-icons'
+import { useEffect, useState } from 'react'
import { Episode } from '../types'
import { stripURL } from '../utils/format'
+import Loading from 'react-loading'
+
+const formatMinutes = (seconds: number) => {
+ const _seconds = Math.floor(seconds)
+ const minutes = Math.floor(_seconds / 60)
+ const secondsLeft = _seconds % 60
+ return `${minutes}:${secondsLeft < 10 ? '0' : ''}${secondsLeft}`
+}
+
+const useAudio = (url?: string) => {
+ const [audio, setAudio] = useState(null)
+ const [playing, setPlaying] = useState(false)
+ const [ready, setReady] = useState(false)
+ const [currentTime, setCurrentTime] = useState(0)
+ const [duration, setDuration] = useState(0)
+
+ useEffect(() => {
+ let tick: NodeJS.Timer
+ if (url) {
+ if (audio) {
+ setReady(false)
+ audio?.pause()
+ setAudio(null)
+ }
+ const _audio = new Audio(url)
+ if (_audio) {
+ _audio.addEventListener('canplaythrough', (event) => {
+ setDuration(_audio.duration)
+ setReady(true)
+ _audio.play()
+ setPlaying(true)
+ })
+
+ _audio.addEventListener('timeupdate', (event) => {
+ setCurrentTime(_audio.currentTime)
+ })
+ setAudio(_audio)
+ }
+ }
+
+ return () => {
+ audio?.pause()
+ setAudio(null)
+ tick && clearInterval(tick)
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [url])
+
+ useEffect(() => {
+ if (audio) {
+ if (playing) {
+ audio.play()
+ } else {
+ audio.pause()
+ }
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [playing])
+
+ return { audio, playing, currentTime, duration, setPlaying, ready }
+}
export default function PodPlayer({
playingEp,
@@ -12,31 +74,85 @@ export default function PodPlayer({
setPlayingEp: (ep: Episode | undefined) => void
setActiveItem: (ep: Episode | undefined) => void
}) {
- if (!playingEp) {
+ const { audio, duration, currentTime, playing, setPlaying, ready } = useAudio(
+ playingEp?.podurl
+ )
+
+ if (!playingEp || !audio) {
return null
}
+ if (!ready) {
+ return (
+
+
+
+ )
+ }
+
return (
-
- {
- // setPlayingEp(playingEp)
+
+ }
/>
+
+ {
+ audio!.currentTime = Number(e.target.value)
+ }}
+ style={{ minWidth: 400 }}
+ />
+
+ {formatMinutes(currentTime)}
+ {formatMinutes(duration)}
+
+