Ver Fonte

新增试看视频功能,更新主页和视频播放器组件以支持免费视频列表展示和播放,同时优化排序选项和样式,提升用户体验。更新service worker缓存版本以确保最新内容加载。

wuyi há 2 meses atrás
pai
commit
06d7edebf8
4 ficheiros alterados com 175 adições e 8 exclusões
  1. 1 1
      dev-dist/sw.js
  2. 54 0
      src/data/freeVideo.ts
  3. 74 4
      src/views/Home.vue
  4. 46 3
      src/views/VideoPlayer.vue

+ 1 - 1
dev-dist/sw.js

@@ -79,7 +79,7 @@ define(['./workbox-f2cb1a81'], (function (workbox) { 'use strict';
    */
   workbox.precacheAndRoute([{
     "url": "index.html",
-    "revision": "0.6qs42s98bgo"
+    "revision": "0.m57cp4vo8l8"
   }], {});
   workbox.cleanupOutdatedCaches();
   workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {

+ 54 - 0
src/data/freeVideo.ts

@@ -0,0 +1,54 @@
+/**
+ * 试看视频数据接口
+ */
+export interface FreeVideo {
+  id: string;
+  cover: string;
+  m3u8: string;
+  name: string;
+}
+
+/**
+ * 试看视频数据
+ */
+export const freeVideos: FreeVideo[] = [
+  {
+    id: "free-1",
+    cover: "https://cknz.t1mg0oa.com/ts4/2510/7NE42EETD31O/cover",
+    m3u8: "https://api.xmqspco.com//v/cTDMWpLWoPEwmn5Vn0l51Q.m3u8?user_id=605500911&plat_id=60005",
+    name: "MARAA-212_Himitsu-chan_是_H_杯___Himitsu-chan_与_Inst",
+  },
+  {
+    id: "free-2",
+    cover: "https://cknz.t1mg0oa.com/ts4/2510/7H1JO3C92O64/cover",
+    m3u8: "https://api.xmqspco.com//v/NJto-NuaAdzLH9ZvzBjv4g.m3u8?user_id=605500911&plat_id=60005",
+    name: "START-411_現役工廠妹子來當一天宿舍媽媽!SODSTAR天音環奈親自到宿舍照顧你~上班前、下",
+  },
+  {
+    id: "free-3",
+    cover: "https://cknz.t1mg0oa.com/ts4/2510/550264K68J9J/cover",
+    m3u8: "https://api.xmqspco.com//v/R7dZv_VU5UyXbE7hvvfISw.m3u8?user_id=605500911&plat_id=60005",
+    name: "【高清】麻豆传媒 m220 18岁艺考生的献祭为名次贡献自己的初夜",
+  },
+  {
+    id: "free-4",
+    cover: "https://cknz.t1mg0oa.com/ts4/2510/8AORMJIE8F24/cover",
+    m3u8: "https://api.xmqspco.com//v/NXl77-NVV6438VnlPowBlw.m3u8?user_id=605500911&plat_id=60005",
+    name: "【高清】麻豆传媒 m215 无套双飞JK萝莉高中生两少女一起争着吃鸡巴",
+  },
+  {
+    id: "free-5",
+    cover: "https://cknz.t1mg0oa.com/ts4/2509/E6O45R5VVNG2/cover",
+    m3u8: "https://api.xmqspco.com//v/vF4W9CE_C28-iGklVPTVmw.m3u8?user_id=605500911&plat_id=60005",
+    name: "CARIBBEANCOM-090225-001_老师像我一样做!_!_〜热爱并关心每次射精的老师〜",
+  },
+  {
+    id: "free-6",
+    cover: "https://cknz.t1mg0oa.com/ts4/2510/0J6BH028UMKT/cover",
+    m3u8: "https://api.xmqspco.com//v/OFnZyzVFkKyuJ8cx3lNu-A.m3u8?user_id=605500911&plat_id=60005",
+    name: "WAAA-572_コンドームが破れてまさかの生ハメ!超加速するピストンで何度も中出し!_新井里真",
+  },
+];
+
+// 默认导出
+export default freeVideos;

+ 74 - 4
src/views/Home.vue

@@ -34,7 +34,10 @@
         v-for="sortOption in sortOptions"
         :key="sortOption.value"
         class="sort-chip"
-        :class="{ 'sort-chip-active': selectedSort === sortOption.value }"
+        :class="{
+          'sort-chip-active': selectedSort === sortOption.value,
+          'sort-chip-free': sortOption.value === 'free',
+        }"
         @click="selectSort(sortOption.value)"
       >
         {{ sortOption.label }}
@@ -57,6 +60,7 @@
             cover-class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
           />
           <div
+            v-if="selectedSort !== 'free'"
             class="absolute bottom-2 right-2 bg-black/70 text-white text-xs px-2 py-1 rounded"
           >
             {{ formatDuration(video.duration) }}
@@ -68,7 +72,10 @@
           <h3 class="text-sm font-medium text-white/90 line-clamp-2 mb-1">
             {{ video.name }}
           </h3>
-          <p class="text-xs text-white/50 truncate">
+          <p
+            v-if="selectedSort !== 'free'"
+            class="text-xs text-white/50 truncate"
+          >
             {{ formatNumber(video.view) }} 次观看 ·
             {{ formatNumber(video.like) }} 点赞
           </p>
@@ -107,7 +114,7 @@
     </div>
 
     <!-- 分页组件 -->
-    <div v-if="totalPages > 1" class="py-6">
+    <div v-if="totalPages > 1 && selectedSort !== 'free'" class="py-6">
       <!-- 桌面端:完整分页 -->
       <div class="hidden sm:block">
         <!-- 上一页、页码、下一页 -->
@@ -368,6 +375,7 @@ import { ref, onMounted, onBeforeUnmount, watch, nextTick } from "vue";
 import { useRouter, useRoute } from "vue-router";
 import { searchVideoByTags, searchVideoByKeyword } from "@/services/api";
 import { videoMenus as fixedVideoMenus } from "@/data/videoMenus";
+import { freeVideos } from "@/data/freeVideo";
 import VideoJSPlayer from "@/components/VideoJSPlayer.vue";
 import { useUserStore } from "@/store/user";
 import { VipLevel } from "@/types/vip";
@@ -415,6 +423,7 @@ const sortOptions = ref([
   { value: "time", label: "最新" },
   { value: "view", label: "热门" },
   { value: "like", label: "点赞" },
+  { value: "free", label: "试看" },
 ]);
 const selectedSort = ref<string>("time");
 
@@ -506,6 +515,13 @@ const selectMenu = async (hash: string) => {
 // 选择排序方式
 const selectSort = async (sort: string) => {
   selectedSort.value = sort;
+
+  // 如果是免费视频,直接显示免费视频列表
+  if (sort === "free") {
+    showFreeVideos();
+    return;
+  }
+
   // 重新查询当前显示的内容
   if (isSearchMode.value) {
     // 如果是搜索模式,重新执行搜索
@@ -524,6 +540,18 @@ const toggleTags = () => {
   showAllTags.value = !showAllTags.value;
 };
 
+// 显示免费视频
+const showFreeVideos = () => {
+  loading.value = false;
+  videoList.value = freeVideos;
+  totalPages.value = 1;
+  totalCount.value = freeVideos.length;
+  currentPage.value = 1;
+  // 清除搜索模式
+  isSearchMode.value = false;
+  currentSearchKeyword.value = "";
+};
+
 // 搜索功能
 const handleSearch = async (keyword: string, page = 1) => {
   if (!keyword.trim()) {
@@ -578,7 +606,19 @@ const playVideo = (video: any) => {
 
   const vipLevel = userStore.getVipLevel();
 
-  if (vipLevel === VipLevel.GUEST || vipLevel === VipLevel.FREE) {
+  // 如果是试看视频,直接通过URL参数传递所有信息
+  if (selectedSort.value === "free" || video.id?.startsWith("free-")) {
+    router.push({
+      name: "VideoPlayer",
+      params: { id: video.id },
+      query: {
+        cover: video.cover,
+        m3u8: video.m3u8,
+        name: video.name,
+        isFree: "true",
+      },
+    });
+  } else if (vipLevel === VipLevel.GUEST || vipLevel === VipLevel.FREE) {
     // guest和free用户通过URL参数传递cover和m3u8,同时包含视频ID
     router.push({
       name: "VideoPlayer",
@@ -760,4 +800,34 @@ onBeforeUnmount(() => {
 .sort-chip-active {
   @apply bg-emerald-500/20 text-emerald-400 border-emerald-400/30;
 }
+
+.sort-chip-free {
+  @apply relative overflow-hidden;
+  box-shadow: 0 0 10px rgba(16, 185, 129, 0.3);
+}
+
+.sort-chip-free::before {
+  content: "";
+  position: absolute;
+  top: 0;
+  left: -100%;
+  width: 100%;
+  height: 100%;
+  background: linear-gradient(
+    90deg,
+    transparent,
+    rgba(255, 255, 255, 0.4),
+    transparent
+  );
+  animation: sparkle 1.5s ease-in-out infinite;
+}
+
+@keyframes sparkle {
+  0% {
+    left: -100%;
+  }
+  100% {
+    left: 100%;
+  }
+}
 </style>

+ 46 - 3
src/views/VideoPlayer.vue

@@ -46,6 +46,34 @@
       </div>
     </div>
 
+    <!-- 试看视频标识 -->
+    <div v-if="isFreeVideo" class="mb-4">
+      <div
+        class="inline-flex items-center gap-2 px-3 py-1.5 bg-emerald-500/20 border border-emerald-400/30 rounded-full"
+      >
+        <svg
+          class="w-4 h-4 text-emerald-400"
+          fill="none"
+          stroke="currentColor"
+          viewBox="0 0 24 24"
+        >
+          <path
+            stroke-linecap="round"
+            stroke-linejoin="round"
+            stroke-width="2"
+            d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
+          />
+          <path
+            stroke-linecap="round"
+            stroke-linejoin="round"
+            stroke-width="2"
+            d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
+          />
+        </svg>
+        <span class="text-sm font-medium text-emerald-400">试看视频</span>
+      </div>
+    </div>
+
     <!-- 视频播放器区域 -->
     <div class="relative rounded-2xl overflow-hidden bg-black">
       <div class="aspect-video video-container">
@@ -461,7 +489,10 @@
         <h1 class="text-xl font-semibold text-white leading-tight">
           {{ videoInfo.name || "视频标题" }}
         </h1>
-        <div class="flex items-center gap-4 text-sm text-white/60">
+        <div
+          v-if="!isFreeVideo"
+          class="flex items-center gap-4 text-sm text-white/60"
+        >
           <div class="flex items-center gap-1">
             <svg
               class="w-4 h-4"
@@ -766,6 +797,13 @@ const openPaymentPage = (url: string) => {
 // 计算属性
 const currentVipLevel = computed(() => userStore.getVipLevel());
 
+// 判断是否为试看视频
+const isFreeVideo = computed(() => {
+  return (
+    route.query.isFree === "true" || videoInfo.value.id?.startsWith("free-")
+  );
+});
+
 // 参考Account.vue的用户类型判断
 const isGuest = computed(() => {
   return userStore.userInfo?.vipLevel === "guest";
@@ -1202,14 +1240,14 @@ const loadVideoInfo = async () => {
     userInfo.vipLevel === "guest" ||
     userInfo.vipLevel === "free"
   ) {
-    const { cover, name, duration, view, like } = route.query;
+    const { cover, name, duration, view, like, m3u8, isFree } = route.query;
 
     if (cover && name) {
       videoInfo.value = {
         id: videoId || "unknown",
         name: name as string,
         cover: cover as string,
-        m3u8: "", // guest和free用户不提供 m3u8 地址
+        m3u8: (m3u8 as string) || "", // 如果是免费视频,提供 m3u8 地址
         duration: parseInt(duration as string) || 0,
         view: parseInt(view as string) || 0,
         like: parseInt(like as string) || 0,
@@ -1217,6 +1255,11 @@ const loadVideoInfo = async () => {
         taginfo: [],
       };
 
+      // 如果是免费视频,标记为已购买状态,这样可以直接播放
+      if (isFree === "true") {
+        isSinglePurchased.value = true;
+      }
+
       // 设置页面标题
       document.title = `${videoInfo.value.name} - 视频`;