├── .editorconfig
├── .eslintignore
├── .eslintrc.cjs
├── .github
├── ISSUE_TEMPLATE
│ ├── bug.yaml
│ ├── config.yml
│ └── feature.yaml
├── dependabot.yml
└── workflows
│ ├── CI-build.yml
│ ├── CI-test.yml
│ ├── Release.yml
│ ├── issue-helper.yml
│ └── issue-translator.yml
├── .gitignore
├── .prettierignore
├── .prettierrc.yaml
├── LICENSE
├── README.md
├── README_i18n
└── README_zh.md
├── build
├── entitlements.mac.plist
├── icon.icns
├── icon.ico
├── icon.png
├── macosDMGbg.jpeg
└── notarize.js
├── electron-builder.yml
├── electron.vite.config.ts
├── package.json
├── pnpm-lock.yaml
├── resources
├── download-core.js
├── icon.png
├── taryTemplate.png
├── tray.png
└── trayTemplate@2x.png
├── src
├── main
│ ├── RunCommand.ts
│ ├── index.ts
│ └── openDirectory.ts
├── preload
│ ├── index.d.ts
│ └── index.ts
└── renderer
│ ├── index.html
│ └── src
│ ├── App.vue
│ ├── assets
│ ├── final2xlogo.png
│ └── final2xlogoDarkMode.png
│ ├── components
│ ├── MyDarkMode.vue
│ ├── MyExternalLink.vue
│ ├── MyProgress.vue
│ ├── MySetting.vue
│ ├── NaiveDarkMode.vue
│ ├── TrafficLightsButtons.vue
│ └── bottomNavigation.vue
│ ├── env.d.ts
│ ├── locales
│ ├── en.ts
│ ├── fr.ts
│ ├── ja.ts
│ └── zh.ts
│ ├── main.ts
│ ├── plugins
│ └── i18n.ts
│ ├── public
│ ├── favicon.ico
│ ├── img
│ │ └── icons
│ │ │ ├── android-chrome-192x192.png
│ │ │ ├── android-chrome-512x512.png
│ │ │ ├── android-chrome-maskable-192x192.png
│ │ │ ├── android-chrome-maskable-512x512.png
│ │ │ ├── apple-touch-icon-120x120.png
│ │ │ ├── apple-touch-icon-152x152.png
│ │ │ ├── apple-touch-icon-180x180.png
│ │ │ ├── apple-touch-icon-60x60.png
│ │ │ ├── apple-touch-icon-76x76.png
│ │ │ ├── apple-touch-icon.png
│ │ │ ├── favicon-16x16.png
│ │ │ ├── favicon-32x32.png
│ │ │ ├── msapplication-icon-144x144.png
│ │ │ ├── mstile-150x150.png
│ │ │ └── safari-pinned-tab.svg
│ ├── index.html
│ └── robots.txt
│ ├── router
│ └── index.ts
│ ├── store
│ ├── SRSettingsStore.ts
│ ├── globalSettingsStore.ts
│ └── ioPathStore.ts
│ ├── utils
│ ├── IOPath.ts
│ ├── ModelOptions.ts
│ ├── getFinal2xconfig.ts
│ ├── index.ts
│ ├── pathFormat.ts
│ └── switchLanguage.ts
│ └── views
│ ├── Final2xHome.vue
│ └── Final2xSettings.vue
├── test
└── utils
│ ├── IOPath.test.ts
│ ├── getFinal2xconfig.test.ts
│ ├── index.test.ts
│ ├── pathFormat.test.ts
│ └── switchLanguage.test.ts
├── tsconfig.json
├── tsconfig.node.json
├── tsconfig.web.json
└── vitest.config.ts
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | out
4 | .gitignore
5 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | require('@rushstack/eslint-patch/modern-module-resolution')
3 |
4 | module.exports = {
5 | root: true,
6 | env: {
7 | browser: true,
8 | commonjs: true,
9 | es6: true,
10 | node: true,
11 | 'vue/setup-compiler-macros': true
12 | },
13 | extends: [
14 | 'plugin:vue/vue3-recommended',
15 | 'eslint:recommended',
16 | '@vue/eslint-config-typescript/recommended',
17 | '@vue/eslint-config-prettier'
18 | ],
19 | // rules for typescript
20 | rules: {
21 | '@typescript-eslint/ban-ts-comment': ['error', { 'ts-ignore': 'allow-with-description' }],
22 | '@typescript-eslint/explicit-function-return-type': 'error',
23 | '@typescript-eslint/explicit-module-boundary-types': 'off',
24 | '@typescript-eslint/no-empty-function': ['error', { allow: ['arrowFunctions'] }],
25 | '@typescript-eslint/no-explicit-any': ['off'],
26 | '@typescript-eslint/no-non-null-assertion': 'off',
27 | '@typescript-eslint/no-var-requires': 'off',
28 | '@typescript-eslint/no-inferrable-types': 'off',
29 | 'vue/require-default-prop': 'off',
30 | 'vue/multi-word-component-names': 'off'
31 | },
32 | overrides: [
33 | {
34 | files: ['*.js'],
35 | rules: {
36 | '@typescript-eslint/explicit-function-return-type': 'off'
37 | }
38 | }
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug.yaml:
--------------------------------------------------------------------------------
1 | name: 🐛 Bug report | 错误报告 | BUG報告
2 | description: Create a bug report to help us improve | 创建bug报告以帮助我们改进 | 改善を支援するためのレポートを作成する
3 | title: '[Bug] '
4 | labels: ['bug']
5 | body:
6 | - type: checkboxes
7 | id: checks
8 | attributes:
9 | label: Please carefully review each item in the checklist below | 请认真检查以下清单中的每一项 | 以下のチェックリストの各項目を注意深く確認してください
10 | options:
11 | - label: Searched and didn't find a similar issue | 已经搜索过,没有发现类似issue | 類似の問題が見つかりませんでした
12 | - label: Searched documentation and didn't find relevant content | 已经搜索过文档,没有发现相关内容 | ドキュメントを検索して関連する内容が見つかりませんでした
13 | - label: Tried with the latest version and the issue still exists | 已经尝试使用过最新版,问题依旧存在 | 最新バージョンを試しましたが問題は解消されませんでした
14 | - type: input
15 | id: app-version
16 | attributes:
17 | label: Software Version | 软件版本 | ソフトウェアバージョン
18 | placeholder: '1.1.4'
19 | validations:
20 | required: true
21 | - type: dropdown
22 | id: system-type
23 | attributes:
24 | label: Operating System | 操作系统 | オペレーティングシステム
25 | options:
26 | - Windows x64
27 | - Windows arm64
28 | - macOS x64 (Intel)
29 | - macOS arm64 (M1,M2...)
30 | - Ubuntu x64
31 | - Debian x64
32 | - Arch Linux x64
33 | - Other Linux x64
34 | validations:
35 | required: true
36 | - type: input
37 | id: system-version
38 | attributes:
39 | label: System Version | 系统版本 | システムバージョン
40 | validations:
41 | required: true
42 | - type: textarea
43 | id: description
44 | attributes:
45 | label: Describe the bug | 描述错误 | BUGの説明
46 | description: |
47 | A clear and concise description of what the bug is
48 | 描述错误的详细信息
49 | バグの内容を明確かつ簡潔に説明してください
50 | validations:
51 | required: true
52 | - type: textarea
53 | id: reproduce-steps
54 | attributes:
55 | label: To reproduce | 复现步骤 | 再現方法
56 | description: Steps to reproduce the behavior | 复现行为的步骤 | 不具合の再現手順
57 | value: |
58 | 1. Go to '...'
59 | 2. Click on '....'
60 | 3. See error
61 | validations:
62 | required: true
63 | - type: textarea
64 | id: log
65 | attributes:
66 | label: Error log | 报错日志 | ログ
67 | description: your error log | 您的错误日志 | エラーログ
68 | value: |
69 | ```
70 | your error log
71 | ```
72 | validations:
73 | required: true
74 | - type: textarea
75 | id: other
76 | attributes:
77 | label: Additional context | 附加内容 | 追加コンテキスト
78 | description: |
79 | Add any other context and screenshots to help explain your problem
80 | 添加任何其他上下文和截图,以帮助解释您的问题
81 | 問題を説明するために他の文脈やスクリーンショットを追加してください
82 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature.yaml:
--------------------------------------------------------------------------------
1 | name: 🚀 Feature request | 功能请求 | フィーチャーリクエスト
2 | description: Suggest an idea for this project | 为项目提供一个创意建议 | このプロジェクトにアイデアを提案する
3 | title: '[FEATURE] '
4 | labels: ['enhancement']
5 | body:
6 | - type: checkboxes
7 | id: checks
8 | attributes:
9 | label: Please carefully review each item in the checklist below | 请认真检查以下清单中的每一项 | 以下のチェックリストの各項目を注意深く確認してください
10 | options:
11 | - label: Searched and didn't find a similar issue | 已经搜索过,没有发现类似issue | 類似の問題が見つかりませんでした
12 | - type: textarea
13 | id: is-related
14 | attributes:
15 | label: Is your feature request related to a problem? | 你的feature请求是否与一个问题有关? | あなたのfeatureリクエストは質問に関連していますか?
16 | description: |
17 | A clear and concise description of what the problem is
18 | 请清楚而简明地描述问题是什么
19 | 問題が何であるかを明確かつ簡潔に説明してください
20 | validations:
21 | required: true
22 | - type: textarea
23 | id: detail
24 | attributes:
25 | label: Detail | 详细描述 | 詳細な説明
26 | description: |
27 | A clear and concise description of what you want to happen
28 | 请清楚而简明地描述您想要实现的内容
29 | 実現したい内容を明確かつ簡潔に説明してください
30 | validations:
31 | required: true
32 | - type: textarea
33 | id: log
34 | attributes:
35 | label: Additional context | 附加内容 | 追加コンテキスト
36 | description: |
37 | Add any other context or screenshots about the feature request here
38 | 在这里添加任何其他上下文或截图,以帮助解释您的功能请求
39 | その他の文脈やスクリーンショットを追加して、機能リクエストについて説明してください
40 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: 'npm' # See documentation for possible values
9 | directory: '/' # Location of package manifests
10 | schedule:
11 | interval: 'weekly'
12 | open-pull-requests-limit: 100
13 |
--------------------------------------------------------------------------------
/.github/workflows/CI-build.yml:
--------------------------------------------------------------------------------
1 | name: CI-build
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | paths-ignore:
8 | - '**.md'
9 | - LICENSE
10 | pull_request:
11 | paths-ignore:
12 | - '**.md'
13 | - LICENSE
14 | workflow_dispatch:
15 |
16 | jobs:
17 | windows:
18 | strategy:
19 | matrix:
20 | os-version: ['x64', 'arm64']
21 |
22 | runs-on: windows-latest
23 | steps:
24 | - uses: actions/checkout@v3
25 | with:
26 | submodules: recursive
27 |
28 | - uses: actions/setup-node@v3
29 | with:
30 | node-version: 20
31 |
32 | - uses: pnpm/action-setup@v2
33 | with:
34 | version: 8
35 |
36 | - name: build
37 | run: |
38 | pnpm install
39 | pnpm run build:win-${{ matrix.os-version }}
40 | env:
41 | GH_TOKEN: ${{ secrets.GH_TOKEN }}
42 |
43 | - name: zip-unpacked-x64
44 | if: matrix.os-version == 'x64'
45 | run: |
46 | cd .\dist\win-unpacked
47 | 7z a -r Final2x-windows-${{ matrix.os-version }}-unpacked.7z *
48 |
49 | - name: zip-unpacked-arm64
50 | if: matrix.os-version == 'arm64'
51 | run: |
52 | cd .\dist\win-arm64-unpacked
53 | 7z a -r Final2x-windows-${{ matrix.os-version }}-unpacked.7z *
54 |
55 | - name: upload-setup
56 | uses: actions/upload-artifact@v3
57 | with:
58 | name: Final2x-windows-${{ matrix.os-version }}-setup
59 | path: dist/*.exe
60 |
61 | - name: upload-unpacked-x64
62 | if: matrix.os-version == 'x64'
63 | uses: actions/upload-artifact@v3
64 | with:
65 | name: Final2x-windows-${{ matrix.os-version }}-unpacked
66 | path: dist/win-unpacked/*.7z
67 |
68 | - name: upload-unpacked-arm64
69 | if: matrix.os-version == 'arm64'
70 | uses: actions/upload-artifact@v3
71 | with:
72 | name: Final2x-windows-${{ matrix.os-version }}-unpacked
73 | path: dist/win-arm64-unpacked/*.7z
74 |
75 | macos:
76 | strategy:
77 | matrix:
78 | os-version: ['x64', 'arm64']
79 |
80 | runs-on: macos-14
81 | steps:
82 | - uses: actions/checkout@v3
83 | with:
84 | submodules: recursive
85 |
86 | - uses: actions/setup-node@v3
87 | with:
88 | node-version: 20
89 |
90 | - uses: pnpm/action-setup@v2
91 | with:
92 | version: 8
93 |
94 | - name: build
95 | run: |
96 | pnpm install
97 | pnpm run build:mac-${{ matrix.os-version }}
98 | env:
99 | ARCH: ${{ matrix.os-version }}
100 | GH_TOKEN: ${{ secrets.GH_TOKEN }}
101 |
102 | - name: zip-unpacked-x64
103 | if: matrix.os-version == 'x64'
104 | run: |
105 | cd ./dist/mac
106 | 7z a -r Final2x-macos-${{ matrix.os-version }}-unpacked.7z *
107 |
108 | - name: zip-unpacked-arm64
109 | if: matrix.os-version == 'arm64'
110 | run: |
111 | cd ./dist/mac-arm64
112 | 7z a -r Final2x-macos-${{ matrix.os-version }}-unpacked.7z *
113 |
114 | - name: upload-dmg
115 | uses: actions/upload-artifact@v3
116 | with:
117 | name: Final2x-macos-${{ matrix.os-version }}-dmg
118 | path: dist/*.dmg
119 |
120 | - name: upload-unpacked-x64
121 | if: matrix.os-version == 'x64'
122 | uses: actions/upload-artifact@v3
123 | with:
124 | name: Final2x-macos-${{ matrix.os-version }}-unpacked
125 | path: dist/mac/*.7z
126 |
127 | - name: upload-unpacked-arm64
128 | if: matrix.os-version == 'arm64'
129 | uses: actions/upload-artifact@v3
130 | with:
131 | name: Final2x-macos-${{ matrix.os-version }}-unpacked
132 | path: dist/mac-arm64/*.7z
133 |
134 | linux-pip:
135 | strategy:
136 | matrix:
137 | os-version: ['x64']
138 |
139 | runs-on: ubuntu-20.04
140 | steps:
141 | - uses: actions/checkout@v3
142 | with:
143 | submodules: recursive
144 |
145 | - uses: actions/setup-node@v3
146 | with:
147 | node-version: 20
148 |
149 | - uses: pnpm/action-setup@v2
150 | with:
151 | version: 8
152 |
153 | - name: build
154 | run: |
155 | pnpm install
156 | pnpm run build:linux-${{ matrix.os-version }}
157 | env:
158 | SKIP_DOWNLOAD_CORE: true
159 | GH_TOKEN: ${{ secrets.GH_TOKEN }}
160 |
161 | - name: zip-unpacked
162 | run: |
163 | cd ./dist/linux-unpacked
164 | 7z a -r Final2x-linux-pip-${{ matrix.os-version }}-unpacked.7z *
165 |
166 | - name: upload-snap
167 | uses: actions/upload-artifact@v3
168 | with:
169 | name: Final2x-linux-pip-${{ matrix.os-version }}-snap
170 | path: dist/*.snap
171 |
172 | - name: upload-AppImage
173 | uses: actions/upload-artifact@v3
174 | with:
175 | name: Final2x-linux-pip-${{ matrix.os-version }}-AppImage
176 | path: dist/*.AppImage
177 |
178 | - name: upload-deb
179 | uses: actions/upload-artifact@v3
180 | with:
181 | name: Final2x-linux-pip-${{ matrix.os-version }}-deb
182 | path: dist/*.deb
183 |
184 | - name: upload-unpacked
185 | uses: actions/upload-artifact@v3
186 | with:
187 | name: Final2x-linux-pip-${{ matrix.os-version }}-unpacked
188 | path: dist/linux-unpacked/*.7z
189 |
--------------------------------------------------------------------------------
/.github/workflows/CI-test.yml:
--------------------------------------------------------------------------------
1 | name: CI-test
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | paths-ignore:
8 | - '**.md'
9 | - LICENSE
10 | pull_request:
11 | paths-ignore:
12 | - '**.md'
13 | - LICENSE
14 | workflow_dispatch:
15 |
16 | jobs:
17 | test:
18 | strategy:
19 | matrix:
20 | os-version: ['macos-latest', 'windows-latest', 'ubuntu-20.04']
21 |
22 | runs-on: ${{ matrix.os-version }}
23 | steps:
24 | - uses: actions/checkout@v3
25 | with:
26 | submodules: recursive
27 |
28 | - uses: actions/setup-node@v3
29 | with:
30 | node-version: 20
31 |
32 | - uses: pnpm/action-setup@v2
33 | with:
34 | version: 8
35 |
36 | - name: Test
37 | run: |
38 | pnpm install
39 | pnpm run lint
40 | pnpm run typecheck
41 | pnpm run test-cov
42 | env:
43 | SKIP_DOWNLOAD_CORE: true
44 | GH_TOKEN: ${{ secrets.GH_TOKEN }}
45 |
--------------------------------------------------------------------------------
/.github/workflows/Release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | setup:
8 | runs-on: ubuntu-latest
9 | outputs:
10 | DATE: ${{ steps.get_date.outputs.DATE }}
11 | steps:
12 | - name: Get current date
13 | id: get_date
14 | run: echo "DATE=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
15 |
16 | windows:
17 | strategy:
18 | matrix:
19 | os-version: ['x64', 'arm64']
20 |
21 | runs-on: windows-latest
22 | steps:
23 | - uses: actions/checkout@v3
24 | with:
25 | submodules: recursive
26 |
27 | - uses: actions/setup-node@v3
28 | with:
29 | node-version: 20
30 |
31 | - uses: pnpm/action-setup@v2
32 | with:
33 | version: 8
34 |
35 | - name: build
36 | run: |
37 | pnpm install
38 | pnpm run build:win-${{ matrix.os-version }}
39 | env:
40 | GH_TOKEN: ${{ secrets.GH_TOKEN }}
41 |
42 | - name: zip-unpacked-x64
43 | if: matrix.os-version == 'x64'
44 | run: |
45 | cd .\dist\win-unpacked
46 | 7z a -r Final2x-windows-${{ matrix.os-version }}-unpacked.7z *
47 |
48 | - name: zip-unpacked-arm64
49 | if: matrix.os-version == 'arm64'
50 | run: |
51 | cd .\dist\win-arm64-unpacked
52 | 7z a -r Final2x-windows-${{ matrix.os-version }}-unpacked.7z *
53 |
54 | - name: rename
55 | run: |
56 | cd .\dist
57 | ren *.exe Final2x-windows-${{ matrix.os-version }}-setup.exe
58 | shell: cmd
59 |
60 | - name: upload-setup
61 | uses: actions/upload-artifact@v3
62 | with:
63 | path: dist/*.exe
64 |
65 | - name: upload-unpacked-x64
66 | if: matrix.os-version == 'x64'
67 | uses: actions/upload-artifact@v3
68 | with:
69 | path: dist/win-unpacked/*.7z
70 |
71 | - name: upload-unpacked-arm64
72 | if: matrix.os-version == 'arm64'
73 | uses: actions/upload-artifact@v3
74 | with:
75 | path: dist/win-arm64-unpacked/*.7z
76 |
77 | macos:
78 | strategy:
79 | matrix:
80 | os-version: ['x64', 'arm64']
81 |
82 | runs-on: macos-14
83 | steps:
84 | - uses: actions/checkout@v3
85 | with:
86 | submodules: recursive
87 |
88 | - uses: actions/setup-node@v3
89 | with:
90 | node-version: 20
91 |
92 | - uses: pnpm/action-setup@v2
93 | with:
94 | version: 8
95 |
96 | - name: build
97 | run: |
98 | pnpm install
99 | pnpm run build:mac-${{ matrix.os-version }}
100 | env:
101 | ARCH: ${{ matrix.os-version }}
102 | GH_TOKEN: ${{ secrets.GH_TOKEN }}
103 |
104 | - name: rename
105 | run: |
106 | cd ./dist
107 | mv *.dmg Final2x-macos-${{ matrix.os-version }}-dmg.dmg
108 |
109 | - name: zip-unpacked-x64
110 | if: matrix.os-version == 'x64'
111 | run: |
112 | cd ./dist/mac
113 | 7z a -r Final2x-macos-${{ matrix.os-version }}-unpacked.7z *
114 |
115 | - name: zip-unpacked-arm64
116 | if: matrix.os-version == 'arm64'
117 | run: |
118 | cd ./dist/mac-arm64
119 | 7z a -r Final2x-macos-${{ matrix.os-version }}-unpacked.7z *
120 |
121 | - name: upload-dmg
122 | uses: actions/upload-artifact@v3
123 | with:
124 | path: dist/*.dmg
125 |
126 | - name: upload-unpacked-x64
127 | if: matrix.os-version == 'x64'
128 | uses: actions/upload-artifact@v3
129 | with:
130 | path: dist/mac/*.7z
131 |
132 | - name: upload-unpacked-arm64
133 | if: matrix.os-version == 'arm64'
134 | uses: actions/upload-artifact@v3
135 | with:
136 | path: dist/mac-arm64/*.7z
137 |
138 | linux-pip:
139 | strategy:
140 | matrix:
141 | os-version: ['x64']
142 |
143 | runs-on: ubuntu-20.04
144 | steps:
145 | - uses: actions/checkout@v3
146 | with:
147 | submodules: recursive
148 |
149 | - uses: actions/setup-node@v3
150 | with:
151 | node-version: 20
152 |
153 | - uses: pnpm/action-setup@v2
154 | with:
155 | version: 8
156 |
157 | - name: build
158 | run: |
159 | pnpm install
160 | pnpm run build:linux-${{ matrix.os-version }}
161 | env:
162 | SKIP_DOWNLOAD_CORE: true
163 | GH_TOKEN: ${{ secrets.GH_TOKEN }}
164 |
165 | - name: zip-unpacked
166 | run: |
167 | cd ./dist/linux-unpacked
168 | 7z a -r Final2x-linux-pip-${{ matrix.os-version }}-unpacked.7z *
169 |
170 | - name: rename
171 | run: |
172 | cd ./dist
173 | mv *.snap Final2x-linux-pip-${{ matrix.os-version }}-snap.snap
174 | mv *.AppImage Final2x-linux-pip-${{ matrix.os-version }}-AppImage.AppImage
175 | mv *.deb Final2x-linux-pip-${{ matrix.os-version }}-deb.deb
176 |
177 | - name: upload-snap
178 | uses: actions/upload-artifact@v3
179 | with:
180 | path: dist/*.snap
181 |
182 | - name: upload-AppImage
183 | uses: actions/upload-artifact@v3
184 | with:
185 | path: dist/*.AppImage
186 |
187 | - name: upload-deb
188 | uses: actions/upload-artifact@v3
189 | with:
190 | path: dist/*.deb
191 |
192 | - name: upload-unpacked
193 | uses: actions/upload-artifact@v3
194 | with:
195 | path: dist/linux-unpacked/*.7z
196 |
197 | Release:
198 | needs: [setup, windows, macos, linux-pip]
199 | runs-on: ubuntu-latest
200 | steps:
201 | - uses: actions/download-artifact@v3
202 | with:
203 | path: asset
204 |
205 | - name: dist
206 | run: |
207 | mkdir dist
208 | cp asset/artifact/* dist
209 | cd dist && ls
210 |
211 | - name: Create Release and Upload Release Asset
212 | uses: softprops/action-gh-release@v1
213 | with:
214 | name: Release ${{ needs.setup.outputs.DATE }}
215 | tag_name: ${{ needs.setup.outputs.DATE }}
216 | body: Auto Release.
217 | draft: false
218 | prerelease: false
219 | files: dist/*
220 |
--------------------------------------------------------------------------------
/.github/workflows/issue-helper.yml:
--------------------------------------------------------------------------------
1 | name: issue-helper
2 |
3 | on:
4 | issues:
5 | types: [opened, reopened, edited]
6 |
7 | jobs:
8 | check-inactive:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: close-issues
12 | uses: actions-cool/issues-helper@v2
13 | with:
14 | actions: 'close-issues'
15 | token: ${{ secrets.GH_TOKEN }}
16 | inactive-day: 100
17 | body: |
18 | Hello! your issue has been closed because it has been inactive for a long time.
19 |
20 | 你好,你的 issue 因为长时间不活跃而被自动关闭。
21 |
22 | こんにちは、お問い合わせは長期間活動がないため、閉じられました。
23 |
24 | check-title:
25 | runs-on: ubuntu-latest
26 | if: github.event.issue.title == '[BUG] ' || github.event.issue.title == '[FEATURE] ' || (contains(github.event.issue.title, '[BUG]') == false && contains(github.event.issue.title, '[FEATURE]') == false)
27 | steps:
28 | - name: close issue
29 | uses: actions-cool/issues-helper@v3
30 | with:
31 | actions: 'create-comment, add-labels, close-issue'
32 | token: ${{ secrets.GH_TOKEN }}
33 | issue-number: ${{ github.event.issue.number }}
34 | labels: 'Invalid'
35 | body: |
36 | Hello @${{ github.event.issue.user.login }}, your issue has been closed because the title does not conform to our specification.
37 |
38 | 你好 @${{ github.event.issue.user.login }},为了能够进行高效沟通,我们对 issue 有一定的格式要求,你的 issue 因为标题不符合规范而被自动关闭。
39 |
40 | こんにちは、@${{ github.event.issue.user.login }}さん、タイトルが仕様に準拠していないため、ご提案いただいた問題はクローズされました。
41 |
--------------------------------------------------------------------------------
/.github/workflows/issue-translator.yml:
--------------------------------------------------------------------------------
1 | name: 'issue-translator'
2 | on:
3 | issue_comment:
4 | types: [created]
5 | issues:
6 | types: [opened]
7 |
8 | jobs:
9 | translate:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: usthe/issues-translate-action@v2.7
13 | with:
14 | CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically.
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | out
4 | *.log*
5 | *.DS_Store
6 | /resources/Final2x-core/
7 | /outputs/
8 | /.idea
9 | /coverage/
10 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | out
2 | dist
3 | pnpm-lock.yaml
4 | LICENSE.md
5 | tsconfig.json
6 | tsconfig.*.json
7 |
--------------------------------------------------------------------------------
/.prettierrc.yaml:
--------------------------------------------------------------------------------
1 | singleQuote: true
2 | semi: false
3 | printWidth: 100
4 | trailingComma: none
5 | endOfLine: crlf
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2023, Tohrusky
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | 2. Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | 3. Neither the name of the copyright holder nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 
10 | 
11 | 
12 | 
13 | 
14 | [](https://github.com/Tohrusky/Final2x/actions/workflows/CI-test.yml)
15 | [](https://github.com/Tohrusky/Final2x/actions/workflows/CI-build.yml)
16 | [](https://github.com/Tohrusky/Final2x/actions/workflows/Release.yml)
17 | 
18 | 
19 |
20 | This is a powerful tool that allows for image super-resolution to arbitrary sizes using [multiple models](./src/renderer/src/utils/ModelOptions.ts), designed to enhance the resolution and quality of images, making them clearer and more detailed.
21 |
22 | - News🎉: We are thrilled to announce the release of Final2x v2.0.0, which marks a major milestone as we transition to utilizing [ccrestoration](https://github.com/TensoRaws/ccrestoration) (PyTorch) for our algorithm implementation.
23 | - News🎉: Want to enhance your video? Try [FinalRip](https://github.com/TensoRaws/FinalRip)!
24 |
25 | ### Comparison
26 |
27 |
28 |

29 |
30 | use Final2x to perform 4x super-resolution on a 256x256 Hutao RGBA image
31 |
32 | ## Screenshots
33 |
34 |
35 |

36 |

37 |
38 |
39 | ### Installation
40 |
41 | ##### [Download the latest release from here.](https://github.com/Tohrusky/Final2x/releases)
42 |
43 | #### Windows
44 |
45 | Just Run! Furthermore, you can use package mananger to install and upgrade.
46 |
47 | ##### winget
48 |
49 | ```bash
50 | winget install Final2x
51 | ```
52 |
53 | #### MacOS
54 |
55 | ```bash
56 | sudo spctl --master-disable
57 | # Disable Gatekeeper, then allow applications downloaded from anywhere in System Preferences > Security & Privacy > General
58 | xattr -cr /Applications/Final2x.app
59 | ```
60 |
61 | In first time, you need to run the command above in terminal to allow the app to run.
62 |
63 | #### Linux
64 |
65 | For Linux User, you need to install the dependencies first.
66 |
67 | Make sure you have Python >= 3.9 and PyTorch >= 1.13 installed
68 |
69 | ```bash
70 | pip install Final2x-core
71 | Final2x-core -h # check if the installation is successful
72 | apt install -y libomp5 xdg-utils
73 | ```
74 |
75 | ### Reference
76 |
77 | The following references were referenced in the development of this project:
78 |
79 | - [Final2x-core](https://github.com/Tohrusky/Final2x-core)
80 | - [ccrestoration](https://github.com/TensoRaws/ccrestoration)
81 | - [PyTorch](https://github.com/pytorch/pytorch)
82 | - [ncnn](https://github.com/Tencent/ncnn)
83 | - [naive-ui](https://github.com/tusen-ai/naive-ui)
84 | - [electron-vite](https://github.com/alex8088/electron-vite)
85 |
86 | ### License
87 |
88 | This project is licensed under the BSD 3-Clause - see
89 | the [LICENSE file](https://github.com/Tohrusky/Final2x/blob/main/LICENSE) for details.
90 |
91 | ### Acknowledgements
92 |
93 | Feel free to reach out to the project maintainers with any questions or concerns~
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/README_i18n/README_zh.md:
--------------------------------------------------------------------------------
1 | # Final2x
2 |
--------------------------------------------------------------------------------
/build/entitlements.mac.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.cs.allow-jit
6 |
7 | com.apple.security.cs.allow-unsigned-executable-memory
8 |
9 | com.apple.security.cs.allow-dyld-environment-variables
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/build/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/build/icon.icns
--------------------------------------------------------------------------------
/build/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/build/icon.ico
--------------------------------------------------------------------------------
/build/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/build/icon.png
--------------------------------------------------------------------------------
/build/macosDMGbg.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/build/macosDMGbg.jpeg
--------------------------------------------------------------------------------
/build/notarize.js:
--------------------------------------------------------------------------------
1 | const { notarize } = require('@electron/notarize')
2 |
3 | module.exports = async (context) => {
4 | if (process.platform !== 'darwin') return
5 |
6 | console.log('aftersign hook triggered, start to notarize app.')
7 |
8 | if (!process.env.CI) {
9 | console.log(`skipping notarizing, not in CI.`)
10 | return
11 | }
12 |
13 | if (!('APPLE_ID' in process.env && 'APPLE_ID_PASS' in process.env)) {
14 | console.warn('skipping notarizing, APPLE_ID and APPLE_ID_PASS env variables must be set.')
15 | return
16 | }
17 |
18 | const appId = 'com.electron.app'
19 |
20 | const { appOutDir } = context
21 |
22 | const appName = context.packager.appInfo.productFilename
23 |
24 | try {
25 | await notarize({
26 | appBundleId: appId,
27 | appPath: `${appOutDir}/${appName}.app`,
28 | appleId: process.env.APPLE_ID,
29 | appleIdPassword: process.env.APPLEIDPASS
30 | })
31 | } catch (error) {
32 | console.error(error)
33 | }
34 |
35 | console.log(`done notarizing ${appId}.`)
36 | }
37 |
--------------------------------------------------------------------------------
/electron-builder.yml:
--------------------------------------------------------------------------------
1 | appId: com.electron.app
2 | productName: Final2x
3 | directories:
4 | buildResources: build
5 | files:
6 | - '!**/.vscode/*'
7 | - '!src/*'
8 | - '!electron.vite.config.{js,ts,mjs,cjs}'
9 | - '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
10 | - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
11 | - '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}'
12 |
13 | asar: false
14 |
15 | afterSign: build/notarize.js
16 |
17 | win:
18 | executableName: Final2x
19 |
20 | nsis:
21 | artifactName: ${name}-${version}-setup.${ext}
22 | shortcutName: ${productName}
23 | uninstallDisplayName: ${productName}
24 | createDesktopShortcut: always
25 |
26 | mac:
27 | entitlementsInherit: build/entitlements.mac.plist
28 | extendInfo:
29 | - NSCameraUsageDescription: Application requests access to the device's camera.
30 | - NSMicrophoneUsageDescription: Application requests access to the device's microphone.
31 | - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
32 | - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
33 |
34 | dmg:
35 | artifactName: ${name}-${version}.${ext}
36 | background: build/macosDMGbg.jpeg
37 | window:
38 | x: 100
39 | y: 100
40 | width: 480
41 | height: 500
42 |
43 | linux:
44 | target:
45 | - AppImage
46 | - snap
47 | - deb
48 | maintainer: electronjs.org
49 | category: Utility
50 | appImage:
51 | artifactName: ${name}-${version}.${ext}
52 | npmRebuild: false
53 |
--------------------------------------------------------------------------------
/electron.vite.config.ts:
--------------------------------------------------------------------------------
1 | import { resolve } from 'path'
2 | import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
3 | import vue from '@vitejs/plugin-vue'
4 |
5 | export default defineConfig({
6 | main: {
7 | plugins: [externalizeDepsPlugin()]
8 | },
9 | preload: {
10 | plugins: [externalizeDepsPlugin()]
11 | },
12 | renderer: {
13 | resolve: {
14 | alias: {
15 | '@renderer': resolve('src/renderer/src')
16 | }
17 | },
18 | plugins: [vue()]
19 | }
20 | })
21 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Final2x",
3 | "productName": "Final2x",
4 | "version": "2.1.0",
5 | "description": "A cross-platform image super-resolution tool.",
6 | "main": "./out/main/index.js",
7 | "author": "Tohrusky",
8 | "homepage": "https://github.com/Tohrusky/Final2x",
9 | "scripts": {
10 | "dev": "electron-vite dev",
11 | "test": "vitest",
12 | "test-cov": "vitest run --coverage",
13 | "lint": "prettier --write . && eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.vue --fix",
14 | "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
15 | "typecheck:web": "vue-tsc --noEmit -p tsconfig.web.json --composite false",
16 | "typecheck": "pnpm run typecheck:node && npm run typecheck:web",
17 | "start": "electron-vite preview",
18 | "build": "electron-vite build",
19 | "postinstall": "electron-builder install-app-deps && node ./resources/download-core.js",
20 | "build:mac-arm64": "pnpm run build && electron-builder --mac --arm64",
21 | "build:mac-x64": "pnpm run build && electron-builder --mac --x64",
22 | "build:win-arm64": "pnpm run build && electron-builder --win --arm64",
23 | "build:win-x64": "pnpm run build && electron-builder --win --x64",
24 | "build:linux-x64": "pnpm run build && electron-builder --linux --x64",
25 | "build:linux-arm64": "pnpm run build && electron-builder --linux --arm64"
26 | },
27 | "engines": {
28 | "node": ">=18.0.0"
29 | },
30 | "dependencies": {
31 | "@intlify/unplugin-vue-i18n": "^4.0.0",
32 | "@vicons/antd": "^0.12.0",
33 | "@vicons/ionicons5": "^0.12.0",
34 | "core-js": "^3.39.0",
35 | "naive-ui": "^2.40.1",
36 | "pinia": "^2.2.6",
37 | "pinia-plugin-persistedstate": "^3.2.3",
38 | "sass": "^1.80.6",
39 | "systeminformation": "^5.23.5",
40 | "vfonts": "^0.0.3",
41 | "vue": "^3.5.12",
42 | "vue-i18n": "^9.14.1",
43 | "vue-router": "^4.4.5"
44 | },
45 | "devDependencies": {
46 | "@electron-toolkit/preload": "^3.0.1",
47 | "@electron-toolkit/tsconfig": "^1.0.1",
48 | "@electron-toolkit/utils": "^3.0.0",
49 | "@electron/notarize": "^2.5.0",
50 | "@rushstack/eslint-patch": "^1.10.4",
51 | "@types/node": "20.14.9",
52 | "@vitejs/plugin-vue": "^5.1.4",
53 | "@vitest/coverage-v8": "^1.6.0",
54 | "@vue/eslint-config-prettier": "^9.0.0",
55 | "@vue/eslint-config-typescript": "^13.0.0",
56 | "@vue/test-utils": "^2.4.6",
57 | "electron": "^27.3.11",
58 | "electron-builder": "^23.6.0",
59 | "electron-vite": "^2.3.0",
60 | "eslint": "^8.57.1",
61 | "eslint-plugin-vue": "^9.30.0",
62 | "extract-zip": "^2.0.1",
63 | "jsdom": "^24.1.3",
64 | "node-fetch": "^3.3.2",
65 | "prettier": "^3.3.3",
66 | "typescript": "^5.6.3",
67 | "vite": "^5.4.10",
68 | "vitest": "^1.6.0",
69 | "vue-tsc": "^2.1.10"
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/resources/download-core.js:
--------------------------------------------------------------------------------
1 | // download Final2x-core from https://github.com/Final2x/Final2x-core/releases
2 | // and put it in resources folder
3 |
4 | const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args))
5 | const fs = require('fs')
6 | const path = require('path')
7 |
8 | const child_process = require('child_process')
9 |
10 | const coreDict = {
11 | 'macos-arm64':
12 | 'https://github.com/Tohrusky/Final2x-core/releases/download/2024-12-14/Final2x-core-macos-arm64.7z',
13 | 'macos-x64':
14 | 'https://github.com/Tohrusky/Final2x-core/releases/download/2024-12-14/Final2x-core-macos-x64.7z',
15 | 'windows-x64':
16 | 'https://github.com/Tohrusky/Final2x-core/releases/download/2024-12-14/Final2x-core-windows-latest.7z'
17 | }
18 |
19 | console.log('-'.repeat(50))
20 |
21 | // 判断当前平台
22 | const PLATFORM = process.env.PLATFORM || process.platform
23 | // 判断当前平台架构
24 | const ARCH = process.env.ARCH || process.arch
25 | console.log(`Platform: ${PLATFORM}`, `| Arch: ${ARCH}`)
26 | if (process.env.SKIP_DOWNLOAD_CORE) {
27 | console.log('Skip download Final2x-core by env SKIP_DOWNLOAD_CORE')
28 | process.exit(0)
29 | }
30 |
31 | async function downloadAndUnzip(url, targetPath) {
32 | const zipFileName = path.basename(url)
33 | const zipFilePath = path.join(targetPath, zipFileName)
34 |
35 | const res = await fetch(url)
36 | const dest = fs.createWriteStream(zipFilePath)
37 |
38 | dest.on('finish', () => {
39 | console.log(`Download ${zipFileName} success!`)
40 | // 解压缩文件, 命令行调用 7z
41 | const Final2xCorePath = path.join(targetPath, 'Final2x-core')
42 | const unzipCmd = `7z x ${zipFilePath} -o${Final2xCorePath}`
43 | console.log(`Unzip command: ${unzipCmd}`)
44 | // 使用异步方式执行解压命令
45 | child_process.exec(unzipCmd, (error) => {
46 | if (error) {
47 | console.error(`Unzip error: ${error}`)
48 | return
49 | }
50 | console.log(`Unzip ${zipFileName} success!`)
51 | // 删除压缩文件
52 | fs.unlinkSync(zipFilePath)
53 | console.log(`Delete ${zipFileName} success!`)
54 | })
55 | })
56 |
57 | res.body.pipe(dest)
58 | }
59 |
60 | async function downloadAndUnzipCore(platform) {
61 | const url = coreDict[platform]
62 | if (!url) {
63 | console.error('Invalid platform')
64 | return
65 | }
66 |
67 | const targetPath = path.join(__dirname)
68 | console.log(`Target path: ${targetPath}`)
69 |
70 | if (fs.existsSync(path.join(targetPath, 'Final2x-core'))) {
71 | console.log('Final2x-core already exists, skip download!')
72 | return
73 | }
74 |
75 | if (!fs.existsSync(targetPath)) {
76 | fs.mkdirSync(targetPath, { recursive: true })
77 | }
78 |
79 | await downloadAndUnzip(url, targetPath)
80 | }
81 |
82 | // 选择要下载的平台
83 | let platformToDownload = ''
84 | if (PLATFORM === 'darwin') {
85 | platformToDownload = ARCH === 'arm64' ? 'macos-arm64' : 'macos-x64'
86 | } else if (PLATFORM === 'linux') {
87 | console.error('Skip download Final2x-core for linux! Please use pip to install Final2x-core')
88 | process.exit(0)
89 | } else if (PLATFORM === 'win32') {
90 | platformToDownload = 'windows-x64'
91 | } else {
92 | console.error('Unsupported platform!')
93 | process.exit(1)
94 | }
95 |
96 | console.log(`Downloading Final2x-core for ${platformToDownload}...`)
97 | // 执行下载和解压
98 | downloadAndUnzipCore(platformToDownload)
99 | .then()
100 | .catch((err) => {
101 | console.error(err)
102 | })
103 |
--------------------------------------------------------------------------------
/resources/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/resources/icon.png
--------------------------------------------------------------------------------
/resources/taryTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/resources/taryTemplate.png
--------------------------------------------------------------------------------
/resources/tray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/resources/tray.png
--------------------------------------------------------------------------------
/resources/trayTemplate@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/resources/trayTemplate@2x.png
--------------------------------------------------------------------------------
/src/main/RunCommand.ts:
--------------------------------------------------------------------------------
1 | import { spawn, spawnSync } from 'child_process'
2 | import path from 'path'
3 | import { app } from 'electron'
4 |
5 | let child
6 |
7 | export async function RunCommand(
8 | event,
9 | config_json: string,
10 | openOutputFolder: boolean
11 | ): Promise {
12 | let resourceUrl: string
13 |
14 | // ---- 还是直接传base64吧
15 | // config_json = JSON.stringify(config_json) // 转义转义
16 | // ----
17 | config_json = Buffer.from(config_json, 'utf8').toString('base64')
18 |
19 | if (!CheckPipPackage()) {
20 | if (process.env.NODE_ENV === 'development') {
21 | resourceUrl = path.join(app.getAppPath(), '/resources/Final2x-core/Final2x-core')
22 | } else {
23 | resourceUrl = path.join(app.getAppPath(), '/resources/Final2x-core/Final2x-core')
24 | }
25 | } else {
26 | resourceUrl = 'Final2x-core'
27 | }
28 |
29 | let command = `"${resourceUrl}" -b ${config_json}`
30 |
31 | if (!openOutputFolder) {
32 | command += ' -n'
33 | }
34 |
35 | console.log(command)
36 |
37 | child = spawn(command, { shell: true })
38 |
39 | child.stdout.on('data', (data) => {
40 | event.sender.send('command-stdout', data.toString())
41 | })
42 |
43 | child.stderr.on('data', (data) => {
44 | event.sender.send('command-stderr', data.toString())
45 | })
46 |
47 | child.on('close', (code) => {
48 | event.sender.send('command-close-code', code)
49 | })
50 | }
51 |
52 | export async function KillCommand(): Promise {
53 | if (child) {
54 | child.kill()
55 | }
56 | }
57 |
58 | function CheckPipPackage(): boolean {
59 | const command = `Final2x-core -h`
60 |
61 | const result = spawnSync(command, { shell: true, encoding: 'utf-8' })
62 |
63 | return result.status === 0
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/index.ts:
--------------------------------------------------------------------------------
1 | import { app, BrowserWindow, ipcMain, Menu, nativeImage, shell, Tray } from 'electron'
2 | import { join } from 'path'
3 | import { electronApp, is, optimizer } from '@electron-toolkit/utils'
4 | import { KillCommand, RunCommand } from './RunCommand'
5 | import { openDirectory } from './openDirectory'
6 |
7 | const icon = join(__dirname, '../../resources/icon.png')
8 | const trayIcon = join(__dirname, '../../resources/tray.png')
9 |
10 | function createWindow(): void {
11 | // Create the browser window.
12 | const mainWindow = new BrowserWindow({
13 | width: 670,
14 | height: 470,
15 | maxWidth: 870,
16 | minWidth: 670,
17 | maxHeight: 670,
18 | minHeight: 470,
19 | frame: false,
20 | show: false,
21 | autoHideMenuBar: true,
22 | icon: nativeImage.createFromPath(icon),
23 | webPreferences: {
24 | preload: join(__dirname, '../preload/index.js'),
25 | sandbox: false
26 | }
27 | })
28 |
29 | if (process.platform === 'darwin') {
30 | app.dock.setIcon(nativeImage.createFromPath(icon))
31 | }
32 |
33 | ipcMain.on('execute-command', RunCommand)
34 |
35 | ipcMain.on('kill-command', KillCommand)
36 |
37 | ipcMain.on('open-directory-dialog', openDirectory)
38 |
39 | ipcMain.on('minimize', () => {
40 | mainWindow.minimize()
41 | })
42 |
43 | ipcMain.on('maximize', () => {
44 | if (mainWindow.isMaximized()) {
45 | mainWindow.restore()
46 | } else {
47 | mainWindow.maximize()
48 | }
49 | })
50 |
51 | ipcMain.on('close', () => {
52 | if (process.platform !== 'darwin') {
53 | app.quit()
54 | } else {
55 | app.hide()
56 | }
57 | })
58 |
59 | mainWindow.on('ready-to-show', () => {
60 | mainWindow.show()
61 | })
62 |
63 | mainWindow.webContents.setWindowOpenHandler((details) => {
64 | shell.openExternal(details.url)
65 | return { action: 'deny' }
66 | })
67 |
68 | // HMR for renderer base on electron-vite cli.
69 | // Load the remote URL for development or the local html file for production.
70 | if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
71 | mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
72 | mainWindow.webContents.openDevTools()
73 | } else {
74 | mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
75 | }
76 | }
77 |
78 | let tray
79 | function setTray(): void {
80 | const Image = nativeImage.createFromPath(trayIcon)
81 | Image.setTemplateImage(true)
82 | tray = new Tray(Image)
83 |
84 | const contextMenu = Menu.buildFromTemplate([
85 | {
86 | label: 'Open',
87 | click: (): void => {
88 | // On macOS it's common to re-create a window in the app when the
89 | // dock icon is clicked and there are no other windows open.
90 | if (BrowserWindow.getAllWindows().length === 0) {
91 | createWindow()
92 | } else {
93 | BrowserWindow.getAllWindows()[0].show()
94 | }
95 | }
96 | },
97 | {
98 | label: 'Exit',
99 | click: (): void => {
100 | app.quit()
101 | }
102 | }
103 | ])
104 |
105 | tray.setToolTip('Final2x')
106 | tray.setContextMenu(contextMenu)
107 | }
108 |
109 | // This method will be called when Electron has finished
110 | // initialization and is ready to create browser windows.
111 | // Some APIs can only be used after this event occurs.
112 | app.whenReady().then(() => {
113 | // Set app user model id for windows
114 | electronApp.setAppUserModelId('com.electron')
115 |
116 | // Default open or close DevTools by F12 in development
117 | // and ignore CommandOrControl + R in production.
118 | // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
119 | app.on('browser-window-created', (_, window) => {
120 | optimizer.watchWindowShortcuts(window)
121 | })
122 |
123 | setTray()
124 | createWindow()
125 |
126 | app.on('activate', function () {
127 | // On macOS it's common to re-create a window in the app when the
128 | // dock icon is clicked and there are no other windows open.
129 | if (BrowserWindow.getAllWindows().length === 0) createWindow()
130 | })
131 | })
132 |
133 | // Quit when all windows are closed, except on macOS. There, it's common
134 | // for applications and their menu bar to stay active until the user quits
135 | // explicitly with Cmd + Q.
136 | app.on('window-all-closed', () => {
137 | if (process.platform !== 'darwin') {
138 | app.quit()
139 | }
140 | })
141 |
142 | // In this file you can include the rest of your app"s specific main process
143 | // code. You can also put them in separate files and require them here.
144 |
--------------------------------------------------------------------------------
/src/main/openDirectory.ts:
--------------------------------------------------------------------------------
1 | import { dialog } from 'electron'
2 |
3 | /**
4 | * @description Open a directory or file/multiple files
5 | * @param event The event that triggered the function
6 | * @param p The properties of the dialog
7 | */
8 | export function openDirectory(event, p: Array): void {
9 | dialog
10 | .showOpenDialog({
11 | properties: p
12 | })
13 | .then((result) => {
14 | console.log(result)
15 | event.sender.send('selectedItem', result.filePaths)
16 | })
17 | .catch((err) => {
18 | console.log(err)
19 | })
20 | }
21 |
--------------------------------------------------------------------------------
/src/preload/index.d.ts:
--------------------------------------------------------------------------------
1 | import { ElectronAPI } from '@electron-toolkit/preload'
2 |
3 | declare global {
4 | interface Window {
5 | electron: ElectronAPI
6 | api: unknown
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/preload/index.ts:
--------------------------------------------------------------------------------
1 | import { contextBridge } from 'electron'
2 | import { electronAPI } from '@electron-toolkit/preload'
3 |
4 | // Custom APIs for renderer
5 | const api = {}
6 |
7 | // Use `contextBridge` APIs to expose Electron APIs to
8 | // renderer only if context isolation is enabled, otherwise
9 | // just add to the DOM global.
10 | if (process.contextIsolated) {
11 | try {
12 | contextBridge.exposeInMainWorld('electron', electronAPI)
13 | contextBridge.exposeInMainWorld('api', api)
14 | } catch (error) {
15 | console.error(error)
16 | }
17 | } else {
18 | // @ts-ignore (define in dts)
19 | window.electron = electronAPI
20 | // @ts-ignore (define in dts)
21 | window.api = api
22 | }
23 |
--------------------------------------------------------------------------------
/src/renderer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Final2x
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/renderer/src/App.vue:
--------------------------------------------------------------------------------
1 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
117 |
--------------------------------------------------------------------------------
/src/renderer/src/assets/final2xlogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/assets/final2xlogo.png
--------------------------------------------------------------------------------
/src/renderer/src/assets/final2xlogoDarkMode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/assets/final2xlogoDarkMode.png
--------------------------------------------------------------------------------
/src/renderer/src/components/MyDarkMode.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/renderer/src/components/MyExternalLink.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
44 |
--------------------------------------------------------------------------------
/src/renderer/src/components/MyProgress.vue:
--------------------------------------------------------------------------------
1 |
169 |
170 |
171 |
172 |
173 |
181 |
182 | {{ t('MyProgress.text6') }}
183 |
184 |
185 |
186 | {{ t('MyProgress.text7') }}
187 |
188 |
189 |
190 | {{ t('MyProgress.text8') }}
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
238 |
--------------------------------------------------------------------------------
/src/renderer/src/components/MySetting.vue:
--------------------------------------------------------------------------------
1 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
77 |
--------------------------------------------------------------------------------
/src/renderer/src/components/NaiveDarkMode.vue:
--------------------------------------------------------------------------------
1 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
--------------------------------------------------------------------------------
/src/renderer/src/components/TrafficLightsButtons.vue:
--------------------------------------------------------------------------------
1 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
53 |
58 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
74 |
79 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
267 |
--------------------------------------------------------------------------------
/src/renderer/src/components/bottomNavigation.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
33 |
--------------------------------------------------------------------------------
/src/renderer/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '*.vue' {
4 | import type { DefineComponent } from 'vue'
5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
6 | const component: DefineComponent<{}, {}, any>
7 | export default component
8 | }
9 |
--------------------------------------------------------------------------------
/src/renderer/src/locales/en.ts:
--------------------------------------------------------------------------------
1 | export const en = {
2 | MyProgress: {
3 | text0: 'Processing started',
4 | text1: 'Processing in progress',
5 | text2: 'Please add an image',
6 | text3: 'Image list is empty',
7 | text4: 'Processing terminated',
8 | text5: 'Processing failed, skipping',
9 | text6: 'START',
10 | text7: 'TERMINATE',
11 | text8: 'LOG',
12 | text9: 'Processing failed',
13 | text10: 'Please click on the log to view the error message'
14 | },
15 | Final2xHome: {
16 | text0: 'Removal successful',
17 | text1: 'Click or drag and drop images or folders here to upload'
18 | },
19 | Final2xSettings: {
20 | text10: 'Device',
21 | text11: 'Model',
22 | text15: 'Custom Scale',
23 | text16: 'Default',
24 | text17: 'Output Folder',
25 | text18: 'Proxy'
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/renderer/src/locales/fr.ts:
--------------------------------------------------------------------------------
1 | export const fr = {
2 | MyProgress: {
3 | text0: 'Traitement commencé',
4 | text1: 'Traitement en cours',
5 | text2: 'Veuillez ajouter une image',
6 | text3: "La liste d'images est vide",
7 | text4: 'Traitement terminé',
8 | text5: 'Échec du traitement, passage à la suite',
9 | text6: 'DÉMARRER',
10 | text7: 'ARRÊTER',
11 | text8: 'JOURNAL',
12 | text9: 'Échec du traitement',
13 | text10: "Veuillez cliquer sur le journal pour voir le message d'erreur"
14 | },
15 | Final2xHome: {
16 | text0: 'Suppression réussie',
17 | text1: 'Cliquez ou faites glisser les images ou dossiers ici pour les téléverser'
18 | },
19 | Final2xSettings: {
20 | text10: 'Périph.',
21 | text11: 'Modèle',
22 | text15: 'Échelle (num.)',
23 | text16: 'Par déf.',
24 | text17: 'Dossier de sortie',
25 | text18: 'Proxy'
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/renderer/src/locales/ja.ts:
--------------------------------------------------------------------------------
1 | export const ja = {
2 | MyProgress: {
3 | text0: '処理を開始します',
4 | text1: '処理中です',
5 | text2: '画像を追加してください',
6 | text3: '画像リストは空です',
7 | text4: '処理が中断されました',
8 | text5: '処理に失敗しました。スキップします',
9 | text6: '開始',
10 | text7: '中止',
11 | text8: 'ログ',
12 | text9: '処理失敗',
13 | text10: 'エラーメッセージを確認するには、ログをクリックしてください'
14 | },
15 | Final2xHome: {
16 | text0: '削除が成功しました',
17 | text1: '画像やフォルダをここにクリックまたはドラッグ&ドロップしてアップロードしてください'
18 | },
19 | Final2xSettings: {
20 | text10: 'デバイス',
21 | text11: 'モデル',
22 | text15: 'Custom Scale',
23 | text16: 'Default',
24 | text17: '出力フォルダ',
25 | text18: 'プロキシ'
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/renderer/src/locales/zh.ts:
--------------------------------------------------------------------------------
1 | export const zh = {
2 | MyProgress: {
3 | text0: '开始处理',
4 | text1: '处理中',
5 | text2: '请添加图片',
6 | text3: '图片列表为空',
7 | text4: '已终止处理',
8 | text5: '处理失败,跳过',
9 | text6: '开始',
10 | text7: '终止',
11 | text8: '日志',
12 | text9: '处理失败',
13 | text10: '请点击日志查看错误信息'
14 | },
15 | Final2xHome: {
16 | text0: '移除成功',
17 | text1: '点击或拖拽图片或文件夹到此处上传'
18 | },
19 | Final2xSettings: {
20 | text10: '设备',
21 | text11: '模型',
22 | text15: '自定义倍率',
23 | text16: '默认',
24 | text17: '输出文件夹',
25 | text18: '下载代理'
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/renderer/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import i18n from './plugins/i18n'
5 | import { createPinia } from 'pinia'
6 | import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
7 | // 通用字体
8 | import 'vfonts/OpenSans.css'
9 | import {
10 | // create naive ui
11 | create,
12 | // component
13 | NButton,
14 | NDivider,
15 | NSpace,
16 | NIcon,
17 | NImage,
18 | NCard,
19 | NDrawer,
20 | NDrawerContent,
21 | NLog,
22 | NProgress,
23 | NText,
24 | NUpload,
25 | NUploadDragger,
26 | NInput,
27 | NInputNumber,
28 | NPopover,
29 | NSelect,
30 | NSwitch
31 | } from 'naive-ui'
32 |
33 | const naive = create({
34 | components: [
35 | NButton,
36 | NDivider,
37 | NSpace,
38 | NIcon,
39 | NImage,
40 | NCard,
41 | NDrawer,
42 | NDrawerContent,
43 | NLog,
44 | NProgress,
45 | NText,
46 | NUpload,
47 | NUploadDragger,
48 | NInput,
49 | NInputNumber,
50 | NPopover,
51 | NSelect,
52 | NSwitch
53 | ]
54 | })
55 |
56 | const pinia = createPinia()
57 | pinia.use(piniaPluginPersistedstate)
58 |
59 | createApp(App).use(naive).use(i18n).use(pinia).use(router).mount('#app')
60 |
--------------------------------------------------------------------------------
/src/renderer/src/plugins/i18n.ts:
--------------------------------------------------------------------------------
1 | import { createI18n } from 'vue-i18n'
2 | import { en } from '../locales/en'
3 | import { zh } from '../locales/zh'
4 | import { ja } from '../locales/ja'
5 | import { fr } from '../locales/fr'
6 |
7 | // -----------------------------------------------------------------------------
8 | // to add a new language, add the language file to the locales folder and add the language id to the LANG_LIST array
9 | // and "import { xx } from '../locales/xx'" at the top of this file
10 | // and add the language to the messages object below
11 | export const LANG_LIST: string[] = ['en', 'zh', 'ja', 'fr']
12 | // -----------------------------------------------------------------------------
13 |
14 | const i18n = createI18n({
15 | legacy: false,
16 | fallbackLocale: 'en',
17 | globalInjection: true, // 全局注册$t方法
18 | messages: {
19 | en,
20 | zh,
21 | ja,
22 | fr
23 | }
24 | })
25 |
26 | export default i18n
27 |
--------------------------------------------------------------------------------
/src/renderer/src/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/favicon.ico
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/android-chrome-maskable-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/android-chrome-maskable-192x192.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/android-chrome-maskable-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/android-chrome-maskable-512x512.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/apple-touch-icon.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/msapplication-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/msapplication-icon-144x144.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tohrusky/Final2x/8a115e4ce298f44b9773bf8d810259993309ef23/src/renderer/src/public/img/icons/mstile-150x150.png
--------------------------------------------------------------------------------
/src/renderer/src/public/img/icons/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/renderer/src/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/renderer/src/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/src/renderer/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHashHistory } from 'vue-router'
2 | import Final2xHome from '../views/Final2xHome.vue'
3 | import Final2xSettings from '../views/Final2xSettings.vue'
4 |
5 | export default createRouter({
6 | history: createWebHashHistory(),
7 | routes: [
8 | {
9 | path: '/',
10 | redirect: '/Final2xHome'
11 | },
12 | {
13 | path: '/Final2xHome',
14 | name: 'Final2xHome',
15 | component: Final2xHome
16 | },
17 | {
18 | path: '/Final2xSettings',
19 | name: 'Final2xSettings',
20 | component: Final2xSettings
21 | }
22 | ]
23 | })
24 |
--------------------------------------------------------------------------------
/src/renderer/src/store/SRSettingsStore.ts:
--------------------------------------------------------------------------------
1 | import { ref, Ref } from 'vue'
2 | import { defineStore } from 'pinia'
3 |
4 | export const useSRSettingsStore = defineStore(
5 | 'SRSettings',
6 | () => {
7 | const selectedSRModel = ref('RealESRGAN_RealESRGAN_x2plus_2x.pth')
8 | const ghProxy: Ref = ref(null)
9 | const targetScale: Ref = ref(null)
10 |
11 | return {
12 | selectedSRModel,
13 | ghProxy,
14 | targetScale
15 | }
16 | },
17 | {
18 | persist: {
19 | storage: localStorage,
20 | paths: ['selectedSRModel', 'ghProxy', 'targetScale']
21 | }
22 | }
23 | )
24 |
--------------------------------------------------------------------------------
/src/renderer/src/store/globalSettingsStore.ts:
--------------------------------------------------------------------------------
1 | import { ref, Ref } from 'vue'
2 | import { defineStore } from 'pinia'
3 | import { LogInst } from 'naive-ui'
4 | import type { NaiveDarkModeType } from '../components/NaiveDarkMode.vue'
5 |
6 | export const useGlobalSettingsStore = defineStore(
7 | 'GlobalSettings',
8 | () => {
9 | const darkMode: Ref = ref('system')
10 | const globalcolor = ref('#fffafa')
11 | const naiveTheme: Ref = ref(undefined)
12 |
13 | const changeRoute = ref(false)
14 |
15 | const langsNum = ref(114514)
16 |
17 | const selectedTorchDevice = ref('auto')
18 | const torchDeviceList: Ref = ref([
19 | { value: 'auto', label: 'Auto' },
20 | { value: 'cuda', label: 'CUDA' },
21 | { value: 'mps', label: 'MPS' },
22 | { value: 'cpu', label: 'CPU' }
23 | ])
24 |
25 | const ProgressPercentage = ref(0)
26 | const CommandLOG = ref('')
27 | const logInstRef = ref(null)
28 | const StartCommandLock = ref(false)
29 | const SrSuccess = ref(false)
30 |
31 | const openOutputFolder = ref(true)
32 |
33 | return {
34 | darkMode,
35 | globalcolor,
36 | naiveTheme,
37 | changeRoute,
38 | langsNum,
39 | selectedTorchDevice,
40 | torchDeviceList,
41 | ProgressPercentage,
42 | CommandLOG,
43 | StartCommandLock,
44 | SrSuccess,
45 | logInstRef,
46 | openOutputFolder
47 | }
48 | },
49 | {
50 | persist: {
51 | storage: localStorage,
52 | paths: [
53 | 'langsNum',
54 | 'selectedTorchDevice',
55 | 'darkMode',
56 | 'naiveTheme',
57 | 'globalcolor',
58 | 'openOutputFolder'
59 | ]
60 | }
61 | }
62 | )
63 |
--------------------------------------------------------------------------------
/src/renderer/src/store/ioPathStore.ts:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 | import { defineStore } from 'pinia'
3 | import { UploadFileInfo } from 'naive-ui'
4 |
5 | export const useIOPathStore = defineStore(
6 | 'IOPath',
7 | () => {
8 | const inputpathMap = ref