Browse Source

1. load audio file by main process
2. load audio file immediately after choose the file
3. show error message when selected file type is not supported or file cannot be played

MaysWind 3 years ago
parent
commit
e9f0fcad9b

+ 3 - 0
app/langs/zh_Hans.txt

@@ -9,6 +9,7 @@ Confirm=确认
 Cancel=取消
 Close=关闭
 Browse=浏览
+Clear=清空
 True=是
 False=否
 DEBUG=调试 (Debug)
@@ -197,7 +198,9 @@ Low (Up to 1 Notification / 5 Minutes)=低 (最多 1 条通知 / 每5分钟)
 Play Sound After Download Finished=下载完成后播放声音
 Play Sound=播放声音
 Stop Playing Sound=停止播放声音
+This sound file type is not supported.=不支持该音频文件类型.
 Sound file not exists.=声音文件不存在.
+Cannot play this sound file.=无法播放该声音文件.
 WebSocket Auto Reconnect Interval=WebSocket 自动重连时间
 Aria2 RPC Alias=Aria2 RPC 别名
 Aria2 RPC Address=Aria2 RPC 地址

+ 3 - 0
app/langs/zh_Hant.txt

@@ -9,6 +9,7 @@ Confirm=確認
 Cancel=取消
 Close=關閉
 Browse=瀏覽
+Clear=清除
 True=是
 False=否
 DEBUG=偵錯 (Debug)
@@ -197,7 +198,9 @@ Low (Up to 1 Notification / 5 Minutes)=低 (最多 1 條通知 / 每5分鐘)
 Play Sound After Download Finished=下載完成後播放音效
 Play Sound=播放音效
 Stop Playing Sound=停止播放音效
+This sound file type is not supported.=不支援該音效檔案類型.
 Sound file not exists.=音效檔案不存在.
+Cannot play this sound file.=無法播放该音效檔案.
 WebSocket Auto Reconnect Interval=WebSocket 自动重連線時間
 Aria2 RPC Alias=Aria2 RPC 別名
 Aria2 RPC Address=Aria2 RPC 位址

+ 3 - 0
app/scripts/config/defaultLanguage.js

@@ -13,6 +13,7 @@
             'Cancel': 'Cancel',
             'Close': 'Close',
             'Browse': 'Browse',
+            'Clear': 'Clear',
             'True': 'True',
             'False': 'False',
             'DEBUG': 'Debug',
@@ -201,7 +202,9 @@
             'Play Sound After Download Finished': 'Play Sound After Download Finished',
             'Play Sound': 'Play Sound',
             'Stop Playing Sound': 'Stop Playing Sound',
+            'This sound file type is not supported.': 'This sound file type is not supported.',
             'Sound file not exists.': 'Sound file not exists.',
+            'Cannot play this sound file.': 'Cannot play this sound file.',
             'WebSocket Auto Reconnect Interval': 'WebSocket Auto Reconnect Interval',
             'Aria2 RPC Alias': 'Aria2 RPC Alias',
             'Aria2 RPC Address': 'Aria2 RPC Address',

+ 7 - 1
app/scripts/config/fileTypes.js

@@ -208,5 +208,11 @@
                 '.zip'
             ]
         }
-    });
+    }).constant('ariaNgSupportedAudioFileTypes', {
+         '.mp3': 'audio/mpeg',
+         '.aac': 'audio/aac',
+         '.flac': 'audio/flac',
+         '.ogg': 'audio/ogg',
+         '.wav': 'audio/wav',
+     });
 }());

+ 26 - 7
app/scripts/controllers/settings-ariang.js

