mirror of
https://github.com/zimplexing/OrionTV.git
synced 2026-05-23 02:50:42 +08:00
feat: enhance PlayScreen and VideoCard with improved video loading and app state handling; update player store for better episode management
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { create } from "zustand";
|
||||
import Cookies from "@react-native-cookies/cookies";
|
||||
import { api, ServerConfig } from "@/services/api";
|
||||
import { api } from "@/services/api";
|
||||
|
||||
interface AuthState {
|
||||
isLoggedIn: boolean;
|
||||
|
||||
@@ -17,7 +17,7 @@ interface DetailState {
|
||||
controller: AbortController | null;
|
||||
isFavorited: boolean;
|
||||
|
||||
init: (q: string, preferredSource?: string, id?: string) => void;
|
||||
init: (q: string, preferredSource?: string, id?: string) => Promise<void>;
|
||||
setDetail: (detail: SearchResultWithResolution) => void;
|
||||
abort: () => void;
|
||||
toggleFavorite: () => Promise<void>;
|
||||
|
||||
@@ -119,7 +119,7 @@ const useHomeStore = create<HomeState>((set, get) => ({
|
||||
play_time: record.play_time,
|
||||
};
|
||||
})
|
||||
.filter((record) => record.progress !== undefined && record.progress > 0 && record.progress < 1)
|
||||
// .filter((record) => record.progress !== undefined && record.progress > 0 && record.progress < 1)
|
||||
.sort((a, b) => (b.lastPlayed || 0) - (a.lastPlayed || 0));
|
||||
|
||||
set({ contentData: rowItems, hasMore: false });
|
||||
|
||||
@@ -27,7 +27,7 @@ interface PlayerState {
|
||||
introEndTime?: number;
|
||||
outroStartTime?: number;
|
||||
setVideoRef: (ref: RefObject<Video>) => void;
|
||||
loadVideo: (source: string, episodeIndex: number, position?: number) => Promise<void>;
|
||||
loadVideo: (options: {source: string, id: string, title: string; episodeIndex: number, position?: number}) => Promise<void>;
|
||||
playEpisode: (index: number) => void;
|
||||
togglePlayPause: () => void;
|
||||
seek: (duration: number) => void;
|
||||
@@ -48,7 +48,7 @@ interface PlayerState {
|
||||
const usePlayerStore = create<PlayerState>((set, get) => ({
|
||||
videoRef: null,
|
||||
episodes: [],
|
||||
currentEpisodeIndex: 0,
|
||||
currentEpisodeIndex: -1,
|
||||
status: null,
|
||||
isLoading: true,
|
||||
showControls: false,
|
||||
@@ -65,22 +65,31 @@ const usePlayerStore = create<PlayerState>((set, get) => ({
|
||||
|
||||
setVideoRef: (ref) => set({ videoRef: ref }),
|
||||
|
||||
loadVideo: async (source, episodeIndex, position) => {
|
||||
const detail = useDetailStore.getState().detail;
|
||||
const episodes = episodesSelectorBySource(source)(useDetailStore.getState());
|
||||
|
||||
if (!detail || !episodes || episodes.length === 0) return;
|
||||
loadVideo: async ({ source, id, episodeIndex, position, title }) => {
|
||||
let detail = useDetailStore.getState().detail;
|
||||
let episodes = episodesSelectorBySource(source)(useDetailStore.getState());
|
||||
|
||||
set({
|
||||
isLoading: true,
|
||||
});
|
||||
|
||||
if (!detail || !episodes || episodes.length === 0 || detail.title !== title) {
|
||||
await useDetailStore.getState().init(title, source, id);
|
||||
detail = useDetailStore.getState().detail;
|
||||
episodes = episodesSelectorBySource(source)(useDetailStore.getState());
|
||||
if (!detail) {
|
||||
console.info("Detail not found after initialization");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const playRecord = await PlayRecordManager.get(detail.source, detail.id.toString());
|
||||
const initialPositionFromRecord = playRecord?.play_time ? playRecord.play_time * 1000 : 0;
|
||||
set({
|
||||
isLoading: false,
|
||||
currentEpisodeIndex: episodeIndex,
|
||||
initialPosition: position || 0,
|
||||
initialPosition: position || initialPositionFromRecord,
|
||||
episodes: episodes.map((ep, index) => ({
|
||||
url: ep,
|
||||
title: `第 ${index + 1} 集`,
|
||||
@@ -94,7 +103,7 @@ const usePlayerStore = create<PlayerState>((set, get) => ({
|
||||
}
|
||||
},
|
||||
|
||||
playEpisode: (index) => {
|
||||
playEpisode: async (index) => {
|
||||
const { episodes, videoRef } = get();
|
||||
if (index >= 0 && index < episodes.length) {
|
||||
set({
|
||||
@@ -104,27 +113,42 @@ const usePlayerStore = create<PlayerState>((set, get) => ({
|
||||
progressPosition: 0,
|
||||
seekPosition: 0,
|
||||
});
|
||||
videoRef?.current?.replayAsync();
|
||||
}
|
||||
},
|
||||
|
||||
togglePlayPause: () => {
|
||||
const { status, videoRef } = get();
|
||||
if (status?.isLoaded) {
|
||||
if (status.isPlaying) {
|
||||
videoRef?.current?.pauseAsync();
|
||||
} else {
|
||||
videoRef?.current?.playAsync();
|
||||
try {
|
||||
await videoRef?.current?.replayAsync();
|
||||
} catch (error) {
|
||||
console.error("Failed to replay video:", error);
|
||||
Toast.show({ type: "error", text1: "播放失败" });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
seek: (duration) => {
|
||||
togglePlayPause: async () => {
|
||||
const { status, videoRef } = get();
|
||||
if (status?.isLoaded) {
|
||||
try {
|
||||
if (status.isPlaying) {
|
||||
await videoRef?.current?.pauseAsync();
|
||||
} else {
|
||||
await videoRef?.current?.playAsync();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to toggle play/pause:", error);
|
||||
Toast.show({ type: "error", text1: "操作失败" });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
seek: async (duration) => {
|
||||
const { status, videoRef } = get();
|
||||
if (!status?.isLoaded || !status.durationMillis) return;
|
||||
|
||||
const newPosition = Math.max(0, Math.min(status.positionMillis + duration, status.durationMillis));
|
||||
videoRef?.current?.setPositionAsync(newPosition);
|
||||
try {
|
||||
await videoRef?.current?.setPositionAsync(newPosition);
|
||||
} catch (error) {
|
||||
console.error("Failed to seek video:", error);
|
||||
Toast.show({ type: "error", text1: "快进/快退失败" });
|
||||
}
|
||||
|
||||
set({
|
||||
isSeeking: true,
|
||||
@@ -202,10 +226,10 @@ const usePlayerStore = create<PlayerState>((set, get) => ({
|
||||
PlayRecordManager.save(detail.source, detail.id.toString(), {
|
||||
title: detail.title,
|
||||
cover: detail.poster || "",
|
||||
index: currentEpisodeIndex,
|
||||
index: currentEpisodeIndex + 1,
|
||||
total_episodes: episodes.length,
|
||||
play_time: status.positionMillis,
|
||||
total_time: status.durationMillis || 0,
|
||||
play_time: Math.floor(status.positionMillis / 1000),
|
||||
total_time: status.durationMillis ? Math.floor(status.durationMillis / 1000) : 0,
|
||||
source_name: detail.source_name,
|
||||
year: detail.year || "",
|
||||
...existingRecord,
|
||||
@@ -282,3 +306,9 @@ const usePlayerStore = create<PlayerState>((set, get) => ({
|
||||
}));
|
||||
|
||||
export default usePlayerStore;
|
||||
|
||||
export const selectCurrentEpisode = (state: PlayerState) => {
|
||||
if (state.episodes.length > state.currentEpisodeIndex) {
|
||||
return state.episodes[state.currentEpisodeIndex];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@ import { create } from "zustand";
|
||||
import { SettingsManager } from "@/services/storage";
|
||||
import { api, ServerConfig } from "@/services/api";
|
||||
import { storageConfig } from "@/services/storageConfig";
|
||||
// import useHomeStore from './homeStore';
|
||||
|
||||
interface SettingsState {
|
||||
apiBaseUrl: string;
|
||||
@@ -77,7 +76,7 @@ export const useSettingsStore = create<SettingsState>((set, get) => ({
|
||||
});
|
||||
api.setBaseUrl(apiBaseUrl);
|
||||
set({ isModalVisible: false });
|
||||
// useHomeStore.getState().fetchInitialData();
|
||||
await get().fetchServerConfig();
|
||||
},
|
||||
showModal: () => set({ isModalVisible: true }),
|
||||
hideModal: () => set({ isModalVisible: false }),
|
||||
|
||||
Reference in New Issue
Block a user