diff --git a/public/about.html b/public/about.html new file mode 100644 index 0000000..ac44896 --- /dev/null +++ b/public/about.html @@ -0,0 +1,61 @@ + + + + + About Aria2Desktop + + + +
+ +
About Aria2Desktop
+ +
+ source: aria2desktop +
+
+ + + + diff --git a/public/aria2cli/aria2.conf b/public/aria2cli/aria2.conf index be56835..cc7d4b3 100755 --- a/public/aria2cli/aria2.conf +++ b/public/aria2cli/aria2.conf @@ -20,14 +20,14 @@ ## 下载连接相关 ## # 最大同时下载任务数, 运行时可修改, 默认:5 -#@max-concurrent-downloads=10 +max-concurrent-downloads=10 # 同一服务器连接数, 添加时可指定, 默认:1 -#@max-connection-per-server=15 +max-connection-per-server=16 # 最小文件分片大小, 添加时可指定, 取值范围1M -1024M, 默认:20M # 假定size=10M, 文件为20MiB 则使用两个来源下载; 文件为15MiB 则使用一个来源下载 #@min-split-size=10M # 单个任务最大线程数, 添加时可指定, 默认:5 -#@split=15 +split=16 # 整体下载速度限制, 运行时可修改, 默认:0 #@max-overall-download-limit=0 # 单个任务下载速度限制, 默认:0 diff --git a/public/index.html b/public/index.html index 0afef42..82feaa1 100644 --- a/public/index.html +++ b/public/index.html @@ -20,6 +20,11 @@ } } + + diff --git a/public/main.js b/public/main.js index af71fad..70b333a 100644 --- a/public/main.js +++ b/public/main.js @@ -1,16 +1,18 @@ const { - app, BrowserWindow, Menu, ipcMain, shell, - Tray, dialog, globalShortcut + app, BrowserWindow, Menu, shell, + Tray, globalShortcut } = require('electron'); const child_process = require('child_process'); const path = require('path'); const fs = require('fs'); const url = require('url'); -let platform = process.platform; -const userHomeDir = require('os').homedir() +const userHomeDir = require('os').homedir(); const ARIA2DESKTOP_DEV = process.env.ARIA2DESKTOP_DEV === 'true'; +const platform = process.platform; +let secret; + const template = [ { label: '编辑', @@ -77,82 +79,6 @@ let menu = Menu.buildFromTemplate(template); let mainWindow; -const aria2dir = path.resolve(__dirname, 'aria2cli'); - -const aria2home = path.join(userHomeDir, app.getName()); -const aria2Cli = path.resolve(aria2home, 'aria2c'); -const aria2DownloadDir = path.join(userHomeDir, 'Downloads'); -const sessionFile = path.join(aria2home, 'aria2.session'); -const aria2ConfFile = path.join(aria2home, 'aria2.conf'); - -if (!fs.existsSync(aria2home)) { - fs.mkdirSync(aria2home); -} - -fs.readdirSync(aria2dir).forEach(file => { - var src = path.join(aria2dir, file), - dest = path.join(aria2home, file); - if (!fs.existsSync(dest)) { - console.log('释放文件: ', src); - if ('copyFileSync' in fs) { - fs.copyFileSync(src, dest); - } else { - fs.writeFileSync(dest, fs.readFileSync(src)); - if (file === 'aria2c') { - fs.chmodSync(dest, 755) - } - } - } -}); - -let secret = Math.random().toString(32).substr(2); -if (fs.existsSync(aria2ConfFile)) { - let confContent = fs.readFileSync(aria2ConfFile).toString(); - let c = confContent.replace(/\\n/g, "\n").replace(/#.+/g, ''); - let m = c.match(/rpc-secret=(.+)/i); - if (m && m.length > 1) { - secret = m[1] - } else { - confContent = confContent.replace(/rpc-secret=(.+)/i, 'rpc-secret=' + secret); - fs.writeFileSync(aria2ConfFile, confContent); - } -} - -const aria2Conf = [ - '--dir', aria2DownloadDir, - '--conf-path', aria2ConfFile, - '--input-file', sessionFile, - '--save-session', sessionFile, - // '--max-concurrent-downloads', 10, - // '--max-connection-per-server', 16, - // '--min-split-size', '1024K', - // '--split', 16, - // '--max-overall-download-limit', '0K', - // '--max-overall-upload-limit', '0K', - // '--max-download-limit', '0K', - // '--max-upload-limit', '0K', - // '--continue', 'true', - // '--auto-file-renaming', 'true', - // '--allow-overwrite', 'true', - // '--disk-cache', '0M', - // '--max-tries', 0, - // '--retry-wait', 5, - '--rpc-secret', secret -]; - -if (fs.existsSync(aria2Cli)) { - console.log('rpc-secret: ', secret); - const worker = child_process.spawn(aria2Cli, aria2Conf); - - worker.stdout.on('data', function (data) { - console.log(data.toString()); - }); - - process.on('exit', function () { - worker.killed || worker.kill(); - }); -} - function createWindow() { mainWindow = new BrowserWindow({ width: 900, @@ -178,20 +104,6 @@ function createWindow() { mainWindow = null }); - ipcMain.on('close-window', function () { - mainWindow.close() - }); - ipcMain.on('set-window-maximize', function () { - mainWindow.isMaximized() ? mainWindow.unmaximize() : mainWindow.maximize() - }); - ipcMain.on('set-window-minimize', function () { - mainWindow.minimize() - }); - - ipcMain.on('open-file-dialog', function () { - dialog.showOpenDialog({properties: ['openDirectory', 'multiSelections']}) - }); - mainWindow.once('ready-to-show', () => { Menu.setApplicationMenu(process.platform === 'darwin' ? menu : null); mainWindow.show() @@ -212,47 +124,155 @@ function toggleWindow() { let tray; let templateMenu = [ - {role: 'about', label: '关于' + app.getName()}, + {label: '关于' + app.getName(), click:function () { + let aboutWin = new BrowserWindow({ + width: 600, + height: 400, + titleBarStyle: 'hiddenInset', + center: true, + resizable: false, + title: '关于' + app.getName(), + parent: mainWindow + }); + const aboutUrl = url.format({ + pathname: path.join(__dirname, 'about.html'), + protocol: 'file:', + slashes: true + }) + aboutWin.loadURL(aboutUrl) + }}, {type: 'separator'}, {role: 'quit', label: '完全退出'} ]; -app.on('ready', function () { - createWindow(); - tray = new Tray(path.join(__dirname, 'aria2icon_16.png')); - tray.setToolTip('aria2 desktop'); - if (platform === 'darwin') { - tray.on('right-click', () => { - tray.popUpContextMenu(Menu.buildFromTemplate(templateMenu)) - }) + +const shouldQuit = app.makeSingleInstance(() => { + if (mainWindow) { + if (mainWindow.isMinimized()) { + mainWindow.restore(); + } + mainWindow.focus(); } else { - templateMenu.splice(1, 0, {type: 'separator'}, { - label: '显示/隐藏', - click(){ - toggleWindow() + createWindow(); + } +}); +if (shouldQuit) { + app.quit(); +} else { + app.on('ready', function () { + createWindow(); + tray = new Tray(path.join(__dirname, 'aria2icon_16.png')); + tray.setToolTip('aria2 desktop'); + if (platform === 'darwin') { + tray.on('right-click', () => { + tray.popUpContextMenu(Menu.buildFromTemplate(templateMenu)) + }) + } else { + templateMenu.splice(1, 0, {type: 'separator'}, { + label: '显示/隐藏', + click() { + toggleWindow() + } + }); + tray.setContextMenu(Menu.buildFromTemplate(templateMenu)) + } + tray.on('click', () => { + toggleWindow() + }); + globalShortcut.register('CommandOrControl+Alt+J', () => { + if (mainWindow && mainWindow.webContents) { + mainWindow.webContents.openDevTools() } }); - tray.setContextMenu(Menu.buildFromTemplate(templateMenu)) - } - tray.on('click', () => { - toggleWindow() }); - globalShortcut.register('CommandOrControl+Alt+J', () => { - if (mainWindow && mainWindow.webContents) { - mainWindow.webContents.openDevTools() + + app.on('window-all-closed', function () { + // if (process.platform !== 'darwin') { + // app.quit() + // } + }); + + app.on('activate', function () { + if (mainWindow === null) { + createWindow() } + mainWindow.isFocused() || mainWindow.focus(); }); -}); -app.on('window-all-closed', function () { - // if (process.platform !== 'darwin') { - // app.quit() - // } -}); -app.on('activate', function () { - if (mainWindow === null) { - createWindow() + + const aria2dir = path.resolve(__dirname, 'aria2cli'); + + const aria2home = path.join(userHomeDir, app.getName()); + const aria2Cli = path.resolve(aria2home, 'aria2c'); + const aria2DownloadDir = path.join(userHomeDir, 'Downloads'); + const sessionFile = path.join(aria2home, 'aria2.session'); + const aria2ConfFile = path.join(aria2home, 'aria2.conf'); + + if (!fs.existsSync(aria2home)) { + fs.mkdirSync(aria2home); } - mainWindow.isFocused() || mainWindow.focus(); -}); + fs.readdirSync(aria2dir).forEach(file => { + let src = path.join(aria2dir, file); + let dest = path.join(aria2home, file); + if (!fs.existsSync(dest)) { + console.log('释放文件: ', src); + if ('copyFileSync' in fs) { + fs.copyFileSync(src, dest); + } else { + fs.writeFileSync(dest, fs.readFileSync(src)); + if (file === 'aria2c') { + fs.chmodSync(dest, 755) + } + } + } + }); + + secret = Math.random().toString(32).substr(2); + if (fs.existsSync(aria2ConfFile)) { + let confContent = fs.readFileSync(aria2ConfFile).toString(); + let c = confContent.replace(/\\n/g, "\n").replace(/#.+/g, ''); + let m = c.match(/rpc-secret=(.+)/i); + if (m && m.length > 1) { + secret = m[1] + } else { + confContent = confContent.replace(/rpc-secret=(.+)/i, 'rpc-secret=' + secret); + fs.writeFileSync(aria2ConfFile, confContent); + } + } + + const aria2Conf = [ + '--dir', aria2DownloadDir, + '--conf-path', aria2ConfFile, + '--input-file', sessionFile, + '--save-session', sessionFile, + // '--max-concurrent-downloads', 10, + // '--max-connection-per-server', 16, + // '--min-split-size', '1024K', + // '--split', 16, + // '--max-overall-download-limit', '0K', + // '--max-overall-upload-limit', '0K', + // '--max-download-limit', '0K', + // '--max-upload-limit', '0K', + // '--continue', 'true', + // '--auto-file-renaming', 'true', + // '--allow-overwrite', 'true', + // '--disk-cache', '0M', + // '--max-tries', 0, + // '--retry-wait', 5, + '--rpc-secret', secret + ]; + + if (fs.existsSync(aria2Cli)) { + console.log('rpc-secret: ', secret); + const worker = child_process.spawn(aria2Cli, aria2Conf); + + worker.stdout.on('data', function (data) { + console.log(data.toString()); + }); + + process.on('exit', function () { + worker.killed || worker.kill(); + }); + } +} diff --git a/src/App.css b/src/App.css index b1fc9d2..96fa8b4 100644 --- a/src/App.css +++ b/src/App.css @@ -8,6 +8,7 @@ } button, a, input { + /*noinspection CssUnknownProperty*/ -webkit-app-region: no-drag; } @@ -38,9 +39,10 @@ button, a, input { display: flex; align-items: center; justify-content: center; + visibility: hidden; } -.device-web .window-control{ +.device-web .window-control { right: 15px; } @@ -56,20 +58,22 @@ button, a, input { .window-control button:hover, .window-control button:active, -.window-control button:focus{ +.window-control button:focus { background-color: transparent; } .device-electron.device-linux .window-control, -.device-electron.device-windows .window-control{ +.device-electron.device-windows .window-control, +.device-web .window-control{ visibility: visible; } -@media all and (min-width: 1000px){ - .device-web #root{ +@media all and (min-width: 1000px) { + .device-web #root { display: flex; background: #cae5dc; } + .device-web .App.ant-layout { max-width: 900px; height: 600px; @@ -77,15 +81,18 @@ button, a, input { border-radius: 6px; box-shadow: 0 35px 56px rgba(0, 0, 0, .3); } + .device-web .header-toolbar { position: relative; } + .device-web .header-toolbar .resize-window { position: absolute; right: 14px; color: #595959; - visibility:visible; + visibility: visible; } + .device-web.device-fullscreen .App.ant-layout { max-width: 100%; height: 100%; @@ -102,7 +109,7 @@ button, a, input { .ant-layout-sider, .ant-menu-dark, -.ant-menu-dark .ant-menu-sub { +.ant-menu-dark .ant-menu-sub { background-color: #32373f; } @@ -132,6 +139,7 @@ button, a, input { min-width: 70px; display: flex; justify-content: space-between; + cursor: pointer; } .userName .ant-badge-status-text { @@ -163,6 +171,7 @@ button, a, input { text-align: center; background-color: #e7e7e7; } + .header-toolbar { background-color: #f7f7f7; height: 44px; @@ -183,8 +192,9 @@ button, a, input { user-select: none; -webkit-user-select: none; } + .ant-list-item-meta-description, -.ant-layout-sider-children{ +.ant-layout-sider-children { user-select: none; -webkit-user-select: none; } @@ -235,8 +245,12 @@ button, a, input { } @keyframes App-logo-spin { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } /* 下载详情card */ @@ -244,12 +258,14 @@ button, a, input { .download-item-details-card .ant-card-body { padding: 0; } + .download-item-details-card .ant-card-head { min-height: 35px; padding: 0 10px; user-select: none; -webkit-user-select: none; } + .download-item-details-card .ant-tabs-large .ant-tabs-tab { padding: 6px; } @@ -260,7 +276,8 @@ button, a, input { white-space: nowrap; text-overflow: ellipsis; } -.download-item-details-card .ant-card-grid:hover{ + +.download-item-details-card .ant-card-grid:hover { box-shadow: none; } @@ -268,6 +285,7 @@ button, a, input { .Setting .ant-list-item-content { width: auto; } + .Setting .ant-card-body { padding: 1px 0px; } @@ -289,7 +307,6 @@ button, a, input { padding: 0; } - .SettingModal .ant-modal-close-x { width: 40px; height: 40px; @@ -311,10 +328,10 @@ button, a, input { line-height: 18px; } - .SettingModal .ant-modal-body { padding: 5px 24px; } + .SettingModal .ant-form-item { margin-bottom: 0; } diff --git a/src/App.js b/src/App.js index c831828..ec7a26b 100644 --- a/src/App.js +++ b/src/App.js @@ -54,11 +54,12 @@ class App extends Component { this.aria2.onConnect = async () => { this.aria2.getGlobalOption().then(config => { - this.setState({online: true}); if (!getDownloadSaveDir()){ setDownloadSaveDir(config.dir); } eventBus.emit('aria2_connect', config); + this.setState({online: true}); + console.log('aria2_connect'); }).catch(e => { message.error(`连接服务器失败: ${e.message}`); this.setState({online: false}) @@ -87,8 +88,8 @@ class App extends Component { stopped: [], isRemoteServer: isRemoteServer() }); - this.aria2.close(); try { + await this.aria2.close(); this.aria2.setOptions(server); await this.aria2.connect() } catch (e) { diff --git a/src/components/WindowControl.js b/src/components/WindowControl.js index db9163e..f9ab7c5 100644 --- a/src/components/WindowControl.js +++ b/src/components/WindowControl.js @@ -2,51 +2,55 @@ import React from 'react' import {Icon, Button} from 'antd' import device from '../device' -const {ipcRenderer, remote} = window.require('electron') -const {BrowserWindow} = remote +const {BrowserWindow} = window.require('electron').remote const classList = document.body.parentElement.classList export default class WindowControl extends React.Component{ state = { - isFullSecreen: classList.contains('device-fullscreen') + isFullScreen: classList.contains('device-fullscreen') } onResizeClick(){ if (device.electron) { - ipcRenderer.send('set-window-maximize') - setTimeout(() => { - let win = BrowserWindow.getFocusedWindow() - if(win){ + const win = BrowserWindow.getFocusedWindow() + if (win) { + win.isMaximized() ? win.unmaximize() : win.maximize() + setTimeout(() => { this.setState({ - isFullSecreen: win.isMaximized() + isFullScreen: win.isMaximized() }) - } - }, 500) + }, 500) + } } else { classList.contains('device-fullscreen') ? classList.remove('device-fullscreen') : classList.add('device-fullscreen') this.setState({ - isFullSecreen: classList.contains('device-fullscreen') + isFullScreen: classList.contains('device-fullscreen') }) } } + onCloseClick(){ + const win = BrowserWindow.getFocusedWindow() + win && win.close() + } + + onMinimizeClick(){ + const win = BrowserWindow.getFocusedWindow() + win && win.minimize() + } + render(){ - const {isFullSecreen} = this.state + const {isFullScreen} = this.state return (
- -