Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
236 changes: 236 additions & 0 deletions .github/workflows/dev-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
name: Dev Release Build

on:
workflow_dispatch:
inputs:
platform:
description: 'Target platform'
required: true
type: choice
options:
- macos
- linux
- windows
version:
description: 'Version to set (optional)'
required: false
type: string

jobs:
build-macos:
runs-on: macos-latest
if: ${{ inputs.platform == 'macos' }}

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
run_install: false

- name: Get pnpm store directory
shell: bash
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- name: Setup pnpm cache
uses: actions/cache@v3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Update deprecated actions/cache to v4

The workflow uses actions/cache@v3 which is deprecated. GitHub recommends updating to v4 for continued support and security updates.

-        uses: actions/cache@v3
+        uses: actions/cache@v4

Apply this update to all three occurrences (lines 44, 117, 190).

Also applies to: 117-117, 190-190

🧰 Tools
🪛 actionlint (1.7.7)

44-44: the runner of "actions/cache@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🤖 Prompt for AI Agents
In .github/workflows/dev-release.yml around lines 44, 117 and 190 the workflow
references actions/cache@v3 which is deprecated; update each occurrence to
actions/cache@v4 to follow GitHub recommendations and ensure ongoing support and
security updates—locate the three uses at those line numbers and change the
version tag from v3 to v4.

with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-

- name: Install dependencies
run: pnpm install

