diff --git a/jm/src/findmaimaibotJM/__init__.py b/jm/src/findmaimaibotJM/__init__.py
index 6b66489..9bfcc24 100755
--- a/jm/src/findmaimaibotJM/__init__.py
+++ b/jm/src/findmaimaibotJM/__init__.py
@@ -58,17 +58,17 @@ from datetime import timedelta
cache_time = timedelta(days=3)
@app.get("/search/")
-@cache_result(cache_time)
+# @cache_result(cache_time)
def search_site(search_query: str, page: int = 1):
try:
page = client.search_site(search_query=search_query, page=page)
- results = [{"album_id": album_id, "title": title} for album_id, title in page]
+ results = [{"album_id": album_id, "name": title} for album_id, title in page]
return results
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/album/{album_id}/")
-@cache_result(cache_time)
+# @cache_result(cache_time)
def get_album_details(album_id: int):
try:
page = client.search_site(search_query=str(album_id))
@@ -77,6 +77,92 @@ def get_album_details(album_id: int):
image_urls = []
nums = []
# 遍历每个章节
+
+
+ for photo in album:
+ # 章节实体类
+ photo_detail = client.get_photo_detail(photo.photo_id, False)
+
+ # 遍历每个图片
+ for image in photo_detail:
+ # 图片实体类
+ image_urls.append(image.img_url)
+ nums.append(JmImageTool.get_num_by_url(image.scramble_id, image.img_url))
+
+ return {
+ "album_id": album.album_id,
+ "scramble_id": album.scramble_id,
+ "name": album.name,
+ "page_count": album.page_count,
+ "pub_date": album.pub_date,
+ "update_date": album.update_date,
+ "likes": album.likes,
+ "views": album.views,
+ "comment_count": album.comment_count,
+ "works": album.works,
+ "actors": album.actors,
+ "authors": album.authors,
+ "tags": album.tags,
+ "related_list": album.related_list,
+ "episode_list": album.episode_list,
+ "image_urls": image_urls,
+ "nums": nums
+ }
+ except Exception as e:
+ raise HTTPException(status_code=400, detail=str(e))
+
+
+@app.get("/album/{album_id}/debug")
+# @cache_result(cache_time)
+def get_album_details(album_id: int):
+ try:
+ page = client.search_site(search_query=str(album_id))
+ album = page.single_album
+
+ # 输出调试信息到控制台
+ import json as json_module
+
+ # 创建简单的序列化函数,避免复杂对象导致的问题
+ def simple_serialize(obj):
+ if hasattr(obj, '__dict__'):
+ result = {}
+ for key, value in obj.__dict__.items():
+ try:
+ # 尝试直接序列化
+ json_module.dumps(value)
+ result[key] = value
+ except:
+ # 如果不能序列化,转换为字符串
+ result[key] = str(value)
+ return result
+ else:
+ return str(obj)
+
+ # 输出page和album的调试信息到控制台
+ print("=" * 50)
+ print("DEBUG: Page object")
+ print("=" * 50)
+ try:
+ print(json_module.dumps(simple_serialize(page), indent=2, ensure_ascii=False))
+ except Exception as e:
+ print(f"无法序列化page对象: {e}")
+ print(f"Page类型: {type(page)}")
+ print(f"Page属性: {[attr for attr in dir(page) if not attr.startswith('_')]}")
+
+ print("\n" + "=" * 50)
+ print("DEBUG: Album object")
+ print("=" * 50)
+ try:
+ print(json_module.dumps(simple_serialize(album), indent=2, ensure_ascii=False))
+ except Exception as e:
+ print(f"无法序列化album对象: {e}")
+ print(f"Album类型: {type(album)}")
+ print(f"Album属性: {[attr for attr in dir(album) if not attr.startswith('_')]}")
+
+ # 存储所有图片的URL
+ image_urls = []
+ nums = []
+ # 遍历每个章节
for photo in album:
# 章节实体类
photo_detail = client.get_photo_detail(photo.photo_id, False)
@@ -110,57 +196,8 @@ def get_album_details(album_id: int):
raise HTTPException(status_code=400, detail=str(e))
-@app.get("/album/{album_id}/chapters/")
-@cache_result(cache_time)
-def get_album_chapters_paginated(album_id: int, page: int = 1, per_page: int = 5):
- """
- 分页获取专辑章节列表
- :param album_id: 专辑ID
- :param page: 页码(从1开始)
- :param per_page: 每页章节数
- """
- try:
- page_result = client.search_site(search_query=str(album_id))
- album = page_result.single_album
-
- # 计算分页信息
- total_chapters = len(album.photos)
- total_pages = (total_chapters + per_page - 1) // per_page # 向上取整
-
- if page < 1 or page > total_pages:
- raise HTTPException(status_code=404, detail="Page out of range")
-
- # 计算当前页的章节范围
- start_index = (page - 1) * per_page
- end_index = min(start_index + per_page, total_chapters)
-
- # 获取当前页的章节信息
- chapters = []
- for i in range(start_index, end_index):
- photo = album.photos[i]
- chapters.append({
- "chapter_index": i,
- "chapter_id": photo.photo_id,
- "title": photo.name,
- "page_count": photo.page_count,
- "pub_date": photo.pub_date
- })
-
- return {
- "album_id": album.album_id,
- "album_name": album.name,
- "current_page": page,
- "per_page": per_page,
- "total_chapters": total_chapters,
- "total_pages": total_pages,
- "chapters": chapters
- }
- except Exception as e:
- raise HTTPException(status_code=400, detail=str(e))
-
-
@app.get("/fast/{album_id}/")
-# @cache_result(cache_time)
+@cache_result(cache_time)
def get_album_details(album_id: int):
try:
page = client.search_site(search_query=str(album_id))
diff --git a/reijm-read/index.html b/reijm-read/index.html
index 8446fa6..8bc58d8 100644
--- a/reijm-read/index.html
+++ b/reijm-read/index.html
@@ -7,24 +7,24 @@
Powered by Reisa
-
-
+
+
-
-
+
+
-
+
-
-
-
+
+
+
@@ -35,7 +35,7 @@
{
"@context": "https://schema.org",
"@type": "Organization",
- "name": " Powered by Reisa",
+ "name": " Powered by ReiJM",
"url": "https://www.godserver.cn",
"logo": "/src/assets/logo.png",
"sameAs": ["https://github.com/Spaso1", "https://twitter.com/Spaso1"]
diff --git a/reijm-read/src/components/layout/TheHeader.vue b/reijm-read/src/components/layout/TheHeader.vue
index 07561c3..a8f441d 100644
--- a/reijm-read/src/components/layout/TheHeader.vue
+++ b/reijm-read/src/components/layout/TheHeader.vue
@@ -85,7 +85,7 @@ const toggleMenu = () => {
- Union
+ ReiJM
diff --git a/reijm-read/src/config/site.ts b/reijm-read/src/config/site.ts
index fc250d7..1e0c1e1 100644
--- a/reijm-read/src/config/site.ts
+++ b/reijm-read/src/config/site.ts
@@ -1,6 +1,6 @@
export const siteConfig = {
// 基本信息
- name: "Powered by Reisa", // 作者名称
+ name: "Re", // 作者名称
title: "FindMaimaiDX开发者 学生", // 职位头衔
siteName: "ReisaSpasol | MaimaiDX", // 网站标题
siteDescription:
diff --git a/reijm-read/src/views/HomeView.vue b/reijm-read/src/views/HomeView.vue
index a658331..87bc8ed 100644
--- a/reijm-read/src/views/HomeView.vue
+++ b/reijm-read/src/views/HomeView.vue
@@ -1,17 +1,581 @@
-
+
+
+
+
+
+
+
![]()
{
+ const target = $event.target as HTMLImageElement;
+ if (album.image_urls && album.image_urls.length > 0) {
+ target.src = album.image_urls[0];
+ }
+ }"
+ />
+
加载中...
+
+
+
{{ album.name }}
+
+ 作者: {{ album.authors.join(', ') }}
+
+
+
+ {{ tag }}
+
+
+
+
+
+
+
+
+
+
diff --git a/reijm-read/src/views/Manga.vue b/reijm-read/src/views/Manga.vue
index 765d3e1..ee8a588 100644
--- a/reijm-read/src/views/Manga.vue
+++ b/reijm-read/src/views/Manga.vue
@@ -3,8 +3,10 @@
import { ref, onMounted, onUnmounted, computed, watch } from 'vue'
import { useRoute } from 'vue-router'
import axios from 'axios'
+import router from "@/router";
const route = useRoute()
+const token = localStorage.getItem('token')
// 漫画专辑数据
interface AlbumData {
@@ -25,7 +27,7 @@ const albumInfo = ref | null>(null)
const showMenu = ref(false)
const isFullscreen = ref(false)
const showDrawer = ref(false)
-const currentImageIndex = ref(0) // 当前显示的图片索引
+let currentImageIndex = ref(0) // 当前显示的图片索引
const imageStates = ref>([])
const loading = ref(true)
const canvasImages = ref([]) // 解码后的图片
@@ -35,6 +37,20 @@ const abortLoading = ref(false) // 取消加载标志
const shouldHideHeader = computed(() => {
return route.meta?.hideHeader === true
})
+// 在现有代码中添加新的函数
+const reportReadManga = async (mangaId: string, index: number) => {
+ try {
+ await axios.post('/api/manga/read', {}, {
+ headers: {
+ Token: token || '',
+ mangaId: mangaId,
+ index: index.toString()
+ }
+ });
+ } catch (error) {
+ console.error('上报阅读进度失败:', error);
+ }
+}
// 计算当前页码信息
const currentPageInfo = computed(() => {
@@ -51,10 +67,12 @@ const fetchAlbum = async (id: string) => {
try {
loading.value = true
- console.log('发送请求到:', `/api/manga/read?mangaId=${id}`)
const response = await axios.get(`/api/manga/read?mangaId=${id}`, {
maxRedirects: 5,
validateStatus: (status) => status < 500,
+ headers: {
+ Token: `${token}`
+ }
})
console.log('收到响应:', response)
@@ -96,6 +114,9 @@ const fetchAlbum = async (id: string) => {
} else {
loading.value = false
}
+ scrollToImage(data.readIndex)
+ currentImageIndex.value = data.readIndex
+ console.log(currentImageIndex.value)
} catch (error) {
console.error('加载专辑失败', error)
loading.value = false
@@ -286,7 +307,7 @@ const handleTouchMove = (index: number, event: TouchEvent) => {
}
}
-// 处理滚轮缩放(仅鼠标滚轮)
+// 处理滚轮缩放(以鼠标位置为中心点缩放)
const handleWheel = (index: number, event: WheelEvent) => {
// 确保是鼠标滚轮事件而不是触摸板手势
if (Math.abs(event.deltaX) > Math.abs(event.deltaY) * 2) {
@@ -297,15 +318,50 @@ const handleWheel = (index: number, event: WheelEvent) => {
event.preventDefault()
const currentState = imageStates.value[index]
+ // 获取图片元素
+ const imgElement = document.getElementById(`image-${index}`)?.querySelector('.manga-image')
+ if (!imgElement) return
+
+ // 计算鼠标在图片中的相对位置
+ const rect = imgElement.getBoundingClientRect()
+ const mouseX = event.clientX - rect.left
+ const mouseY = event.clientY - rect.top
+
+ // 计算当前鼠标位置相对于图片中心的偏移(减小移动幅度)
+ const centerX = rect.width / 2.7
+ const centerY = rect.height / 2.5
+ const offsetX = (mouseX - centerX) * 0.4 // 减少移动幅度
+ const offsetY = (mouseY - centerY) * 0.4 // 减少移动幅度
+
if (event.deltaY < 0) {
// 向上滚动放大
if (currentState.scale < 3) {
- currentState.scale *= 1.1
+ const newScale = currentState.scale * 1.1
+ const scaleRatio = newScale / currentState.scale
+
+ // 以鼠标位置为中心进行缩放(减小位移)
+ const newTranslateX = currentState.translateX - offsetX * (scaleRatio - 1)
+ const newTranslateY = currentState.translateY - offsetY * (scaleRatio - 1)
+
+ currentState.scale = newScale
+ currentState.translateX = newTranslateX
+ currentState.translateY = newTranslateY
}
} else {
// 向下滚动缩小
if (currentState.scale > 1) {
- currentState.scale /= 1.1
+ const newScale = currentState.scale / 1.1
+ const scaleRatio = newScale / currentState.scale
+
+ // 以鼠标位置为中心进行缩放(减小位移)
+ const newTranslateX = currentState.translateX - offsetX * (scaleRatio - 1)
+ const newTranslateY = currentState.translateY - offsetY * (scaleRatio - 1)
+
+ currentState.scale = newScale
+ currentState.translateX = newTranslateX
+ currentState.translateY = newTranslateY
+
+ // 如果缩放到原始大小,重置位置
if (currentState.scale <= 1) {
currentState.scale = 1
currentState.translateX = 0
@@ -381,6 +437,10 @@ const handleScroll = () => {
}
}
+const back = () => {
+ router.push('/')
+}
+
// 使用节流优化滚动处理
const throttledHandleScroll = throttle(handleScroll, 100)
@@ -416,9 +476,31 @@ watch(
},
{ immediate: true }
)
+let refreshInterval: number | null = null;
+// 新增:刷新token的函数
+const refreshToken = async () => {
+ try {
+ const token = localStorage.getItem('token');
+ if (!token) return;
+
+ const response = await axios.post('/api/user/ref', {
+ data: token,
+ timestamp: Date.now()
+ }, {
+ headers: {
+ 'Token' : token,
+ 'Content-Type': 'application/json'
+ }
+ });
+ } catch (error) {
+ console.error('Refresh token failed:', error);
+ }
+};
// 组件挂载时添加事件监听器
onMounted(() => {
+ refreshInterval = window.setInterval(refreshToken, 30000);
+
window.addEventListener('keydown', handleKeydown)
// 直接监听 manga-reader 元素的滚动事件,而不是 manga-content
const mangaReader = document.querySelector('.manga-reader')
@@ -429,6 +511,16 @@ onMounted(() => {
// 初始化当前图片索引
handleScroll()
})
+// 替换现有的 watch 监听器
+watch([currentImageIndex, loading, mangaImages], ([newIndex, isLoading, images]) => {
+ // 只有在非加载状态且索引有效时才发送请求
+ if (albumInfo.value && !isLoading && newIndex >= 0 &&
+ newIndex < images.length) {
+ reportReadManga(albumInfo.value.album_id, newIndex);
+ }
+});
+
+
// 组件卸载时移除事件监听器
onUnmounted(() => {
@@ -446,10 +538,10 @@ onUnmounted(() => {
@click="toggleMenu"
:class="{ 'no-header': shouldHideHeader }">
-
-
-
-
+
+
+
+
{
>