diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 8ffc2fa..ef8723b 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -16,9 +16,12 @@ concurrency: cancel-in-progress: true env: REGISTRY: ghcr.io + IMAGE_NAME: katelya77/katelyatv jobs: build-and-push: runs-on: ubuntu-latest + env: + IMAGE_NAME: ${{ github.repository }} permissions: contents: read packages: write @@ -35,7 +38,8 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - name: Set image name to lowercase - run: echo "IMAGE_NAME=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV + id: image_name + run: echo "name=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: @@ -52,7 +56,7 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + images: ${{ env.REGISTRY }}/${{ steps.image_name.outputs.name }} tags: | type=ref,event=branch type=ref,event=pr @@ -63,8 +67,6 @@ jobs: org.opencontainers.image.description=katelyatv - A modern streaming platform org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }} org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} - org.opencontainers.image.version=${{ steps.meta.outputs.version }} - org.opencontainers.image.created=${{ steps.meta.outputs.created }} org.opencontainers.image.revision=${{ github.sha }} org.opencontainers.image.licenses=MIT - name: Build Docker image @@ -78,7 +80,7 @@ jobs: cache-from: type=gha,scope=${{ github.ref_name }}-${{ matrix.platform }} cache-to: type=gha,mode=max,scope=${{ github.ref_name }}-${{ matrix.platform }} outputs: | - type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }} + type=image,name=${{ env.REGISTRY }}/${{ steps.image_name.outputs.name }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }} provenance: false sbom: false - name: Export digest @@ -105,9 +107,12 @@ jobs: needs: - build-and-push if: github.event_name != 'pull_request' + env: + REGISTRY: ghcr.io steps: - name: Set image name to lowercase - run: echo "IMAGE_NAME=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV + id: image_name + run: echo "name=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT - name: Download digests uses: actions/download-artifact@v4 with: @@ -126,7 +131,7 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + images: ${{ env.REGISTRY }}/${{ steps.image_name.outputs.name }} tags: | type=ref,event=branch type=sha,prefix={{branch}}- @@ -135,28 +140,28 @@ jobs: working-directory: /tmp/digests run: | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ - $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *) + $(printf '${{ env.REGISTRY }}/${{ steps.image_name.outputs.name }}@sha256:%s ' *) - name: Get multi-arch digest id: get_digest run: | # 直接从 docker pull 获取 digest,这是最可靠的方法 - digest=$(docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} 2>&1 | grep "Digest:" | cut -d' ' -f2 || echo "") + digest=$(docker pull ${{ env.REGISTRY }}/${{ steps.image_name.outputs.name }}:${{ steps.meta.outputs.version }} 2>&1 | grep "Digest:" | cut -d' ' -f2 || echo "") if [ -z "$digest" ]; then # 备选方案:使用 crane 风格的检查(如果支持的话) - digest=$(docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} | grep "Digest:" | head -1 | cut -d' ' -f2 || echo "") + digest=$(docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ steps.image_name.outputs.name }}:${{ steps.meta.outputs.version }} | grep "Digest:" | head -1 | cut -d' ' -f2 || echo "") fi if [ -z "$digest" ]; then # 最后备选:从 raw manifest 计算 - digest=$(docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} --raw | sha256sum | awk '{print "sha256:"$1}') + digest=$(docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ steps.image_name.outputs.name }}:${{ steps.meta.outputs.version }} --raw | sha256sum | awk '{print "sha256:"$1}') fi echo "digest=$digest" >> $GITHUB_OUTPUT - name: Inspect image run: | - docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} + docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ steps.image_name.outputs.name }}:${{ steps.meta.outputs.version }} - name: Generate artifact attestation if: github.event_name != 'pull_request' uses: actions/attest-build-provenance@v1 with: - subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} + subject-name: ${{ env.REGISTRY }}/${{ steps.image_name.outputs.name}} subject-digest: ${{ steps.get_digest.outputs.digest }} push-to-registry: true diff --git a/src/app/page.tsx b/src/app/page.tsx index 75e08ed..64fa537 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -20,6 +20,7 @@ import { DoubanItem } from '@/lib/types'; import CapsuleSwitch from '@/components/CapsuleSwitch'; import ContinueWatching from '@/components/ContinueWatching'; import PageLayout from '@/components/PageLayout'; +import PaginatedRow from '@/components/PaginatedRow'; import { useSite } from '@/components/SiteProvider'; import VideoCard from '@/components/VideoCard'; @@ -291,7 +292,7 @@ function HomeClient() { -
+ {loading ? // 加载状态显示灰色占位数据 (显示10个,2行x5列) Array.from({ length: 10 }).map((_, index) => ( @@ -305,8 +306,8 @@ function HomeClient() {
)) - : // 显示真实数据,只显示前10个实现2行布局 - hotMovies.slice(0, 10).map((movie, index) => ( + : // 显示真实数据 + hotMovies.map((movie, index) => (
))} - + {/* 热门剧集 */} @@ -339,7 +340,7 @@ function HomeClient() { -
+ {loading ? // 加载状态显示灰色占位数据 (显示10个,2行x5列) Array.from({ length: 10 }).map((_, index) => ( @@ -353,8 +354,8 @@ function HomeClient() {
)) - : // 显示真实数据,只显示前10个实现2行布局 - hotTvShows.slice(0, 10).map((show, index) => ( + : // 显示真实数据 + hotTvShows.map((show, index) => (
))} - + {/* 热门综艺 */} @@ -386,7 +387,7 @@ function HomeClient() { -
+ {loading ? // 加载状态显示灰色占位数据 (显示10个,2行x5列) Array.from({ length: 10 }).map((_, index) => ( @@ -400,8 +401,8 @@ function HomeClient() {
)) - : // 显示真实数据,只显示前10个实现2行布局 - hotVarietyShows.slice(0, 10).map((show, index) => ( + : // 显示真实数据 + hotVarietyShows.map((show, index) => (
))} - + {/* 首页底部 Logo */} diff --git a/src/components/PaginatedRow.tsx b/src/components/PaginatedRow.tsx new file mode 100644 index 0000000..5a67bdb --- /dev/null +++ b/src/components/PaginatedRow.tsx @@ -0,0 +1,104 @@ +'use client'; + +import { ChevronLeft, ChevronRight } from 'lucide-react'; +import { useMemo, useState } from 'react'; + +interface PaginatedRowProps { + children: React.ReactNode[]; + itemsPerPage?: number; + className?: string; +} + +export default function PaginatedRow({ + children, + itemsPerPage = 10, + className = '', +}: PaginatedRowProps) { + const [currentPage, setCurrentPage] = useState(0); + + // 计算总页数 + const totalPages = Math.ceil(children.length / itemsPerPage); + + // 获取当前页的项目 + const currentItems = useMemo(() => { + const startIndex = currentPage * itemsPerPage; + const endIndex = startIndex + itemsPerPage; + return children.slice(startIndex, endIndex); + }, [children, currentPage, itemsPerPage]); + + // 是否显示左右按钮 + const showLeftButton = currentPage > 0; + const showRightButton = currentPage < totalPages - 1; + + const handlePrevPage = () => { + if (currentPage > 0) { + setCurrentPage(currentPage - 1); + } + }; + + const handleNextPage = () => { + if (currentPage < totalPages - 1) { + setCurrentPage(currentPage + 1); + } + }; + + // 如果没有足够的内容需要分页,就不显示按钮 + const needsPagination = totalPages > 1; + + return ( +
+ {/* 内容区域 */} +
+ {currentItems} +
+ + {/* 左箭头按钮 */} + {needsPagination && showLeftButton && ( +
+
+ +
+
+ )} + + {/* 右箭头按钮 */} + {needsPagination && showRightButton && ( +
+
+ +
+
+ )} + + {/* 页码指示器 (可选) */} + {needsPagination && ( +
+ {Array.from({ length: totalPages }, (_, index) => ( +
+ )} +
+ ); +} diff --git a/src/components/VideoCard.tsx b/src/components/VideoCard.tsx index ccff9f9..81cf12e 100644 --- a/src/components/VideoCard.tsx +++ b/src/components/VideoCard.tsx @@ -228,7 +228,7 @@ export default function VideoCard({ const configs = { playrecord: { showSourceName: true, - showProgress: true, + showProgress: false, showPlayButton: true, showHeart: true, showCheckCircle: true,