Add files via upload

This commit is contained in:
Savsis 2026-04-27 21:01:17 +05:00 • committed by GitHub
commit 675493bafc
28 changed files with 2176 additions and 0 deletions

96
hooks/useAudio.ts Normal file
View file

@ -0,0 +1,96 @@
import { useEffect, useRef, useCallback } from 'react';
import { Audio, AVPlaybackStatus } from 'expo-av';
import { usePlayer } from '../store';
let _sound: Audio.Sound | null = null;
// Module-level singleton so the sound survives re-renders
export async function getSound() { return _sound; }
export function useAudio() {
const initialized = useRef(false);
const {
queue, index, playing,
setPlaying, setProgress, setDuration,
nextTrack, setIndex, repeat,
} = usePlayer();
const currentTrack = queue[index] ?? null;
// Init audio session once
useEffect(() => {
if (initialized.current) return;
initialized.current = true;
Audio.setAudioModeAsync({
staysActiveInBackground: true,
playsInSilentModeIOS: true,
interruptionModeIOS: 1,
shouldDuckAndroid: true,
});
}, []);
// Load new track whenever index/id changes
useEffect(() => {
if (!currentTrack) return;
const load = async () => {
// Unload previous
if (_sound) {
await _sound.stopAsync().catch(() => {});
await _sound.unloadAsync().catch(() => {});
_sound = null;
}
const { sound } = await Audio.Sound.createAsync(
{ uri: currentTrack.stream_url },
{ shouldPlay: true, progressUpdateIntervalMillis: 500 },
(status: AVPlaybackStatus) => {
if (!status.isLoaded) return;
setProgress(status.positionMillis / 1000);
setDuration((status.durationMillis ?? 0) / 1000);
if (status.isPlaying !== usePlayer.getState().playing) {
setPlaying(status.isPlaying);
}
if (status.didJustFinish) {
const state = usePlayer.getState();
const ni = state.nextTrack();
if (ni !== state.index || state.repeat === 2) {
setIndex(ni);
} else {
setPlaying(false);
}
}
},
);
_sound = sound;
};
load().catch(console.error);
}, [currentTrack?.id]);
const togglePlay = useCallback(async () => {
if (!_sound) return;
const status = await _sound.getStatusAsync();
if (!status.isLoaded) return;
if (status.isPlaying) {
await _sound.pauseAsync();
} else {
await _sound.playAsync();
}
}, []);
const seek = useCallback(async (seconds: number) => {
if (!_sound) return;
await _sound.setPositionAsync(seconds * 1000);
}, []);
// Cleanup on unmount
useEffect(() => {
return () => {
_sound?.unloadAsync().catch(() => {});
_sound = null;
};
}, []);
return { togglePlay, seek };
}

27
hooks/useAuth.ts Normal file
View file

@ -0,0 +1,27 @@
import { useEffect } from 'react';
import { getAccessToken, getMe, clearTokens } from '../services/api';
import { useAuth } from '../store';
export function useBootAuth() {
const { setUser, setReady } = useAuth();
useEffect(() => {
(async () => {
try {
const token = await getAccessToken();
if (!token) { setReady(true); return; }
const me = await getMe();
setUser(me);
} catch {
// ignore
} finally {
setReady(true);
}
})();
}, []);
}
export async function logout() {
await clearTokens();
useAuth.getState().setUser(null);
}