mirror of
https://github.com/Molunerfinn/PicGo.git
synced 2026-09-20 03:16:37 +00:00
Compare commits
39
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89c24e7f8d | ||
|
|
54d15a6749 | ||
|
|
2cc29833df | ||
|
|
f695e7ccaf | ||
|
|
366ac11ee2 | ||
|
|
9d4ea8277d | ||
|
|
56f61d458e | ||
|
|
8e94b2a4d4 | ||
|
|
db627a450f | ||
|
|
070ce2b666 | ||
|
|
b421c4b42a | ||
|
|
d6c0a85a0f | ||
|
|
ca805f36f8 | ||
|
|
cccd2954db | ||
|
|
cfb6146de5 | ||
|
|
45b3227456 | ||
|
|
2450a524ff | ||
|
|
4a29bf2b50 | ||
|
|
24e4a829d8 | ||
|
|
e0d45fa7a2 | ||
|
|
de441a892e | ||
|
|
f1817eb1e1 | ||
|
|
2bd5d0653b | ||
|
|
9841418779 | ||
|
|
7bc70628f9 | ||
|
|
a928b4c8ab | ||
|
|
7df37a2526 | ||
|
|
dacb926f17 | ||
|
|
1ea074e75f | ||
|
|
04140def7c | ||
|
|
c9fe4023f0 | ||
|
|
c8ba547edb | ||
|
|
316928edc3 | ||
|
|
ff35335126 | ||
|
|
ff7336b99e | ||
|
|
917ec73027 | ||
|
|
8e91582adc | ||
|
|
aaec99f466 | ||
|
|
50e0a64519 |
@@ -1,4 +0,0 @@
|
||||
test/unit/coverage/**
|
||||
test/unit/*.js
|
||||
test/e2e/*.js
|
||||
dist/
|
||||
@@ -1,38 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
globals: {
|
||||
__static: 'readonly'
|
||||
},
|
||||
env: {
|
||||
node: true
|
||||
},
|
||||
parser: 'vue-eslint-parser',
|
||||
extends: [
|
||||
'plugin:vue/vue3-recommended',
|
||||
'@vue/standard',
|
||||
'@vue/typescript'
|
||||
],
|
||||
plugins: ['@typescript-eslint'],
|
||||
rules: {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'off' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
indent: 'off',
|
||||
'no-async-promise-executor': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'error',
|
||||
'@typescript-eslint/indent': ['error', 2],
|
||||
'vue/no-v-html': 'off'
|
||||
},
|
||||
parserOptions: {
|
||||
parser: '@typescript-eslint/parser'
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts', '*.vue'],
|
||||
rules: {
|
||||
'no-undef': 'off' // https://typescript-eslint.io/docs/linting/troubleshooting/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors
|
||||
}
|
||||
}
|
||||
],
|
||||
ignorePatterns: ['src/**/*.d.ts']
|
||||
}
|
||||
+1
-1
@@ -1 +1 @@
|
||||
custom: ["https://paypal.me/Molunerfinn"]
|
||||
github: ["Molunerfinn"]
|
||||
|
||||
+116
-41
@@ -1,61 +1,136 @@
|
||||
# main.yml
|
||||
name: Build & Release
|
||||
|
||||
# Workflow's name
|
||||
name: Build
|
||||
|
||||
# Workflow's trigger
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- v*
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
test_upload_dist:
|
||||
description: "Test upload-dist.js script"
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
env:
|
||||
NODE_VERSION: 22.x
|
||||
|
||||
# Workflow's jobs
|
||||
jobs:
|
||||
# job's id
|
||||
release:
|
||||
# job's name
|
||||
name: build and release electron app
|
||||
|
||||
# the type of machine to run the job on
|
||||
# parallel build jobs
|
||||
build:
|
||||
name: Build on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
# create a build matrix for jobs
|
||||
strategy:
|
||||
# if one job fails, do not stop other jobs
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-11]
|
||||
|
||||
# create steps
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
steps:
|
||||
# step1: check out repository
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# step2: install node env
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
- name: Install system deps
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
- name: Clean workspace on Windows
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils
|
||||
if (Test-Path dist) { Remove-Item -Recurse -Force dist }
|
||||
if (Test-Path dist_electron) { Remove-Item -Recurse -Force dist_electron }
|
||||
if (Test-Path node_modules) { Remove-Item -Recurse -Force node_modules }
|
||||
|
||||
# step3: yarn
|
||||
- name: Yarn install
|
||||
if (Test-Path "$env:LOCALAPPDATA\electron-builder") {
|
||||
Remove-Item "$env:LOCALAPPDATA\electron-builder" -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
if (Test-Path "$env:LOCALAPPDATA\electron") {
|
||||
Remove-Item "$env:LOCALAPPDATA\electron" -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
- name: Clean workspace on macOS & Linux
|
||||
if: runner.os == 'macOS' || runner.os == 'Linux'
|
||||
run: |
|
||||
yarn
|
||||
yarn global add xvfb-maybe
|
||||
|
||||
- name: Build & release app
|
||||
run: |
|
||||
yarn release
|
||||
yarn upload-dist
|
||||
rm -rf dist dist_electron node_modules ~/.cache/electron-builder ~/.cache/electron
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
- name: Ubuntu Update with sudo
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt-get update
|
||||
- name: Build Windows x64 & ARM64 App
|
||||
if: runner.os == 'Windows'
|
||||
run: yarn build:win || true
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
PICGO_ENV_COS_SECRET_ID: ${{ secrets.PICGO_ENV_COS_SECRET_ID }}
|
||||
PICGO_ENV_COS_SECRET_KEY: ${{ secrets.PICGO_ENV_COS_SECRET_KEY }}
|
||||
- name: Build macOS x64 & ARM64 App
|
||||
if: runner.os == 'macOS'
|
||||
run: yarn build:mac || true
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
- name: Build Linux x64 & ARM64 App
|
||||
if: runner.os == 'Linux'
|
||||
run: yarn build:linux || true
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: PicGo-${{ runner.os }}
|
||||
path: dist/*.*
|
||||
- name: Upload to release.picgo.app
|
||||
if: startsWith(github.ref, 'refs/tags/v') || github.event.inputs.test_upload_dist
|
||||
run: |
|
||||
yarn upload-dist
|
||||
env:
|
||||
PICGO_ENV_S3_SECRET_ID: ${{ secrets.PICGO_ENV_S3_SECRET_ID }}
|
||||
PICGO_ENV_S3_SECRET_KEY: ${{ secrets.PICGO_ENV_S3_SECRET_KEY }}
|
||||
PICGO_ENV_S3_ACCOUNT_ID: ${{ secrets.PICGO_ENV_S3_ACCOUNT_ID }}
|
||||
release:
|
||||
name: Publish GitHub Release
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Publish GitHub Dev Release
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
uses: softprops/action-gh-release@v2
|
||||
continue-on-error: true
|
||||
with:
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
tag_name: dev
|
||||
draft: true
|
||||
prerelease: false
|
||||
files: |
|
||||
!artifacts/**/*-unpacked/**
|
||||
artifacts/**/*.exe
|
||||
artifacts/**/*.dmg
|
||||
artifacts/**/*.zip
|
||||
artifacts/**/*.AppImage
|
||||
artifacts/**/*.deb
|
||||
artifacts/**/*.snap
|
||||
artifacts/**/*.tar.gz
|
||||
artifacts/**/*.yml
|
||||
artifacts/**/*.blockmap
|
||||
- name: Publish GitHub Release
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: softprops/action-gh-release@v2
|
||||
continue-on-error: true
|
||||
with:
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
generate_release_notes: true
|
||||
draft: true
|
||||
prerelease: false
|
||||
files: |
|
||||
!artifacts/**/*-unpacked/**
|
||||
artifacts/**/*.exe
|
||||
artifacts/**/*.dmg
|
||||
artifacts/**/*.zip
|
||||
artifacts/**/*.AppImage
|
||||
artifacts/**/*.deb
|
||||
artifacts/**/*.snap
|
||||
artifacts/**/*.tar.gz
|
||||
artifacts/**/*.yml
|
||||
artifacts/**/*.blockmap
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
# main.yml
|
||||
|
||||
# Workflow's name
|
||||
name: Build
|
||||
|
||||
# Workflow's trigger
|
||||
on: workflow_dispatch
|
||||
|
||||
# Workflow's jobs
|
||||
jobs:
|
||||
# job's id
|
||||
release:
|
||||
# job's name
|
||||
name: build and release electron app
|
||||
|
||||
# the type of machine to run the job on
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
# create a build matrix for jobs
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-11]
|
||||
|
||||
# create steps
|
||||
steps:
|
||||
# step1: check out repository
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# step2: install node env
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
- name: Install system deps
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils
|
||||
|
||||
# step3: yarn
|
||||
- name: Yarn install
|
||||
run: |
|
||||
yarn
|
||||
yarn global add xvfb-maybe
|
||||
|
||||
- name: Build & release app
|
||||
run: |
|
||||
yarn release
|
||||
yarn upload-dist
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
PICGO_ENV_COS_SECRET_ID: ${{ secrets.PICGO_ENV_COS_SECRET_ID }}
|
||||
PICGO_ENV_COS_SECRET_KEY: ${{ secrets.PICGO_ENV_COS_SECRET_KEY }}
|
||||
PICGO_ENV_S3_SECRET_ID: ${{ secrets.PICGO_ENV_S3_SECRET_ID }}
|
||||
PICGO_ENV_S3_SECRET_KEY: ${{ secrets.PICGO_ENV_S3_SECRET_KEY }}
|
||||
PICGO_ENV_S3_ACCOUNT_ID: ${{ secrets.PICGO_ENV_S3_ACCOUNT_ID }}
|
||||
+3
-1
@@ -21,4 +21,6 @@ test.js
|
||||
scripts/*.yml
|
||||
|
||||
#Electron-builder output
|
||||
/dist_electron
|
||||
/dist_electron
|
||||
.serena/
|
||||
dist/*
|
||||
@@ -0,0 +1 @@
|
||||
22
|
||||
Vendored
+11
-3
@@ -11,8 +11,13 @@
|
||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
|
||||
},
|
||||
"preLaunchTask": "electron-debug",
|
||||
"args": ["--remote-debugging-port=9223", "./dist_electron"],
|
||||
"outFiles": ["${workspaceFolder}/dist_electron/**/*.js"]
|
||||
"args": [
|
||||
"--remote-debugging-port=9223",
|
||||
"./dist"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Electron: Renderer",
|
||||
@@ -30,7 +35,10 @@
|
||||
"compounds": [
|
||||
{
|
||||
"name": "Electron: All",
|
||||
"configurations": ["Electron: Main", "Electron: Renderer"]
|
||||
"configurations": [
|
||||
"Electron: Main",
|
||||
"Electron: Renderer"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+8
-3
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"eslint.enable": true,
|
||||
"eslint.alwaysShowStatus": true,
|
||||
"eslint.format.enable": true,
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
@@ -20,7 +21,11 @@
|
||||
"stylusSupremacy.sortProperties": "grouped",
|
||||
"stylusSupremacy.quoteChar": "\"",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true,
|
||||
"source.organizeImports": false
|
||||
}
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.organizeImports": "never"
|
||||
},
|
||||
"prettier.enable": false,
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Project Structure & Module Organization
|
||||
PicGo is an Electron + Vue 3 desktop client. Source lives in `src/`: `src/main` for main-process and IPC logic, `src/renderer` for Vue views, and `src/universal` for shared helpers (`types/`, `events/constants.ts`). `background.ts` wires Electron Builder. Static assets and locale YAML files stay in `public/` (add languages under `public/i18n/`), while `docs/` hosts user-facing guides. Automation scripts live in `scripts/`, and legacy tests sit under `test/unit` (Karma) and `test/e2e` (Spectron).
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
- `pnpm install` — install dependencies; `npm install` is unsupported.
|
||||
- Always add/remove dependencies with `pnpm` (never edit package.json versions by hand then install).
|
||||
- `pnpm dev` — electron-vite dev server for main/preload/renderer.
|
||||
- `pnpm build` — electron-vite build outputs to `dist/main`, `dist/preload`, `dist/renderer`; `pnpm preview` for preview mode.
|
||||
- Packaging config lives in `electron-builder.yml` (read by electron-builder via package.json `build` field/extraResources); set `ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/` if downloads are slow.
|
||||
- `pnpm lint` / `pnpm lint:fix` — run or auto-fix ESLint (Standard, TypeScript, Vue rules).
|
||||
- `pnpm lint:dpdm` — fail fast on circular dependencies in `src/`.
|
||||
- `pnpm gen-i18n` — regenerate typed locales after touching `public/i18n/*.yml`.
|
||||
|
||||
## Coding Style & Naming Conventions
|
||||
Follow ESLint Standard defaults: two-space indentation, single quotes, trailing commas where allowed, and no stray semicolons. Author new modules in TypeScript. Keep renderer files browser-safe; route Node APIs through IPC helpers such as `src/main/events/picgoCoreIPC.ts`. Name Vue components in PascalCase (`UploadPanel.vue`) and use camelCase for utilities. Centralize IPC event names inside `src/universal/events/constants.ts`, and store enums/types under `src/universal/types/` so they stay reusable. Static assets are served from `public/` and resolved via `getStaticPath`/`getStaticFileUrl` (`src/universal/utils/staticPath.ts`); avoid using `__static` directly.
|
||||
Static assets are served from `public/`. In the main process use `getStaticPath`/`getStaticFileUrl` (`src/universal/utils/staticPath.ts`). In the renderer, place assets under `public/` and resolve them via `import.meta.env.BASE_URL + filename` (helper: `src/renderer/utils/static.ts`); do not rely on `__static` in renderer code.
|
||||
- Do not use `as any` under any circumstances; keep typings explicit and safe.
|
||||
|
||||
## Testing Guidelines
|
||||
Place renderer unit specs in `test/unit/specs` with the `.spec.js` suffix; Karma picks them up via `require.context`. Run them with `npx karma start test/unit/karma.conf.js --single-run` and ensure new renderer folders are covered. Spectron e2e cases live in `test/e2e/specs`; build first (`pnpm build`), then run `npx mocha test/e2e/index.js` so Spectron can launch `dist/electron/main.js`. Document any test data, IPC stubs, or fixtures you add to keep suites reproducible.
|
||||
|
||||
## Commit & Pull Request Guidelines
|
||||
Commits follow the PicGo conventional preset enforced by Husky (`pnpm lint:dpdm` + Commitlint). Stage your changes and run `pnpm cz` to craft messages that pass CI. Pull requests should explain the change, link related issues, and attach UI screenshots or recordings. Note how you validated the work (dev server, build, Karma, Spectron) and call out migration or configuration steps reviewers must perform.
|
||||
|
||||
## Internationalization Tips
|
||||
Add locales by creating `public/i18n/<locale>.yml`, exposing its `LANG_DISPLAY_LABEL`, and registering it in `src/universal/i18n/index.ts`. Finish with `pnpm gen-i18n` so the generated typings stay in sync.
|
||||
+111
@@ -1,3 +1,114 @@
|
||||
## :tada: 2.4.1-beta.1 (2025-12-10)
|
||||
|
||||
|
||||
### :bug: Bug Fixes
|
||||
|
||||
* **custom:** the issue that x64 macOS app can't be opened ([54d15a6](https://github.com/Molunerfinn/PicGo/commit/54d15a6)), closes [#1363](https://github.com/Molunerfinn/PicGo/issues/1363)
|
||||
|
||||
|
||||
### :package: Chore
|
||||
|
||||
* update builder config && add legacy version file upload process ([2cc2983](https://github.com/Molunerfinn/PicGo/commit/2cc2983))
|
||||
|
||||
|
||||
|
||||
## :tada: 2.4.1-beta.0 (2025-12-09)
|
||||
|
||||
|
||||
### :bug: Bug Fixes
|
||||
|
||||
* fix docs link ([d6c0a85](https://github.com/Molunerfinn/PicGo/commit/d6c0a85))
|
||||
* pic-migrater post handler error ([b421c4b](https://github.com/Molunerfinn/PicGo/commit/b421c4b))
|
||||
* tray window clipboard image not show bug ([#1362](https://github.com/Molunerfinn/PicGo/issues/1362)) ([56f61d4](https://github.com/Molunerfinn/PicGo/commit/56f61d4))
|
||||
|
||||
|
||||
### :package: Chore
|
||||
|
||||
* change release url ([9d4ea82](https://github.com/Molunerfinn/PicGo/commit/9d4ea82))
|
||||
* disabled build universal installer ([366ac11](https://github.com/Molunerfinn/PicGo/commit/366ac11))
|
||||
* fix some workflow bug ([db627a4](https://github.com/Molunerfinn/PicGo/commit/db627a4))
|
||||
* fix upload dist arch bug ([8e94b2a](https://github.com/Molunerfinn/PicGo/commit/8e94b2a))
|
||||
* upgrade electron version && migrate to electron-vite ([#1361](https://github.com/Molunerfinn/PicGo/issues/1361)) ([070ce2b](https://github.com/Molunerfinn/PicGo/commit/070ce2b))
|
||||
|
||||
|
||||
|
||||
# :tada: 2.4.0 (2025-11-23)
|
||||
|
||||
|
||||
### :pencil: Documentation
|
||||
|
||||
* add 2.4.0 changelog ([cccd295](https://github.com/Molunerfinn/PicGo/commit/cccd295))
|
||||
* add warp sponsor shoutout ([e0d45fa](https://github.com/Molunerfinn/PicGo/commit/e0d45fa))
|
||||
* add warp sponsor shoutout ([de441a8](https://github.com/Molunerfinn/PicGo/commit/de441a8))
|
||||
* update docs ([4a29bf2](https://github.com/Molunerfinn/PicGo/commit/4a29bf2))
|
||||
* update docs ([24e4a82](https://github.com/Molunerfinn/PicGo/commit/24e4a82))
|
||||
* update readme & warp sponsor link ([45b3227](https://github.com/Molunerfinn/PicGo/commit/45b3227))
|
||||
|
||||
|
||||
### :package: Chore
|
||||
|
||||
* change funding yml ([2450a52](https://github.com/Molunerfinn/PicGo/commit/2450a52))
|
||||
* update picgo core to 1.5.11 to solve url encode bug ([cfb6146](https://github.com/Molunerfinn/PicGo/commit/cfb6146))
|
||||
|
||||
|
||||
|
||||
# :tada: 2.4.0-beta.10 (2025-06-08)
|
||||
|
||||
|
||||
### :sparkles: Features
|
||||
|
||||
* finish form uploader for picgo server ([9841418](https://github.com/Molunerfinn/PicGo/commit/9841418))
|
||||
* **server:** add support for form upload in PicGo Server ([#1327](https://github.com/Molunerfinn/PicGo/issues/1327)) ([a928b4c](https://github.com/Molunerfinn/PicGo/commit/a928b4c)), closes [#428](https://github.com/Molunerfinn/PicGo/issues/428)
|
||||
|
||||
|
||||
### :bug: Bug Fixes
|
||||
|
||||
* auto-copy url can't be turned off ([#1300](https://github.com/Molunerfinn/PicGo/issues/1300)) ([dacb926](https://github.com/Molunerfinn/PicGo/commit/dacb926))
|
||||
* encoded url filename unreadable ([2bd5d06](https://github.com/Molunerfinn/PicGo/commit/2bd5d06))
|
||||
* unable to use clip in wayland ([#1301](https://github.com/Molunerfinn/PicGo/issues/1301)) ([7df37a2](https://github.com/Molunerfinn/PicGo/commit/7df37a2))
|
||||
|
||||
|
||||
|
||||
# :tada: 2.4.0-beta.9 (2024-12-02)
|
||||
|
||||
|
||||
### :bug: Bug Fixes
|
||||
|
||||
* clipboard filename missing second ([c9fe402](https://github.com/Molunerfinn/PicGo/commit/c9fe402)), closes [#1293](https://github.com/Molunerfinn/PicGo/issues/1293)
|
||||
* copy text bug ([c8ba547](https://github.com/Molunerfinn/PicGo/commit/c8ba547)), closes [#1210](https://github.com/Molunerfinn/PicGo/issues/1210) [#1280](https://github.com/Molunerfinn/PicGo/issues/1280)
|
||||
* plugin list search bug ([04140de](https://github.com/Molunerfinn/PicGo/commit/04140de)), closes [#1297](https://github.com/Molunerfinn/PicGo/issues/1297)
|
||||
|
||||
|
||||
### :package: Chore
|
||||
|
||||
* update ci macos version ([316928e](https://github.com/Molunerfinn/PicGo/commit/316928e))
|
||||
|
||||
|
||||
|
||||
# :tada: 2.4.0-beta.8 (2024-07-16)
|
||||
|
||||
|
||||
### :bug: Bug Fixes
|
||||
|
||||
* tencent cos url encode bug ([ff7336b](https://github.com/Molunerfinn/PicGo/commit/ff7336b)), closes [#1265](https://github.com/Molunerfinn/PicGo/issues/1265)
|
||||
|
||||
|
||||
|
||||
# :tada: 2.4.0-beta.7 (2024-04-22)
|
||||
|
||||
|
||||
### :sparkles: Features
|
||||
|
||||
* add startup mode ([aaec99f](https://github.com/Molunerfinn/PicGo/commit/aaec99f)), closes [#915](https://github.com/Molunerfinn/PicGo/issues/915)
|
||||
|
||||
|
||||
### :bug: Bug Fixes
|
||||
|
||||
* config page scroll bug ([8e91582](https://github.com/Molunerfinn/PicGo/commit/8e91582)), closes [#1237](https://github.com/Molunerfinn/PicGo/issues/1237)
|
||||
* tray menu open bug ([50e0a64](https://github.com/Molunerfinn/PicGo/commit/50e0a64)), closes [#1217](https://github.com/Molunerfinn/PicGo/issues/1217)
|
||||
|
||||
|
||||
|
||||
# :tada: 2.4.0-beta.6 (2023-11-19)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## 常见问题
|
||||
|
||||
> 在使用 PicGo 期间你会遇到很多问题,不过很多问题其实之前就有人提问过,也被解决,所以你可以先看看 [使用文档](https://picgo.github.io/PicGo-Doc/zh/guide/getting-started.html#%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B),这份 FAQ,以及那些被关闭的 [issues](https://github.com/Molunerfinn/PicGo/issues?q=is%3Aissue+is%3Aclosed),应该能找到答案。
|
||||
> 在使用 PicGo 期间你会遇到很多问题,不过很多问题其实之前就有人提问过,也被解决,所以你可以先看看 [使用文档](https://picgo.github.io/PicGo-Doc/guide/getting-started.html#%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B),这份 FAQ,以及那些被关闭的 [issues](https://github.com/Molunerfinn/PicGo/issues?q=is%3Aissue+is%3Aclosed),应该能找到答案。
|
||||
|
||||
## 1. 七牛图床上传图片成功后,相册里无法显示或图片无`http://`前缀
|
||||
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
<div align="center" markdown="1">
|
||||
<sup>Special thanks to:</sup>
|
||||
<br>
|
||||
<a href="https://go.warp.dev/picgo">
|
||||
<img alt="Warp sponsorship" width="400" src="https://raw.githubusercontent.com/warpdotdev/brand-assets/refs/heads/main/Github/Sponsor/Warp-Github-LG-03.png">
|
||||
</a>
|
||||
|
||||
### [Warp, the intelligent terminal for developers](https://go.warp.dev/picgo)
|
||||
[Available for MacOS, Linux, & Windows](https://go.warp.dev/picgo)<br>
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/Molunerfinn/test/master/picgo/New%20LOGO-150.png" alt="">
|
||||
<h1>PicGo</h1>
|
||||
@@ -50,19 +64,18 @@ PicGo 本体支持如下图床:
|
||||
- 开发进度可以查看 [Projects](https://github.com/Molunerfinn/PicGo/projects),会同步更新开发进度
|
||||
<!-- - 欢迎加入 [官方讨论区](https://github.com/Molunerfinn/PicGo/discussions) 与我交流 -->
|
||||
|
||||
**如果第一次使用,请参考应用 [使用文档](https://picgo.github.io/PicGo-Doc/zh/guide/getting-started.html)。遇到问题了还可以看看 [FAQ](https://github.com/Molunerfinn/PicGo/blob/dev/FAQ.md) 以及被关闭的 [issues](https://github.com/Molunerfinn/PicGo/issues?q=is%3Aissue+is%3Aclosed)。**
|
||||
**如果第一次使用,请参考应用 [使用文档](https://picgo.github.io/PicGo-Doc/guide/getting-started.html)。遇到问题了还可以看看 [FAQ](https://github.com/Molunerfinn/PicGo/blob/dev/FAQ.md) 以及被关闭的 [issues](https://github.com/Molunerfinn/PicGo/issues?q=is%3Aissue+is%3Aclosed)。**
|
||||
|
||||
## 下载安装
|
||||
|
||||
| 下载源 | 地址/安装方式 | 平台 | 备注 |
|
||||
|---|---|---|---|
|
||||
| GitHub Release | https://github.com/Molunerfinn/PicGo/releases | All | 国内下载速度可能会慢 |
|
||||
| [腾讯云COS](https://cloud.tencent.com/product/cos) | https://github.com/Molunerfinn/PicGo/releases 附在更新日志结尾 | All | 感谢 [腾讯云COS](https://cloud.tencent.com/product/cos) 提供的赞助支持 |
|
||||
| [山东大学镜像站](https://mirrors.sdu.edu.cn/) | https://mirrors.sdu.edu.cn/github-release/Molunerfinn_PicGo | All | 感谢 [山东大学镜像站](https://mirrors.sdu.edu.cn/) 提供的镜像支持 |
|
||||
| [Scoop](https://scoop.sh/) | `scoop bucket add extras` & `scoop install picgo` | Windows | 感谢 @huangnauh 和 @Gladtbam 的贡献 |
|
||||
| [Chocolatey](https://chocolatey.org/) | `choco install picgo` | Windows | 感谢 @iYato 的贡献 |
|
||||
| [Homebrew](https://brew.sh/) | `brew install picgo --cask` | macOS | 感谢 @womeimingzi11 的贡献 |
|
||||
| [AUR](https://aur.archlinux.org/packages/yay) | `yay -S picgo-appimage` | Arch-Linux | 感谢 @houbaron 的贡献 |
|
||||
| 下载源 | 地址/安装方式 | 平台 | 备注 |
|
||||
| --------------------------------------------- | ----------------------------------------------------------- | ---------- | ----------------------------------------------------------------- |
|
||||
| GitHub Release | https://github.com/Molunerfinn/PicGo/releases | All | 国内下载速度可能会慢 |
|
||||
| [山东大学镜像站](https://mirrors.sdu.edu.cn/) | https://mirrors.sdu.edu.cn/github-release/Molunerfinn_PicGo | All | 感谢 [山东大学镜像站](https://mirrors.sdu.edu.cn/) 提供的镜像支持 |
|
||||
| [Scoop](https://scoop.sh/) | `scoop bucket add extras` & `scoop install picgo` | Windows | 感谢 @huangnauh 和 @Gladtbam 的贡献 |
|
||||
| [Chocolatey](https://chocolatey.org/) | `choco install picgo` | Windows | 感谢 @iYato 的贡献 |
|
||||
| [Homebrew](https://brew.sh/) | `brew install picgo --cask` | macOS | 感谢 @womeimingzi11 的贡献 |
|
||||
| [AUR](https://aur.archlinux.org/packages/yay) | `yay -S picgo-appimage` | Arch-Linux | 感谢 @houbaron 的贡献 |
|
||||
|
||||
## 应用截图
|
||||
|
||||
@@ -90,21 +103,21 @@ PicGo 本体支持如下图床:
|
||||
|
||||
```bash
|
||||
ctrl+c # 退出开发模式
|
||||
npm run electron:serve # 重新进入开发模式
|
||||
npm run dev # 重新进入开发模式
|
||||
```
|
||||
|
||||
**注:Windows 开发模式运行之后会在底部任务栏的右下角应用区出现 PicGo 的应用图标。**
|
||||
|
||||
### 生产模式
|
||||
|
||||
如果你需要自行构建,可以 `npm run electron:build` 开始进行构建。构建成功后,会在 `dist_electron` 目录里出现构建成功的相应安装文件。
|
||||
如果你需要自行构建,可以 `npm run build` 开始进行构建。构建成功后,会在 `dist` 目录里出现构建成功的相应安装文件。
|
||||
|
||||
**注意**:如果你的网络环境不太好,可能会出现 `electron-builder` 下载 `electron` 二进制文件失败的情况。这个时候需要在 `npm run electron:build` 之前指定一下 `electron` 的源为国内源:
|
||||
**注意**:如果你的网络环境不太好,可能会出现 `electron-builder` 下载 `electron` 二进制文件失败的情况。这个时候需要在 build 之前指定一下 `electron` 的源为国内源:
|
||||
|
||||
```bash
|
||||
export ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/"
|
||||
# 在 Windows 上,则可以使用 set ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ (无需引号)
|
||||
npm run electron:build
|
||||
npm run build
|
||||
```
|
||||
|
||||
只需第一次构建的时候指定一下国内源即可。后续构建不需要特地指定。二进制文件下载在 `~/.electron/` 目录下。如果想要更新 `electron` 构建版本,可以删除 `~/.electron/` 目录,然后重新运行上一步,让 `electron-builder `去下载最新的 `electron` 二进制文件。
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
# Commented sections below can be used to run tests on the CI server
|
||||
# https://simulatedgreg.gitbooks.io/electron-vue/content/en/testing.html#on-the-subject-of-ci-testing
|
||||
version: 0.1.{build}
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
image: Visual Studio 2017
|
||||
platform:
|
||||
- x64
|
||||
|
||||
cache:
|
||||
- '%APPDATA%\npm-cache'
|
||||
- '%USERPROFILE%\.electron'
|
||||
- '%USERPROFILE%\AppData\Local\Yarn\cache'
|
||||
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
install:
|
||||
- ps: Install-Product node 16 x64
|
||||
- git reset --hard HEAD
|
||||
- yarn
|
||||
- node --version
|
||||
|
||||
build_script:
|
||||
#- yarn test
|
||||
- yarn release
|
||||
- yarn upload-dist
|
||||
|
||||
test: false
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 164 KiB |
@@ -0,0 +1,131 @@
|
||||
# PicGo 2.4.0 Changelog
|
||||
|
||||
## Features
|
||||
- 新增 相册页新增文件名展示,参考 #1050
|
||||
- 新增 相册中和顶部栏窗口中无法展示的图片或者 url 将会展示默认图片,参考#1050
|
||||

|
||||
- 新增 macOS 顶部栏窗口新增文件名展示,参考 #1054
|
||||
- 新增 同种类型图床支持多份配置,上传时可以指定某一份配置进行上传。感谢 @STDSuperman ,参考 #1016
|
||||

|
||||
- 新增 选择图床的菜单可以支持选择该图床类型某一项具体配置
|
||||

|
||||
- 新增 显示 dock 栏图标选项,参考 #1045
|
||||
<img width="787" alt="image" src="https://github.com/Molunerfinn/PicGo/assets/12621342/bb9492f1-6522-45ce-ae5d-c614901d8b06" />
|
||||
- 新增 PicGo 修复工具箱,可以自行排查一些问题
|
||||
<img width="324" alt="image" src="https://github.com/Molunerfinn/PicGo/assets/12621342/98cf6e64-7313-4ebe-83d0-aa86e4514109" />
|
||||
- 新增 对输出的 URL 进行 encode 转义的选项,参考 #731
|
||||
<img width="775" alt="image" src="https://github.com/Molunerfinn/PicGo/assets/12621342/6e0c13dd-3404-4b07-9c99-412321835b27" />
|
||||
- 新增 支持拖拽任意格式文件上传,参考 #1052
|
||||
- 新增 腾讯云 COS 支持 `Endpoint` 配置 和 `极智压缩` 配置。 感谢 @palmcivet @yc910920 的贡献!
|
||||

|
||||
- 新增 `tips` 配置渲染的支持,可以动态渲染 Uploader config 的 tips。支持 markdown 格式。参考 [tcyun uploader config](https://github.com/PicGo/PicGo-Core/blob/dev/src/plugins/uploader/tcyun.ts#L280)
|
||||

|
||||
- 新增 上传界面展示当前图床使用的配置名
|
||||

|
||||
- 新增 相册页工具栏,目前内置 `批量修改图片 URL HOST 的功能` 。参考 #875
|
||||
注意:需要先选中指定的图片,然后会根据已选中的图片进行修改,你可以通过图床筛选功能只筛选出需要修改的图片。
|
||||
例如,你有一批图片都是 `https://www.a.com/...` 打头的 URL,你想把 `www.a.com` 批量修改成 `www.b.com` ,就可以用这个功能
|
||||

|
||||
- 新增 `启动模式`,可以设置启动的时候是否要打开窗口。全平台支持 `静默启动`(默认值) & `打开主窗口`,Windows 和 Linux 额外支持 `打开 Mini 窗口`。参考 #915
|
||||
<img width="577" alt="image" src="https://github.com/Molunerfinn/PicGo/assets/12621342/7e63bb5c-44b0-480e-824f-3c2edbed4fbb" />
|
||||
- 新增 PicGo Server 支持表单形式上传图片。参考 #428 ,感谢 @happy-game
|
||||
表单字段为 files。参考截图:
|
||||
<img width="951" alt="image" src="https://github.com/user-attachments/assets/14244f1d-60f5-487f-bde6-6d0e009645fb" />
|
||||
|
||||
## Bug Fixes
|
||||
- 修复 windows 右键菜单配置生成脚本,参考 #1019
|
||||
- 修复 自定义链接 URL encode 问题,参考 #1112
|
||||
- 修复 日志写入可能存在死循环问题,参考 #1101
|
||||
- 修复 拖拽文件到顶部栏图标报错问题,参考 #1107
|
||||
- 修复 文件名 encode 问题。参考 #1121
|
||||
- 修复 GitHub 重名文件上传不再报错。
|
||||
- 修复 beta.2 版本部分样式问题
|
||||
- 修复 重命名窗口某些情况下显示文件名过慢的问题,参考 #1130
|
||||
- 修复 打开配置文件打开的是日志文件的 bug,参考 #1163
|
||||
- 修复 插件配置弹窗打开后无法正确读取和保存配置的问题。
|
||||
- 修复 无法新增图床配置的问题(新增变成了编辑)。参考 #1198,#1196
|
||||
- 修复 macOS 右键菜单消失问题。感谢 @muwoo 。参考 #1179
|
||||
- 修复 macOS 顶部栏窗口右键之后一闪而过的问题。 感谢 @QThans。 参考 #1217
|
||||
- 修复 图床配置页面配置项过多时无法滚动到底部的问题。参考 #1237
|
||||
- 修复 腾讯云 COS URL encode 的问题。参考 #1265
|
||||
- 修复 插件列表无法搜索的问题。 参考 #1297
|
||||
- 修复 剪贴板文件名丢失 `秒` 的问题。 参考 #1293
|
||||
- 修复 macOS 顶部栏点击图片复制链接失效的问题。 参考 #1280 , #1210
|
||||
- 修复 自动复制 URL 这个开关无法被关闭的问题。参考 #1294 ,感谢 @happy-game
|
||||
- 修复 wayland 里无法使用剪贴板图片的问题。参考 #1261 ,感谢 @happy-game
|
||||
- 修复 直接通过 URL 上传图片的时候,带有汉字的 URL 上传后,文件名被 encode 的问题。 参考 #1339
|
||||
|
||||
## Other
|
||||
- 由于 PicGo 存储的 COS 空间被恶意刷大量流量导致欠费,暂时停止 COS 渠道的 PicGo 分发。
|
||||
- 更新至 Vue3
|
||||
- 重构部分代码
|
||||
- 重构部分代码
|
||||
- 补充更详细的快捷键相关日志,参考 #1031
|
||||
- 已知问题:部分按钮样式有点问题,下个版本会修复
|
||||
- 更新 README中的 scoop 下载安装的部分,感谢 @wuhang2003
|
||||
|
||||
----------
|
||||
|
||||
# PicGo 2.4.0 Changelog
|
||||
|
||||
## Features
|
||||
- Add filename display in the gallery (#1050).
|
||||
- Add default placeholders when images/URLs cannot be shown in the gallery or tray window (#1050).
|
||||

|
||||
- Add filename display in the macOS tray window (#1054).
|
||||
- Allow multiple configs per uploader type and choose one for upload (thanks @STDSuperman, #1016).
|
||||

|
||||
- Allow the uploader selection menu to pick a specific config entry for that uploader type.
|
||||

|
||||
- Add Dock icon visibility option (#1045).
|
||||
<img width="787" alt="image" src="https://github.com/Molunerfinn/PicGo/assets/12621342/bb9492f1-6522-45ce-ae5d-c614901d8b06" />
|
||||
- Add PicGo Repair Toolbox for self-diagnosis.
|
||||
<img width="324" alt="image" src="https://github.com/Molunerfinn/PicGo/assets/12621342/98cf6e64-7313-4ebe-83d0-aa86e4514109" />
|
||||
- Add option to encode/escape output URLs (#731).
|
||||
<img width="775" alt="image" src="https://github.com/Molunerfinn/PicGo/assets/12621342/6e0c13dd-3404-4b07-9c99-412321835b27" />
|
||||
- Support drag-and-drop uploads for arbitrary file formats (#1052).
|
||||
- Tencent COS: add Endpoint and Intelligent Compression settings (thanks @palmcivet @yc910920).
|
||||

|
||||
- Add Markdown-rendered tips for uploader config (see tcyun uploader config).
|
||||

|
||||
- Show the active uploader config name in the upload screen.
|
||||

|
||||
- Gallery toolbar: bulk replace image URL host (#875).
|
||||
Note: select images first; you can filter by uploader; e.g., replace `https://www.a.com/...` with `https://www.b.com/...`.
|
||||

|
||||
- Add “Startup Mode”: Silent (default) / Main Window; Windows/Linux also support Mini Window (#915).
|
||||
<img width="577" alt="image" src="https://github.com/Molunerfinn/PicGo/assets/12621342/7e63bb5c-44b0-480e-824f-3c2edbed4fbb" />
|
||||
- PicGo Server: support multipart form uploads (field `files`, #428, thanks @happy-game).
|
||||
<img width="951" alt="image" src="https://github.com/user-attachments/assets/14244f1d-60f5-487f-bde6-6d0e009645fb" />
|
||||
|
||||
## Bug Fixes
|
||||
- Fix Windows context-menu config script generation (#1019).
|
||||
- Fix custom link URL encoding (#1112).
|
||||
- Fix potential logging dead loop (#1101).
|
||||
- Fix drag-to-tray upload error (#1107).
|
||||
- Fix filename encoding (#1121).
|
||||
- Prevent errors on GitHub uploads with duplicate filenames.
|
||||
- Fix beta.2 style issues.
|
||||
- Fix slow filename display in the rename window (#1130).
|
||||
- Fix “open config file” actually opening the log file (#1163).
|
||||
- Fix plugin config dialog not reading/saving correctly.
|
||||
- Fix inability to add new uploader configs (created as edit) (#1198, #1196).
|
||||
- Fix macOS context menu disappearing (thanks @muwoo, #1179).
|
||||
- Fix macOS tray window flashing after right-click (thanks @QThans, #1217).
|
||||
- Fix uploader config page not scrollable when many fields (#1237).
|
||||
- Fix Tencent COS URL encoding (#1265).
|
||||
- Fix plugin list search not working (#1297).
|
||||
- Fix clipboard filename losing “seconds” (#1293).
|
||||
- Fix macOS tray copy-link failing on click (#1280, #1210).
|
||||
- Fix auto-copy URL toggle not turning off (#1294, thanks @happy-game).
|
||||
- Fix Wayland clipboard image upload issue (#1261, thanks @happy-game).
|
||||
- Fix URL uploads with Chinese characters being encoded in filenames (#1339).
|
||||
|
||||
## Other
|
||||
- COS distribution paused due to malicious traffic charges.
|
||||
- Upgrade to Vue3.
|
||||
- Refactor parts of the code.
|
||||
- Refactor parts of the code (again).
|
||||
- Add more detailed hotkey logs (#1031).
|
||||
- Known issue: some button styles were incorrect (fixed in later betas).
|
||||
- Update README scoop installation section (thanks @wuhang2003).
|
||||
@@ -0,0 +1,48 @@
|
||||
# gen_changelog.md
|
||||
|
||||
This guide describes how to generate a consolidated changelog for any PicGo release series (e.g., 2.4.0, 2.5.0) from the GitHub release notes of its betas and finals.
|
||||
|
||||
## Source of truth
|
||||
- Use GitHub release pages only (e.g., `https://github.com/Molunerfinn/PicGo/releases/tag/vX.Y.Z-beta.N` and `vX.Y.Z` if present). You can fetch these via MCP GitHub APIs (e.g., `get_release_by_tag`, `list_releases`) instead of manual browsing.
|
||||
- Do **not** use `CHANGELOG.md` in the repo.
|
||||
- Preserve all text and images exactly as written in the releases.
|
||||
|
||||
## Structure
|
||||
- Target file: `changelog/X.Y.Z.md` (replace with the series version).
|
||||
- Three top-level sections: `## Features`, `## Bug Fixes`, `## Other`.
|
||||
- Do **not** nest content under individual beta version headers; merge all items into these sections.
|
||||
- Keep items in chronological order (early → late) within each section, mirroring the beta sequence.
|
||||
- Keep inline issue references, thanks, and notes as-is.
|
||||
- Remove download-link sections entirely.
|
||||
- After the Chinese sections, insert a line with `----------`, then add a full English translation with the same structure/content (including images).
|
||||
|
||||
## Formatting rules
|
||||
- Markdown, plain ASCII.
|
||||
- Bullet lists only; no numbered lists required.
|
||||
- Indent images under their bullet with two spaces to keep association clear.
|
||||
- Keep inline HTML image tags from the releases (e.g., `<img width="...">`) untouched.
|
||||
- Keep line breaks and multi-line notes intact.
|
||||
- Do not reword or summarize; copy content verbatim except for removing beta headers and download sections.
|
||||
- English translation must mirror the Chinese bullets in order and content (keep images alongside the translated bullets).
|
||||
|
||||
## Regeneration steps
|
||||
1) Collect all release bodies for the target series (e.g., `vX.Y.Z-beta.0…N` and, if present, `vX.Y.Z`) from GitHub releases.
|
||||
2) For each release, copy bullets and images into the appropriate section:
|
||||
- Features ↔ “Feature(s)” or “Features” blocks.
|
||||
- Bug Fixes ↔ “Bug Fixes” blocks.
|
||||
- Other ↔ “Other”, “Notice”, or misc notes that are not features/bugs.
|
||||
3) Omit “国内可下载链接” (or any download links) entirely.
|
||||
4) Drop beta subheadings; keep only section-level bullets in chronological order.
|
||||
5) Ensure images remain adjacent to their bullets with indentation.
|
||||
6) After the Chinese sections are complete, insert `----------` on its own line.
|
||||
7) Append the English translation, preserving bullet order and images, under `## Features`, `## Bug Fixes`, `## Other` again (same section titles, just English content; no “(English)” suffix).
|
||||
8) Save the result to `changelog/X.Y.Z.md`.
|
||||
|
||||
## Quick checklist
|
||||
- [ ] All features present with images kept.
|
||||
- [ ] All bug fixes present.
|
||||
- [ ] All “Other” notes present.
|
||||
- [ ] No beta headers.
|
||||
- [ ] No download links.
|
||||
- [ ] Chronological ordering preserved.
|
||||
- [ ] English translation present with matching bullets/images after `----------`.
|
||||
+2
-2
@@ -7,13 +7,13 @@
|
||||
small(v-if="version") {{ version }}
|
||||
h2.desc 图片上传+管理新体验
|
||||
button.download(@click="goLink('https://github.com/Molunerfinn/picgo/releases')") 免费下载
|
||||
button.download(@click="goLink('https://picgo.github.io/PicGo-Doc/zh/guide/')") 查看文档
|
||||
button.download(@click="goLink('https://picgo.github.io/PicGo-Doc/guide/')") 查看文档
|
||||
h3.desc
|
||||
| 基于#[a(href="https://github.com/SimulatedGREG/electron-vue" target="_blank") electron-vue]开发
|
||||
h3.desc
|
||||
| 支持macOS,Windows,Linux
|
||||
h3.desc
|
||||
| 支持#[a(href="https://picgo.github.io/PicGo-Doc/zh/guide/config.html#%E6%8F%92%E4%BB%B6%E8%AE%BE%E7%BD%AE%EF%BC%88v2-0%EF%BC%89" target="_blank") 插件系统],让PicGo更强大
|
||||
| 支持#[a(href="https://picgo.github.io/PicGo-Doc/guide/config.html#%E6%8F%92%E4%BB%B6%E8%AE%BE%E7%BD%AE%EF%BC%88v2-0%EF%BC%89" target="_blank") 插件系统],让PicGo更强大
|
||||
#container.container-fluid
|
||||
.row.ex-width
|
||||
img.gallery.col-xs-10.col-xs-offset-1.col-md-offset-2.col-md-8(src="https://cdn.jsdelivr.net/gh/Molunerfinn/test/picgo-site/first.png")
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
|
||||
import type { Configuration } from 'electron-builder'
|
||||
|
||||
const config: Configuration = {
|
||||
appId: 'com.molunerfinn.picgo',
|
||||
productName: 'PicGo',
|
||||
// publish: [
|
||||
// {
|
||||
// provider: 'github',
|
||||
// owner: 'Molunerfinn',
|
||||
// repo: 'PicGo',
|
||||
// releaseType: 'draft'
|
||||
// }
|
||||
// ],
|
||||
// temporarily disable auto update feature
|
||||
publish: [],
|
||||
files: [
|
||||
'dist_electron/**/*',
|
||||
'public/**/*',
|
||||
'package.json',
|
||||
'!node_modules/@babel/**/*',
|
||||
"!**/node_modules/typescript{,/**}"
|
||||
],
|
||||
extraResources: [
|
||||
{
|
||||
from: 'public',
|
||||
to: 'public'
|
||||
}
|
||||
],
|
||||
dmg: {
|
||||
contents: [
|
||||
{
|
||||
x: 410,
|
||||
y: 150,
|
||||
type: 'link',
|
||||
path: '/Applications'
|
||||
},
|
||||
{
|
||||
x: 130,
|
||||
y: 150,
|
||||
type: 'file'
|
||||
}
|
||||
]
|
||||
},
|
||||
mac: {
|
||||
icon: 'build/icons/512x512.png',
|
||||
extendInfo: {
|
||||
LSUIElement: 0
|
||||
},
|
||||
target: [
|
||||
{
|
||||
target: 'dmg',
|
||||
arch: ['x64', 'arm64']
|
||||
}
|
||||
],
|
||||
artifactName: 'PicGo-${version}-${arch}.${ext}'
|
||||
},
|
||||
win: {
|
||||
icon: 'build/icons/icon.ico',
|
||||
artifactName: 'PicGo-${version}-${arch}.exe',
|
||||
target: [
|
||||
{
|
||||
target: 'nsis',
|
||||
arch: ['x64']
|
||||
},
|
||||
{
|
||||
target: 'nsis',
|
||||
arch: ['ia32']
|
||||
},
|
||||
{
|
||||
target: 'nsis',
|
||||
arch: ['arm64']
|
||||
}
|
||||
]
|
||||
},
|
||||
nsis: {
|
||||
shortcutName: 'PicGo',
|
||||
oneClick: false,
|
||||
allowToChangeInstallationDirectory: true,
|
||||
buildUniversalInstaller: false,
|
||||
include: 'build/installer.nsh'
|
||||
},
|
||||
linux: {
|
||||
executableName: 'PicGo',
|
||||
icon: 'build/icons/512x512.png',
|
||||
artifactName: 'PicGo-${version}-${arch}.${ext}',
|
||||
target: [
|
||||
{
|
||||
target: 'AppImage',
|
||||
arch: ['x64', 'arm64']
|
||||
},
|
||||
{
|
||||
target: 'deb',
|
||||
arch: ['x64', 'arm64']
|
||||
},
|
||||
{
|
||||
target: 'snap',
|
||||
arch: ['x64']
|
||||
}
|
||||
],
|
||||
maintainer: 'Molunerfinn',
|
||||
category: 'Utility',
|
||||
publish: []
|
||||
}
|
||||
}
|
||||
|
||||
export default config
|
||||
@@ -0,0 +1,58 @@
|
||||
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
// temp for webUtils
|
||||
import electronRenderer from '@molunerfinn/vite-plugin-electron-renderer'
|
||||
import { resolve } from 'path'
|
||||
|
||||
const alias = {
|
||||
'@': resolve(__dirname, 'src/renderer'),
|
||||
'~': resolve(__dirname, 'src'),
|
||||
'#': resolve(__dirname, 'src/universal'),
|
||||
root: resolve(__dirname, '.'),
|
||||
apis: resolve(__dirname, 'src/main/apis'),
|
||||
'@core': resolve(__dirname, 'src/main/apis/core')
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
main: {
|
||||
plugins: [externalizeDepsPlugin()],
|
||||
resolve: { alias },
|
||||
build: {
|
||||
outDir: 'dist_electron/main',
|
||||
rollupOptions: {
|
||||
input: {
|
||||
index: resolve(__dirname, 'src/background.ts')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
preload: {
|
||||
plugins: [externalizeDepsPlugin()],
|
||||
resolve: { alias },
|
||||
build: {
|
||||
outDir: 'dist_electron/preload',
|
||||
rollupOptions: {
|
||||
input: {
|
||||
index: resolve(__dirname, 'src/preload/index.ts')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
renderer: {
|
||||
root: 'src/renderer',
|
||||
publicDir: resolve(__dirname, 'src/renderer/public'),
|
||||
resolve: { alias },
|
||||
plugins: [vue(), electronRenderer()],
|
||||
build: {
|
||||
outDir: 'dist_electron/renderer',
|
||||
rollupOptions: {
|
||||
input: {
|
||||
index: resolve(__dirname, 'src/renderer/index.html')
|
||||
}
|
||||
}
|
||||
},
|
||||
server: {
|
||||
port: 5173
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,126 @@
|
||||
const path = require('node:path')
|
||||
const eslintJs = require('@eslint/js')
|
||||
const tsPlugin = require('@typescript-eslint/eslint-plugin')
|
||||
const tsParser = require('@typescript-eslint/parser')
|
||||
const importPlugin = require('eslint-plugin-import')
|
||||
const promisePlugin = require('eslint-plugin-promise')
|
||||
const vuePlugin = require('eslint-plugin-vue')
|
||||
|
||||
const isProduction = process.env.NODE_ENV === 'production'
|
||||
const vueConfigs = vuePlugin.configs['flat/recommended'].map(config => ({
|
||||
...config,
|
||||
languageOptions: {
|
||||
...(config.languageOptions || {}),
|
||||
parserOptions: {
|
||||
...(config.languageOptions?.parserOptions || {}),
|
||||
parser: tsParser,
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
extraFileExtensions: ['.vue']
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
const tsConfigs = tsPlugin.configs['flat/recommended'].map(config => ({
|
||||
...config,
|
||||
files: config.files || ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts'],
|
||||
languageOptions: {
|
||||
...(config.languageOptions || {}),
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
...(config.languageOptions?.parserOptions || {}),
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
extraFileExtensions: ['.vue'],
|
||||
project: path.join(__dirname, 'tsconfig.json'),
|
||||
tsconfigRootDir: __dirname
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
...(config.rules || {}),
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': ['error', {
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
caughtErrors: 'none'
|
||||
}],
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'@typescript-eslint/no-require-imports': 'off',
|
||||
'@typescript-eslint/no-unsafe-function-type': 'off',
|
||||
'@typescript-eslint/no-empty-object-type': 'off'
|
||||
}
|
||||
}))
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
ignores: [
|
||||
'dist/**',
|
||||
'dist_electron/**',
|
||||
'build/**',
|
||||
'test/unit/coverage/**',
|
||||
'test/unit/*.js',
|
||||
'test/e2e/*.js',
|
||||
'node_modules/**'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'eslint/base',
|
||||
languageOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
globals: {
|
||||
__static: 'readonly'
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
import: importPlugin,
|
||||
promise: promisePlugin
|
||||
},
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
node: {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx', '.d.ts', '.vue']
|
||||
}
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
...eslintJs.configs.recommended.rules,
|
||||
...importPlugin.configs.recommended.rules,
|
||||
...promisePlugin.configs.recommended.rules,
|
||||
'import/named': 'off',
|
||||
'import/no-named-as-default-member': 'off',
|
||||
'import/no-unresolved': 'off',
|
||||
'promise/catch-or-return': 'off',
|
||||
'promise/always-return': 'off',
|
||||
'no-console': 'off',
|
||||
'no-debugger': isProduction ? 'error' : 'off',
|
||||
'no-async-promise-executor': 'off',
|
||||
'no-empty': ['error', { allowEmptyCatch: true }],
|
||||
'no-unused-vars': 'off'
|
||||
}
|
||||
},
|
||||
...vueConfigs,
|
||||
{
|
||||
files: ['*.vue', '**/*.vue'],
|
||||
rules: {
|
||||
'vue/no-v-html': 'off',
|
||||
'vue/attribute-hyphenation': 'off'
|
||||
}
|
||||
},
|
||||
...tsConfigs,
|
||||
{
|
||||
files: ['**/*.{ts,tsx,vue}'],
|
||||
rules: {
|
||||
'no-undef': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.d.ts'],
|
||||
rules: {
|
||||
'no-var': 'off',
|
||||
'@typescript-eslint/no-empty-object-type': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off'
|
||||
}
|
||||
}
|
||||
]
|
||||
+41
-35
@@ -1,42 +1,56 @@
|
||||
{
|
||||
"name": "picgo",
|
||||
"version": "2.4.0-beta.6",
|
||||
"version": "2.4.1-beta.1",
|
||||
"private": true,
|
||||
"main": "dist_electron/main/index.js",
|
||||
"description": "A powerful & simple image uploader for creators.",
|
||||
"author": {
|
||||
"name": "Molunerfinn",
|
||||
"email": "marksz@teamsz.xyz"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "vue-cli-service electron:build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"build": "electron-vite build && electron-builder --config electron-builder.config.ts",
|
||||
"build:win": "npm run build && electron-builder --config electron-builder.config.ts --win",
|
||||
"build:mac": "npm run build && electron-builder --config electron-builder.config.ts --mac",
|
||||
"build:linux": "npm run build && electron-builder --config electron-builder.config.ts --linux",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.vue src/",
|
||||
"tsc": "tsc --noEmit",
|
||||
"bump": "bump-version",
|
||||
"cz": "git-cz",
|
||||
"dev": "vue-cli-service electron:serve",
|
||||
"electron:build": "vue-cli-service electron:build",
|
||||
"electron:serve": "vue-cli-service electron:serve",
|
||||
"dev": "electron-vite dev",
|
||||
"preview": "electron-vite preview",
|
||||
"gen-i18n": "node ./scripts/gen-i18n-types.js",
|
||||
"lint:fix": "eslint --fix --ext .js,.jsx,.ts,.tsx,.vue src/",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"postuninstall": "electron-builder install-app-deps",
|
||||
"release": "vue-cli-service electron:build --publish always",
|
||||
"upload-dist": "node ./scripts/upload-dist.js",
|
||||
"lint:dpdm": "dpdm -T --tsconfig ./tsconfig.json --no-tree --no-warning --exit-code circular:1 src/background.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.0.10",
|
||||
"@element-plus/icons-vue": "^2.3.2",
|
||||
"@picgo/i18n": "^1.0.0",
|
||||
"@picgo/store": "^2.1.0",
|
||||
"axios": "^0.19.0",
|
||||
"clip-filepaths": "^0.3.0",
|
||||
"compare-versions": "^4.1.3",
|
||||
"core-js": "^3.27.1",
|
||||
"dayjs": "^1.11.19",
|
||||
"element-plus": "^2.3.7",
|
||||
"epipebomb": "^1.0.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"keycode": "^2.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-id": "^0.14.0",
|
||||
"lowdb": "^1.0.0",
|
||||
"marked": "^7.0.4",
|
||||
"mitt": "^3.0.0",
|
||||
"picgo": "^1.5.6",
|
||||
"mitt": "^3.0.1",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"picgo": "^1.6.0",
|
||||
"qrcode.vue": "^3.3.3",
|
||||
"semver": "^7.7.3",
|
||||
"shell-path": "2.1.0",
|
||||
"tunnel": "^0.0.6",
|
||||
"uuid": "^9.0.0",
|
||||
"vue": "^3.3.4",
|
||||
"vue-router": "^4.2.2",
|
||||
@@ -47,49 +61,45 @@
|
||||
"devDependencies": {
|
||||
"@aws-sdk/client-s3": "^3.276.0",
|
||||
"@aws-sdk/lib-storage": "^3.276.0",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.16.7",
|
||||
"@eslint/js": "^9.39.1",
|
||||
"@molunerfinn/vite-plugin-electron-renderer": "^0.14.7",
|
||||
"@picgo/bump-version": "^1.1.2",
|
||||
"@types/electron-devtools-installer": "^2.2.0",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/inquirer": "^6.5.0",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/lodash": "^4.17.21",
|
||||
"@types/lowdb": "^1.0.9",
|
||||
"@types/node": "^16.10.2",
|
||||
"@types/multer": "^1.4.12",
|
||||
"@types/node": "^20",
|
||||
"@types/request-promise-native": "^1.0.17",
|
||||
"@types/semver": "^7.3.8",
|
||||
"@types/tunnel": "^0.0.3",
|
||||
"@types/uuid": "^9.0.2",
|
||||
"@types/write-file-atomic": "^4.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.0",
|
||||
"@typescript-eslint/parser": "^5.48.0",
|
||||
"@vue/cli-plugin-babel": "^5.0.8",
|
||||
"@vue/cli-plugin-eslint": "^5.0.8",
|
||||
"@vue/cli-plugin-router": "^5.0.8",
|
||||
"@vue/cli-plugin-typescript": "^5.0.8",
|
||||
"@vue/cli-service": "^5.0.8",
|
||||
"@vue/eslint-config-standard": "^8.0.1",
|
||||
"@vue/eslint-config-typescript": "^11.0.2",
|
||||
"@vue/runtime-dom": "^3.2.45",
|
||||
"@typescript-eslint/eslint-plugin": "^8.49.0",
|
||||
"@typescript-eslint/parser": "^8.49.0",
|
||||
"@vitejs/plugin-vue": "^6.0.2",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"conventional-changelog": "^3.1.18",
|
||||
"cz-customizable": "^6.2.0",
|
||||
"dotenv": "^16.0.1",
|
||||
"dpdm": "^3.13.1",
|
||||
"electron": "^16.0.6",
|
||||
"electron": "^38",
|
||||
"electron-builder": "26.1.0",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"eslint": "^8.31.0",
|
||||
"eslint-config-standard": ">=16.0.0",
|
||||
"eslint-plugin-import": "^2.24.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
"eslint-plugin-vue": "^9.8.0",
|
||||
"electron-vite": "^4.0.1",
|
||||
"eslint": "^9.39.1",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-promise": "^7.2.1",
|
||||
"eslint-plugin-vue": "^10.6.2",
|
||||
"husky": "^3.1.0",
|
||||
"postcss": "^8.4.23",
|
||||
"stylus": "^0.54.7",
|
||||
"stylus-loader": "^3.0.2",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"typescript": "^4.4.3",
|
||||
"vue-cli-plugin-electron-builder": "^3.0.0-alpha.4"
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.2.6"
|
||||
},
|
||||
"commitlint": {
|
||||
"extends": [
|
||||
@@ -108,9 +118,5 @@
|
||||
"hooks": {
|
||||
"commit-msg": "npm run lint:dpdm && commitlint -E HUSKY_GIT_PARAMS"
|
||||
}
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/node": "^16.10.2",
|
||||
"vue-cli-plugin-electron-builder/**/electron-builder": "23.3.3"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+11845
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
onlyBuiltDependencies:
|
||||
- core-js
|
||||
- ejs
|
||||
- electron
|
||||
- electron-winstaller
|
||||
- esbuild
|
||||
- husky
|
||||
- vue-demi
|
||||
|
||||
# for multi-arch builds, include both x64 and arm64 versions of electron
|
||||
# will be deprecated in future(use different arch machine to build different arch binaries)
|
||||
supportedArchitectures:
|
||||
os:
|
||||
- current
|
||||
cpu:
|
||||
- x64
|
||||
- arm64
|
||||
+10
-6
@@ -1,4 +1,4 @@
|
||||
LANG_DISPLAY_LABEL: 'English'
|
||||
LANG_DISPLAY_LABEL: "English"
|
||||
ABOUT: About
|
||||
OPEN_MAIN_WINDOW: Open Main Window
|
||||
CHOOSE_DEFAULT_PICBED: Choose Default Picbed
|
||||
@@ -28,7 +28,7 @@ OPEN_TOOLBOX: Open Toolbox
|
||||
|
||||
# ---renderer i18n begin---
|
||||
|
||||
CHOOSE_YOUR_DEFAULT_PICBED: 'Choose ${d} as your default picbed:'
|
||||
CHOOSE_YOUR_DEFAULT_PICBED: "Choose ${d} as your default picbed:"
|
||||
UPLOAD_AREA: Upload Area
|
||||
GALLERY: Gallery
|
||||
PICBEDS_SETTINGS: Picbeds Settings
|
||||
@@ -85,7 +85,7 @@ SETTINGS_AUTO_COPY_URL_AFTER_UPLOAD: Auto Copy URL After Upload
|
||||
SETTINGS_TIPS_PLACEHOLDER_URL: Use $url to represent url position
|
||||
SETTINGS_TIPS_PLACEHOLDER_FILENAME: Use $fileName to represent file name position
|
||||
SETTINGS_TIPS_PLACEHOLDER_EXTNAME: Use $extName to represent file's ext position
|
||||
SETTINGS_TIPS_SUCH_AS: 'Such as: $url/$fileName'
|
||||
SETTINGS_TIPS_SUCH_AS: "Such as: $url/$fileName"
|
||||
SETTINGS_UPLOAD_PROXY: Upload Proxy
|
||||
SETTINGS_PLUGIN_INSTALL_PROXY: Proxy for Plugin Install
|
||||
SETTINGS_PLUGIN_INSTALL_MIRROR: Mirror for Plugin Install
|
||||
@@ -121,6 +121,10 @@ UPLOADER_CONFIG_PLACEHOLDER: Please Enter Configuration Name
|
||||
SELECTED_SETTING_HINT: Selected
|
||||
SETTINGS_ENCODE_OUTPUT_URL: Encode Output(or Copyed) URL
|
||||
SETTINGS_SHOW_DOCK_ICON: Show Dock icon
|
||||
SETTINGS_STARTUP_MODE: Startup Mode
|
||||
SETTINGS_STARTUP_MODE_MAIN_WINDOW: Open Main Window
|
||||
SETTINGS_STARTUP_MODE_MINI_WINDOW: Open Mini Window
|
||||
SETTINGS_STARTUP_MODE_HIDE: Silent Startup
|
||||
|
||||
# shortcut-page
|
||||
|
||||
@@ -202,10 +206,10 @@ UPDATE_PLUGIN: Update Plugin
|
||||
|
||||
# toolbox
|
||||
TOOLBOX: Toolbox
|
||||
TOOLBOX_TITLE: Troubleshoot PicGo runtime issues
|
||||
TOOLBOX_TITLE: Troubleshoot PicGo runtime issues
|
||||
TOOLBOX_SUB_TITLE: Scan the following items immediately to fix usage issues
|
||||
TOOLBOX_CHECK_CONFIG_FILE_BROKEN: Check if the configuration file is damaged
|
||||
TOOLBOX_CHECK_GALLERY_FILE_BROKEN: Check if the album file is damaged
|
||||
TOOLBOX_CHECK_GALLERY_FILE_BROKEN: Check if the album file is damaged
|
||||
TOOLBOX_CHECK_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD: Check if there is a problem with clipboard picture upload
|
||||
TOOLBOX_CHECK_PROBLEM_WITH_PROXY: Check if the proxy settings are normal
|
||||
TOOLBOX_FIX_DONE_NEED_RELOAD: Repair completed, need to restart to take effect, restart or not
|
||||
@@ -236,7 +240,7 @@ TIPS_PLUGIN_OVERWRITE_GALLERY: Plugin is trying to overwrite the album gallery,
|
||||
TIPS_UPLOAD_NOT_PICTURES: The latest clipboard item is not a picture
|
||||
TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_DEFAULT: PicGo config file broken, has been restored to default
|
||||
TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP: PicGo config file broken, has been restored to backup
|
||||
TIPS_PICGO_BACKUP_FILE_VERSION: 'Backup file version: ${v}'
|
||||
TIPS_PICGO_BACKUP_FILE_VERSION: "Backup file version: ${v}"
|
||||
TIPS_CUSTOM_CONFIG_FILE_PATH_ERROR: Custom config file parse error, please check the path content
|
||||
TIPS_SHORTCUT_MODIFIED_SUCCEED: Shortcut modified successfully
|
||||
TIPS_SHORTCUT_MODIFIED_CONFLICT: Shortcut conflict, please reset
|
||||
|
||||
@@ -121,6 +121,10 @@ UPLOADER_CONFIG_PLACEHOLDER: 请输入配置名称
|
||||
SELECTED_SETTING_HINT: 已选中
|
||||
SETTINGS_ENCODE_OUTPUT_URL: 输出(复制) URL 时进行转义
|
||||
SETTINGS_SHOW_DOCK_ICON: 显示 Dock 栏图标
|
||||
SETTINGS_STARTUP_MODE: 启动模式
|
||||
SETTINGS_STARTUP_MODE_MAIN_WINDOW: 打开主窗口
|
||||
SETTINGS_STARTUP_MODE_MINI_WINDOW: 打开 Mini 窗口
|
||||
SETTINGS_STARTUP_MODE_HIDE: 静默启动
|
||||
|
||||
# shortcut-page
|
||||
|
||||
@@ -236,7 +240,7 @@ TIPS_PLUGIN_OVERWRITE_GALLERY: 有插件正在试图覆盖相册列表,是否
|
||||
TIPS_UPLOAD_NOT_PICTURES: 剪贴板最新的一条记录不是图片
|
||||
TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_DEFAULT: PicGo 配置文件损坏,已经恢复为默认配置
|
||||
TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP: PicGo 配置文件损坏,已经恢复为备份配置
|
||||
TIPS_PICGO_BACKUP_FILE_VERSION: '备份文件版本: ${v}'
|
||||
TIPS_PICGO_BACKUP_FILE_VERSION: "备份文件版本: ${v}"
|
||||
TIPS_CUSTOM_CONFIG_FILE_PATH_ERROR: 自定义文件解析出错,请检查路径内容是否正确
|
||||
TIPS_SHORTCUT_MODIFIED_SUCCEED: 快捷键已经修改成功
|
||||
TIPS_SHORTCUT_MODIFIED_CONFLICT: 快捷键冲突,请重新设置
|
||||
|
||||
+11
-7
@@ -121,6 +121,10 @@ UPLOADER_CONFIG_PLACEHOLDER: 請輸入配置名稱
|
||||
SELECTED_SETTING_HINT: 已選中
|
||||
SETTINGS_ENCODE_OUTPUT_URL: 輸出(複製) URL 時進行轉義
|
||||
SETTINGS_SHOW_DOCK_ICON: 顯示 Dock 欄圖示
|
||||
SETTINGS_STARTUP_MODE: 啟動模式
|
||||
SETTINGS_STARTUP_MODE_MAIN_WINDOW: 打開主視窗
|
||||
SETTINGS_STARTUP_MODE_MINI_WINDOW: 打開 Mini 視窗
|
||||
SETTINGS_STARTUP_MODE_HIDE: 靜默啟動
|
||||
|
||||
# shortcut-page
|
||||
|
||||
@@ -202,27 +206,27 @@ UPDATE_PLUGIN: 更新插件
|
||||
|
||||
# toolbox
|
||||
TOOLBOX: 工具箱
|
||||
TOOLBOX_TITLE: 排查 PicGo 執行時問題
|
||||
TOOLBOX_TITLE: 排查 PicGo 執行時問題
|
||||
TOOLBOX_SUB_TITLE: 立即掃描以下項目,修復使用問題
|
||||
TOOLBOX_CHECK_CONFIG_FILE_BROKEN: 檢查配置文件是否損壞
|
||||
TOOLBOX_CHECK_GALLERY_FILE_BROKEN: 檢查相冊文件是否損壞
|
||||
TOOLBOX_CHECK_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD: 檢查剪貼板圖片上傳是否存在問題
|
||||
TOOLBOX_CHECK_PROBLEM_WITH_PROXY: 檢查代理設置是否正常
|
||||
TOOLBOX_FIX_DONE_NEED_RELOAD: 修復完成,需要重啓生效,是否重啓
|
||||
TOOLBOX_CANT_AUTO_FIX: 無法自動修復,請自行修復以下問題
|
||||
TOOLBOX_CANT_AUTO_FIX: 無法自動修復,請自行修復以下問題
|
||||
TOOLBOX_START_SCAN: 開始掃描
|
||||
TOOLBOX_RE_SCAN: 重新掃描
|
||||
TOOLBOX_START_FIX: 開始修復
|
||||
TOOLBOX_SUCCESS_TIPS: 恭喜你,沒有檢查出問題
|
||||
TOOLBOX_CHECK_CONFIG_FILE_PATH_TIPS: 配置文件路徑是:${path}
|
||||
TOOLBOX_CHECK_CONFIG_FILE_BROKEN_TIPS: 配置文件已損壞
|
||||
TOOLBOX_CHECK_GALLERY_FILE_PATH_TIPS: 相冊文件路徑是:${path}
|
||||
TOOLBOX_CHECK_CONFIG_FILE_BROKEN_TIPS: 配置文件已損壞
|
||||
TOOLBOX_CHECK_GALLERY_FILE_PATH_TIPS: 相冊文件路徑是:${path}
|
||||
TOOLBOX_CHECK_GALLERY_FILE_BROKEN_TIPS: 相冊文件已損壞
|
||||
TOOLBOX_CHECK_PROXY_SUCCESS_TIPS: 代理設置正常
|
||||
TOOLBOX_CHECK_PROXY_SUCCESS_TIPS: 代理設置正常
|
||||
TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS: 無代理設置
|
||||
TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_CORRECT: 代理設置不正確
|
||||
TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_WORKING: 代理設置不可用
|
||||
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_TIPS: 剪貼板圖片臨時文件夾路徑是:${path}
|
||||
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_TIPS: 剪貼板圖片臨時文件夾路徑是:${path}
|
||||
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_NOT_EXIST_TIPS: 剪貼板圖片臨時文件夾不存在:${path}
|
||||
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_ERROR_TIPS: 請自行創建文件夾:${path}
|
||||
|
||||
@@ -236,7 +240,7 @@ TIPS_PLUGIN_OVERWRITE_GALLERY: 有插件正在試圖覆蓋相簿列表,是否
|
||||
TIPS_UPLOAD_NOT_PICTURES: 剪貼簿最新的一條記錄不是圖片
|
||||
TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_DEFAULT: PicGo 設定檔案已損壞,已經恢復為預設設定
|
||||
TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP: PicGo 設定檔案已損壞,已經恢復為備份設定
|
||||
TIPS_PICGO_BACKUP_FILE_VERSION: '備份檔案版本: ${v}'
|
||||
TIPS_PICGO_BACKUP_FILE_VERSION: "備份檔案版本: ${v}"
|
||||
TIPS_CUSTOM_CONFIG_FILE_PATH_ERROR: 自訂設定檔案解析出錯,請檢查路徑內容是否正確
|
||||
TIPS_SHORTCUT_MODIFIED_SUCCEED: 快捷鍵已經修改成功
|
||||
TIPS_SHORTCUT_MODIFIED_CONFLICT: 快捷鍵衝突,請重新設定
|
||||
|
||||
+12
-12
@@ -17,18 +17,18 @@ if [ "$XDG_SESSION_TYPE" = "x11" ]; then
|
||||
echo $filePath
|
||||
fi
|
||||
elif [ "$XDG_SESSION_TYPE" = "wayland" ]; then
|
||||
command -v wl-copy >/dev/null 2>&1 || { echo >&1 "no wl-clipboard"; exit 1; }
|
||||
filePath=`wl-copy -o 2>/dev/null | grep ^file:// | cut -c8-`
|
||||
if [ ! -n "$filePath" ] ;then
|
||||
if
|
||||
wl-copy -t image/png -o >/dev/null 2>&1
|
||||
then
|
||||
wl-copy -t image/png image/png -o >$1 2>/dev/null
|
||||
echo $1
|
||||
else
|
||||
echo "no image"
|
||||
fi
|
||||
command -v wl-paste >/dev/null 2>&1 || { echo >&1 "no wl-clipboard"; exit 1; }
|
||||
isImage=`wl-paste --list-types | grep image`
|
||||
if [ -n "$isImage" ]; then
|
||||
wl-paste --type image/png > $1 2>/dev/null
|
||||
echo $1
|
||||
else
|
||||
echo $filePath
|
||||
echo "no image"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# fallback for unsupported session types
|
||||
echo >&2 "Error: Unsupported session type '$XDG_SESSION_TYPE'."
|
||||
echo >&2 "Solution: The variable of XDG_SESSION_TYPE must set as 'x11' or 'wayland'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
+39
-23
@@ -1,45 +1,61 @@
|
||||
// different platform has different format
|
||||
|
||||
// macos
|
||||
// macos (dmg, x64 + arm64)
|
||||
const darwin = [{
|
||||
appNameWithPrefix: 'PicGo-',
|
||||
ext: '.dmg',
|
||||
arch: '-arm64',
|
||||
appNameWithPrefix: 'PicGo',
|
||||
ext: 'dmg',
|
||||
arch: 'arm64',
|
||||
'version-file': 'latest-mac.yml'
|
||||
}, {
|
||||
appNameWithPrefix: 'PicGo-',
|
||||
ext: '.dmg',
|
||||
arch: '-x64',
|
||||
appNameWithPrefix: 'PicGo',
|
||||
ext: 'dmg',
|
||||
arch: 'x64',
|
||||
'version-file': 'latest-mac.yml'
|
||||
}]
|
||||
|
||||
// linux (AppImage, deb, snap)
|
||||
const linux = [{
|
||||
appNameWithPrefix: 'PicGo-',
|
||||
ext: '.AppImage',
|
||||
arch: '',
|
||||
appNameWithPrefix: 'PicGo',
|
||||
ext: 'AppImage',
|
||||
arch: 'arm64',
|
||||
'version-file': 'latest-linux-arm64.yml'
|
||||
}, {
|
||||
appNameWithPrefix: 'PicGo',
|
||||
ext: 'AppImage',
|
||||
arch: 'x86_64',
|
||||
'version-file': 'latest-linux.yml'
|
||||
}, {
|
||||
appNameWithPrefix: 'picgo_',
|
||||
ext: '.snap',
|
||||
arch: '_amd64',
|
||||
appNameWithPrefix: 'PicGo',
|
||||
ext: 'deb',
|
||||
arch: 'arm64',
|
||||
'version-file': 'latest-linux-arm64.yml'
|
||||
}, {
|
||||
appNameWithPrefix: 'PicGo',
|
||||
ext: 'deb',
|
||||
arch: 'amd64',
|
||||
'version-file': 'latest-linux.yml'
|
||||
}, {
|
||||
appNameWithPrefix: 'PicGo',
|
||||
ext: 'snap',
|
||||
arch: 'amd64',
|
||||
'version-file': 'latest-linux.yml'
|
||||
}]
|
||||
|
||||
// windows
|
||||
// windows (nsis, x64 + ia32 + arm64)
|
||||
const win32 = [{
|
||||
appNameWithPrefix: 'PicGo-Setup-',
|
||||
ext: '.exe',
|
||||
arch: '-ia32',
|
||||
appNameWithPrefix: 'PicGo',
|
||||
ext: 'exe',
|
||||
arch: 'ia32',
|
||||
'version-file': 'latest.yml'
|
||||
}, {
|
||||
appNameWithPrefix: 'PicGo-Setup-',
|
||||
ext: '.exe',
|
||||
arch: '-x64',
|
||||
appNameWithPrefix: 'PicGo',
|
||||
ext: 'exe',
|
||||
arch: 'x64',
|
||||
'version-file': 'latest.yml'
|
||||
}, {
|
||||
appNameWithPrefix: 'PicGo-Setup-',
|
||||
ext: '.exe',
|
||||
arch: '', // 32 & 64
|
||||
appNameWithPrefix: 'PicGo',
|
||||
ext: 'exe',
|
||||
arch: 'arm64',
|
||||
'version-file': 'latest.yml'
|
||||
}]
|
||||
|
||||
|
||||
+33
-17
@@ -1,23 +1,39 @@
|
||||
const pkg = require('../package.json')
|
||||
const version = pkg.version
|
||||
// TODO: use the same name format
|
||||
const generateURL = (platform, ext, prefix = 'PicGo-') => {
|
||||
return `https://picgo-release.molunerfinn.com/${version}/${prefix}${version}${platform}${ext}`
|
||||
}
|
||||
|
||||
const platformExtList = [
|
||||
['-arm64', '.dmg', 'PicGo-'],
|
||||
['-x64', '.dmg', 'PicGo-'],
|
||||
['', '.AppImage', 'PicGo-'],
|
||||
['-ia32', '.exe', 'PicGo-Setup-'],
|
||||
['-x64', '.exe', 'PicGo-Setup-'],
|
||||
['', '.exe', 'PicGo-Setup-'],
|
||||
['_amd64', '.snap', 'picgo_']
|
||||
const generateURL = (arch, ext, prefix = 'PicGo-') => `https://release.picgo.app/${version}/${prefix}${version}${arch}${ext}`
|
||||
|
||||
const windows = [
|
||||
{ label: '32 bit', arch: '-ia32', ext: '.exe' },
|
||||
{ label: '64 bit', arch: '-x64', ext: '.exe' },
|
||||
{ label: 'ARM64', arch: '-arm64', ext: '.exe' }
|
||||
]
|
||||
|
||||
const links = platformExtList.map(([arch, ext, prefix]) => {
|
||||
const markdownLink = `[${prefix}${version}${arch}${ext}](${generateURL(arch, ext, prefix)})`
|
||||
return markdownLink
|
||||
})
|
||||
const macos = [
|
||||
{ label: 'Intel', arch: '-x64', ext: '.dmg' },
|
||||
{ label: 'Apple Silicon', arch: '-arm64', ext: '.dmg' }
|
||||
]
|
||||
|
||||
console.log(links.join('\n'))
|
||||
const linux = {
|
||||
AppImage: [
|
||||
{ label: '64 bit', arch: '-x64', ext: '.AppImage' },
|
||||
{ label: 'ARM64', arch: '-arm64', ext: '.AppImage' }
|
||||
],
|
||||
Deb: [
|
||||
{ label: '64 bit', arch: '-x64', ext: '.deb' },
|
||||
{ label: 'ARM64', arch: '-arm64', ext: '.deb' }
|
||||
],
|
||||
Snap: [
|
||||
{ label: '64 bit', arch: '-x64', ext: '.snap' }
|
||||
]
|
||||
}
|
||||
|
||||
const renderLine = (items) => items.map(({ label, arch, ext }) => `[${label}](${generateURL(arch, ext)})`).join(' | ')
|
||||
|
||||
const sections = [
|
||||
`### Windows\n- ${renderLine(windows)}`,
|
||||
`### macOS\n- ${renderLine(macos)}`,
|
||||
`### Linux\n- AppImage: ${renderLine(linux.AppImage)}\n- Deb: ${renderLine(linux.Deb)}\n- Snap: ${renderLine(linux.Snap)}`
|
||||
]
|
||||
|
||||
console.log(sections.join('\n\n'))
|
||||
|
||||
+55
-22
@@ -9,20 +9,24 @@ const pkg = require('../package.json')
|
||||
const configList = require('./config')
|
||||
const mime = require('mime-types')
|
||||
const path = require('path')
|
||||
const distPath = path.join(__dirname, '../dist_electron')
|
||||
const distPath = path.join(__dirname, '../dist')
|
||||
const S3Client = require('@aws-sdk/client-s3').S3Client
|
||||
const Upload = require('@aws-sdk/lib-storage').Upload
|
||||
// const BUCKET = 'picgo-1251750343'
|
||||
// const COS_SECRET_ID = process.env.PICGO_ENV_COS_SECRET_ID
|
||||
// const COS_SECRET_KEY = process.env.PICGO_ENV_COS_SECRET_KEY
|
||||
|
||||
const S3_BUCKET = 'picgo'
|
||||
const S3_BUCKET = 'release'
|
||||
const S3_LEGACY_BUCKET = 'picgo'
|
||||
// const AREA = 'ap-chengdu'
|
||||
const VERSION = pkg.version
|
||||
const FILE_PATH = `${VERSION}/`
|
||||
const S3_SECRET_ID = process.env.PICGO_ENV_S3_SECRET_ID
|
||||
const S3_SECRET_KEY = process.env.PICGO_ENV_S3_SECRET_KEY
|
||||
const S3_ACCOUNT_ID = process.env.PICGO_ENV_S3_ACCOUNT_ID
|
||||
const S3_LEGACY_SECRET_ID = process.env.PICGO_ENV_S3_LEGACY_SECRET_ID
|
||||
const S3_LEGACY_SECRET_KEY = process.env.PICGO_ENV_S3_LEGACY_SECRET_KEY
|
||||
const S3_LEGACY_ACCOUNT_ID = process.env.PICGO_ENV_S3_LEGACY_ACCOUNT_ID
|
||||
|
||||
const S3Options = {
|
||||
credentials: {
|
||||
@@ -34,6 +38,17 @@ const S3Options = {
|
||||
region: 'auto'
|
||||
}
|
||||
|
||||
// for legacy release file fetch
|
||||
const S3LegacyOptions = {
|
||||
credentials: {
|
||||
accessKeyId: S3_LEGACY_SECRET_ID,
|
||||
secretAccessKey: S3_LEGACY_SECRET_KEY
|
||||
},
|
||||
endpoint: `https://${S3_LEGACY_ACCOUNT_ID}.r2.cloudflarestorage.com`,
|
||||
sslEnabled: true,
|
||||
region: 'auto'
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/product/436/7778#signature
|
||||
// /**
|
||||
// * @param {string} fileName
|
||||
@@ -117,35 +132,39 @@ const uploadDist = async () => {
|
||||
try {
|
||||
const platform = process.platform
|
||||
if (configList[platform]) {
|
||||
let versionFileHasUploaded = false
|
||||
const uploadedVersionFiles = new Set()
|
||||
for (const [index, config] of configList[platform].entries()) {
|
||||
const fileName = `${config.appNameWithPrefix}${VERSION}${config.arch}${config.ext}`
|
||||
const fileName = `${config.appNameWithPrefix}-${VERSION}-${config.arch}.${config.ext}`
|
||||
const filePath = path.join(distPath, fileName)
|
||||
const versionFilePath = path.join(distPath, config['version-file'])
|
||||
let versionFileName = config['version-file']
|
||||
if (VERSION.toLocaleLowerCase().includes('beta')) {
|
||||
versionFileName = versionFileName.replace('.yml', '.beta.yml')
|
||||
}
|
||||
|
||||
console.log('[PicGo Dist] Preparing to upload', fileName)
|
||||
const client = new S3Client(S3Options)
|
||||
const uploadDistToS3 = new Upload({
|
||||
client,
|
||||
params: {
|
||||
Bucket: S3_BUCKET,
|
||||
Key: `${FILE_PATH}${fileName}`,
|
||||
Body: fs.createReadStream(filePath),
|
||||
ContentType: 'application/octet-stream'
|
||||
}
|
||||
})
|
||||
// upload dist file
|
||||
console.log('[PicGo Dist] Uploading...', fileName, `${index + 1}/${configList[platform].length}`)
|
||||
uploadDistToS3.on('httpUploadProgress', progress => {
|
||||
console.log(`[PicGo Dist] Uploading... ${progress.loaded}/${progress.total}`)
|
||||
})
|
||||
await uploadDistToS3.done()
|
||||
if (fs.existsSync(filePath)) {
|
||||
const uploadDistToS3 = new Upload({
|
||||
client,
|
||||
params: {
|
||||
Bucket: S3_BUCKET,
|
||||
Key: `${FILE_PATH}${fileName}`,
|
||||
Body: fs.createReadStream(filePath),
|
||||
ContentType: 'application/octet-stream'
|
||||
}
|
||||
})
|
||||
// upload dist file
|
||||
console.log('[PicGo Dist] Uploading...', fileName, `${index + 1}/${configList[platform].length}`)
|
||||
uploadDistToS3.on('httpUploadProgress', progress => {
|
||||
console.log(`[PicGo Dist] Uploading... ${progress.loaded}/${progress.total}`)
|
||||
})
|
||||
await uploadDistToS3.done()
|
||||
} else {
|
||||
console.warn('[PicGo Dist] File not found:', fileName)
|
||||
}
|
||||
|
||||
// upload version file
|
||||
if (!versionFileHasUploaded) {
|
||||
if (!uploadedVersionFiles.has(versionFileName) && fs.existsSync(versionFilePath)) {
|
||||
const uploadVersionFileToS3 = new Upload({
|
||||
client,
|
||||
params: {
|
||||
@@ -155,9 +174,23 @@ const uploadDist = async () => {
|
||||
ContentType: mime.lookup(versionFileName)
|
||||
}
|
||||
})
|
||||
// upload to legacy bucket as well
|
||||
// will be deprecated in 2.5.0
|
||||
const legacyClient = new S3Client(S3LegacyOptions)
|
||||
const uploadVersionFileToLegacyS3 = new Upload({
|
||||
client: legacyClient,
|
||||
params: {
|
||||
Bucket: S3_LEGACY_BUCKET,
|
||||
Key: `${versionFileName}`,
|
||||
Body: fs.createReadStream(versionFilePath),
|
||||
ContentType: mime.lookup(versionFileName)
|
||||
}
|
||||
})
|
||||
console.log('[PicGo Version File] Uploading...', versionFileName)
|
||||
await uploadVersionFileToS3.done()
|
||||
versionFileHasUploaded = true
|
||||
await uploadVersionFileToLegacyS3.done()
|
||||
uploadedVersionFiles.add(versionFileName)
|
||||
console.log('[PicGo Version File] Upload successfully')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { initStaticPath } from '~/main/utils/env'
|
||||
import { bootstrap } from '~/main/lifeCycle'
|
||||
|
||||
initStaticPath()
|
||||
bootstrap.launchApp()
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import fs from 'fs-extra'
|
||||
import {
|
||||
app,
|
||||
Menu,
|
||||
@@ -14,11 +13,13 @@ import windowManager from 'apis/app/window/windowManager'
|
||||
import { IWindowList } from '#/types/enum'
|
||||
import pasteTemplate from '~/main/utils/pasteTemplate'
|
||||
import pkg from 'root/package.json'
|
||||
import { ensureFilePath, handleCopyUrl } from '~/main/utils/common'
|
||||
import { ensureFilePath, getClipboardFilePathList, handleCopyUrl } from '~/main/utils/common'
|
||||
import { privacyManager } from '~/main/utils/privacyManager'
|
||||
import { T } from '~/main/i18n'
|
||||
import { isMacOSVersionGreaterThanOrEqualTo } from '~/main/utils/getMacOSVersion'
|
||||
import { buildPicBedListMenu } from '~/main/events/remotes/menu'
|
||||
import { isLinux, isMacOS } from '~/universal/utils/common'
|
||||
import { getStaticPath } from '#/utils/staticPath'
|
||||
let contextMenu: Menu | null
|
||||
let menu: Menu | null
|
||||
let tray: Tray | null
|
||||
@@ -137,9 +138,11 @@ export function createContextMenu () {
|
||||
const getTrayIcon = () => {
|
||||
if (process.platform === 'darwin') {
|
||||
const isMacOSGreaterThan11 = isMacOSVersionGreaterThanOrEqualTo('11')
|
||||
return isMacOSGreaterThan11 ? `${__static}/menubar-newdarwinTemplate.png` : `${__static}/menubar.png`
|
||||
return isMacOSGreaterThan11
|
||||
? getStaticPath('menubar-newdarwinTemplate.png')
|
||||
: getStaticPath('menubar.png')
|
||||
} else {
|
||||
return `${__static}/menubar-nodarwin.png`
|
||||
return getStaticPath('menubar-nodarwin.png')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,36 +156,27 @@ export function createTray () {
|
||||
windowManager.get(IWindowList.TRAY_WINDOW)!.hide()
|
||||
}
|
||||
createContextMenu()
|
||||
tray!.popUpContextMenu(contextMenu!)
|
||||
setTimeout(() => {
|
||||
tray!.popUpContextMenu(contextMenu!)
|
||||
}, 0)
|
||||
})
|
||||
tray.on('click', (event, bounds) => {
|
||||
if (process.platform === 'darwin') {
|
||||
toggleWindow(bounds)
|
||||
setTimeout(async () => {
|
||||
const img = clipboard.readImage()
|
||||
const obj: ImgInfo[] = []
|
||||
if (!img.isEmpty()) {
|
||||
// 从剪贴板来的图片默认转为png
|
||||
// https://github.com/electron/electron/issues/9035
|
||||
const imgPath = clipboard.read('public.file-url')
|
||||
if (imgPath) {
|
||||
const imgPathList = getClipboardFilePathList()
|
||||
if (imgPathList.length > 0) {
|
||||
for (const imgPath of imgPathList) {
|
||||
const decodePath = ensureFilePath(imgPath)
|
||||
if (decodePath === imgPath) {
|
||||
obj.push({
|
||||
imgUrl: imgPath
|
||||
})
|
||||
} else {
|
||||
if (decodePath !== '') {
|
||||
// 带有中文的路径,无法直接被img.src所使用,会被转义
|
||||
const base64 = await fs.readFile(decodePath.replace('file://', ''), { encoding: 'base64' })
|
||||
obj.push({
|
||||
imgUrl: `data:image/png;base64,${base64}`
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
obj.push({
|
||||
imgUrl: decodePath
|
||||
})
|
||||
}
|
||||
} else {
|
||||
const img = clipboard.readImage()
|
||||
if (!img.isEmpty()) {
|
||||
const imgUrl = img.toDataURL()
|
||||
// console.log(imgUrl)
|
||||
obj.push({
|
||||
width: img.getSize().width,
|
||||
height: img.getSize().height,
|
||||
@@ -190,7 +184,9 @@ export function createTray () {
|
||||
})
|
||||
}
|
||||
}
|
||||
windowManager.get(IWindowList.TRAY_WINDOW)!.webContents.send('clipboardFiles', obj)
|
||||
windowManager
|
||||
.get(IWindowList.TRAY_WINDOW)!
|
||||
.webContents.send('clipboardFiles', obj)
|
||||
}, 0)
|
||||
} else {
|
||||
if (windowManager.has(IWindowList.TRAY_WINDOW)) {
|
||||
@@ -207,9 +203,9 @@ export function createTray () {
|
||||
|
||||
tray.on('drag-enter', () => {
|
||||
if (nativeTheme.shouldUseDarkColors) {
|
||||
tray!.setImage(`${__static}/upload-dark.png`)
|
||||
tray!.setImage(getStaticPath('upload-dark.png'))
|
||||
} else {
|
||||
tray!.setImage(`${__static}/upload.png`)
|
||||
tray!.setImage(getStaticPath('upload.png'))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -220,7 +216,7 @@ export function createTray () {
|
||||
|
||||
// drop-files only be supported in macOS
|
||||
// so the tray window must be available
|
||||
tray.on('drop-files', async (event: Event, files: string[]) => {
|
||||
tray.on('drop-files', async (event, files: string[]) => {
|
||||
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
|
||||
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
|
||||
const imgs = await uploader
|
||||
@@ -229,7 +225,9 @@ export function createTray () {
|
||||
if (imgs !== false) {
|
||||
const pasteText: string[] = []
|
||||
for (let i = 0; i < imgs.length; i++) {
|
||||
pasteText.push(pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink')))
|
||||
pasteText.push(
|
||||
pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink'))
|
||||
)
|
||||
const notification = new Notification({
|
||||
title: T('UPLOAD_SUCCEED'),
|
||||
body: imgs[i].imgUrl!
|
||||
@@ -245,21 +243,21 @@ export function createTray () {
|
||||
}
|
||||
})
|
||||
// toggleWindow()
|
||||
} else if (process.platform === 'linux') {
|
||||
// click事件在Ubuntu上无法触发,Unity不支持(在Mac和Windows上可以触发)
|
||||
// 需要使用 setContextMenu 设置菜单
|
||||
} else if (isLinux) {
|
||||
// click事件在Ubuntu上无法触发,Unity不支持(在Mac和Windows上可以触发)
|
||||
// 需要使用 setContextMenu 设置菜单
|
||||
createContextMenu()
|
||||
tray!.setContextMenu(contextMenu)
|
||||
}
|
||||
}
|
||||
|
||||
export function handleDockIcon () {
|
||||
if (process.platform === 'darwin') {
|
||||
if (isMacOS) {
|
||||
if (db.get('settings.showDockIcon') !== false) {
|
||||
app.dock.show()
|
||||
app.dock.setMenu(createContextMenu())
|
||||
app.dock?.show()
|
||||
app.dock?.setMenu(createContextMenu())
|
||||
} else {
|
||||
app.dock.hide()
|
||||
app.dock?.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,25 +267,35 @@ export function createMenu () {
|
||||
return menu
|
||||
}
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
const template = [{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{ label: 'Undo', accelerator: 'CmdOrCtrl+Z', selector: 'undo:' },
|
||||
{ label: 'Redo', accelerator: 'Shift+CmdOrCtrl+Z', selector: 'redo:' },
|
||||
{ type: 'separator' },
|
||||
{ label: 'Cut', accelerator: 'CmdOrCtrl+X', selector: 'cut:' },
|
||||
{ label: 'Copy', accelerator: 'CmdOrCtrl+C', selector: 'copy:' },
|
||||
{ label: 'Paste', accelerator: 'CmdOrCtrl+V', selector: 'paste:' },
|
||||
{ label: 'Select All', accelerator: 'CmdOrCtrl+A', selector: 'selectAll:' },
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: 'CmdOrCtrl+Q',
|
||||
click () {
|
||||
app.quit()
|
||||
const template = [
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{ label: 'Undo', accelerator: 'CmdOrCtrl+Z', selector: 'undo:' },
|
||||
{
|
||||
label: 'Redo',
|
||||
accelerator: 'Shift+CmdOrCtrl+Z',
|
||||
selector: 'redo:'
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ label: 'Cut', accelerator: 'CmdOrCtrl+X', selector: 'cut:' },
|
||||
{ label: 'Copy', accelerator: 'CmdOrCtrl+C', selector: 'copy:' },
|
||||
{ label: 'Paste', accelerator: 'CmdOrCtrl+V', selector: 'paste:' },
|
||||
{
|
||||
label: 'Select All',
|
||||
accelerator: 'CmdOrCtrl+A',
|
||||
selector: 'selectAll:'
|
||||
},
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: 'CmdOrCtrl+Q',
|
||||
click () {
|
||||
app.quit()
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}]
|
||||
]
|
||||
}
|
||||
]
|
||||
// @ts-ignore
|
||||
menu = Menu.buildFromTemplate(template)
|
||||
Menu.setApplicationMenu(menu)
|
||||
|
||||
@@ -12,7 +12,7 @@ import windowManager from 'apis/app/window/windowManager'
|
||||
import { IWindowList } from '#/types/enum'
|
||||
import util from 'util'
|
||||
import { IPicGo } from 'picgo'
|
||||
import { showNotification, calcDurationRange, getClipboardFilePath } from '~/main/utils/common'
|
||||
import { showNotification, calcDurationRange, getClipboardFilePathList } from '~/main/utils/common'
|
||||
import { GET_RENAME_FILE_NAME, RENAME_FILE_NAME, TALKING_DATA_EVENT } from '~/universal/events/constants'
|
||||
import logger from '@core/picgo/logger'
|
||||
import { T } from '~/main/i18n'
|
||||
@@ -21,11 +21,13 @@ import path from 'path'
|
||||
import { privacyManager } from '~/main/utils/privacyManager'
|
||||
import writeFile from 'write-file-atomic'
|
||||
import { CLIPBOARD_IMAGE_FOLDER } from '~/universal/utils/static'
|
||||
import { cleanupFormUploaderFiles } from '~/main/utils/cleanupFormUploaderFiles'
|
||||
import { IpcMainEvent } from 'electron/main'
|
||||
|
||||
const waitForRename = (window: BrowserWindow, id: number): Promise<string|null> => {
|
||||
return new Promise((resolve) => {
|
||||
const windowId = window.id
|
||||
ipcMain.once(`${RENAME_FILE_NAME}${id}`, (evt: Event, newName: string) => {
|
||||
ipcMain.once(`${RENAME_FILE_NAME}${id}`, (evt: IpcMainEvent, newName: string) => {
|
||||
resolve(newName)
|
||||
window.close()
|
||||
})
|
||||
@@ -85,7 +87,7 @@ class Uploader {
|
||||
let name: undefined | string | null
|
||||
let fileName: string | undefined
|
||||
if (autoRename) {
|
||||
fileName = dayjs().add(index, 'ms').format('YYYYMMDDHHmmSSS') + item.extname
|
||||
fileName = dayjs().add(index, 'ms').format('YYYYMMDDHHmmssSSS') + item.extname
|
||||
} else {
|
||||
fileName = item.fileName
|
||||
}
|
||||
@@ -118,20 +120,20 @@ class Uploader {
|
||||
async uploadWithBuildInClipboard (): Promise<ImgInfo[]|false> {
|
||||
let filePath = ''
|
||||
try {
|
||||
const imgPath = getClipboardFilePath()
|
||||
if (!imgPath) {
|
||||
const imgPath = getClipboardFilePathList()
|
||||
if (!imgPath.length) {
|
||||
const nativeImage = clipboard.readImage()
|
||||
if (nativeImage.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
const buffer = nativeImage.toPNG()
|
||||
const baseDir = picgo.baseDir
|
||||
const fileName = `${dayjs().format('YYYYMMDDHHmmSSS')}.png`
|
||||
const fileName = `${dayjs().format('YYYYMMDDHHmmssSSS')}.png`
|
||||
filePath = path.join(baseDir, CLIPBOARD_IMAGE_FOLDER, fileName)
|
||||
await writeFile(filePath, buffer)
|
||||
return await this.upload([filePath])
|
||||
} else {
|
||||
return await this.upload([imgPath])
|
||||
return await this.upload(imgPath)
|
||||
}
|
||||
} catch (e: any) {
|
||||
logger.error(e)
|
||||
@@ -176,6 +178,7 @@ class Uploader {
|
||||
return false
|
||||
} finally {
|
||||
ipcMain.removeAllListeners(GET_RENAME_FILE_NAME)
|
||||
cleanupFormUploaderFiles(img)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
import { buildRendererUrl } from '~/main/utils/env'
|
||||
|
||||
export const TRAY_WINDOW_URL = isDevelopment
|
||||
? (process.env.WEBPACK_DEV_SERVER_URL as string)
|
||||
: 'picgo://./index.html'
|
||||
export const TRAY_WINDOW_URL = buildRendererUrl()
|
||||
|
||||
export const SETTING_WINDOW_URL = isDevelopment
|
||||
? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#main-page/upload`
|
||||
: 'picgo://./index.html#main-page/upload'
|
||||
export const SETTING_WINDOW_URL = buildRendererUrl('main-page/upload')
|
||||
|
||||
export const MINI_WINDOW_URL = isDevelopment
|
||||
? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#mini-page`
|
||||
: 'picgo://./index.html#mini-page'
|
||||
export const MINI_WINDOW_URL = buildRendererUrl('mini-page')
|
||||
|
||||
export const RENAME_WINDOW_URL = process.env.NODE_ENV === 'development'
|
||||
? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#rename-page`
|
||||
: 'picgo://./index.html#rename-page'
|
||||
export const RENAME_WINDOW_URL = buildRendererUrl('rename-page')
|
||||
|
||||
export const TOOLBOX_WINDOW_URL = process.env.NODE_ENV === 'development'
|
||||
? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#toolbox-page`
|
||||
: 'picgo://./index.html#toolbox-page'
|
||||
export const TOOLBOX_WINDOW_URL = buildRendererUrl('toolbox-page')
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// import path from 'path'
|
||||
import {
|
||||
SETTING_WINDOW_URL,
|
||||
TRAY_WINDOW_URL,
|
||||
@@ -5,17 +6,27 @@ import {
|
||||
RENAME_WINDOW_URL,
|
||||
TOOLBOX_WINDOW_URL
|
||||
} from './constants'
|
||||
import { IWindowList } from '#/types/enum'
|
||||
import { IStartupMode, IWindowList } from '#/types/enum'
|
||||
import bus from '@core/bus'
|
||||
import { CREATE_APP_MENU } from '@core/bus/constants'
|
||||
import db from '~/main/apis/core/datastore'
|
||||
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants'
|
||||
import { app } from 'electron'
|
||||
import { T } from '~/main/i18n'
|
||||
import { isLinux } from '~/universal/utils/common'
|
||||
import { getStaticPath } from '#/utils/staticPath'
|
||||
// import { URLSearchParams } from 'url'
|
||||
|
||||
const windowList = new Map<IWindowList, IWindowListItem>()
|
||||
|
||||
const defaultWebPreferences = {
|
||||
// preload: path.join(__dirname, '../preload/index.js'),
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
nodeIntegrationInWorker: true,
|
||||
backgroundThrottling: false
|
||||
}
|
||||
|
||||
const handleWindowParams = (windowURL: string) => {
|
||||
// const [baseURL, hash = ''] = windowURL.split('#')
|
||||
// const search = new URLSearchParams()
|
||||
@@ -25,6 +36,21 @@ const handleWindowParams = (windowURL: string) => {
|
||||
return windowURL
|
||||
}
|
||||
|
||||
export const isWindowShouldShowOnStartup = (currentWindow: IWindowList) => {
|
||||
const startupMode = db.get('settings.startupMode') || (isLinux ? IStartupMode.SHOW_MINI_WINDOW : IStartupMode.HIDE)
|
||||
switch (currentWindow) {
|
||||
case IWindowList.MINI_WINDOW: {
|
||||
return startupMode === IStartupMode.SHOW_MINI_WINDOW
|
||||
}
|
||||
case IWindowList.SETTING_WINDOW: {
|
||||
return startupMode === IStartupMode.SHOW_MAIN_WINDOW
|
||||
}
|
||||
default: {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
windowList.set(IWindowList.TRAY_WINDOW, {
|
||||
isValid: process.platform !== 'linux',
|
||||
multiple: false,
|
||||
@@ -39,10 +65,7 @@ windowList.set(IWindowList.TRAY_WINDOW, {
|
||||
transparent: true,
|
||||
vibrancy: 'ultra-dark',
|
||||
webPreferences: {
|
||||
nodeIntegration: !!process.env.ELECTRON_NODE_INTEGRATION,
|
||||
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
|
||||
nodeIntegrationInWorker: true,
|
||||
backgroundThrottling: false,
|
||||
...defaultWebPreferences,
|
||||
webSecurity: false
|
||||
}
|
||||
}
|
||||
@@ -69,24 +92,18 @@ windowList.set(IWindowList.SETTING_WINDOW, {
|
||||
fullscreenable: false,
|
||||
resizable: false,
|
||||
title: 'PicGo',
|
||||
vibrancy: 'ultra-dark',
|
||||
transparent: true,
|
||||
skipTaskbar: !showDockIcon,
|
||||
titleBarStyle: 'hidden',
|
||||
webPreferences: {
|
||||
backgroundThrottling: false,
|
||||
nodeIntegration: !!process.env.ELECTRON_NODE_INTEGRATION,
|
||||
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
|
||||
nodeIntegrationInWorker: true,
|
||||
...defaultWebPreferences,
|
||||
webSecurity: false
|
||||
}
|
||||
}
|
||||
if (process.platform !== 'darwin') {
|
||||
options.show = false
|
||||
options.frame = false
|
||||
options.backgroundColor = '#3f3c37'
|
||||
options.transparent = false
|
||||
options.icon = `${__static}/logo.png`
|
||||
options.icon = getStaticPath('logo.png')
|
||||
options.skipTaskbar = false
|
||||
}
|
||||
return options
|
||||
@@ -113,18 +130,15 @@ windowList.set(IWindowList.MINI_WINDOW, {
|
||||
const obj: IBrowserWindowOptions = {
|
||||
height: 64,
|
||||
width: 64,
|
||||
show: process.platform === 'linux',
|
||||
show: isLinux,
|
||||
frame: false,
|
||||
fullscreenable: false,
|
||||
skipTaskbar: true,
|
||||
resizable: false,
|
||||
transparent: process.platform !== 'linux',
|
||||
icon: `${__static}/logo.png`,
|
||||
icon: getStaticPath('logo.png'),
|
||||
webPreferences: {
|
||||
backgroundThrottling: false,
|
||||
nodeIntegration: !!process.env.ELECTRON_NODE_INTEGRATION,
|
||||
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
|
||||
nodeIntegrationInWorker: true
|
||||
...defaultWebPreferences
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,19 +162,14 @@ windowList.set(IWindowList.RENAME_WINDOW, {
|
||||
show: true,
|
||||
fullscreenable: false,
|
||||
resizable: false,
|
||||
vibrancy: 'ultra-dark',
|
||||
backgroundColor: 'rgba(26,40,42,0.9)',
|
||||
webPreferences: {
|
||||
nodeIntegration: !!process.env.ELECTRON_NODE_INTEGRATION,
|
||||
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
|
||||
nodeIntegrationInWorker: true,
|
||||
backgroundThrottling: false
|
||||
...defaultWebPreferences
|
||||
}
|
||||
}
|
||||
if (process.platform !== 'darwin') {
|
||||
options.show = true
|
||||
options.backgroundColor = '#3f3c37'
|
||||
options.autoHideMenuBar = true
|
||||
options.transparent = false
|
||||
}
|
||||
return options
|
||||
},
|
||||
@@ -195,21 +204,16 @@ windowList.set(IWindowList.TOOLBOX_WINDOW, {
|
||||
center: true,
|
||||
fullscreenable: false,
|
||||
resizable: false,
|
||||
title: `PicGo ${T('TOOLBOX')}`,
|
||||
vibrancy: 'ultra-dark',
|
||||
icon: `${__static}/logo.png`,
|
||||
backgroundColor: 'rgba(26,40,42,0.9)',
|
||||
title: `PicGo-${T('TOOLBOX')}`,
|
||||
icon: getStaticPath('logo.png'),
|
||||
webPreferences: {
|
||||
backgroundThrottling: false,
|
||||
nodeIntegration: !!process.env.ELECTRON_NODE_INTEGRATION,
|
||||
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
|
||||
nodeIntegrationInWorker: true,
|
||||
...defaultWebPreferences,
|
||||
webSecurity: false
|
||||
}
|
||||
}
|
||||
if (process.platform !== 'darwin') {
|
||||
options.backgroundColor = '#3f3c37'
|
||||
options.autoHideMenuBar = true
|
||||
options.transparent = false
|
||||
}
|
||||
return options
|
||||
},
|
||||
|
||||
@@ -23,6 +23,10 @@ class WindowManager implements IWindowManager {
|
||||
this.windowIdMap.set(window.id, name)
|
||||
}
|
||||
windowConfig.callback(window, this)
|
||||
// https://github.com/electron/electron/issues/1594
|
||||
window.on('page-title-updated', (evt) => {
|
||||
evt.preventDefault()
|
||||
})
|
||||
window.on('close', () => {
|
||||
this.deleteById(id)
|
||||
})
|
||||
|
||||
@@ -5,6 +5,7 @@ import { app as APP } from 'electron'
|
||||
import { getLogger } from '@core/utils/localLogger'
|
||||
import dayjs from 'dayjs'
|
||||
import { T } from '~/main/i18n'
|
||||
import { FORM_IMAGE_FOLDER } from '~/universal/utils/static'
|
||||
const STORE_PATH = APP.getPath('userData')
|
||||
const configFilePath = path.join(STORE_PATH, 'data.json')
|
||||
const configFileBackupPath = path.join(STORE_PATH, 'data.bak.json')
|
||||
@@ -131,9 +132,19 @@ function getGalleryDBPath (): {
|
||||
}
|
||||
}
|
||||
|
||||
function getFormImageFolderPath (): string {
|
||||
const STORE_PATH = dbPathDir()
|
||||
const formImagesPath = path.join(STORE_PATH, FORM_IMAGE_FOLDER)
|
||||
if (!fs.existsSync(formImagesPath)) {
|
||||
fs.mkdirSync(formImagesPath, { recursive: true })
|
||||
}
|
||||
return formImagesPath
|
||||
}
|
||||
|
||||
export {
|
||||
dbChecker,
|
||||
dbPathChecker,
|
||||
dbPathDir,
|
||||
getGalleryDBPath
|
||||
getGalleryDBPath,
|
||||
getFormImageFolderPath
|
||||
}
|
||||
|
||||
@@ -20,9 +20,7 @@ import { DBStore } from '@picgo/store'
|
||||
import { T } from '~/main/i18n'
|
||||
import { IRPCActionType } from '~/universal/types/enum'
|
||||
|
||||
// Cross-process support may be required in the future
|
||||
class GuiApi implements IGuiApi {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
private static instance: GuiApi
|
||||
private windowId: number = -1
|
||||
private settingWindowId: number = -1
|
||||
@@ -62,7 +60,7 @@ class GuiApi implements IGuiApi {
|
||||
await this.showSettingWindow()
|
||||
this.getWebContentsByWindowId(this.settingWindowId)?.send(SHOW_INPUT_BOX, options)
|
||||
return new Promise<string>((resolve) => {
|
||||
ipcMain.once(SHOW_INPUT_BOX, (event: Event, value: string) => {
|
||||
ipcMain.once(SHOW_INPUT_BOX, (event, value: string) => {
|
||||
resolve(value)
|
||||
})
|
||||
})
|
||||
@@ -140,7 +138,7 @@ class GuiApi implements IGuiApi {
|
||||
await this.showSettingWindow()
|
||||
this.getWebContentsByWindowId(this.settingWindowId)?.send(IRPCActionType.OPEN_CONFIG_DIALOG, options)
|
||||
return new Promise<T | false>((resolve) => {
|
||||
ipcMain.once(IRPCActionType.OPEN_CONFIG_DIALOG, (event: Event, value: T | false) => {
|
||||
ipcMain.once(IRPCActionType.OPEN_CONFIG_DIALOG, (event, value: T | false) => {
|
||||
resolve(value)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -167,7 +167,9 @@ export default {
|
||||
server.restart()
|
||||
})
|
||||
ipcMain.on(OPEN_DEVTOOLS, (event: IpcMainEvent) => {
|
||||
event.sender.openDevTools()
|
||||
event.sender.openDevTools({
|
||||
mode: 'detach'
|
||||
})
|
||||
})
|
||||
// menu & window methods
|
||||
ipcMain.on(SHOW_MINI_PAGE_MENU, () => {
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
ipcMain,
|
||||
clipboard
|
||||
} from 'electron'
|
||||
import fs from 'fs-extra'
|
||||
import { IPasteStyle, IPicGoHelperType, IWindowList } from '#/types/enum'
|
||||
import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
|
||||
import picgo from '@core/picgo'
|
||||
@@ -39,11 +40,7 @@ import pasteTemplate from '../utils/pasteTemplate'
|
||||
import { i18nManager, T } from '~/main/i18n'
|
||||
import { rpcServer } from './rpc'
|
||||
|
||||
// eslint-disable-next-line
|
||||
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
|
||||
// const PluginHandler = requireFunc('picgo/lib/PluginHandler').default
|
||||
const STORE_PATH = path.dirname(dbPathChecker())
|
||||
// const CONFIG_PATH = path.join(STORE_PATH, '/data.json')
|
||||
|
||||
interface GuiMenuItem {
|
||||
label: string
|
||||
@@ -84,7 +81,7 @@ const getPluginList = (): IPicGoPlugin[] => {
|
||||
for (const i in pluginList) {
|
||||
const plugin = picgo.pluginLoader.getPlugin(pluginList[i])!
|
||||
const pluginPath = path.join(STORE_PATH, `/node_modules/${pluginList[i]}`)
|
||||
const pluginPKG = requireFunc(path.join(pluginPath, 'package.json'))
|
||||
const pluginPKG = fs.readJSONSync(path.join(pluginPath, 'package.json'), 'utf-8')
|
||||
const uploaderName = plugin.uploader || ''
|
||||
const transformerName = plugin.transformer || ''
|
||||
let menu: Omit<IGuiMenuItem, 'handle'>[] = []
|
||||
|
||||
@@ -105,7 +105,9 @@ const buildMainPageMenu = (win: BrowserWindow) => {
|
||||
{
|
||||
label: T('SHOW_DEVTOOLS'),
|
||||
click () {
|
||||
win?.webContents?.openDevTools()
|
||||
win?.webContents?.openDevTools({
|
||||
mode: 'detach'
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ systemRouter
|
||||
})
|
||||
.add(IRPCActionType.SHOW_DOCK_ICON, async (args) => {
|
||||
const [visible] = args as IShowDockIconArgs
|
||||
app.dock[visible ? 'show' : 'hide']()
|
||||
app.dock?.[visible ? 'show' : 'hide']()
|
||||
const win = windowManager.get(IWindowList.SETTING_WINDOW)
|
||||
if (!visible) {
|
||||
win?.show()
|
||||
|
||||
@@ -2,11 +2,12 @@ import yaml from 'js-yaml'
|
||||
import { ObjectAdapter, I18n } from '@picgo/i18n'
|
||||
import path from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import { getStaticPath } from '#/utils/staticPath'
|
||||
import { builtinI18nList } from '#/i18n'
|
||||
|
||||
class I18nManager {
|
||||
private i18n: I18n | null = null
|
||||
private builtinI18nFolder = path.join(__static, 'i18n')
|
||||
private builtinI18nFolder = getStaticPath('i18n')
|
||||
private outerI18nFolder = ''
|
||||
private localesMap: Map<string, ILocales> = new Map()
|
||||
private currentLanguage: string = 'zh-CN'
|
||||
|
||||
@@ -5,9 +5,6 @@ import {
|
||||
protocol,
|
||||
Notification
|
||||
} from 'electron'
|
||||
import {
|
||||
createProtocol
|
||||
} from 'vue-cli-plugin-electron-builder/lib'
|
||||
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
|
||||
import beforeOpen from '~/main/utils/beforeOpen'
|
||||
import ipcList from '~/main/events/ipcList'
|
||||
@@ -37,8 +34,10 @@ import fixPath from './fixPath'
|
||||
import { initI18n } from '~/main/utils/handleI18n'
|
||||
import { remoteNoticeHandler } from 'apis/app/remoteNotice'
|
||||
import { isMacOS } from '../utils/getMacOSVersion'
|
||||
import { isWindowShouldShowOnStartup } from '../apis/app/window/windowList'
|
||||
import { initStaticPath, isDev } from '../utils/env'
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
const isDevelopment = isDev
|
||||
|
||||
const handleStartUpFiles = (argv: string[], cwd: string) => {
|
||||
const files = getUploadFiles(argv, cwd, logger)
|
||||
@@ -73,13 +72,12 @@ class LifeCycle {
|
||||
private onReady () {
|
||||
const readyFunction = async () => {
|
||||
console.log('on ready')
|
||||
createProtocol('picgo')
|
||||
if (isDevelopment && !process.env.IS_TEST) {
|
||||
// Install Vue Devtools
|
||||
try {
|
||||
await installExtension(VUEJS_DEVTOOLS)
|
||||
} catch (e: any) {
|
||||
console.error('Vue Devtools failed to install:', e.toString())
|
||||
console.error('Vue Devtools failed to install:', e?.toString())
|
||||
}
|
||||
}
|
||||
windowManager.create(IWindowList.TRAY_WINDOW)
|
||||
@@ -87,6 +85,17 @@ class LifeCycle {
|
||||
settingWindow?.once('show', () => {
|
||||
remoteNoticeHandler.triggerHook(IRemoteNoticeTriggerHook.SETTING_WINDOW_OPEN)
|
||||
})
|
||||
if (isWindowShouldShowOnStartup(IWindowList.SETTING_WINDOW)) {
|
||||
settingWindow?.show()
|
||||
settingWindow?.focus()
|
||||
}
|
||||
if (!isMacOS) {
|
||||
if (isWindowShouldShowOnStartup(IWindowList.MINI_WINDOW)) {
|
||||
const miniWindow = windowManager.create(IWindowList.MINI_WINDOW)
|
||||
miniWindow?.show()
|
||||
miniWindow?.focus()
|
||||
}
|
||||
}
|
||||
createTray()
|
||||
handleDockIcon()
|
||||
db.set('needReload', false)
|
||||
@@ -128,7 +137,6 @@ class LifeCycle {
|
||||
}
|
||||
})
|
||||
app.on('activate', () => {
|
||||
createProtocol('picgo')
|
||||
if (!windowManager.has(IWindowList.TRAY_WINDOW)) {
|
||||
windowManager.create(IWindowList.TRAY_WINDOW)
|
||||
}
|
||||
@@ -188,6 +196,7 @@ class LifeCycle {
|
||||
if (!gotTheLock) {
|
||||
app.quit()
|
||||
} else {
|
||||
initStaticPath()
|
||||
await this.beforeReady()
|
||||
this.onReady()
|
||||
this.onRunning()
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import picgo from '@core/picgo'
|
||||
import logger from '@core/picgo/logger'
|
||||
import axios from 'axios'
|
||||
import formUploader from './middlewares/formUploader'
|
||||
|
||||
class Server {
|
||||
private httpServer: http.Server
|
||||
@@ -56,6 +57,8 @@ class Server {
|
||||
success: false
|
||||
}
|
||||
})
|
||||
} else if (formUploader.isFileUpload(request)) {
|
||||
formUploader.handleFileUpload(request, response)
|
||||
} else {
|
||||
let body: string = ''
|
||||
let postObj: IObj
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
import http from 'http'
|
||||
import multer from 'multer'
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import { dbPathDir } from 'apis/core/datastore/dbChecker'
|
||||
import logger from '@core/picgo/logger'
|
||||
import { handleResponse } from '../utils'
|
||||
import routers from '../routerManager'
|
||||
import { FORM_IMAGE_FOLDER } from '~/universal/utils/static'
|
||||
|
||||
// Multer 错误类型定义
|
||||
export interface MulterError extends Error {
|
||||
code: string
|
||||
field?: string
|
||||
storageErrors?: any[]
|
||||
}
|
||||
|
||||
// Multer 中间件适配器类型
|
||||
export type MulterMiddleware = (
|
||||
req: http.IncomingMessage,
|
||||
res: http.ServerResponse,
|
||||
callback: (error?: MulterError) => void
|
||||
) => void;
|
||||
|
||||
// 扩展 multer 函数的返回类型
|
||||
declare module 'multer' {
|
||||
interface Multer {
|
||||
array(fieldname: string, maxCount?: number): MulterMiddleware;
|
||||
single(fieldname: string): MulterMiddleware;
|
||||
fields(fields: { name: string; maxCount?: number }[]): MulterMiddleware;
|
||||
none(): MulterMiddleware;
|
||||
}
|
||||
}
|
||||
|
||||
class FormUploader {
|
||||
private upload!: multer.Multer
|
||||
private formImagesPath!: string
|
||||
|
||||
constructor () {
|
||||
this.initializeStorage()
|
||||
this.setupMulter()
|
||||
}
|
||||
|
||||
private initializeStorage () {
|
||||
const STORE_PATH = dbPathDir()
|
||||
this.formImagesPath = path.join(STORE_PATH, FORM_IMAGE_FOLDER)
|
||||
if (!fs.existsSync(this.formImagesPath)) {
|
||||
fs.mkdirSync(this.formImagesPath, { recursive: true })
|
||||
}
|
||||
}
|
||||
|
||||
private setupMulter () {
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req: http.IncomingMessage, file: Express.Multer.File, cb: (error: Error | null, destination: string) => void) => {
|
||||
cb(null, this.formImagesPath)
|
||||
},
|
||||
filename: (req: http.IncomingMessage, file: Express.Multer.File, cb: (error: Error | null, filename: string) => void) => {
|
||||
cb(null, file.originalname || Date.now() + path.extname(file.originalname))
|
||||
}
|
||||
})
|
||||
|
||||
this.upload = multer({
|
||||
storage
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文件上传的中间件
|
||||
*/
|
||||
public handleFileUpload = (request: http.IncomingMessage, response: http.ServerResponse): void => {
|
||||
logger.info('[PicGo Server] handling file upload')
|
||||
|
||||
this.upload.array('files')(request, response, async (err?: MulterError) => {
|
||||
if (err) {
|
||||
logger.error('[PicGo Server] file upload error', err)
|
||||
return handleResponse({
|
||||
response,
|
||||
body: {
|
||||
success: false,
|
||||
message: 'File upload failed'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
const files = request.files
|
||||
if (!files || files.length === 0) {
|
||||
return handleResponse({
|
||||
response,
|
||||
body: {
|
||||
success: false,
|
||||
message: 'No files were uploaded'
|
||||
}
|
||||
})
|
||||
}
|
||||
const filePaths = files.map((file) => file.path)
|
||||
logger.info('[PicGo Server] files uploaded: ' + filePaths.join(', '))
|
||||
|
||||
const handler = routers.getHandler(request.url!)
|
||||
handler!({
|
||||
list: filePaths,
|
||||
response
|
||||
})
|
||||
} catch (err: any) {
|
||||
logger.error('[PicGo Server] process upload files error', err)
|
||||
handleResponse({
|
||||
response,
|
||||
body: {
|
||||
success: false,
|
||||
message: 'Failed to process uploaded files'
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查请求是否为文件上传
|
||||
*/
|
||||
public isFileUpload (request: http.IncomingMessage): boolean {
|
||||
return !!(request.headers['content-type'] && request.headers['content-type'].includes('multipart/form-data'))
|
||||
}
|
||||
}
|
||||
|
||||
export default new FormUploader()
|
||||
@@ -5,6 +5,7 @@ import { dbPathChecker } from 'apis/core/datastore/dbChecker'
|
||||
import yaml from 'js-yaml'
|
||||
import { i18nManager } from '~/main/i18n'
|
||||
// import { ILocales } from '~/universal/types/i18n'
|
||||
import { getStaticPath } from '#/utils/staticPath'
|
||||
|
||||
const configPath = dbPathChecker()
|
||||
const CONFIG_DIR = path.dirname(configPath)
|
||||
@@ -23,7 +24,7 @@ function copyFileOutsideOfElectronAsar (
|
||||
if (fs.existsSync(sourceInAsarArchive)) {
|
||||
// file will be copied
|
||||
if (fs.statSync(sourceInAsarArchive).isFile()) {
|
||||
const file = destOutsideAsarArchive;
|
||||
const file = destOutsideAsarArchive
|
||||
const dir = path.dirname(file)
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true })
|
||||
@@ -34,8 +35,8 @@ function copyFileOutsideOfElectronAsar (
|
||||
copyFileOutsideOfElectronAsar(
|
||||
`${sourceInAsarArchive}/${fileOrFolderName}`,
|
||||
`${destOutsideAsarArchive}/${fileOrFolderName}`
|
||||
);
|
||||
});
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +50,7 @@ function resolveMacWorkFlow () {
|
||||
return true
|
||||
} else {
|
||||
try {
|
||||
copyFileOutsideOfElectronAsar(path.join(__static, 'Upload pictures with PicGo.workflow'), dest)
|
||||
copyFileOutsideOfElectronAsar(getStaticPath('Upload pictures with PicGo.workflow'), dest)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
@@ -87,16 +88,16 @@ function resolveClipboardImageGenerator () {
|
||||
|
||||
function getClipboardFiles () {
|
||||
const files = [
|
||||
'/linux.sh',
|
||||
'/mac.applescript',
|
||||
'/windows.ps1',
|
||||
'/windows10.ps1',
|
||||
'/wsl.sh'
|
||||
'linux.sh',
|
||||
'mac.applescript',
|
||||
'windows.ps1',
|
||||
'windows10.ps1',
|
||||
'wsl.sh'
|
||||
]
|
||||
|
||||
return files.map(item => {
|
||||
return {
|
||||
origin: path.join(__static, item),
|
||||
origin: getStaticPath(item),
|
||||
dest: path.join(CONFIG_DIR, item)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import { getFormImageFolderPath } from '@core/datastore/dbChecker'
|
||||
import logger from '@core/picgo/logger'
|
||||
|
||||
export const cleanupFormUploaderFiles = (fileInfoList?: string[] | ImgInfo[]): void => {
|
||||
const formImageFolderPath = getFormImageFolderPath()
|
||||
if (Array.isArray(fileInfoList)) {
|
||||
fileInfoList.forEach(async fileInfo => {
|
||||
const filePath = typeof fileInfo === 'string' ? fileInfo : fileInfo?.imgPath
|
||||
if (!filePath) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
// 检查文件路径是否在 formImageFolderPath 目录下
|
||||
const relativePath = path.relative(formImageFolderPath, filePath)
|
||||
const isWithinFolder = !relativePath.startsWith('..') && !path.isAbsolute(relativePath)
|
||||
|
||||
if (isWithinFolder && await fs.pathExists(filePath)) {
|
||||
await fs.remove(filePath)
|
||||
logger.info(`[PicGo] Deleted temp file: ${filePath}`)
|
||||
}
|
||||
} catch (error: any) {
|
||||
logger.error('[PicGo] Failed to delete temp file', filePath, error)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,10 @@ import fs from 'fs-extra'
|
||||
import db from '~/main/apis/core/datastore'
|
||||
import { clipboard, Notification, dialog } from 'electron'
|
||||
import { handleUrlEncode } from '~/universal/utils/common'
|
||||
import { readClipboardFilePaths } from 'clip-filepaths'
|
||||
|
||||
export const handleCopyUrl = (str: string): void => {
|
||||
if (db.get('settings.autoCopy') !== false) {
|
||||
if (db.get('settings.autoCopyUrl') !== false) {
|
||||
clipboard.writeText(str)
|
||||
}
|
||||
}
|
||||
@@ -97,26 +98,9 @@ export const ensureFilePath = (filePath: string, prefix = 'file://'): string =>
|
||||
* for builtin clipboard to get image path from clipboard
|
||||
* @returns
|
||||
*/
|
||||
export const getClipboardFilePath = (): string => {
|
||||
// TODO: linux support
|
||||
const img = clipboard.readImage()
|
||||
if (img.isEmpty()) {
|
||||
if (process.platform === 'win32') {
|
||||
const imgPath = clipboard.readBuffer('FileNameW')?.toString('ucs2')?.replace(RegExp(String.fromCharCode(0), 'g'), '')
|
||||
if (imgPath) {
|
||||
return imgPath
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (process.platform === 'darwin') {
|
||||
let imgPath = clipboard.read('public.file-url') // will get file://xxx/xxx
|
||||
imgPath = ensureFilePath(imgPath)
|
||||
if (imgPath) {
|
||||
return imgPath.replace('file://', '')
|
||||
}
|
||||
}
|
||||
}
|
||||
return ''
|
||||
export const getClipboardFilePathList = (): string[] => {
|
||||
const { filePaths } = readClipboardFilePaths()
|
||||
return filePaths
|
||||
}
|
||||
|
||||
export const handleUrlEncodeWithSetting = (url: string) => {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import path from 'path'
|
||||
import { app } from 'electron'
|
||||
import { pathToFileURL } from 'url'
|
||||
|
||||
export const isDev = !app.isPackaged
|
||||
|
||||
const defaultStaticPath = process.env.STATIC_PATH || (isDev
|
||||
? path.join(process.cwd(), 'public')
|
||||
: path.join(process.resourcesPath, 'public'))
|
||||
|
||||
process.env.STATIC_PATH = defaultStaticPath
|
||||
|
||||
const rendererHtmlPath = path.join(__dirname, '../renderer/index.html')
|
||||
|
||||
export const initStaticPath = () => defaultStaticPath
|
||||
|
||||
export const getRendererBaseUrl = () => {
|
||||
if (isDev && process.env.ELECTRON_RENDERER_URL) {
|
||||
return process.env.ELECTRON_RENDERER_URL
|
||||
}
|
||||
return pathToFileURL(rendererHtmlPath).toString()
|
||||
}
|
||||
|
||||
export const buildRendererUrl = (hash?: string) => {
|
||||
const base = getRendererBaseUrl()
|
||||
if (!hash) return base
|
||||
const cleanedHash = hash.startsWith('#') ? hash : `#${hash}`
|
||||
return `${base}${cleanedHash}`
|
||||
}
|
||||
|
||||
export const getStaticPath = () => process.env.STATIC_PATH || defaultStaticPath
|
||||
@@ -0,0 +1,13 @@
|
||||
// temp no used
|
||||
// will be refactor in future
|
||||
import { contextBridge, webUtils } from 'electron'
|
||||
|
||||
const getFilePath = (file: File): string => webUtils.getPathForFile(file)
|
||||
|
||||
const electronApi = {
|
||||
getFilePath
|
||||
}
|
||||
|
||||
contextBridge.exposeInMainWorld('electronApi', electronApi)
|
||||
|
||||
export type ElectronApi = typeof electronApi
|
||||
@@ -0,0 +1,10 @@
|
||||
import { onBeforeMount, ref } from 'vue'
|
||||
|
||||
export const useOS = () => {
|
||||
const os = ref<string>('')
|
||||
|
||||
onBeforeMount(() => {
|
||||
os.value = process.platform
|
||||
})
|
||||
return os
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="referrer" content="never" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<title>PicGo</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="./main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,7 +2,6 @@
|
||||
<div id="main-page">
|
||||
<div
|
||||
class="fake-title-bar"
|
||||
:class="{ 'darwin': os === 'darwin' }"
|
||||
>
|
||||
<div class="fake-title-bar__title">
|
||||
PicGo - {{ version }}
|
||||
@@ -103,7 +102,6 @@
|
||||
:offset="5"
|
||||
style="height: 428px"
|
||||
class="main-wrapper"
|
||||
:class="{ 'darwin': os === 'darwin' }"
|
||||
>
|
||||
<router-view
|
||||
v-slot="{ Component }"
|
||||
@@ -236,11 +234,12 @@ import {
|
||||
GET_PICBEDS
|
||||
} from '~/universal/events/constants'
|
||||
import { getConfig, sendToMain } from '@/utils/dataSender'
|
||||
import { useOS } from '@/hooks/useOS'
|
||||
const version = ref(process.env.NODE_ENV === 'production' ? pkg.version : 'Dev')
|
||||
const routerConfig = reactive(config)
|
||||
const defaultActive = ref(routerConfig.UPLOAD_PAGE)
|
||||
const visible = ref(false)
|
||||
const os = ref('')
|
||||
const os = useOS()
|
||||
const $router = useRouter()
|
||||
const picBed: Ref<IPicBedType[]> = ref([])
|
||||
const qrcodeVisible = ref(false)
|
||||
@@ -250,7 +249,6 @@ const choosedPicBedForQRCode: Ref<string[]> = ref([])
|
||||
const keepAlivePages = $router.getRoutes().filter(item => item.meta.keepAlive).map(item => item.name as string)
|
||||
|
||||
onBeforeMount(() => {
|
||||
os.value = process.platform
|
||||
sendToMain(GET_PICBEDS)
|
||||
ipcRenderer.on(GET_PICBEDS, getPicBeds)
|
||||
handleGetPicPeds()
|
||||
@@ -350,7 +348,8 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
$darwinBg = transparentify(#172426, #000, 0.7)
|
||||
$bg = transparentify(#172426, #000, 0.9)
|
||||
$sideBg = transparentify(#000, 0.7)
|
||||
.setting-list-scroll
|
||||
height 425px
|
||||
overflow-y auto
|
||||
@@ -388,17 +387,16 @@ $darwinBg = transparentify(#172426, #000, 0.7)
|
||||
line-height h
|
||||
position fixed
|
||||
z-index 100
|
||||
&.darwin
|
||||
background transparent
|
||||
background-image linear-gradient(
|
||||
to right,
|
||||
transparent 0%,
|
||||
transparent 167px,
|
||||
$darwinBg 167px,
|
||||
$darwinBg 100%
|
||||
)
|
||||
.fake-title-bar__title
|
||||
padding-left 167px
|
||||
background transparent
|
||||
background-image linear-gradient(
|
||||
to right,
|
||||
$sideBg 0%,
|
||||
$sideBg 170px,
|
||||
$bg 170px,
|
||||
$bg 100%
|
||||
)
|
||||
.fake-title-bar__title
|
||||
padding-left 167px
|
||||
.handle-bar
|
||||
position absolute
|
||||
top 2px
|
||||
@@ -419,14 +417,14 @@ $darwinBg = transparentify(#172426, #000, 0.7)
|
||||
&:hover
|
||||
color #69C282
|
||||
.main-wrapper
|
||||
&.darwin
|
||||
background $darwinBg
|
||||
background $bg
|
||||
.side-bar-menu
|
||||
position fixed
|
||||
height calc(100vh - 22px)
|
||||
overflow-x hidden
|
||||
overflow-y auto
|
||||
width 170px
|
||||
background $sideBg
|
||||
.info-window
|
||||
cursor pointer
|
||||
position fixed
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
import './renderer/assets/css/tailwind.css'
|
||||
import './assets/css/tailwind.css'
|
||||
import { createApp } from 'vue'
|
||||
import App from './renderer/App.vue'
|
||||
import router from './renderer/router'
|
||||
import { webFrame } from 'electron'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import ElementUI from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
import { webFrame } from 'electron'
|
||||
import VueLazyLoad from 'vue3-lazyload'
|
||||
import axios from 'axios'
|
||||
import { mainMixin } from './renderer/utils/mainMixin'
|
||||
import { mainMixin } from './utils/mainMixin'
|
||||
import { dragMixin } from '@/utils/mixin'
|
||||
import { initTalkingData } from './renderer/utils/analytics'
|
||||
import db from './renderer/utils/db'
|
||||
import { i18nManager, T } from './renderer/i18n/index'
|
||||
import { initTalkingData } from './utils/analytics'
|
||||
import db from './utils/db'
|
||||
import { i18nManager, T } from './i18n/index'
|
||||
import { getConfig, saveConfig, sendToMain, triggerRPC } from '@/utils/dataSender'
|
||||
import { store } from '@/store'
|
||||
import vue3PhotoPreview from 'vue3-photo-preview'
|
||||
import 'vue3-photo-preview/dist/index.css'
|
||||
import { getRendererStaticFileUrl } from './utils/static'
|
||||
|
||||
webFrame.setVisualZoomLevelLimits(1, 1)
|
||||
|
||||
// do here before vue init
|
||||
// handleURLParams()
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.config.globalProperties.$builtInPicBed = [
|
||||
@@ -48,7 +46,7 @@ app.mixin(mainMixin)
|
||||
app.mixin(dragMixin)
|
||||
|
||||
app.use(VueLazyLoad, {
|
||||
error: `file://${__static.replace(/\\/g, '/')}/unknown-file-type.svg`
|
||||
error: getRendererStaticFileUrl('unknown-file-type.svg')
|
||||
})
|
||||
app.use(ElementUI)
|
||||
app.use(router)
|
||||
@@ -202,6 +202,7 @@ import { T as $T } from '@/i18n/index'
|
||||
import $$db from '@/utils/db'
|
||||
import GalleryToolbar from './components/gallery/GalleryToolbar.vue'
|
||||
import { IRPCActionType } from '~/universal/types/enum'
|
||||
import { getRawData } from '@/utils/common'
|
||||
const images = ref<ImgInfo[]>([])
|
||||
const dialogVisible = ref(false)
|
||||
const imgInfo = reactive({
|
||||
@@ -367,7 +368,7 @@ function handleClose () {
|
||||
}
|
||||
|
||||
async function copy (item: ImgInfo) {
|
||||
const copyLink = await ipcRenderer.invoke(PASTE_TEXT, item)
|
||||
const copyLink = await ipcRenderer.invoke(PASTE_TEXT, getRawData(item))
|
||||
const obj = {
|
||||
title: $T('COPY_LINK_SUCCEED'),
|
||||
body: copyLink
|
||||
@@ -498,7 +499,7 @@ async function multiCopy () {
|
||||
if (selectedList[key]) {
|
||||
const item = await $$db.getById<ImgInfo>(key)
|
||||
if (item) {
|
||||
const txt = await ipcRenderer.invoke(PASTE_TEXT, item)
|
||||
const txt = await ipcRenderer.invoke(PASTE_TEXT, getRawData(item))
|
||||
copyString.push(txt)
|
||||
selectedList[key] = false
|
||||
}
|
||||
|
||||
@@ -42,7 +42,10 @@ import {
|
||||
isUrl
|
||||
} from '~/universal/utils/common'
|
||||
import { sendToMain } from '@/utils/dataSender'
|
||||
const logo = require('../assets/squareLogo.png')
|
||||
import { getFilePath } from '@/utils/common'
|
||||
import { getRendererStaticFileUrl } from '@/utils/static'
|
||||
import { useOS } from '@/hooks/useOS'
|
||||
const logo = ref(getRendererStaticFileUrl('squareLogo.png'))
|
||||
const dragover = ref(false)
|
||||
const progress = ref(0)
|
||||
const showProgress = ref(false)
|
||||
@@ -52,10 +55,9 @@ const wX = ref(-1)
|
||||
const wY = ref(-1)
|
||||
const screenX = ref(-1)
|
||||
const screenY = ref(-1)
|
||||
const os = ref('')
|
||||
const os = useOS()
|
||||
|
||||
onBeforeMount(() => {
|
||||
os.value = process.platform
|
||||
ipcRenderer.on('uploadProgress', (event: IpcRendererEvent, _progress: number) => {
|
||||
if (_progress !== -1) {
|
||||
showProgress.value = true
|
||||
@@ -134,12 +136,14 @@ function onChange (e: any) {
|
||||
function ipcSendFiles (files: FileList) {
|
||||
const sendFiles: IFileWithPath[] = []
|
||||
Array.from(files).forEach((item) => {
|
||||
const obj = {
|
||||
const filePath = getFilePath(item)
|
||||
if (!filePath) return
|
||||
sendFiles.push({
|
||||
name: item.name,
|
||||
path: item.path
|
||||
}
|
||||
sendFiles.push(obj)
|
||||
path: filePath
|
||||
})
|
||||
})
|
||||
if (!sendFiles.length) return
|
||||
sendToMain('uploadChoosedFiles', sendFiles)
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ import { ElForm } from 'element-plus'
|
||||
import { Reading } from '@element-plus/icons-vue'
|
||||
import { IConfig } from 'picgo'
|
||||
import { T as $T } from '@/i18n/index'
|
||||
import { enforceNumber } from '~/universal/utils/common'
|
||||
import { enforceNumber, isLinux } from '~/universal/utils/common'
|
||||
import { onBeforeMount, reactive, ref } from 'vue'
|
||||
import { getConfig } from '@/utils/dataSender'
|
||||
import ButtonAreaSettings from './components/settings/buttonArea/ButtonAreaSettings.vue'
|
||||
@@ -56,6 +56,7 @@ import SwitchAreaSettings from './components/settings/switchArea/SwitchAreaSetti
|
||||
import CustomAreaSettings from './components/settings/customArea/CustomAreaSettings.vue'
|
||||
import SelectAreaSettings from './components/settings/selectArea/SelectAreaSettings.vue'
|
||||
import { openURL } from '@/utils/common'
|
||||
import { IStartupMode } from '#/types/enum'
|
||||
|
||||
const form = reactive<ISettingForm>({
|
||||
showUpdateTip: false,
|
||||
@@ -80,7 +81,8 @@ const form = reactive<ISettingForm>({
|
||||
port: 36677,
|
||||
host: '127.0.0.1',
|
||||
enable: true
|
||||
}
|
||||
},
|
||||
startupMode: IStartupMode.HIDE
|
||||
})
|
||||
|
||||
const proxy = ref('')
|
||||
@@ -101,7 +103,7 @@ async function initData () {
|
||||
form.uploadNotification = settings.uploadNotification || false
|
||||
form.miniWindowOnTop = settings.miniWindowOnTop || false
|
||||
form.logLevel = initLogLevel(settings.logLevel || [])
|
||||
form.autoCopyUrl = settings.autoCopy === undefined ? true : settings.autoCopy
|
||||
form.autoCopyUrl = settings.autoCopyUrl === undefined ? true : settings.autoCopyUrl
|
||||
form.checkBetaUpdate = settings.checkBetaUpdate === undefined ? true : settings.checkBetaUpdate
|
||||
form.useBuiltinClipboard = settings.useBuiltinClipboard === undefined ? false : settings.useBuiltinClipboard
|
||||
form.language = settings.language ?? 'zh-CN'
|
||||
@@ -113,6 +115,7 @@ async function initData () {
|
||||
form.server = settings.server
|
||||
form.logFileSizeLimit = enforceNumber(settings.logFileSizeLimit) || 10
|
||||
form.showDockIcon = settings.showDockIcon === undefined ? true : settings.showDockIcon
|
||||
form.startupMode = settings.startupMode || (isLinux ? IStartupMode.SHOW_MINI_WINDOW : IStartupMode.HIDE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +131,7 @@ function initLogLevel (logLevel: string | string[]) {
|
||||
}
|
||||
|
||||
function goConfigPage () {
|
||||
openURL('https://picgo.github.io/PicGo-Doc/zh/guide/config.html#picgo设置')
|
||||
openURL('https://picgo.github.io/PicGo-Doc/guide/config.html#picgo设置')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
>
|
||||
<div
|
||||
class="plugin-item"
|
||||
:class="{ 'darwin': os === 'darwin' }"
|
||||
>
|
||||
<div
|
||||
v-if="!item.gui"
|
||||
@@ -217,6 +216,7 @@ import { computed, ref, onBeforeMount, onBeforeUnmount, watch } from 'vue'
|
||||
import { getConfig, saveConfig, sendRPC, sendToMain } from '@/utils/dataSender'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import axios from 'axios'
|
||||
import { getRendererStaticFileUrl } from '@/utils/static'
|
||||
import { IRPCActionType } from '~/universal/types/enum'
|
||||
const $confirm = ElMessageBox.confirm
|
||||
const searchText = ref('')
|
||||
@@ -231,8 +231,7 @@ const needReload = ref(false)
|
||||
const pluginListToolTip = $T('PLUGIN_LIST')
|
||||
const importLocalPluginToolTip = $T('PLUGIN_IMPORT_LOCAL')
|
||||
// const id = ref('')
|
||||
const os = ref('')
|
||||
const defaultLogo = ref(`this.src="file://${__static.replace(/\\/g, '/')}/roundLogo.png"`)
|
||||
const defaultLogo = ref(`this.src="${getRendererStaticFileUrl('roundLogo.png')}"`)
|
||||
const $configForm = ref<InstanceType<typeof ConfigForm> | null>(null)
|
||||
const npmSearchText = computed(() => {
|
||||
return searchText.value.match('picgo-plugin-')
|
||||
@@ -264,7 +263,6 @@ watch(dialogVisible, (val: boolean) => {
|
||||
})
|
||||
|
||||
onBeforeMount(async () => {
|
||||
os.value = process.platform
|
||||
ipcRenderer.on('hideLoading', () => {
|
||||
loading.value = false
|
||||
})
|
||||
@@ -485,7 +483,7 @@ function handleSearchResult (item: INPMSearchResultObject) {
|
||||
return {
|
||||
name,
|
||||
fullName: item.package.name,
|
||||
author: item.package.author.name,
|
||||
author: item.package.maintainers[0]?.username || '',
|
||||
description: item.package.description,
|
||||
logo: `https://cdn.jsdelivr.net/npm/${item.package.name}/logo.png`,
|
||||
config: {},
|
||||
@@ -549,7 +547,7 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
$darwinBg = #172426
|
||||
$bg = #172426
|
||||
#plugin-view
|
||||
position relative
|
||||
padding 0 20px 0
|
||||
@@ -619,12 +617,9 @@ $darwinBg = #172426
|
||||
padding 3px 8px
|
||||
background #49B1F5
|
||||
color #eee
|
||||
&.darwin
|
||||
background transparentify($darwinBg, #000, 0.75)
|
||||
&:hover
|
||||
background transparentify($darwinBg, #000, 0.85)
|
||||
background transparentify($bg, #000, 0.75)
|
||||
&:hover
|
||||
background #333
|
||||
background transparentify($bg, #000, 0.85)
|
||||
&__logo
|
||||
width 64px
|
||||
height 64px
|
||||
|
||||
@@ -103,9 +103,10 @@ import { IToolboxItemType, IToolboxItemCheckStatus, IRPCActionType } from '~/uni
|
||||
import { T as $T } from '@/i18n'
|
||||
import ToolboxStatusIcon from '@/components/ToolboxStatusIcon.vue'
|
||||
import ToolboxHandler from '@/components/ToolboxHandler.vue'
|
||||
import { getRendererStaticFileUrl } from '@/utils/static'
|
||||
|
||||
const $confirm = ElMessageBox.confirm
|
||||
const defaultLogo = ref(`file://${__static.replace(/\\/g, '/')}/roundLogo.png`)
|
||||
const defaultLogo = ref(getRendererStaticFileUrl('roundLogo.png'))
|
||||
const activeTypes = ref<IToolboxItemType[]>([])
|
||||
const fixList = reactive<IToolboxMap>({
|
||||
[IToolboxItemType.IS_CONFIG_FILE_BROKEN]: {
|
||||
|
||||
@@ -70,6 +70,8 @@ import { IResult } from '@picgo/store/dist/types'
|
||||
import { PASTE_TEXT, OPEN_WINDOW } from '#/events/constants'
|
||||
import { IWindowList } from '#/types/enum'
|
||||
import { sendToMain } from '@/utils/dataSender'
|
||||
import { getRawData } from '@/utils/common'
|
||||
import { IpcRendererEvent } from 'electron/renderer'
|
||||
|
||||
const files = ref<IResult<ImgInfo>[]>([])
|
||||
const notification = reactive({
|
||||
@@ -92,8 +94,8 @@ async function getData () {
|
||||
|
||||
async function copyTheLink (item: ImgInfo) {
|
||||
notification.body = item.imgUrl!
|
||||
await ipcRenderer.invoke(PASTE_TEXT, getRawData(item))
|
||||
const myNotification = new Notification(notification.title, notification)
|
||||
ipcRenderer.invoke(PASTE_TEXT, item)
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
@@ -125,14 +127,14 @@ function uploadClipboardFiles () {
|
||||
onBeforeMount(() => {
|
||||
disableDragFile()
|
||||
getData()
|
||||
ipcRenderer.on('dragFiles', async (event: Event, _files: string[]) => {
|
||||
ipcRenderer.on('dragFiles', async (event: IpcRendererEvent, _files: string[]) => {
|
||||
for (let i = 0; i < _files.length; i++) {
|
||||
const item = _files[i]
|
||||
await $$db.insert(item)
|
||||
}
|
||||
files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
|
||||
})
|
||||
ipcRenderer.on('clipboardFiles', (event: Event, files: ImgInfo[]) => {
|
||||
ipcRenderer.on('clipboardFiles', (event: IpcRendererEvent, files: ImgInfo[]) => {
|
||||
clipboardFiles.value = files
|
||||
})
|
||||
ipcRenderer.on('uploadFiles', async () => {
|
||||
@@ -162,7 +164,6 @@ export default {
|
||||
body::-webkit-scrollbar
|
||||
width 0px
|
||||
#tray-page
|
||||
background-color transparent
|
||||
.open-main-window
|
||||
background #000
|
||||
height 20px
|
||||
@@ -203,6 +204,7 @@ body::-webkit-scrollbar
|
||||
position absolute
|
||||
top 20px
|
||||
width 100%
|
||||
background-color transparentify(#172426, #000, 0.9)
|
||||
.img-list
|
||||
padding 4px 8px
|
||||
display flex
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
// import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||
import { T as $T } from '@/i18n'
|
||||
import $bus from '@/utils/bus'
|
||||
import { getFilePath } from '@/utils/common'
|
||||
import { getConfig, saveConfig, sendToMain } from '@/utils/dataSender'
|
||||
import { CaretBottom, UploadFilled } from '@element-plus/icons-vue'
|
||||
import {
|
||||
@@ -218,12 +219,14 @@ function onChange (e: any) {
|
||||
function ipcSendFiles (files: FileList) {
|
||||
const sendFiles: IFileWithPath[] = []
|
||||
Array.from(files).forEach((item) => {
|
||||
const obj = {
|
||||
const filePath = getFilePath(item)
|
||||
if (!filePath) return
|
||||
sendFiles.push({
|
||||
name: item.name,
|
||||
path: item.path
|
||||
}
|
||||
sendFiles.push(obj)
|
||||
path: filePath
|
||||
})
|
||||
})
|
||||
if (!sendFiles.length) return
|
||||
sendToMain('uploadChoosedFiles', sendFiles)
|
||||
}
|
||||
|
||||
@@ -272,7 +275,7 @@ async function getDefaultPicBed () {
|
||||
configName.value = currentConfigName
|
||||
}
|
||||
|
||||
function getPicBeds (event: Event, picBeds: IPicBedType[]) {
|
||||
function getPicBeds (event: IpcRendererEvent, picBeds: IPicBedType[]) {
|
||||
picBed.value = picBeds
|
||||
getDefaultPicBed()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<div id="config-list-view">
|
||||
<div
|
||||
id="config-list-view"
|
||||
class="h-[425px]"
|
||||
>
|
||||
<div class="view-title">
|
||||
{{ $T('SETTINGS') }}
|
||||
</div>
|
||||
@@ -239,9 +242,10 @@ export default {
|
||||
.selected
|
||||
border 1px solid #409EFF
|
||||
.set-default-container
|
||||
position absolute
|
||||
position fixed
|
||||
bottom 20px
|
||||
width 100%
|
||||
.set-default-btn
|
||||
width 250px
|
||||
transform translateX(-50%)
|
||||
</style>
|
||||
|
||||
@@ -6,6 +6,12 @@
|
||||
:placeholder="$T('SETTINGS_CHOOSE_LANGUAGE')"
|
||||
@change="handleLanguageChange"
|
||||
/>
|
||||
<SelectFormItem
|
||||
v-model="form.startupMode"
|
||||
:list="startupModeList"
|
||||
:label="$T('SETTINGS_STARTUP_MODE')"
|
||||
@change="handleChangeStartupMode"
|
||||
/>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from 'vue'
|
||||
@@ -13,6 +19,8 @@ import { T as $T, i18nManager } from '@/i18n'
|
||||
import { saveConfig, sendToMain } from '@/utils/dataSender'
|
||||
import { GET_PICBEDS } from '~/universal/events/constants'
|
||||
import SelectFormItem from '@/components/settings/SelectFormItem.vue'
|
||||
import { IStartupMode } from '~/universal/types/enum'
|
||||
import { isMacOS } from '~/universal/utils/common'
|
||||
|
||||
interface IProps {
|
||||
settings: ISettingForm
|
||||
@@ -26,6 +34,22 @@ const languageList = i18nManager.languageList.map(item => ({
|
||||
value: item.value
|
||||
}))
|
||||
|
||||
const startupModeList = [
|
||||
{
|
||||
label: $T('SETTINGS_STARTUP_MODE_MAIN_WINDOW'),
|
||||
value: IStartupMode.SHOW_MAIN_WINDOW
|
||||
},
|
||||
{
|
||||
label: $T('SETTINGS_STARTUP_MODE_MINI_WINDOW'),
|
||||
value: IStartupMode.SHOW_MINI_WINDOW,
|
||||
hide: isMacOS
|
||||
},
|
||||
{
|
||||
label: $T('SETTINGS_STARTUP_MODE_HIDE'),
|
||||
value: IStartupMode.HIDE
|
||||
}
|
||||
].filter(item => !item.hide)
|
||||
|
||||
function handleLanguageChange (val: string) {
|
||||
i18nManager.setCurrentLanguage(val)
|
||||
saveConfig({
|
||||
@@ -34,6 +58,12 @@ function handleLanguageChange (val: string) {
|
||||
sendToMain(GET_PICBEDS)
|
||||
}
|
||||
|
||||
function handleChangeStartupMode (val: IStartupMode) {
|
||||
saveConfig({
|
||||
'settings.startupMode': val
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
|
||||
@@ -63,14 +63,15 @@
|
||||
/>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
import { T as $T } from '@/i18n/index'
|
||||
import { ElMessage as $message } from 'element-plus'
|
||||
import { sendRPC, sendToMain } from '@/utils/dataSender'
|
||||
import { IRPCActionType } from '~/universal/types/enum'
|
||||
import SwitchFormItem from '@/components/settings/SwitchFormItem.vue'
|
||||
import { useOS } from '@/hooks/useOS'
|
||||
|
||||
const os = ref(process.platform)
|
||||
const os = useOS()
|
||||
|
||||
interface IProps {
|
||||
settings: ISettingForm
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable camelcase */
|
||||
import {
|
||||
TALKING_DATA_APPID, TALKING_DATA_EVENT
|
||||
} from '~/universal/events/constants'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { isReactive, isRef, toRaw, unref } from 'vue'
|
||||
import { sendToMain } from './dataSender'
|
||||
import { OPEN_URL, PICGO_OPEN_FILE } from '~/universal/events/constants'
|
||||
import { webUtils } from 'electron'
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
/* eslint-disable camelcase */
|
||||
export const handleTalkingDataEvent = (data: ITalkingDataOptions) => {
|
||||
const { EventId, Label = '', MapKv = {} } = data
|
||||
MapKv.from = window.location.href
|
||||
@@ -70,3 +70,7 @@ export const openFile = (fileName: string) => {
|
||||
export const openURL = (url: string) => {
|
||||
sendToMain(OPEN_URL, url)
|
||||
}
|
||||
|
||||
export const getFilePath = (file: File) => {
|
||||
return webUtils.getPathForFile(file)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ const isSpecialKey = (keyCode: number) => {
|
||||
}
|
||||
|
||||
const keyDetect = (event: KeyboardEvent) => {
|
||||
// TODO: remove process
|
||||
const meta = process.platform === 'darwin' ? 'Cmd' : 'Super'
|
||||
const specialKey = {
|
||||
Ctrl: event.ctrlKey,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export const getRendererStaticFileUrl = (fileName: string) => {
|
||||
return import.meta.env.BASE_URL + fileName
|
||||
}
|
||||
@@ -92,3 +92,9 @@ export enum IToolboxItemCheckStatus {
|
||||
SUCCESS = 'success',
|
||||
ERROR = 'error',
|
||||
}
|
||||
|
||||
export enum IStartupMode {
|
||||
SHOW_MAIN_WINDOW = 'SHOW_SETTING_WINDOW',
|
||||
SHOW_MINI_WINDOW = 'SHOW_MINI_WINDOW',
|
||||
HIDE = 'HIDE'
|
||||
}
|
||||
|
||||
Vendored
+14
@@ -7,3 +7,17 @@ declare var notificationList: IAppNotification[]
|
||||
declare module 'epipebomb' {
|
||||
export default function epipebomb(stream: NodeJS.Process['stdout'], callback: () => void): void
|
||||
}
|
||||
|
||||
// 扩展原生 IncomingMessage,添加 multer 字段
|
||||
declare module 'http' {
|
||||
interface IncomingMessage {
|
||||
files?: {
|
||||
path: string;
|
||||
originalname: string;
|
||||
mimetype: string;
|
||||
size: number;
|
||||
[key: string]: any;
|
||||
}[];
|
||||
body?: any;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+4
@@ -116,6 +116,10 @@ interface ILocales {
|
||||
SELECTED_SETTING_HINT: string
|
||||
SETTINGS_ENCODE_OUTPUT_URL: string
|
||||
SETTINGS_SHOW_DOCK_ICON: string
|
||||
SETTINGS_STARTUP_MODE: string
|
||||
SETTINGS_STARTUP_MODE_MAIN_WINDOW: string
|
||||
SETTINGS_STARTUP_MODE_MINI_WINDOW: string
|
||||
SETTINGS_STARTUP_MODE_HIDE: string
|
||||
SHORTCUT_NAME: string
|
||||
SHORTCUT_BIND: string
|
||||
SHORTCUT_STATUS: string
|
||||
|
||||
Vendored
+5
@@ -1,6 +1,10 @@
|
||||
import Vue, { VNode } from 'vue'
|
||||
|
||||
declare global {
|
||||
interface ElectronApi {
|
||||
getFilePath: (file: File) => string
|
||||
}
|
||||
|
||||
namespace JSX {
|
||||
// tslint:disable no-empty-interface
|
||||
interface Element extends VNode {}
|
||||
@@ -12,6 +16,7 @@ declare global {
|
||||
}
|
||||
|
||||
interface Window {
|
||||
electronApi: ElectronApi
|
||||
TDAPP: {
|
||||
onEvent: (EventId: string, Label?: string, MapKv?: IStringKeyMap) => void
|
||||
}
|
||||
|
||||
Vendored
+14
-6
@@ -18,7 +18,13 @@ declare interface ErrnoException extends Error {
|
||||
stack?: string;
|
||||
}
|
||||
|
||||
declare let __static: string
|
||||
declare namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
STATIC_PATH?: string
|
||||
}
|
||||
}
|
||||
|
||||
declare const __static: string
|
||||
|
||||
declare type ILogType = 'success' | 'info' | 'warn' | 'error'
|
||||
|
||||
@@ -101,6 +107,7 @@ interface IBrowserWindowOptions {
|
||||
fullscreenable: boolean,
|
||||
resizable: boolean,
|
||||
webPreferences: {
|
||||
preload?: string
|
||||
nodeIntegration: boolean,
|
||||
nodeIntegrationInWorker: boolean,
|
||||
contextIsolation: boolean,
|
||||
@@ -213,9 +220,10 @@ interface INPMSearchResultObject {
|
||||
version: string
|
||||
description: string
|
||||
keywords: string[]
|
||||
author: {
|
||||
name: string
|
||||
}
|
||||
maintainers: Array<{
|
||||
email: string
|
||||
username: string
|
||||
}>
|
||||
links: {
|
||||
npm: string
|
||||
homepage: string
|
||||
@@ -243,7 +251,7 @@ interface IShowInputBoxOption {
|
||||
|
||||
type IShowFileExplorerOption = IObj
|
||||
|
||||
type IUploadOption = string[]
|
||||
type IUploadOption = string[] | ImgInfo[]
|
||||
|
||||
interface IShowNotificationOption {
|
||||
title: string
|
||||
@@ -263,7 +271,7 @@ interface IPrivateShowNotificationOption extends IShowNotificationOption{
|
||||
interface IShowMessageBoxOption {
|
||||
title: string
|
||||
message: string
|
||||
type: string
|
||||
type: import('electron').MessageBoxOptions['type']
|
||||
buttons: string[]
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
@@ -22,6 +22,7 @@ interface ISettingForm {
|
||||
host: string
|
||||
enable: boolean
|
||||
}
|
||||
startupMode: import('#/types/enum').IStartupMode
|
||||
}
|
||||
|
||||
interface IShortKeyMap {
|
||||
|
||||
@@ -51,3 +51,7 @@ export const trimValues = (obj: IStringKeyMap) => {
|
||||
})
|
||||
return newObj
|
||||
}
|
||||
|
||||
export const isMacOS = process.platform === 'darwin'
|
||||
export const isWindows = process.platform === 'win32'
|
||||
export const isLinux = process.platform === 'linux'
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export const CLIPBOARD_IMAGE_FOLDER = 'picgo-clipboard-images'
|
||||
export const FORM_IMAGE_FOLDER = 'picgo-form-images'
|
||||
export const RELEASE_URL = 'https://api.github.com/repos/Molunerfinn/PicGo/releases'
|
||||
export const RELEASE_URL_BACKUP = 'https://picgo-release.molunerfinn.com'
|
||||
export const RELEASE_URL_BACKUP = 'https://release.picgo.app'
|
||||
export const STABLE_RELEASE_URL = 'https://github.com/Molunerfinn/PicGo/releases/latest'
|
||||
export const BETA_RELEASE_URL = 'https://github.com/Molunerfinn/PicGo/releases'
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import path from 'path'
|
||||
|
||||
const staticBasePath = process.env.STATIC_PATH || path.join(process.cwd(), 'public')
|
||||
|
||||
export const getStaticPath = (...segments: string[]) => path.join(staticBasePath, ...segments)
|
||||
+11
-7
@@ -1,26 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2019", // https://github.com/TypeStrong/ts-loader/issues/1061
|
||||
"target": "esnext", // https://github.com/TypeStrong/ts-loader/issues/1061
|
||||
"module": "esnext",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"importHelpers": true,
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"types": [
|
||||
"webpack-env",
|
||||
"vite/client",
|
||||
"element-plus/global",
|
||||
"vue3-photo-preview"
|
||||
"vue3-photo-preview",
|
||||
"electron"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./src/universal/types/",
|
||||
"./node_modules/@types",
|
||||
"./node_modules",
|
||||
"./node_modules"
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
@@ -54,7 +56,9 @@
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
"tests/**/*.ts",
|
||||
"tests/**/*.tsx"
|
||||
"tests/**/*.tsx",
|
||||
"electron.vite.config.ts",
|
||||
"electron-builder.config.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
@@ -62,4 +66,4 @@
|
||||
"vueCompilerOptions": {
|
||||
"target": 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
-120
@@ -1,120 +0,0 @@
|
||||
const path = require('path')
|
||||
function resolve (dir) {
|
||||
return path.join(__dirname, dir)
|
||||
}
|
||||
|
||||
const config = {
|
||||
configureWebpack: {
|
||||
devtool: 'nosources-source-map'
|
||||
},
|
||||
chainWebpack: config => {
|
||||
config.resolve.alias
|
||||
.set('@', resolve('src/renderer'))
|
||||
.set('~', resolve('src'))
|
||||
.set('root', resolve('./'))
|
||||
.set('#', resolve('src/universal'))
|
||||
// define
|
||||
// config.plugin('define')
|
||||
// .tap(args => {
|
||||
// return args
|
||||
// })
|
||||
},
|
||||
pluginOptions: {
|
||||
electronBuilder: {
|
||||
nodeIntegration: true, // will remove in the future
|
||||
customFileProtocol: 'picgo://./',
|
||||
externals: ['picgo'],
|
||||
chainWebpackMainProcess: config => {
|
||||
config.resolve.alias
|
||||
.set('@', resolve('src/renderer'))
|
||||
.set('~', resolve('src'))
|
||||
.set('root', resolve('./'))
|
||||
.set('#', resolve('src/universal'))
|
||||
.set('apis', resolve('src/main/apis'))
|
||||
.set('@core', resolve('src/main/apis/core'))
|
||||
config.resolve.mainFields
|
||||
.clear()
|
||||
.add('main') // fix some modules will use browser target
|
||||
.add('module')
|
||||
},
|
||||
builderOptions: {
|
||||
productName: 'PicGo',
|
||||
appId: 'com.molunerfinn.picgo',
|
||||
publish: [
|
||||
{
|
||||
provider: 'github',
|
||||
owner: 'Molunerfinn',
|
||||
repo: 'PicGo',
|
||||
releaseType: 'draft'
|
||||
}
|
||||
],
|
||||
dmg: {
|
||||
contents: [
|
||||
{
|
||||
x: 410,
|
||||
y: 150,
|
||||
type: 'link',
|
||||
path: '/Applications'
|
||||
},
|
||||
{
|
||||
x: 130,
|
||||
y: 150,
|
||||
type: 'file'
|
||||
}
|
||||
]
|
||||
},
|
||||
mac: {
|
||||
icon: 'build/icons/icon.icns',
|
||||
extendInfo: {
|
||||
LSUIElement: 0
|
||||
},
|
||||
target: [{
|
||||
target: 'dmg',
|
||||
arch: [
|
||||
'x64',
|
||||
'arm64'
|
||||
]
|
||||
}],
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
artifactName: 'PicGo-${version}-${arch}.dmg'
|
||||
},
|
||||
win: {
|
||||
icon: 'build/icons/icon.ico',
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
artifactName: 'PicGo-Setup-${version}-${arch}.exe',
|
||||
target: [{
|
||||
target: 'nsis',
|
||||
arch: [
|
||||
'x64',
|
||||
'ia32'
|
||||
]
|
||||
}]
|
||||
},
|
||||
nsis: {
|
||||
shortcutName: 'PicGo',
|
||||
oneClick: false,
|
||||
allowToChangeInstallationDirectory: true,
|
||||
include: 'build/installer.nsh'
|
||||
},
|
||||
linux: {
|
||||
icon: 'build/icons/'
|
||||
},
|
||||
snap: {
|
||||
publish: ['github']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
config.configureWebpack = {
|
||||
devtool: 'source-map'
|
||||
}
|
||||
// for dev main process hot reload
|
||||
config.pluginOptions.electronBuilder.mainProcessWatch = ['src/main/**/*']
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
...config
|
||||
}
|
||||
Reference in New Issue
Block a user