v1.0
@@ -0,0 +1,47 @@
|
|||||||
|
name: Build and Push Docker Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths-ignore:
|
||||||
|
- 'README.md'
|
||||||
|
- 'README_zh.md'
|
||||||
|
- '.github/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# 使用 concurrency 结合延迟效果来实现类似“修改后30分钟构建”的需求是不太直接的。
|
||||||
|
# 通常 GitHub Actions 在 push 后立即触发。
|
||||||
|
# 如果需要“合并触发”,可以使用 workflow_run 或在 push 触发时先 sleep。
|
||||||
|
# 但为了可靠性,这里采用标准的 push 触发,并配合并发限制。
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: actions/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: actions/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
ghcr.io/${{ github.repository_owner }}/embyx:latest
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Dockerfile for EmbyX
|
||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
# 设置工作目录存放原始语言包
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 复制中英文版本到镜像内部存放
|
||||||
|
COPY zh/ /app/dist/zh/
|
||||||
|
COPY en/ /app/dist/en/
|
||||||
|
|
||||||
|
# 复制 nginx 配置
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
# 复制并设置启动脚本
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
|
# 预设默认语言和端口环境变量
|
||||||
|
ENV APP_LANG=en
|
||||||
|
ENV APP_PORT=8090
|
||||||
|
|
||||||
|
# EXPOSE 在 host 模式下仅作声明
|
||||||
|
EXPOSE 8090
|
||||||
|
|
||||||
|
# 使用自定义脚本启动
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
@@ -1,2 +1,99 @@
|
|||||||
# EmbyX
|
# 📱 EmbyX Vertical Player `v1.1`
|
||||||
像刷抖音一样看 Emby 短视频。Watch Emby short videos like Tiktok.
|
|
||||||
|
[中文说明](./README_zh.md) | [English Documentation](./README.md)
|
||||||
|
|
||||||
|
> A TikTok-style web interface for Emby / Jellyfin, designed for browsing and managing short videos in an immersive way.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
|
||||||
|
- **Fluid Playback**: TikTok-style vertical scrolling, immersive full-screen experience.
|
||||||
|
- **Grid View**: Browse with cover walls, supports pagination and random refresh.
|
||||||
|
- **Direct Play**: Works natively on modern devices. Support for 8K, AV1, and HEVC without transcoding.
|
||||||
|
- **Library Sync**: One-tap to favorite/unfavorite videos, fully synced with Emby server.
|
||||||
|
- **Key & Mouse Support**: Complete keyboard shortcut mapping. Friendly for TV and PC browsers.
|
||||||
|
- **PWA Ready**: Install as a desktop or home screen app.
|
||||||
|
- **Privacy First**: All data is stored locally; nothing is uploaded to the cloud.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔮 Playback Performance
|
||||||
|
|
||||||
|
| Device | HEVC Decode | AV1 Decode |
|
||||||
|
|:---:|:---:|:---:|
|
||||||
|
| Apple | A9 (2015) / M1 | A17 Pro (2023) / M3 |
|
||||||
|
| Android | Budget (2016) | Budget (2024) |
|
||||||
|
| PC | Intel Core 6-8th Gen (iGPU) | Intel Core 11th Gen+ (iGPU) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⌨️ Shortcuts Guide
|
||||||
|
|
||||||
|
| Key | Function |
|
||||||
|
|:---:|---|
|
||||||
|
| `W / S / ↑ / ↓` | Previous / Next Video |
|
||||||
|
| `A / D / ← / →` | Seek Back / Forward 15s |
|
||||||
|
| `Space / Click OK` | Pause / Play |
|
||||||
|
| `U / Double Click OK` | Favorite Video |
|
||||||
|
| `J / Menu Key` | Toggle Aspect Ratio |
|
||||||
|
| `M` | Toggle Mute |
|
||||||
|
| `I` | Open Settings / Profile |
|
||||||
|
| `E` | Toggle View Mode (List/Grid) |
|
||||||
|
| `R` | Sequential / Random Mode |
|
||||||
|
| `F` | Fullscreen Mode |
|
||||||
|
| `G` | Toggle Libraries |
|
||||||
|
| `V` | Show File Info |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
embyx/
|
||||||
|
├── zh/ # Chinese Version
|
||||||
|
│ ├── index.html
|
||||||
|
│ ├── manifest.json
|
||||||
|
│ └── ...
|
||||||
|
├── en/ # English Version
|
||||||
|
│ ├── index.html
|
||||||
|
│ ├── manifest.json
|
||||||
|
│ └── ...
|
||||||
|
├── README.md # English (Default)
|
||||||
|
└── README_zh.md # Chinese
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Deployment
|
||||||
|
|
||||||
|
### Option 1: Direct File Hosting (Recommended)
|
||||||
|
|
||||||
|
Simply put all files from either `zh/` or `en/` folder into your web server (Nginx, Apache, etc.).
|
||||||
|
|
||||||
|
### Option 2: Docker Deployment
|
||||||
|
|
||||||
|
One image, multiple languages. Controlled by environment variable.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
--name embyx \
|
||||||
|
--network host \
|
||||||
|
-e APP_LANG=en \
|
||||||
|
-e APP_PORT=8090 \
|
||||||
|
ghcr.io/juneix/embyx:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
| Env | Description | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| `APP_LANG` | `en` (English) / `zh` (Chinese) | `en` |
|
||||||
|
| `APP_PORT` | The port the container will listen on | `8090` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 License
|
||||||
|
|
||||||
|
MIT License — Feel free to use, PRs and Issues are welcome.
|
||||||
|
|
||||||
|
👨🏻💻 Author: [@Juneix](https://juneix.github.io)
|
||||||
|
🛜 Official Site: [June's Hub](https://5nav.eu.org)
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
# 📱 EmbyX 竖屏播放器 `v1.1`
|
||||||
|
|
||||||
|
> 这是一个技术小白借助 Antigravity 和 Emby API 制作的 Web 应用,仿抖音风格浏览、管理 Emby 的短视频。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✨ 功能特色
|
||||||
|
|
||||||
|
- **流式播放**:抖音风格上下滑动,沉浸式全屏体验
|
||||||
|
- **格子视图**:封面墙浏览,支持分页与随机换一批
|
||||||
|
- **直接播放**(Direct Play):安卓 AV1、8K 不转码
|
||||||
|
- **收藏管理**:一键收藏 / 取消,同步 Emby 数据库
|
||||||
|
- **键鼠适配**:完整键盘快捷键,电视/电脑浏览器友好
|
||||||
|
- **PWA 支持**:可安装为桌面/主屏幕应用
|
||||||
|
- **私有化部署**:数据本地存储,不上传云端
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔮 播放性能
|
||||||
|
|
||||||
|
| 设备 | HEVC 硬解 | AV1 硬解 |
|
||||||
|
|:---:|:---:|:---:|
|
||||||
|
| 苹果 | A9 (2015) / M1 | A17 Pro (2023) / M3 |
|
||||||
|
| 安卓 | 千元机 (2016) | 千元机 (2024) |
|
||||||
|
| PC | 6~8 代酷睿·核显 | 11 代酷睿·核显 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⌨️ 快捷键指南
|
||||||
|
|
||||||
|
| 按键 | 功能 |
|
||||||
|
|:---:|---|
|
||||||
|
| `W / S / ↑ / ↓` | 上一个 / 下一个视频 |
|
||||||
|
| `A / D / ← / →` | 快退 / 快进 15 秒 |
|
||||||
|
| `Space / 单击 OK` | 暂停 / 播放 |
|
||||||
|
| `U / 双击 OK` | 收藏视频 |
|
||||||
|
| `J / 菜单键` | 比例切换 |
|
||||||
|
| `M` | 音量开关 |
|
||||||
|
| `I` | 个人中心 |
|
||||||
|
| `E` | 视图切换 |
|
||||||
|
| `R` | 顺序 / 随机 |
|
||||||
|
| `F` | 全屏切换 |
|
||||||
|
| `G` | 选择媒体源 |
|
||||||
|
| `V` | 流媒体详情 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 使用技巧
|
||||||
|
|
||||||
|
- **原生全屏**:iOS 系统限制,不支持全屏按钮
|
||||||
|
- **PWA 应用**:浏览器 📲 添加到主屏幕 / 作为应用安装
|
||||||
|
- **键鼠适配**:电脑、电视浏览器也能快乐摸鱼
|
||||||
|
- **媒体库建议**:单个媒体库建议不超过 **1000 个视频**,可建立多个媒体库分层管理
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ 技术栈
|
||||||
|
|
||||||
|
| 层级 | 技术 |
|
||||||
|
|---|---|
|
||||||
|
| **结构** | HTML5 语义化标签 |
|
||||||
|
| **样式** | Tailwind CSS(CDN,JIT 按需) |
|
||||||
|
| **逻辑** | 原生 JavaScript(无框架) |
|
||||||
|
| **图标** | Lucide Icons(CDN) |
|
||||||
|
| **数据** | Emby REST API |
|
||||||
|
| **离线支持** | Service Worker(PWA) |
|
||||||
|
| **容器** | Nginx Alpine(Docker 部署时) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 文件目录
|
||||||
|
|
||||||
|
```
|
||||||
|
embyx/
|
||||||
|
├── index.html # 核心文件,包含所有逻辑与样式
|
||||||
|
├── poster.webp # 自定义默认封面图(可替换)
|
||||||
|
├── manifest.json # PWA 配置文件
|
||||||
|
├── sw.js # Service Worker(离线缓存)
|
||||||
|
├── icon.png # PWA 图标
|
||||||
|
├── Dockerfile # Docker 镜像构建文件
|
||||||
|
└── docker-compose.yml # 一键部署配置
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 部署方式
|
||||||
|
|
||||||
|
### 方式一:直接部署(推荐个人用户)
|
||||||
|
|
||||||
|
将以下文件放入任意 Web 服务器(Nginx、Apache、NAS 静态服务等)根目录:
|
||||||
|
|
||||||
|
```
|
||||||
|
index.html
|
||||||
|
poster.webp
|
||||||
|
manifest.json
|
||||||
|
sw.js
|
||||||
|
icon.png
|
||||||
|
```
|
||||||
|
|
||||||
|
> **尝鲜玩法**:手机可以直接双击 `index.html`(file:// 协议)本地使用,通过 HTTP 访问 Emby。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 方式二:Docker 部署
|
||||||
|
|
||||||
|
#### 使用 Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 拉取最新镜像
|
||||||
|
docker pull ghcr.io/juneix/embyx:latest
|
||||||
|
|
||||||
|
# 运行容器(映射到本机 8080 端口)
|
||||||
|
docker run -d \
|
||||||
|
--name embyx \
|
||||||
|
--network host \
|
||||||
|
-e APP_LANG=zh \
|
||||||
|
-e APP_PORT=8090 \
|
||||||
|
--restart unless-stopped \
|
||||||
|
ghcr.io/juneix/embyx:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
访问 `http://your-server-ip:8080` 即可使用。
|
||||||
|
|
||||||
|
#### 使用 docker-compose(推荐)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 下载 docker-compose.yml 后执行
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
或者直接复制到群晖、飞牛、Dockge 的 docker-compose 模板:
|
||||||
|
```bash
|
||||||
|
services:
|
||||||
|
embyx:
|
||||||
|
image: ghcr.io/juneix/embyx:latest
|
||||||
|
container_name: embyx
|
||||||
|
restart: unless-stopped
|
||||||
|
network_mode: host
|
||||||
|
environment:
|
||||||
|
- APP_LANG=zh # zh (中文), en (英文)
|
||||||
|
- APP_PORT=8090 # 在 host 模式下,直接定义访问端口
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 开源协议
|
||||||
|
|
||||||
|
MIT License — 随意使用,欢迎 PR 和 Issue。
|
||||||
|
|
||||||
|
👨🏻💻 作者:[@谢週五](https://juneix.github.io)
|
||||||
|
🛜 官网:[谢週五の藏经阁](https://5nav.eu.org)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
services:
|
||||||
|
embyx:
|
||||||
|
image: ghcr.io/juneix/embyx:latest
|
||||||
|
container_name: embyx
|
||||||
|
restart: unless-stopped
|
||||||
|
network_mode: host
|
||||||
|
environment:
|
||||||
|
- APP_LANG=zh # zh (中文), en (English)
|
||||||
|
- APP_PORT=8090 # 访问端口 (Access Port)
|
||||||
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,17 @@
|
|||||||
|
const CACHE_NAME = 'embyx-v1';
|
||||||
|
|
||||||
|
// 安装阶段:不强制缓存大量资源,保持轻量
|
||||||
|
self.addEventListener('install', (event) => {
|
||||||
|
self.skipWaiting();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 激活阶段:清理旧缓存
|
||||||
|
self.addEventListener('activate', (event) => {
|
||||||
|
event.waitUntil(clients.claim());
|
||||||
|
});
|
||||||
|
|
||||||
|
// 核心:必须有 fetch 处理器才能触发安卓 Chrome 的安装横幅
|
||||||
|
self.addEventListener('fetch', (event) => {
|
||||||
|
// 默认直接透传,不做离线缓存以节省空间和避免版本更新延迟
|
||||||
|
event.respondWith(fetch(event.request));
|
||||||
|
});
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# 默认参数
|
||||||
|
APP_LANG=${APP_LANG:-en}
|
||||||
|
APP_PORT=${APP_PORT:-8090}
|
||||||
|
|
||||||
|
echo "Current Configuration:"
|
||||||
|
echo " - Language: $APP_LANG"
|
||||||
|
echo " - Port: $APP_PORT"
|
||||||
|
|
||||||
|
# 动态修改 Nginx 监听端口
|
||||||
|
sed -i "s/listen 80;/listen ${APP_PORT};/g" /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
# 清理 web 根目录
|
||||||
|
rm -rf /usr/share/nginx/html/*
|
||||||
|
|
||||||
|
# 根据环境变量选择性“部署”
|
||||||
|
if [ "$APP_LANG" = "zh" ]; then
|
||||||
|
echo "Deploying Chinese version..."
|
||||||
|
cp -rf /app/dist/zh/* /usr/share/nginx/html/
|
||||||
|
else
|
||||||
|
echo "Deploying English version..."
|
||||||
|
cp -rf /app/dist/en/* /usr/share/nginx/html/
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 启动 nginx
|
||||||
|
exec nginx -g "daemon off;"
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# MIME types
|
||||||
|
types {
|
||||||
|
text/html html htm;
|
||||||
|
application/json json;
|
||||||
|
application/manifest+json webmanifest;
|
||||||
|
text/javascript js;
|
||||||
|
image/webp webp;
|
||||||
|
image/png png;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Service Worker: No caching
|
||||||
|
location = /sw.js {
|
||||||
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||||
|
add_header Pragma "no-cache";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Static assets: Long-term cache
|
||||||
|
location ~* \.(png|webp|ico)$ {
|
||||||
|
expires 30d;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
|
||||||
|
# SPA/PWA routing support
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 132 KiB |
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "EmbyX",
|
||||||
|
"short_name": "EmbyX",
|
||||||
|
"start_url": "./index.html",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#000000",
|
||||||
|
"theme_color": "#000000",
|
||||||
|
"description": "Emby Short Video Player",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "icon.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icon.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,17 @@
|
|||||||
|
const CACHE_NAME = 'embyx-v1';
|
||||||
|
|
||||||
|
// 安装阶段:不强制缓存大量资源,保持轻量
|
||||||
|
self.addEventListener('install', (event) => {
|
||||||
|
self.skipWaiting();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 激活阶段:清理旧缓存
|
||||||
|
self.addEventListener('activate', (event) => {
|
||||||
|
event.waitUntil(clients.claim());
|
||||||
|
});
|
||||||
|
|
||||||
|
// 核心:必须有 fetch 处理器才能触发安卓 Chrome 的安装横幅
|
||||||
|
self.addEventListener('fetch', (event) => {
|
||||||
|
// 默认直接透传,不做离线缓存以节省空间和避免版本更新延迟
|
||||||
|
event.respondWith(fetch(event.request));
|
||||||
|
});
|
||||||
|
After Width: | Height: | Size: 14 KiB |