From b17e9dea28fde0b12d8ef0befab2dfe3f9c18e30 Mon Sep 17 00:00:00 2001
From: eson <474420502@qq.com>
Date: Thu, 14 Aug 2025 00:28:29 +0800
Subject: [PATCH] update
---
server/handler.go | 144 +++++++++++++--------------------
server/main.go | 5 +-
server/movie.go | 4 +-
src/Main.jsx | 59 +++++---------
src/components/VideoPlayer.jsx | 30 +++----
5 files changed, 100 insertions(+), 142 deletions(-)
diff --git a/server/handler.go b/server/handler.go
index 230ecb0..6eea1c1 100644
--- a/server/handler.go
+++ b/server/handler.go
@@ -3,102 +3,20 @@ package main
import (
"log"
"net/http"
- "sort"
"strconv"
"strings"
+ "sort"
"github.com/gin-gonic/gin"
)
-// 重命名电影的处理函数
-func PostRename(c *gin.Context) {
- response := gin.H{
- "code": http.StatusInternalServerError,
- "message": "An unexpected error occurred.",
- }
-
- // 定义请求结构体
- type RenameRequest struct {
- OldName string `json:"old_name" binding:"required"`
- NewName string `json:"new_name" binding:"required"`
- }
-
- var req RenameRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- response["code"] = http.StatusBadRequest
- response["message"] = "Invalid request body: " + err.Error()
- c.JSON(http.StatusBadRequest, response)
- return
- }
-
- oldName := req.OldName
- newName := req.NewName
-
- if oldName == "" || newName == "" {
- response["code"] = http.StatusBadRequest
- response["message"] = "Old name and new name are required."
- c.JSON(http.StatusBadRequest, response)
- return
- }
-
- if oldName == newName {
- response["code"] = http.StatusBadRequest
- response["message"] = "Old name and new name cannot be the same."
- c.JSON(http.StatusBadRequest, response)
- return
- }
-
- MovieDictLock.Lock()
- defer MovieDictLock.Unlock()
-
- // 检查新名称是否已存在
- if _, exists := MovieDict[newName]; exists {
- response["code"] = http.StatusConflict
- response["message"] = "New name already exists."
- c.JSON(http.StatusConflict, response)
- return
- }
-
- // 查找旧名称对应的电影
- movie, exists := MovieDict[oldName]
- if exists {
- // 更新电影信息
- err := movie.RenameVideo(newName) // 重命名视频文件
- if err != nil {
- response["code"] = http.StatusInternalServerError
- response["message"] = "Failed to rename video file."
- c.JSON(http.StatusInternalServerError, response)
- return
- }
-
- delete(MovieDict, oldName) // 删除旧名称的条目
- MovieDict[newName] = movie // 添加新名称的条目
-
- response["code"] = http.StatusOK
- response["message"] = "Movie renamed successfully."
- response["data"] = gin.H{"old_name": oldName, "new_name": newName}
- c.JSON(http.StatusOK, response)
- log.Printf("Movie renamed from %s to %s successfully", oldName, newName)
- return
- }
-
- // 如果旧名称不存在,返回404错误
- response["code"] = http.StatusNotFound
- response["message"] = "Movie not found."
- c.JSON(http.StatusNotFound, response)
- log.Printf("Movie rename failed: %s not found", oldName)
-}
-
+// GetCategoryList 获取分类列表
func GetCategoryList(c *gin.Context) {
response := gin.H{
- "code": http.StatusInternalServerError,
- "message": "An unexpected error occurred.",
- "data": []string{},
+ "code": http.StatusOK,
+ "message": "Success",
+ "data": Categories,
}
-
- response["code"] = http.StatusOK
- response["message"] = "Success"
- response["data"] = Categories
c.JSON(http.StatusOK, response)
}
@@ -227,3 +145,55 @@ func MovieList(c *gin.Context) {
response["data"] = responseData
c.JSON(http.StatusOK, response)
}
+
+// PostRename 重命名文件
+func PostRename(c *gin.Context) {
+ var requestData struct {
+ OldName string `json:"old_name"`
+ NewName string `json:"new_name"`
+ }
+
+ response := gin.H{
+ "code": http.StatusOK,
+ "message": "Success",
+ "data": nil,
+ }
+
+ if err := c.ShouldBindJSON(&requestData); err != nil {
+ response["code"] = http.StatusBadRequest
+ response["message"] = "Invalid request data: " + err.Error()
+ c.JSON(http.StatusBadRequest, response)
+ return
+ }
+
+ if requestData.OldName == "" || requestData.NewName == "" {
+ response["code"] = http.StatusBadRequest
+ response["message"] = "Both old_name and new_name are required"
+ c.JSON(http.StatusBadRequest, response)
+ return
+ }
+
+ // 查找要重命名的电影
+ movie, exists := MovieDict[requestData.OldName]
+ if !exists {
+ response["code"] = http.StatusNotFound
+ response["message"] = "Movie not found"
+ c.JSON(http.StatusNotFound, response)
+ return
+ }
+
+ // 执行重命名
+ if err := movie.RenameVideo(requestData.NewName); err != nil {
+ response["code"] = http.StatusInternalServerError
+ response["message"] = "Failed to rename video: " + err.Error()
+ c.JSON(http.StatusInternalServerError, response)
+ return
+ }
+
+ // 更新全局字典
+ delete(MovieDict, requestData.OldName)
+ MovieDict[requestData.NewName] = movie
+
+ response["message"] = "Rename successful"
+ c.JSON(http.StatusOK, response)
+}
\ No newline at end of file
diff --git a/server/main.go b/server/main.go
index 2142a47..606197f 100644
--- a/server/main.go
+++ b/server/main.go
@@ -10,6 +10,9 @@ import (
func main() {
initMovie()
+ // 设置为发布模式
+ gin.SetMode(gin.ReleaseMode)
+
eg := gin.Default()
eg.Use(Cors())
eg.Static("/res", "movie/")
@@ -37,4 +40,4 @@ func main() {
movie.POST("/rename", PostRename)
eg.Run("0.0.0.0:4444")
-}
+}
\ No newline at end of file
diff --git a/server/movie.go b/server/movie.go
index 0094974..4783878 100644
--- a/server/movie.go
+++ b/server/movie.go
@@ -75,7 +75,7 @@ var Movies []*Movie // 存储所有电影信息的全局切
var MovieDict = make(map[string]*Movie) // 存储需要处理缩略图的视频字典
var MovieDictLock sync.Mutex // 保护MovieDict的并发访问
-var IsRemakePNG = true // 是否重新生成所有PNG缩略图
+var IsRemakePNG = false // 是否重新生成所有PNG缩略图
var Categories = []string{ // 分类
"15min", "30min", "60min", "大于60min", "最新添加"}
@@ -331,4 +331,4 @@ func markRecentMovies() {
for i := 0; i < len(Movies) && i < 20; i++ {
Movies[i].TimeCategory = "最新添加"
}
-}
+}
\ No newline at end of file
diff --git a/src/Main.jsx b/src/Main.jsx
index a10b713..8e32fcb 100644
--- a/src/Main.jsx
+++ b/src/Main.jsx
@@ -1,9 +1,10 @@
+// ...existing code...
import React, { useState, useEffect, useContext, useCallback, useRef } from 'react';
import axios from 'axios';
import Container from '@mui/material/Container';
import Grid from '@mui/material/Grid';
import Pagination from '@mui/material/Pagination';
-import { Link } from 'react-router-dom'; // useLocation removed as not directly used for this fix
+import { Link } from 'react-router-dom';
import CircularProgress from '@mui/material/CircularProgress';
import TextField from '@mui/material/TextField';
import InputAdornment from '@mui/material/InputAdornment';
@@ -11,9 +12,10 @@ import IconButton from '@mui/material/IconButton';
import SearchIcon from '@mui/icons-material/Search';
import ClearIcon from '@mui/icons-material/Clear';
-import ConfigContext from './Config'; // Ensure this path is correct
-import MovieCard from './components/MovieCard'; // Ensure this path is correct
-import CategoryNav from './components/CategoryNav'; // Ensure this path is correct
+import ConfigContext from './Config';
+import MovieCard from './components/MovieCard';
+import CategoryNav from './components/CategoryNav';
+// ...existing code...
// 分类配置
const categories = [
@@ -71,9 +73,9 @@ const Main = () => {
]),
});
- const isMounted = useRef(false);
- const isPopStateNav = useRef(false);
const scrollTimeoutRef = useRef(null);
+ const isPopStateNav = useRef(false);
+ const isMounted = useRef(false);
const fetchMovies = useCallback(async (category, page, search = '', options = {}) => {
setLoading(true);
@@ -114,7 +116,7 @@ const Main = () => {
isPopStateNav.current = false;
}
// IMPORTANT: Removed duplicated scroll logic block that was here
- }, []); // No dependencies that change frequently, setPersistedParams is stable
+ }, [isPopStateNav]);
const navigateAndFetch = useCallback((newCategory, newPage, newSearchQuery = '', options = {}) => {
const { replace = false, preserveScroll = false, isPopStatePaging = false } = options;
@@ -122,33 +124,25 @@ const Main = () => {
setActiveCategory(newCategory);
setCurrentPage(newPage);
setActiveSearchQuery(newSearchQuery);
+
if (newCategory === SEARCH_CATEGORY) {
setSearchInput(newSearchQuery);
} else {
setSearchInput('');
}
- // Determine scroll position for history state
- // If preserving scroll, use current window.scrollY or a remembered scroll for the target category if available
- // Otherwise, new navigations (not popstate) typically scroll to 0 unless specified.
- let scrollForHistory = 0;
- if (preserveScroll) {
- // For general preserveScroll (like back/fwd), use current scrollY.
- // For specific category change restorations, this might be overridden by options.restoreScrollPos in fetchMovies.
- scrollForHistory = window.history.state?.appState?.scrollPos || window.scrollY;
- }
- // If navigating to a category with a known scroll position, that should be prioritized for restoration.
- // This is handled by passing restoreScrollPos to fetchMovies. For history state, use `scrollForHistory`.
-
+ const scrollForHistory = preserveScroll
+ ? (window.history.state?.appState?.scrollPos || window.scrollY)
+ : 0;
const historyState = {
category: newCategory,
page: newPage,
searchQuery: newSearchQuery,
- scrollPos: scrollForHistory, // This is the scroll position *at the moment of navigation*
+ scrollPos: scrollForHistory,
};
- const url = window.location.pathname; // Keep URL simple, no query params in URL itself for now
+ const url = window.location.pathname;
const browserHistoryState = window.history.state?.appState;
const needsPush = !browserHistoryState ||
browserHistoryState.category !== newCategory ||
@@ -168,14 +162,14 @@ const Main = () => {
if (oldCategoryState && oldCategoryState !== newCategory) {
newCategoryHistory[oldCategoryState] = {
...newCategoryHistory[oldCategoryState],
- scrollPos: window.scrollY, // Save scroll of category being left
+ scrollPos: window.scrollY,
};
}
newCategoryHistory[newCategory] = {
...newCategoryHistory[newCategory],
lastPage: newPage,
- scrollPos: scrollForHistory, // Store the scroll we intend to be at for the new state
+ scrollPos: scrollForHistory,
...(newCategory === SEARCH_CATEGORY && { searchQuery: newSearchQuery }),
};
@@ -185,20 +179,11 @@ const Main = () => {
};
});
- // Determine scroll position for fetching movies
- // If preserving scroll, it means we want to restore to where we were or a specific point
- let scrollPosForFetch = scrollForHistory; // Default to the scrollForHistory calculated
- if (!preserveScroll) { // If not preserving, new main navigations usually go to top
- scrollPosForFetch = 0;
- }
- // If navigating to a category and it has a specific remembered scroll, that should be preferred
- // This part becomes complex if we want category changes to always restore *their* scroll.
- // For now, `preserveScroll` will try to keep `window.scrollY`, otherwise `0`.
- // PopState correctly restores its specific scroll.
+ const scrollPosForFetch = preserveScroll ? scrollForHistory : 0;
fetchMovies(newCategory, newPage, newSearchQuery, {
restoreScrollPos: scrollPosForFetch,
- skipScrollRestore: false, // Allow fetchMovies to handle scroll unless explicitly told otherwise later
+ skipScrollRestore: false,
isPopStatePaging: isPopStatePaging,
});
}, [fetchMovies, setPersistedParams]);
@@ -268,7 +253,7 @@ const Main = () => {
clearTimeout(scrollTimeoutRef.current);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [navigateAndFetch, setPersistedParams]); // Removed fetchMovies as navigateAndFetch calls it.
+ }, [navigateAndFetch, setPersistedParams]);
useEffect(() => {
const handleScroll = () => {
@@ -306,7 +291,7 @@ const Main = () => {
window.removeEventListener('scroll', handleScroll);
clearTimeout(scrollTimeoutRef.current);
};
- }, [loading, movies.length, setPersistedParams]);
+ }, [loading, movies.length, setPersistedParams, isPopStateNav, scrollTimeoutRef]);
const handleCategoryChange = useCallback((newCategory) => {
@@ -422,7 +407,7 @@ const Main = () => {
setActiveSearchQuery('');
setPersistedParams(prev => ({ ...prev, lastKnownState: { ...prev.lastKnownState, searchQuery: '' } }));
}
- }, [activeCategory, navigateAndFetch, persistedParams.categoryHistory, setPersistedParams, fetchMovies]);
+ }, [activeCategory, persistedParams.categoryHistory, setPersistedParams, fetchMovies]);
// MODIFIED handleRename
diff --git a/src/components/VideoPlayer.jsx b/src/components/VideoPlayer.jsx
index 5630dd5..a77776c 100644
--- a/src/components/VideoPlayer.jsx
+++ b/src/components/VideoPlayer.jsx
@@ -122,30 +122,30 @@ const VideoPlayer = () => {
file: {
attributes: {
playsInline: true, // 重要:移动端内联播放
- preload: 'metadata'
+ preload: 'metadata',
+ disablePictureInPicture: true // 禁用画中画模式
}
}
}}
style={{
maxWidth: '100%',
- maxHeight: '100%'
+ maxHeight: '100%',
+ margin: 'auto' // 居中显示
}}
/>
- {/* 底部信息(仅桌面端显示) */}
- {!isMobile && (
-
-
- 提示:双击视频可全屏播放
-
-
- )}
+ {/* 底部信息(移动端显示简化提示) */}
+
+
+ {isMobile ? '双击可全屏' : '提示:双击视频可全屏播放'}
+
+
);
};