- name: Set version
if: ${{ inputs.version != '' }}
shell: bash
run: |
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg.version = '${{ inputs.version }}';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
console.log(\`Version set to \${pkg.version}\`);
"

Comment on lines +54 to +65
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Add validation for version input format

The version setting logic doesn't validate the format of the input version string. Consider adding validation to ensure it follows semantic versioning or your project's version format to prevent invalid versions from being set.

       - name: Set version
         if: ${{ inputs.version != '' }}
         shell: bash
         run: |
           node -e "
             const fs = require('fs');
+            const version = '${{ inputs.version }}';
+            // Basic semver validation
+            if (!/^v?\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/.test(version)) {
+              console.error('Invalid version format: ' + version);
+              process.exit(1);
+            }
             const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
-            pkg.version = '${{ inputs.version }}';
+            pkg.version = version;
             fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
             console.log(\`Version set to \${pkg.version}\`);
           "

Also applies to: 127-138, 200-211

🤖 Prompt for AI Agents
In .github/workflows/dev-release.yml around lines 54 to 65 (and similarly at
127-138 and 200-211), the workflow sets package.json version from inputs without
validating the input format; add validation to ensure the provided version
matches your expected pattern (e.g., semantic versioning) before writing. Modify
the step to run a small validation routine in the shell/node snippet that tests
the input against a regex (or semver parser), exit non-zero and print a clear
error if invalid, and only update package.json when the version passes
validation.

- name: Build macOS package
run: |
pnpm build
pnpm exec electron-builder --mac --publish never
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ELECTRON_BUILDER_CHANNEL: dev

- name: List build artifacts
shell: bash
run: |
echo "Build artifacts:"
find dist -type f -name "*" | head -20

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: macos-dev-artifacts
path: |
dist/*.dmg
dist/*.zip
dist/*.yml
dist/*.yaml
dist/*.blockmap
retention-days: 30
if-no-files-found: warn

build-linux:
runs-on: ubuntu-latest
if: ${{ inputs.platform == 'linux' }}

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
run_install: false

- name: Get pnpm store directory
shell: bash
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-

- name: Install dependencies
run: pnpm install

- name: Set version
if: ${{ inputs.version != '' }}
shell: bash
run: |
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg.version = '${{ inputs.version }}';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
console.log(\`Version set to \${pkg.version}\`);
"

- name: Build Linux package
run: |
pnpm build
pnpm exec electron-builder --linux --publish never
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ELECTRON_BUILDER_CHANNEL: dev

- name: List build artifacts
shell: bash
run: |
echo "Build artifacts:"
find dist -type f -name "*" | head -20

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: linux-dev-artifacts
path: |
dist/*.AppImage
dist/*.deb
dist/*.yml
dist/*.yaml
dist/*.blockmap
retention-days: 30
if-no-files-found: warn

build-windows:
runs-on: windows-latest
if: ${{ inputs.platform == 'windows' }}

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
run_install: false

- name: Get pnpm store directory
shell: bash
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-

- name: Install dependencies
run: pnpm install

- name: Set version
if: ${{ inputs.version != '' }}
shell: bash
run: |
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg.version = '${{ inputs.version }}';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
console.log(\`Version set to \${pkg.version}\`);
"

- name: Build Windows package
run: |
pnpm build
pnpm exec electron-builder --win --publish never
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ELECTRON_BUILDER_CHANNEL: dev

- name: List build artifacts
shell: bash
run: |
echo "Build artifacts:"
find dist -type f -name "*" | head -20

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: windows-dev-artifacts
path: |
dist/*.exe
dist/*.yml
dist/*.yaml
dist/*.blockmap
retention-days: 30
if-no-files-found: warn
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
# [1.0.0-alpha.9](https://github.com/mkdir700/EchoPlayer/compare/v1.0.0-alpha.8...v1.0.0-alpha.9) (2025-09-12)

### Bug Fixes

- **homepage:** Fix UI desynchronization issue after deleting video records + i18n support ([#120](https://github.com/mkdir700/EchoPlayer/issues/120)) ([7879ef4](https://github.com/mkdir700/EchoPlayer/commit/7879ef442b888d6956a74739c3c0c1c54bb87387))
- **player:** Fix subtitle navigation when activeCueIndex is -1 ([#119](https://github.com/mkdir700/EchoPlayer/issues/119)) ([b4ad16f](https://github.com/mkdir700/EchoPlayer/commit/b4ad16f2115d324aabd34b08b2a05ca98a3de101))
- **player:** Fix subtitle overlay dragging to bottom and improve responsive design ([#122](https://github.com/mkdir700/EchoPlayer/issues/122)) ([d563c92](https://github.com/mkdir700/EchoPlayer/commit/d563c924c9471caeeab45a3d2ddd6dda5520fcac))
- **player:** Prevent subtitle overlay interactions from triggering video play/pause ([#128](https://github.com/mkdir700/EchoPlayer/issues/128)) ([9730ba1](https://github.com/mkdir700/EchoPlayer/commit/9730ba1184cffe2012dd30e9207a562e88eec140))
- **ui:** Remove white border shadow from modal buttons in dark mode ([#124](https://github.com/mkdir700/EchoPlayer/issues/124)) ([29f70f6](https://github.com/mkdir700/EchoPlayer/commit/29f70f66806f3dc0e3e473a9b3b27867cf67ac0d))

### Features

- **performance:** implement video import performance optimization with parallel processing and warmup strategies ([#121](https://github.com/mkdir700/EchoPlayer/issues/121)) ([2c65f5a](https://github.com/mkdir700/EchoPlayer/commit/2c65f5ae92460391302c24f3fb291f386043e7cd))
- **player:** Implement fullscreen toggle functionality with keyboard shortcuts ([#127](https://github.com/mkdir700/EchoPlayer/issues/127)) ([78d3629](https://github.com/mkdir700/EchoPlayer/commit/78d3629c7d5a14e8bc378967a7f161135c5b5042))
- **scripts:** optimize FFmpeg download progress display ([#125](https://github.com/mkdir700/EchoPlayer/issues/125)) ([be33316](https://github.com/mkdir700/EchoPlayer/commit/be33316f0a66f7b5b2de64d275d7166f12f50379))

# [1.0.0-alpha.8](https://github.com/mkdir700/EchoPlayer/compare/v1.0.0-alpha.7...v1.0.0-alpha.8) (2025-09-10)

### Features
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,10 @@ pnpm test:ui

## 🙏 致谢

- [Cherry Studio](https://github.com/CherryHQ/cherry-studio) - 一款为创造而生的 AI 助手
| 项目名 | 简介 |
| --- | --- |
| [Cherry Studio](https://github.com/CherryHQ/cherry-studio) | 一款为创造而生的 AI 助手 |
| [DashPlayer](https://github.com/solidSpoon/DashPlayer) | 为英语学习者量身打造的视频播放器 |

---

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "echoplayer",
"version": "1.0.0-alpha.8",
"version": "1.0.0-alpha.9",
"description": "EchoPlayer is a video player designed for language learners, helping users learn foreign languages efficiently through sentence-by-sentence intensive listening.",
"main": "./out/main/index.js",
"author": "echoplayer.cc",
Expand Down
17 changes: 17 additions & 0 deletions packages/shared/config/constant.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
export const videoExts = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv']
export const audioExts = ['.mp3', '.wav', '.ogg', '.flac', '.aac']

/**
* 将扩展名数组转换为 Electron dialog 所需的格式(不含点)
* @param extArray 扩展名数组(可包含或不包含点)
* @returns 不含点的扩展名数组
*/
export function toDialogExtensions(extArray: string[]): string[] {
return extArray.map((ext) => (ext.startsWith('.') ? ext.slice(1) : ext))
}
Comment on lines +4 to +11
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix contract mismatch: strip all leading dots and update JSDoc

Doc says “不含点”, but implementation only removes one leading dot (e.g., '..mp4' -> '.mp4'). Make it remove all leading dots to meet the contract and avoid downstream dialog issues.

 /**
- * 将扩展名数组转换为 Electron dialog 所需的格式(不含点)
+ * 将扩展名数组转换为 Electron dialog 所需的格式(不含点)
+ * 注意:会移除所有前导点(如 '..mp4' => 'mp4')
  * @param extArray 扩展名数组(可包含或不包含点)
  * @returns 不含点的扩展名数组
  */
 export function toDialogExtensions(extArray: string[]): string[] {
-  return extArray.map((ext) => (ext.startsWith('.') ? ext.slice(1) : ext))
+  return extArray.map((ext) => ext.replace(/^\.+/, ''))
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* 将扩展名数组转换为 Electron dialog 所需的格式(不含点)
* @param extArray 扩展名数组(可包含或不包含点)
* @returns 不含点的扩展名数组
*/
export function toDialogExtensions(extArray: string[]): string[] {
return extArray.map((ext) => (ext.startsWith('.') ? ext.slice(1) : ext))
}
/**
* 将扩展名数组转换为 Electron dialog 所需的格式(不含点)
* 注意:会移除所有前导点(如 '..mp4' => 'mp4'
* @param extArray 扩展名数组(可包含或不包含点)
* @returns 不含点的扩展名数组
*/
export function toDialogExtensions(extArray: string[]): string[] {
return extArray.map((ext) => ext.replace(/^\.+/, ''))
}
🤖 Prompt for AI Agents
In packages/shared/config/constant.ts around lines 4 to 11, the
toDialogExtensions function's implementation only strips a single leading dot
but the JSDoc promises extensions "不含点"; change the logic to remove all leading
dots from each extension (e.g., use a replace with a regex that strips leading
dots or loop until no leading dot remains) and update the JSDoc if needed to
reflect exact behavior; ensure the function returns each extension with all
leading dots removed.


/**
* 获取用于 Electron dialog 的视频文件扩展名数组
* @returns 不含点的视频扩展名数组
*/
export function getVideoDialogExtensions(): string[] {
return toDialogExtensions(videoExts)
}
Comment on lines +17 to +19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Memoize getVideoDialogExtensions to avoid per-call allocations

This aligns with the test intent “应该缓存结果以提高性能” and avoids repeated mapping.

+let _videoDialogExtensions: string[] | null = null
 export function getVideoDialogExtensions(): string[] {
-  return toDialogExtensions(videoExts)
+  return (_videoDialogExtensions ??= toDialogExtensions(videoExts))
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function getVideoDialogExtensions(): string[] {
return toDialogExtensions(videoExts)
}
let _videoDialogExtensions: string[] | null = null
export function getVideoDialogExtensions(): string[] {
return (_videoDialogExtensions ??= toDialogExtensions(videoExts))
}
🤖 Prompt for AI Agents
In packages/shared/config/constant.ts around lines 17-19,
getVideoDialogExtensions currently calls toDialogExtensions(videoExts) on every
invocation causing repeated allocations; change it to compute the result once
and return a cached reference (e.g. a module-level const initialized by calling
toDialogExtensions(videoExts)) so subsequent calls return the same array
instance, preserving exported API and types.


export const KB = 1024
export const MB = 1024 * KB
export const GB = 1024 * MB
Expand Down
Loading
Loading