@@ -1,7 +1,7 @@
 (function () {
     'use strict';
 
-    angular.module('ariaNg').controller('AriaNgSettingsController', ['$rootScope', '$scope', '$routeParams', '$window', '$interval', '$timeout', '$filter', 'clipboard', 'ariaNgLanguages', 'ariaNgCommonService', 'ariaNgVersionService', 'ariaNgKeyboardService', 'ariaNgNotificationService', 'ariaNgLocalizationService', 'ariaNgLogService', 'ariaNgFileService', 'ariaNgSettingService', 'ariaNgMonitorService', 'ariaNgTitleService', 'aria2SettingService', 'ariaNgNativeElectronService', function ($rootScope, $scope, $routeParams, $window, $interval, $timeout, $filter, clipboard, ariaNgLanguages, ariaNgCommonService, ariaNgVersionService, ariaNgKeyboardService, ariaNgNotificationService, ariaNgLocalizationService, ariaNgLogService, ariaNgFileService, ariaNgSettingService, ariaNgMonitorService, ariaNgTitleService, aria2SettingService, ariaNgNativeElectronService) {
+    angular.module('ariaNg').controller('AriaNgSettingsController', ['$rootScope', '$scope', '$routeParams', '$window', '$interval', '$timeout', '$filter', 'clipboard', 'ariaNgLanguages', 'ariaNgSupportedAudioFileTypes', 'ariaNgCommonService', 'ariaNgVersionService', 'ariaNgKeyboardService', 'ariaNgNotificationService', 'ariaNgLocalizationService', 'ariaNgLogService', 'ariaNgFileService', 'ariaNgSettingService', 'ariaNgMonitorService', 'ariaNgTitleService', 'aria2SettingService', 'ariaNgNativeElectronService', function ($rootScope, $scope, $routeParams, $window, $interval, $timeout, $filter, clipboard, ariaNgLanguages, ariaNgSupportedAudioFileTypes, ariaNgCommonService, ariaNgVersionService, ariaNgKeyboardService, ariaNgNotificationService, ariaNgLocalizationService, ariaNgLogService, ariaNgFileService, ariaNgSettingService, ariaNgMonitorService, ariaNgTitleService, aria2SettingService, ariaNgNativeElectronService) {
         var extendType = $routeParams.extendType;
         var lastRefreshPageNotification = null;
 
@@ -238,21 +238,34 @@
             ariaNgSettingService.setBrowserNotificationFrequency(value);
         };
 
-        $scope.setPlaySoundAfterDownloadFinished = function (value) {
-            ariaNgSettingService.setPlaySoundAfterDownloadFinished(value);
-        };
-
         $scope.browseAndSetPlaySoundAfterDownloadFinished = function () {
+            var supportedExtensions = [];
+
+            for (const extension in ariaNgSupportedAudioFileTypes) {
+                if (!ariaNgSupportedAudioFileTypes.hasOwnProperty(extension)) {
+                    continue;
+                }
+
+                supportedExtensions.push(extension.substring(1));
+            }
+
             ariaNgNativeElectronService.showOpenFileDialogAsync([{
                 name: ariaNgLocalizationService.getLocalizedText('Audios'),
-                extensions: ['mp3', 'wav']
+                extensions: supportedExtensions
             }], function (result) {
                 if (result && !result.canceled && angular.isArray(result.filePaths) && result.filePaths.length) {
                     var filePath = result.filePaths[0];
+                    var fileExtension = ariaNgCommonService.getFileExtension(filePath);
+
+                    if (!ariaNgSupportedAudioFileTypes[fileExtension]) {
+                        ariaNgCommonService.showError('This sound file type is not supported.');
+                        return;
+                    }
 
                     $scope.$apply(function () {
                         $scope.context.settings.playSoundAfterDownloadFinished = filePath;
-                        $scope.setPlaySoundAfterDownloadFinished(filePath);
+                        $rootScope.soundContext.loadSoundFile(filePath);
+                        ariaNgSettingService.setPlaySoundAfterDownloadFinished(filePath);
                     });
                 }
             });
@@ -270,6 +283,12 @@
             $rootScope.soundContext.stopPlayingSound();
         };
 
+        $scope.clearPlaySoundAfterDownloadFinished = function () {
+            $scope.context.settings.playSoundAfterDownloadFinished = '';
+            $rootScope.soundContext.loadSoundFile('');
+            ariaNgSettingService.setPlaySoundAfterDownloadFinished('');
+        };
+
         $scope.setWebSocketReconnectInterval = function (value) {
             setNeedRefreshPage();
             ariaNgSettingService.setWebSocketReconnectInterval(value);

+ 41 - 18
app/scripts/core/root.js

@@ -1,7 +1,7 @@
 (function () {
     'use strict';
 
-    angular.module('ariaNg').run(['$window', '$rootScope', '$location', '$document', '$timeout', 'ariaNgCommonService', 'ariaNgKeyboardService', 'ariaNgNotificationService', 'ariaNgLogService', 'ariaNgLocalizationService', 'ariaNgSettingService', 'aria2TaskService', 'ariaNgNativeElectronService', 'ariaNgVersionService', function ($window, $rootScope, $location, $document, $timeout, ariaNgCommonService, ariaNgKeyboardService, ariaNgNotificationService, ariaNgLogService, ariaNgLocalizationService, ariaNgSettingService, aria2TaskService, ariaNgNativeElectronService, ariaNgVersionService) {
+    angular.module('ariaNg').run(['$window', '$rootScope', '$location', '$document', '$timeout', 'ariaNgSupportedAudioFileTypes', 'ariaNgCommonService', 'ariaNgKeyboardService', 'ariaNgNotificationService', 'ariaNgLogService', 'ariaNgLocalizationService', 'ariaNgSettingService', 'aria2TaskService', 'ariaNgNativeElectronService', 'ariaNgVersionService', function ($window, $rootScope, $location, $document, $timeout, ariaNgSupportedAudioFileTypes, ariaNgCommonService, ariaNgKeyboardService, ariaNgNotificationService, ariaNgLogService, ariaNgLocalizationService, ariaNgSettingService, aria2TaskService, ariaNgNativeElectronService, ariaNgVersionService) {
         var autoRefreshAfterPageLoad = false;
 
         var isAnyTextboxOrTextareaFocus = function () {
@@ -461,23 +461,34 @@
             loadSoundFile: function (filePath, callback, silent) {
                 var player = angular.element('#background-audio')[0];
 
-                ariaNgNativeElectronService.getLocalFSExistsAsync(filePath, function (exists) {
-                    if (exists) {
-                        player.src = 'file://' + filePath;
-                        $rootScope.soundContext.currentSoundFile = filePath;
-                        ariaNgLogService.debug('[root.soundContext.playSound] background audio is set to ' + filePath);
+                if (filePath) {
+                    ariaNgNativeElectronService.getLocalFSFileBufferAsync(filePath, function (buffer) {
+                        if (buffer) {
+                            var soundExtension = ariaNgCommonService.getFileExtension(filePath);
+                            var mimeType = ariaNgSupportedAudioFileTypes[soundExtension];
+                            var blob = new Blob([buffer], { type: mimeType });
+                            player.src = URL.createObjectURL(blob);
+                            $rootScope.soundContext.currentSoundFile = filePath;
+                            ariaNgLogService.debug('[root.soundContext.loadSoundFile] background audio is set to ' + filePath);
+
+                            if (angular.isFunction(callback)) {
+                                callback(filePath);
+                            }
+                        } else {
+                            player.src = '';
+                            $rootScope.soundContext.currentSoundFile = '';
+                            ariaNgLogService.warn('[root.soundContext.loadSoundFile] background audio is set to empty due to the file buffer is null');
 
-                        if (angular.isFunction(callback)) {
-                            callback(filePath);
-                        }
-                    } else {
-                        if (!silent) {
-                            ariaNgCommonService.showError('Sound file not exists.');
+                            if (!silent) {
+                                ariaNgCommonService.showError('Sound file not exists.');
+                            }
                         }
-
-                        ariaNgLogService.warn('[root.soundContext.playSound] sound file not exists ' + filePath);
-                    }
-                });
+                    });
+                } else {
+                    player.src = '';
+                    $rootScope.soundContext.currentSoundFile = '';
+                    ariaNgLogService.debug('[root.soundContext.loadSoundFile] background audio is set to empty');
+                }
             },
             isPlaying: function () {
                 var player = angular.element('#background-audio')[0];
@@ -497,11 +508,23 @@
                 if (this.currentSoundFile !== filePath) {
                     this.loadSoundFile(filePath, function () {
                         player.currentTime = 0;
-                        player.play();
+                        player.play().catch(function (error) {
+                            ariaNgLogService.error('[root.soundContext.playSound] cannot play sound, because ' + error);
+
+                            if (!silent) {
+                                ariaNgCommonService.showError('Cannot play this sound file.');
+                            }
+                        });
                     }, !!silent);
                 } else {
                     player.currentTime = 0;
-                    player.play();
+                    player.play().catch(function (error) {
+                        ariaNgLogService.error('[root.soundContext.playSound] cannot play sound, because ' + error);
+
+                        if (!silent) {
+                            ariaNgCommonService.showError('Cannot play this sound file.');
+                        }
+                    });
                 }
             },
             stopPlayingSound: function () {

+ 8 - 0
app/scripts/services/ariaNgNativeElectronService.js

@@ -272,6 +272,14 @@
             readPackageFile: function (path) {
                 return invokeMainProcessMethodSync('render-sync-get-package-file-content', path);
             },
+            getLocalFSFileBufferAsync: function (fullpath, callback) {
+                return invokeMainProcessMethodAsync('render-get-localfs-file-buffer', fullpath)
+                    .then(function onReceive(buffer) {
+                        if (callback) {
+                            callback(buffer);
+                        }
+                    });
+            },
             getLocalFSExistsAsync: function (fullpath, callback) {
                 return invokeMainProcessMethodAsync('render-get-localfs-exists', fullpath)
                     .then(function onReceive(exists) {

+ 4 - 3
app/views/settings-ariang.html

@@ -159,9 +159,8 @@
                         </div>
                         <div class="setting-value col-sm-8">
                             <div class="input-group">
-                                <input class="form-control" type="text"
-                                       ng-model="context.settings.playSoundAfterDownloadFinished"
-                                       ng-change="setPlaySoundAfterDownloadFinished(context.settings.playSoundAfterDownloadFinished)"/>
+                                <input class="form-control" type="text" readonly="readonly"
+                                       ng-model="context.settings.playSoundAfterDownloadFinished"/>
                                 <div class="input-group-btn">
                                     <button type="button" class="btn btn-default" ng-click="browseAndSetPlaySoundAfterDownloadFinished()">
                                         <span translate>Browse</span>
@@ -173,6 +172,8 @@
                                     <ul class="dropdown-menu dropdown-menu-right">
                                         <li><a class="pointer-cursor" ng-click="playSound()" translate>Play Sound</a></li>
                                         <li><a class="pointer-cursor" ng-click="stopPlayingSound()" translate>Stop Playing Sound</a></li>
+                                        <li class="divider"></li>
+                                        <li><a class="pointer-cursor" ng-click="clearPlaySoundAfterDownloadFinished()" translate>Clear</a></li>
                                     </ul>
                                 </div>
                             </div>

+ 4 - 0
main/ipc/main-process.js

@@ -221,6 +221,10 @@ ipcMain.on('render-sync-get-package-file-content', (event, path) => {
     event.returnValue = localfs.readPackageFile(path);
 });
 
+ipcMain.handle('render-get-localfs-file-buffer', (event, fullpath) => {
+    return localfs.getLocalFSFileBuffer(fullpath);
+});
+
 ipcMain.handle('render-get-localfs-exists', (event, fullpath) => {
     return localfs.isExists(fullpath);
 });

+ 16 - 1
main/lib/localfs.js

@@ -19,9 +19,23 @@ let readPackageFile = function (filePath) {
     return fs.readFileSync(path.join(__dirname, '../../app/', filePath), 'UTF-8');
 };
 
+let getLocalFSFileBuffer = function (fullpath) {
+    try {
+        return Buffer.from(fs.readFileSync(fullpath));
+    } catch (ex) {
+        return null;
+    }
+};
+
 let getLocalFSFileBase64Content = function (fullpath) {
     try {
-        return Buffer.from(fs.readFileSync(fullpath)).toString('base64');
+        const buffer = getLocalFSFileBuffer(fullpath);
+
+        if (buffer) {
+            return buffer.toString('base64');
+        } else {
+            return null;
+        }
     } catch (ex) {
         return null;
     }
@@ -32,5 +46,6 @@ module.exports = {
     isExists: isExists,
     getPackageIconPath: getPackageIconPath,
     readPackageFile: readPackageFile,
+    getLocalFSFileBuffer: getLocalFSFileBuffer,
     getLocalFSFileBase64Content: getLocalFSFileBase64Content
 };