Skip to content

Commit e0aa722

Browse files
authored
Merge pull request #353 from victoralvesf/development
Sync v0.13.0
2 parents fc3c981 + 29afd28 commit e0aa722

16 files changed

Lines changed: 317 additions & 159 deletions

electron-builder.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,15 @@ mac:
4848

4949
linux:
5050
target:
51-
- AppImage
51+
- target: AppImage
52+
arch:
53+
- x64
54+
- arm64
55+
- target: tar.gz
56+
arch:
57+
- x64
58+
- arm64
5259
- deb
53-
- tar.gz
5460
maintainer: victoralvesf
5561
category: AudioVideo
5662
synopsis: 'A modern desktop music client for Navidrome and OpenSubsonic servers.'

flatpak/io.github.victoralvesf.aonsoku.metainfo.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,23 @@
4747
</screenshots>
4848

4949
<releases>
50+
<release version="0.13.0" date="2026-02-26">
51+
<url type="details">https://github.com/victoralvesf/aonsoku/releases/tag/v0.13.0</url>
52+
<description>
53+
<p>New Features</p>
54+
<ul>
55+
<li>Now Playing: Send now playing event when song starts playing to the server.</li>
56+
<li>Linux Builds: Added AppImage and Tar.gz builds for the arm64 architecture.</li>
57+
</ul>
58+
<p>Fixes</p>
59+
<ul>
60+
<li>Audio Player: Improved audio player performance and stability.</li>
61+
<li>Quality Badge: Improved the rendering of the quality badge.</li>
62+
<li>Window Management: Improved the window management state for Linux.</li>
63+
<li>Scrobble: Fixed an issue where scrobbles were sent instantly when a song started playing.</li>
64+
</ul>
65+
</description>
66+
</release>
5067
<release version="0.12.0" date="2026-02-18">
5168
<url type="details">https://github.com/victoralvesf/aonsoku/releases/tag/v0.12.0</url>
5269
<description>

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "aonsoku",
33
"private": true,
4-
"version": "0.12.0",
4+
"version": "0.13.0",
55
"description": "A modern desktop client for Navidrome/Subsonic servers.",
66
"author": {
77
"name": "Victor Alves"
@@ -20,7 +20,7 @@
2020
"cy:open": "cypress open",
2121
"test": "cypress run --component",
2222
"electron:start": "electron-vite preview",
23-
"electron:dev": "electron-vite dev",
23+
"electron:dev": "electron-vite dev --watch",
2424
"electron:build": "electron-vite build",
2525
"postinstall": "electron-builder install-app-deps",
2626
"build:unpack": "electron-builder --dir",

src/app/components/home/carousel/header.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Autoplay from 'embla-carousel-autoplay'
2+
import { HeaderFallback } from '@/app/components/fallbacks/home-fallbacks'
23
import { HeaderItem } from '@/app/components/home/carousel/header-item'
34
import {
45
Carousel,
@@ -7,14 +8,14 @@ import {
78
CarouselNext,
89
CarouselPrevious,
910
} from '@/app/components/ui/carousel'
10-
import { ISong } from '@/types/responses/song'
11+
import { useGetRandomSongs } from '@/app/hooks/use-home'
1112

12-
interface HomeHeaderProps {
13-
songs: ISong[]
14-
}
13+
export function HomeHeader() {
14+
const { data: songs, isLoading, isFetching } = useGetRandomSongs()
15+
16+
if (isLoading || isFetching) return <HeaderFallback />
1517

16-
export default function HomeHeader({ songs }: HomeHeaderProps) {
17-
if (songs.length === 0) return null
18+
if (!songs || songs.length === 0) return null
1819

1920
return (
2021
<Carousel
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useTranslation } from 'react-i18next'
2+
import { PreviewListFallback } from '@/app/components/fallbacks/home-fallbacks'
3+
import { useGetRandomAlbums } from '@/app/hooks/use-home'
4+
import { ROUTES } from '@/routes/routesList'
5+
import PreviewList from './preview-list'
6+
7+
export function Explore() {
8+
const { t } = useTranslation()
9+
const { data, isLoading } = useGetRandomAlbums()
10+
11+
if (isLoading) {
12+
return <PreviewListFallback />
13+
}
14+
15+
if (!data || !data.list || data.list.length === 0) return null
16+
17+
return (
18+
<PreviewList
19+
title={t('home.explore')}
20+
moreRoute={ROUTES.ALBUMS.RANDOM}
21+
list={data.list}
22+
/>
23+
)
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useTranslation } from 'react-i18next'
2+
import { PreviewListFallback } from '@/app/components/fallbacks/home-fallbacks'
3+
import { useGetMostPlayed } from '@/app/hooks/use-home'
4+
import { ROUTES } from '@/routes/routesList'
5+
import PreviewList from './preview-list'
6+
7+
export function MostPlayed() {
8+
const { t } = useTranslation()
9+
const { data, isLoading } = useGetMostPlayed()
10+
11+
if (isLoading) {
12+
return <PreviewListFallback />
13+
}
14+
15+
if (!data || !data.list || data.list.length === 0) return null
16+
17+
return (
18+
<PreviewList
19+
title={t('home.mostPlayed')}
20+
moreRoute={ROUTES.ALBUMS.MOST_PLAYED}
21+
list={data.list}
22+
/>
23+
)
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useTranslation } from 'react-i18next'
2+
import { PreviewListFallback } from '@/app/components/fallbacks/home-fallbacks'
3+
import { useGetRecentlyAdded } from '@/app/hooks/use-home'
4+
import { ROUTES } from '@/routes/routesList'
5+
import PreviewList from './preview-list'
6+
7+
export function RecentlyAdded() {
8+
const { t } = useTranslation()
9+
const { data, isLoading } = useGetRecentlyAdded()
10+
11+
if (isLoading) {
12+
return <PreviewListFallback />
13+
}
14+
15+
if (!data || !data.list || data.list.length === 0) return null
16+
17+
return (
18+
<PreviewList
19+
title={t('home.recentlyAdded')}
20+
moreRoute={ROUTES.ALBUMS.RECENTLY_ADDED}
21+
list={data.list}
22+
/>
23+
)
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useTranslation } from 'react-i18next'
2+
import { PreviewListFallback } from '@/app/components/fallbacks/home-fallbacks'
3+
import { useGetRecentlyPlayed } from '@/app/hooks/use-home'
4+
import { ROUTES } from '@/routes/routesList'
5+
import PreviewList from './preview-list'
6+
7+
export function RecentlyPlayed() {
8+
const { t } = useTranslation()
9+
const { data, isLoading } = useGetRecentlyPlayed()
10+
11+
if (isLoading) {
12+
return <PreviewListFallback />
13+
}
14+
15+
if (!data || !data.list || data.list.length === 0) return null
16+
17+
return (
18+
<PreviewList
19+
title={t('home.recentlyPlayed')}
20+
moreRoute={ROUTES.ALBUMS.RECENTLY_PLAYED}
21+
list={data.list}
22+
/>
23+
)
24+
}

src/app/components/player/player.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ const MemoPlayerExpandButton = memo(PlayerExpandButton)
4545
const MemoPodcastPlaybackRate = memo(PodcastPlaybackRate)
4646
const MemoLyricsButton = memo(PlayerLyricsButton)
4747
const MemoMiniPlayerButton = memo(MiniPlayerButton)
48-
const MemoAudioPlayer = memo(AudioPlayer)
4948

5049
export function Player() {
5150
const audioRef = useRef<HTMLAudioElement>(null)
@@ -237,7 +236,7 @@ export function Player() {
237236
</div>
238237

239238
{isSong && song && (
240-
<MemoAudioPlayer
239+
<AudioPlayer
241240
replayGain={trackReplayGain}
242241
src={getSongStreamUrl(song.id)}
243242
autoPlay={isPlaying}
@@ -254,7 +253,7 @@ export function Player() {
254253
)}
255254

256255
{isRadio && radio && (
257-
<MemoAudioPlayer
256+
<AudioPlayer
258257
src={radio.streamUrl}
259258
autoPlay={isPlaying}
260259
audioRef={radioRef}
@@ -266,7 +265,7 @@ export function Player() {
266265
)}
267266

268267
{isPodcast && podcast && (
269-
<MemoAudioPlayer
268+
<AudioPlayer
270269
src={getProxyURL(podcast.audio_url)}
271270
autoPlay={isPlaying}
272271
audioRef={podcastRef}

src/app/components/player/progress.tsx

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,10 @@
11
import clsx from 'clsx'
2-
import {
3-
RefObject,
4-
useCallback,
5-
useEffect,
6-
useMemo,
7-
useRef,
8-
useState,
9-
} from 'react'
2+
import { RefObject, useCallback, useEffect, useMemo, useState } from 'react'
103
import { ProgressSlider } from '@/app/components/ui/slider'
114
import { podcasts } from '@/service/podcasts'
12-
import { subsonic } from '@/service/subsonic'
135
import {
146
usePlayerActions,
157
usePlayerDuration,
16-
usePlayerIsPlaying,
178
usePlayerMediaType,
189
usePlayerProgress,
1910
usePlayerSonglist,
@@ -31,13 +22,10 @@ export function PlayerProgress({ audioRef }: PlayerProgressProps) {
3122
const progress = usePlayerProgress()
3223
const [localProgress, setLocalProgress] = useState(progress)
3324
const currentDuration = usePlayerDuration()
34-
const isPlaying = usePlayerIsPlaying()
35-
const { currentSong, currentList, podcastList, currentSongIndex } =
36-
usePlayerSonglist()
25+
const { currentList, podcastList, currentSongIndex } = usePlayerSonglist()
3726
const { isSong, isPodcast } = usePlayerMediaType()
3827
const { setProgress, setUpdatePodcastProgress, getCurrentPodcastProgress } =
3928
usePlayerActions()
40-
const isScrobbleSentRef = useRef(false)
4129

4230
const isEmpty = isSong && currentList.length === 0
4331

@@ -77,44 +65,6 @@ export function PlayerProgress({ audioRef }: PlayerProgressProps) {
7765
[currentDuration],
7866
)
7967

80-
const sendScrobble = useCallback(async (songId: string) => {
81-
await subsonic.scrobble.send(songId)
82-
}, [])
83-
84-
const progressTicks = useRef(0)
85-
86-
useEffect(() => {
87-
if (isSeeking || !isPlaying) {
88-
return
89-
}
90-
if (isSong) {
91-
const progressPercentage = (progress / currentDuration) * 100
92-
93-
if (progressPercentage === 0) {
94-
isScrobbleSentRef.current = false
95-
progressTicks.current = 0
96-
} else {
97-
progressTicks.current += 1
98-
99-
if (
100-
(progressTicks.current >= currentDuration / 2 ||
101-
progressTicks.current >= 60 * 4) &&
102-
!isScrobbleSentRef.current
103-
) {
104-
sendScrobble(currentSong.id)
105-
isScrobbleSentRef.current = true
106-
}
107-
}
108-
}
109-
}, [
110-
progress,
111-
currentDuration,
112-
isSong,
113-
sendScrobble,
114-
currentSong.id,
115-
isPlaying,
116-
])
117-
11868
// Used to save listening progress to backend every 30 seconds
11969
useEffect(() => {
12070
if (!isPodcast || !podcastList) return

0 commit comments

Comments
 (0)