예제 #1
0
        public void RegisterWithApiHandler(BloomApiHandler apiHandler)
        {
            // HandleStartRecording seems to need to be on the UI thread in order for HandleEndRecord() to detect the correct state.
            apiHandler.RegisterEndpointHandler("audio/startRecord", HandleStartRecording, true).Measureable();

            // Note: This handler locks and unlocks a shared resource (_completeRecording lock).
            // Any other handlers depending on this resource should not wait on the same thread (i.e. the UI thread) or deadlock can occur.
            apiHandler.RegisterEndpointHandler("audio/endRecord", HandleEndRecord, true).Measureable();

            // Any handler which retrieves information from the audio folder SHOULD wait on the _completeRecording lock (call WaitForRecordingToComplete()) to ensure that it sees
            // a consistent state of the audio folder, and therefore should NOT run on the UI thread.
            // Also, explicitly setting requiresSync to true (even tho that's default anyway) to make concurrency less complicated to think about
            apiHandler.RegisterEndpointHandler("audio/checkForAnyRecording", HandleCheckForAnyRecording, false, true);
            apiHandler.RegisterEndpointHandler("audio/checkForAllRecording", HandleCheckForAllRecording, false, true);
            apiHandler.RegisterEndpointHandler("audio/deleteSegment", HandleDeleteSegment, false, true);
            apiHandler.RegisterEndpointHandler("audio/checkForSegment", HandleCheckForSegment, false, true);
            apiHandler.RegisterEndpointHandler("audio/wavFile", HandleAudioFileRequest, false, true);

            // Doesn't matter whether these are on UI thread or not, so using the old default which was true
            apiHandler.RegisterEndpointHandler("audio/currentRecordingDevice", HandleCurrentRecordingDevice, true);
            apiHandler.RegisterEndpointHandler("audio/devices", HandleAudioDevices, true);

            apiHandler.RegisterEndpointHandler("audio/copyAudioFile", HandleCopyAudioFile, false);

            Debug.Assert(BloomServer.portForHttp > 0, "Need the server to be listening before this can be registered (BL-3337).");
        }
예제 #2
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     // Both of these display UI, expect to require UI thread.
     apiHandler.RegisterEndpointLegacy("addPage", HandleAddPage, true).Measureable("Add Page");
     apiHandler.RegisterEndpointLegacy("changeLayout", HandleChangeLayout, true).Measureable("Change Layout");
     ;
 }
예제 #3
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointHandler(kApiUrlPart + "checkAutoSegmentDependencies", CheckAutoSegmentDependenciesMet, handleOnUiThread: false, requiresSync: false);
     apiHandler.RegisterEndpointHandler(kApiUrlPart + "autoSegmentAudio", AutoSegment, handleOnUiThread: false, requiresSync: false);
     apiHandler.RegisterEndpointHandler(kApiUrlPart + "getForcedAlignmentTimings", GetForcedAlignmentTimings, handleOnUiThread: false, requiresSync: false);
     apiHandler.RegisterEndpointHandler(kApiUrlPart + "eSpeakPreview", ESpeakPreview, handleOnUiThread: false, requiresSync: false);
 }
예제 #4
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointLegacy("signLanguage/recordedVideo", HandleRecordedVideoRequest, true).Measureable("Process recorded video");
     apiHandler.RegisterEndpointLegacy("signLanguage/deleteVideo", HandleDeleteVideoRequest, true).Measureable("Delete video");;
     apiHandler.RegisterEndpointLegacy("signLanguage/importVideo", HandleImportVideoRequest, true);             // has dialog, so measure internally after the dialog.
     apiHandler.RegisterEndpointLegacy("signLanguage/getStats", HandleVideoStatisticsRequest, true);
 }
예제 #5
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointHandler("signLanguage/recordedVideo", HandleRecordedVideoRequest, true);
     apiHandler.RegisterEndpointHandler("signLanguage/deleteVideo", HandleDeleteVideoRequest, true);
     apiHandler.RegisterEndpointHandler("signLanguage/importVideo", HandleImportVideoRequest, true);
     apiHandler.RegisterEndpointHandler("signLanguage/getStats", HandleVideoStatisticsRequest, true);
 }
예제 #6
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     // Must not require sync, because it launches a Bloom dialog, which will make other api requests
     // that will be blocked if this is locked.
     apiHandler.RegisterEndpointHandler("bookCommand/exportToSpreadsheet",
                                        (request) =>
     {
         _spreadsheetApi.ShowExportToSpreadsheetUI(GetBookObjectFromPost(request));
         request.PostSucceeded();
     }, true, false);
     apiHandler.RegisterEndpointHandler("bookCommand/enhanceLabel", (request) =>
     {
         // We want this to be fast...many things are competing for api handling threads while
         // Bloom is starting up, including many buttons sending this request...
         // so we'll postpone until idle even searching for the right BookInfo.
         var collection = request.RequiredParam("collection-id").Trim();
         var id         = request.RequiredParam("id");
         RequestButtonLabelUpdate(collection, id);
         request.PostSucceeded();
     }, false, false);
     apiHandler.RegisterBooleanEndpointHandler("bookCommand/decodable",
                                               request => { return(_collectionModel.IsBookDecodable); },
                                               (request, b) => { _collectionModel.SetIsBookDecodable(b); },
                                               true);
     apiHandler.RegisterBooleanEndpointHandler("bookCommand/leveled",
                                               request => { return(_collectionModel.IsBookLeveled); },
                                               (request, b) => { _collectionModel.SetIsBookLeveled(b); },
                                               true);
     apiHandler.RegisterEndpointLegacy("bookCommand/", HandleBookCommand, true);
 }
예제 #7
0
        public void RegisterWithApiHandler(BloomApiHandler apiHandler)
        {
            apiHandler.RegisterEndpointHandler(kApiUrlPart + "list", HandleListRequest, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "name", request =>
            {
                // always null? request.ReplyWithText(_collection.Name);
                request.ReplyWithText(_settings.CollectionName);
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "books", HandleBooksRequest, true);
            apiHandler.RegisterEndpointHandler(kApiUrlPart + "book", HandleThumbnailRequest, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "selected-book-id", request =>
            {
                switch (request.HttpMethod)
                {
                case HttpMethods.Get:
                    request.ReplyWithText("" + _libraryModel.GetSelectedBookOrNull()?.ID);
                    break;

                case HttpMethods.Post:
                    var book = GetBookObjectFromPost(request);
                    _libraryModel.SelectBook(book);
                    request.PostSucceeded();
                    break;
                }
            }, true);
        }
예제 #8
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointHandler("uiLanguages", HandleUiLanguages, false);
     apiHandler.RegisterEndpointHandler("currentUiLanguage", HandleCurrentUiLanguage, false);
     apiHandler.RegisterEndpointHandler("bubbleLanguages", HandleBubbleLanguages, false);
     apiHandler.RegisterEndpointHandler("authorMode", HandleAuthorMode, false);
     apiHandler.RegisterEndpointHandler("topics", HandleTopics, false);
     apiHandler.RegisterEndpointHandler("common/enterpriseFeaturesEnabled", HandleEnterpriseFeaturesEnabled, false);
     apiHandler.RegisterEndpointHandler("common/error", HandleJavascriptError, false);
     apiHandler.RegisterEndpointHandler("common/preliminaryError", HandlePreliminaryJavascriptError, false);
     apiHandler.RegisterEndpointHandler("common/saveChangesAndRethinkPageEvent", RethinkPageAndReloadIt, true);
     apiHandler.RegisterEndpointHandler("common/requestTranslationGroups", RequestTranslationGroups, true);
     apiHandler.RegisterEndpointHandler("common/showInFolder", HandleShowInFolderRequest, true);
     apiHandler.RegisterEndpointHandler("common/showSettingsDialog", HandleShowSettingsDialog, false);
     // Used when something in JS land wants to copy text to or from the clipboard. For POST, the text to be put on the
     // clipboard is passed as the 'text' property of a JSON requestData.
     apiHandler.RegisterEndpointHandler("common/clipboardText",
                                        request =>
     {
         if (request.HttpMethod == HttpMethods.Get)
         {
             string result = "";                             // initial value is not used, delegate will set it.
             Program.MainContext.Send(o => result = Clipboard.GetText(), null);
             request.ReplyWithText(result);
         }
         else
         {
             // post
             var requestData = DynamicJson.Parse(request.RequiredPostJson());
             string content  = requestData.text;
             if (!string.IsNullOrEmpty(content))
             {
                 Program.MainContext.Post(o =>
                                          Clipboard.SetText(content), null);
             }
             request.PostSucceeded();
         }
     }, false);
     apiHandler.RegisterEndpointHandler("common/checkForUpdates",
                                        request =>
     {
         WorkspaceView.CheckForUpdates();
         request.PostSucceeded();
     }, false);
     apiHandler.RegisterEndpointHandler("common/channel",
                                        request =>
     {
         request.ReplyWithText(ApplicationUpdateSupport.ChannelName);
     }, false);
     // This is useful for debugging TypeScript code, especially on Linux.  I wouldn't necessarily expect
     // to see it used anywhere in code that gets submitted and merged.
     apiHandler.RegisterEndpointHandler("common/debugMessage",
                                        request =>
     {
         var message = request.RequiredPostString();
         Debug.WriteLine("FROM JS: " + message);
         request.PostSucceeded();
     }, false);
 }
예제 #9
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     // We could probably get away with using the server thread here, but the code interacts quite a bit with the
     // current book and other state.
     apiHandler.RegisterEndpointHandler("pageTemplates", HandleTemplatesRequest, true);
     // Being on the UI thread causes a deadlock on Linux/Mono.  See https://silbloom.myjetbrains.com/youtrack/issue/BL-3818.
     apiHandler.RegisterEndpointHandler("pageTemplateThumbnail", HandleThumbnailRequest, false);
 }
예제 #10
0
        public void RegisterWithApiHandler(BloomApiHandler apiHandler)
        {
            // Note: all book commands, including import and export spreadsheets,
            // go through a single "bookCommand/" API, so we don't register that here.
            // Instead all we need to register is any api enpoints used by our own spreadsheet dialogs

            apiHandler.RegisterEndpointLegacy("spreadsheet/export", ExportToSpreadsheet, true);
        }
예제 #11
0
        public void RegisterWithApiHandler(BloomApiHandler apiHandler)
        {
            bool requiresSync = false;

            apiHandler.RegisterEnumEndpointHandler(kApiUrlPart + "defaultAudioRecordingMode",
                                                   request => HandleGet(),
                                                   (request, newDefaultAudioRecordingMode) => HandlePost(newDefaultAudioRecordingMode), requiresSync);
        }
예제 #12
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointHandler("pageList/pages", HandlePagesRequest, false);
     apiHandler.RegisterEndpointHandler("pageList/pageContent", HandlePageContentRequest, false);
     apiHandler.RegisterEndpointHandler("pageList/pageMoved", HandlePageMovedRequest, true);
     apiHandler.RegisterEndpointHandler("pageList/pageClicked", HandlePageClickedRequest, true);
     apiHandler.RegisterEndpointHandler("pageList/menuClicked", HandleShowMenuRequest, true);
 }
예제 #13
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointHandler("dialog/close",
                                        (ApiRequest request) =>
     {
         BrowserDialog.CurrentDialog?.Close();
         request.PostSucceeded();
     }, true);
 }
예제 #14
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointLegacy("dialog/close",
                                       (ApiRequest request) =>
     {
         // Closes the current dialog.
         BrowserDialog.CloseDialog();
         request.PostSucceeded();
     }, true);
 }
예제 #15
0
 public static void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointLegacy("help/.*", (request) =>
     {
         var topic = request.LocalPath().Replace("api/help", "");
         Show(Application.OpenForms.Cast <Form>().Last(), topic);
         //if this is called from a simple html anchor, we don't want the browser to do anything
         request.ExternalLinkSucceeded();
     }, true);             // opening a form, definitely UI thread
 }
예제 #16
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointHandler("editView/setModalState", HandleSetModalState, true);
     apiHandler.RegisterEndpointHandler("editView/chooseWidget", HandleChooseWidget, true);
     apiHandler.RegisterEndpointHandler("editView/getBookColors", HandleGetColors, true);
     apiHandler.RegisterEndpointHandler("editView/editPagePainted", HandleEditPagePainted, true);
     apiHandler.RegisterEndpointHandler("editView/saveToolboxSetting", HandleSaveToolboxSetting, true);
     apiHandler.RegisterEndpointHandler("editView/setTopic", HandleSetTopic, true);
     apiHandler.RegisterEndpointHandler("editView/isTextSelected", HandleIsTextSelected, false);
     apiHandler.RegisterEndpointHandler("editView/getBookLangs", HandleGetBookLangs, false);
     apiHandler.RegisterEndpointHandler("editView/requestTranslationGroupContent", RequestDefaultTranslationGroupContent, true);
 }
예제 #17
0
        public void RegisterWithApiHandler(BloomApiHandler apiHandler)
        {
            apiHandler.RegisterEndpointLegacy("pageList/pages", HandlePagesRequest, false).Measureable();
            apiHandler.RegisterEndpointLegacy("pageList/pageContent", HandlePageContentRequest, false);
            apiHandler.RegisterEndpointLegacy("pageList/pageMoved", HandlePageMovedRequest, true).Measureable();
            apiHandler.RegisterEndpointLegacy("pageList/pageClicked", HandlePageClickedRequest, true);
            apiHandler.RegisterEndpointLegacy("pageList/menuClicked", HandleShowMenuRequest, true).Measureable();

            apiHandler.RegisterEndpointLegacy("pageList/bookAttributesThatMayAffectDisplay", (request) =>
            {
                var attrs = _bookSelection.CurrentSelection.OurHtmlDom.GetBodyAttributesThatMayAffectDisplay();
                // Surely there's a way to do this more safely with JSON.net but I haven't found it yet
                var props = string.Join(",", attrs.Select(a => ("\"" + a.Name + "\": \"" + a.Value.Replace("\"", "\\\"") + "\"")));
                request.ReplyWithJson("{" + props + "}");
            }, true);
        }
예제 #18
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointHandler("teamCollection/repoFolderPath", HandleRepoFolderPath, false);
     apiHandler.RegisterEndpointHandler("teamCollection/isTeamCollectionEnabled", HandleIsTeamCollectionEnabled, false);
     apiHandler.RegisterEndpointHandler("teamCollection/bookStatus", HandleBookStatus, false);
     apiHandler.RegisterEndpointHandler("teamCollection/selectedBookStatus", HandleSelectedBookStatus, false);
     apiHandler.RegisterEndpointHandler("teamCollection/attemptLockOfCurrentBook", HandleAttemptLockOfCurrentBook, true);
     apiHandler.RegisterEndpointHandler("teamCollection/checkInCurrentBook", HandleCheckInCurrentBook, true);
     apiHandler.RegisterEndpointHandler("teamCollection/forgetChangesInSelectedBook", HandleForgetChangesInSelectedBook, true);
     apiHandler.RegisterEndpointHandler("teamCollection/chooseFolderLocation", HandleChooseFolderLocation, true);
     apiHandler.RegisterEndpointHandler("teamCollection/createTeamCollection", HandleCreateTeamCollection, true);
     apiHandler.RegisterEndpointHandler("teamCollection/joinTeamCollection", HandleJoinTeamCollection, true);
     apiHandler.RegisterEndpointHandler("teamCollection/getLog", HandleGetLog, false);
     apiHandler.RegisterEndpointHandler("teamCollection/getCollectionName", HandleGetCollectionName, false);
     apiHandler.RegisterEndpointHandler("teamCollection/showCreateTeamCollectionDialog", HandleShowCreateTeamCollectionDialog, true);
     apiHandler.RegisterEndpointHandler("teamCollection/reportBadZip", HandleReportBadZip, true);
     apiHandler.RegisterEndpointHandler("teamCollection/showRegistrationDialog", HandleShowRegistrationDialog, true, false);
     apiHandler.RegisterEndpointHandler("teamCollection/getHistory", HandleGetHistory, true);
 }
예제 #19
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointLegacy("keyboarding/useLongpress", (ApiRequest request) =>
     {
         try
         {
             //detect if some keyboarding system is active, e.g. KeyMan. If it is, don't enable LongPress
             var form = Application.OpenForms.Cast <Form>().Last();
             request.ReplyWithText(SIL.Windows.Forms.Keyboarding.KeyboardController.IsFormUsingInputProcessor(form)
                                         ? "false"
                                         : "true");
         }
         catch (Exception error)
         {
             request.ReplyWithText("true");                     // This is arbitrary. I don't know if it's better to assume keyman, or not.
             NonFatalProblem.Report(ModalIf.None, PassiveIf.All, "Error checking for keyman", "", error);
         }
     }, handleOnUiThread: false);
 }
예제 #20
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointLegacy("performance/showCsvFile", (request) =>
     {
         Process.Start(_csvFilePath);
         request.PostSucceeded();
     }, false);
     apiHandler.RegisterEndpointLegacy("performance/applicationInfo", (request) =>
     {
         request.ReplyWithText($"Bloom {Shell.GetShortVersionInfo()} {ApplicationUpdateSupport.ChannelName}");
     }, false);
     apiHandler.RegisterEndpointLegacy("performance/allMeasurements", (request) =>
     {
         List <object> l = new List <object>();
         foreach (var measurement in _measurements)
         {
             l.Add(measurement.GetSummary());
         }
         request.ReplyWithJson(l.ToArray());
     }, false);
 }
예제 #21
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointHandler("workspace/openOrCreateCollection/", HandleOpenOrCreateCollection,
                                        true);
 }
예제 #22
0
        public void RegisterWithApiHandler(BloomApiHandler apiHandler)
        {
            apiHandler.RegisterEndpointHandler(kApiUrlPart + "save", request =>
            {
                {
                    string suggestedName = string.Format("{0}-{1}.epub", Path.GetFileName(_bookSelection.CurrentSelection.FolderPath),
                                                         _bookSelection.CurrentSelection.BookData.Language1.GetNameInLanguage("en"));
                    using (var dlg = new DialogAdapters.SaveFileDialogAdapter())
                    {
                        if (!string.IsNullOrEmpty(_lastDirectory) && Directory.Exists(_lastDirectory))
                        {
                            dlg.InitialDirectory = _lastDirectory;
                        }
                        dlg.FileName        = suggestedName;
                        dlg.Filter          = "EPUB|*.epub";
                        dlg.OverwritePrompt = true;
                        if (DialogResult.OK == dlg.ShowDialog())
                        {
                            _lastDirectory = Path.GetDirectoryName(dlg.FileName);
                            lock (_epubMakerLock)
                            {
                                _pendingSaveAsPath = dlg.FileName;
                                if (!_stagingEpub)
                                {
                                    // we can do it right now. No need to check version etc., because anything
                                    // that will change the epub we want to save will immediately trigger a new
                                    // preview, and we will be staging it until we have it.
                                    SaveAsEpub();
                                }
                                // If we ARE in the middle of staging the epub...quite possible since this
                                // handler is registered with permission to execute in parallel with other
                                // API handlers, the user just has to click Save before the preview is finished...
                                // then we need not do any more here. A call to SaveAsEpub at the end of the
                                // preview generation process will pick up the pending request in _pendingSaveAsPath
                                // and complete the Save.
                            }

                            ReportProgress(LocalizationManager.GetString("PublishTab.Epub.Done", "Done"));
                            ReportAnalytics("Save ePUB");
                        }
                    }

                    request.PostSucceeded();
                }
            }, true, false);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "epubSettings", request =>
            {
                if (request.HttpMethod == HttpMethods.Get)
                {
                    request.ReplyWithJson(GetEpubSettings());
                }
                else
                {
                    // post is deprecated.
                    throw new ApplicationException("epubSettings POST is deprecated");
                }
            }, false);

            // The backend here was written with an enum that had two choices for how to publish descriptions, but we only ever
            // have used one of them so far in the UI. So this is a boolean api that converts to an enum underlying value.
            apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "imageDescriptionSetting",
                                                      request => request.CurrentBook.BookInfo.MetaData.Epub_HowToPublishImageDescriptions == BookInfo.HowToPublishImageDescriptions.OnPage,
                                                      (request, onPage) =>
            {
                request.CurrentBook.BookInfo.MetaData.Epub_HowToPublishImageDescriptions = onPage
                                                ? BookInfo.HowToPublishImageDescriptions.OnPage
                                                : BookInfo.HowToPublishImageDescriptions.None;
                request.CurrentBook.BookInfo.Save();
                var newSettings = _desiredEpubSettings.Clone();
                newSettings.howToPublishImageDescriptions = request.CurrentBook.BookInfo.MetaData.Epub_HowToPublishImageDescriptions;
                RefreshPreview(newSettings);
            },
                                                      false);

            // Saving a checkbox setting that the user ticks to say "Use my E-reader's font sizes"
            apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "removeFontSizesSetting",
                                                      request => request.CurrentBook.BookInfo.MetaData.Epub_RemoveFontSizes,
                                                      (request, booleanSetting) => {
                request.CurrentBook.BookInfo.MetaData.Epub_RemoveFontSizes = booleanSetting;
                request.CurrentBook.BookInfo.Save();
                var newSettings             = _desiredEpubSettings.Clone();
                newSettings.removeFontSizes = booleanSetting;
                RefreshPreview(newSettings);
            },
                                                      false);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "updatePreview", request =>
            {
                RefreshPreview(_desiredEpubSettings);
                request.PostSucceeded();
            }, false);             // in fact, must NOT be on UI thread

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "abortPreview", request =>
            {
                AbortMakingEpub();

                request.PostSucceeded();
            }, false, false);
        }
예제 #23
0
        public void RegisterWithApiHandler(BloomApiHandler apiHandler)
        {
            bool requiresSync = false;             // Lets us open the dialog while the epub preview is being generated

            apiHandler.RegisterEndpointHandler("book/metadata", HandleBookMetadata, false, requiresSync);
        }
        public void RegisterWithApiHandler(BloomApiHandler apiHandler)
        {
            apiHandler.RegisterEndpointHandler(kApiUrlPart + "bookName", request =>
            {
                request.ReplyWithText(request.CurrentBook.TitleBestForUserDisplay);
            }, false);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "showAccessibilityChecker", request =>
            {
                AccessibilityCheckWindow.StaticShow(() => _webSocketServer.SendEvent(kWebSocketContext, kWindowActivated));
                request.PostSucceeded();
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "descriptionsForAllImages", request =>
            {
                var problems    = AccessibilityCheckers.CheckDescriptionsForAllImages(request.CurrentBook);
                var resultClass = problems.Any() ? "failed" : "passed";
                request.ReplyWithJson(new { resultClass = resultClass, problems = problems });
            }, false);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "audioForAllImageDescriptions", request =>
            {
                var problems    = AccessibilityCheckers.CheckAudioForAllImageDescriptions(request.CurrentBook);
                var resultClass = problems.Any() ? "failed" : "passed";
                request.ReplyWithJson(new { resultClass = resultClass, problems = problems });
            }, false);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "audioForAllText", request =>
            {
                var problems    = AccessibilityCheckers.CheckAudioForAllText(request.CurrentBook);
                var resultClass = problems.Any() ? "failed" : "passed";
                request.ReplyWithJson(new { resultClass = resultClass, problems = problems });
            }, false);

            // Just a checkbox that the user ticks to say "yes, I checked this"
            // At this point, we don't have a way to clear that when the book changes.
            apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "noEssentialInfoByColor",
                                                      request => request.CurrentBook.BookInfo.MetaData.A11y_NoEssentialInfoByColor,
                                                      (request, b) => {
                request.CurrentBook.BookInfo.MetaData.A11y_NoEssentialInfoByColor = b;
                request.CurrentBook.Save();
            },
                                                      false);

            // Just a checkbox that the user ticks to say "yes, I checked this"
            // At this point, we don't have a way to clear that when the book changes.
            apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "noTextIncludedInAnyImages",
                                                      request => request.CurrentBook.BookInfo.MetaData.A11y_NoTextIncludedInAnyImages,
                                                      (request, b) => {
                request.CurrentBook.BookInfo.MetaData.A11y_NoTextIncludedInAnyImages = b;
                request.CurrentBook.Save();
            },
                                                      false);

            //enhance: this might have to become async to work on large books on slow computers
            apiHandler.RegisterEndpointHandler(kApiUrlPart + "aceByDaisyReportUrl", request => { MakeAceByDaisyReport(request); },
                                               false, false
                                               );

            // A checkbox that the user ticks in the Accessible Image tool to request a preview
            // of how things might look with cataracts.
            // For now this doesn't seem worth persisting, except for the session so it sticks from page to page.
            apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "cataracts",
                                                      request => _simulateCataracts,
                                                      (request, b) => { _simulateCataracts = b; },
                                                      false);
            // A checkbox that the user ticks in the Accessible Image tool to request a preview
            // of how things might look with color-blindness, and a set of radio buttons
            // for choosing different kinds of color-blindness.
            // For now these doesn't seem worth persisting, except for the session so it sticks from page to page.
            apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "colorBlindness",
                                                      request => _simulateColorBlindness,
                                                      (request, b) => { _simulateColorBlindness = b; },
                                                      false);
            apiHandler.RegisterEnumEndpointHandler(kApiUrlPart + "kindOfColorBlindness",
                                                   request => _kindOfColorBlindness,
                                                   (request, kind) => _kindOfColorBlindness = kind, false);
        }
예제 #25
0
        public void RegisterWithApiHandler(BloomApiHandler apiHandler)
        {
            apiHandler.RegisterEndpointHandler(kApiUrlPart + "recordVideo", request =>
            {
                RecordVideo(request);
                request.PostSucceeded();
            }, true, false);

            // This is sent directly from BloomPlayer when it gets to the end of making the recording.
            // The player gives Bloom a list of all the sounds it played and their timings so we can
            // merge them into the captured video.
            apiHandler.RegisterEndpointHandler(kApiUrlPart + "soundLog", request =>
            {
                var soundLog = request.RequiredPostJson();
                _recordVideoWindow.StopRecording(soundLog);
                request.PostSucceeded();
            }, true, false);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "playVideo", request =>
            {
                _recordVideoWindow.PlayVideo();
                request.PostSucceeded();
            }, true, false);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "settings", request =>
            {
                if (request.HttpMethod == HttpMethods.Get)
                {
                    var settings      = request.CurrentBook.BookInfo.PublishSettings.AudioVideo;
                    var lastPageIndex = request.CurrentBook.GetPages().Count() - 1;
                    // this default might be too high but I don't think it will ever be too low.
                    // The HTML side will handle it being too high.
                    var pageRange = new[] { 0, lastPageIndex };
                    if (settings.PageRange != null && settings.PageRange.Length == 2)
                    {
                        // I wanted to do something like this as validation, in case the book changed
                        // since we saved. But we don't have an accurate page count of the modified version
                        // of the book that the range applies to yet. (e.g., switch to device xmatter, strip
                        // activities,...
                        //pageRange[1] = Math.Min(settings.PageRange[1], lastPageIndex); // not more than the pages we have
                        //pageRange[0] = Math.Min(settings.PageRange[0], pageRange[1] - 1); // at least one less than lim
                        //if (pageRange[0] < 0)
                        //	pageRange[0] = 0;
                        //if (pageRange[1] < pageRange[0] + 1)
                        //	pageRange[1] = Math.Min(pageRange[0] + 1, lastPageIndex);
                        pageRange = settings.PageRange;
                    }
                    request.ReplyWithJson(new {
                        format        = settings.Format,
                        pageTurnDelay = settings.PageTurnDelayDouble,
                        motion        = settings.Motion,
                        pageRange
                    });
                }
                else
                {
                    var data        = DynamicJson.Parse(request.RequiredPostJson());
                    var settings    = request.CurrentBook.BookInfo.PublishSettings.AudioVideo;
                    var oldMotion   = settings.Motion;
                    settings.Format = data.format;
                    settings.PageTurnDelayDouble = data.pageTurnDelay;
                    settings.Motion = data.motion;
                    // pageRange also comes in as doubles. "as double[]" does not work, so have to do them individually.
                    settings.PageRange = new int[0];
                    // Typescript passes an empty array if all pages are selected.
                    // This allows us naturally to keep everything selected until the user explicitly changes something.
                    if (data.pageRange.IsArray && data.pageRange.Count == 2)
                    {
                        var start          = (int)data.pageRange[0];
                        var end            = (int)data.pageRange[1];
                        settings.PageRange = new[] { start, end };
                    }

                    request.CurrentBook.BookInfo.SavePublishSettings();

                    _recordVideoWindow?.SetPageReadTime(settings.PageTurnDelayDouble.ToString());
                    _recordVideoWindow?.SetFormat(request.CurrentBook.BookInfo.PublishSettings.AudioVideo.Format,
                                                  ShouldRecordAsLandscape(request.CurrentBook), request.CurrentBook.GetLayout());
                    if (settings.Motion != oldMotion)
                    {
                        UpdatePreview(request);                         // does its own success/fail
                    }
                    else
                    {
                        request.PostSucceeded();
                    }
                }
            }, true, false);
            apiHandler.RegisterEndpointHandler(kApiUrlPart + "videoSettings", request =>
            {
                if (request.HttpMethod == HttpMethods.Get)
                {
                    request.ReplyWithText(request.CurrentBook.BookInfo.PublishSettings.AudioVideo.PlayerSettings ?? "");
                }
                else
                {
                    request.CurrentBook.BookInfo.PublishSettings.AudioVideo.PlayerSettings =
                        request.RequiredPostString();
                    request.CurrentBook.BookInfo.SavePublishSettings();
                    request.PostSucceeded();
                }
            }, true, false);


            apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "hasActivities",
                                                      request =>
            {
                return(request.CurrentBook.HasActivities);
            },
                                                      null,  // no write action
                                                      false,
                                                      true); // we don't really know, just safe default

            // Returns true if publish to MP3 is supported for this book, false otherwise.
            // To be eligible to publish to MP3, the book must contain narration audio.
            // (There's not any point to an MP3 if the book has absolutely no audio...
            // Even a book with background music but no narration, there's not too much point to an MP3 either)
            apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "isMP3FormatSupported", request =>
            {
                // ENHANCE: If desired, you can make it only consider languages in the book that are currently relevant,
                // instead of any language in the book.
                var narrationAudioLangs = request.CurrentBook.GetLanguagesWithAudio();
                return(narrationAudioLangs.Any());
            }, null, false, false);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "startRecording", request =>
            {
                var videoList        = request.GetPostStringOrNull();
                var anyVideoHasAudio = _recordVideoWindow?.AnyVideoHasAudio(videoList, request.CurrentBook.FolderPath) ?? false;
                if (anyVideoHasAudio)
                {
                    var messageBoxButtons = new[]
                    {
                        new MessageBoxButton()
                        {
                            Text = LocalizationManager.GetString("Common.Continue", "Continue"), Id = "continue"
                        },
                        new MessageBoxButton()
                        {
                            Text = LocalizationManager.GetString("Common.Cancel", "Cancel"), Id = "cancel", Default = true
                        }
                    };
                    if (BloomMessageBox.Show(null,
                                             LocalizationManager.GetString("PublishTab.RecordVideo.NoAudioInVideo",
                                                                           "Currently, Bloom does not support including audio from Sign Language videos in video output."),
                                             messageBoxButtons) == "cancel")
                    {
                        request.Failed("canceled");
                        _recordVideoWindow.Close();
                        return;
                    }
                }
                _recordVideoWindow?.StartFfmpegForVideoCapture();
                request.PostSucceeded();
            }, true, false);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "shouldUseOriginalPageSize",
                                               request =>
            {
                RecordVideoWindow.GetDataForFormat(request.CurrentBook.BookInfo.PublishSettings.AudioVideo.Format,
                                                   ShouldRecordAsLandscape(request.CurrentBook), request.CurrentBook.GetLayout(),
                                                   out _, out _, out _, out bool useOriginalPageSize);
                request.ReplyWithBoolean(useOriginalPageSize);
            },
                                               true, // has to be on UI thread because it uses Bloom's main window to find the right screen
                                               false);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "tooBigForScreenMsg",
                                               request =>
            {
                request.ReplyWithText(RecordVideoWindow.GetDataForFormat(request.CurrentBook.BookInfo.PublishSettings.AudioVideo.Format,
                                                                         ShouldRecordAsLandscape(request.CurrentBook), request.CurrentBook.GetLayout(),
                                                                         out _, out _, out _, out _));
            },
                                               true, // has to be on UI thread because it uses Bloom's main window to find the right screen
                                               false);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "saveVideo", request =>
            {
                if (_recordVideoWindow == null)
                {
                    // This shouldn't be possible, but just in case, we'll kick off the recording now.
                    RecordVideo(request);
                }

                _recordVideoWindow?.SetBook(request.CurrentBook);

                // If we bring up the dialog inside this API call, it may time out.
                Application.Idle += SaveVideoOnIdle;
                request.PostSucceeded();
            }, true, false);


            apiHandler.RegisterEndpointHandler(kApiUrlPart + "updatePreview", request => { UpdatePreview(request); }, false);
            apiHandler.RegisterEndpointHandler(kApiUrlPart + "displaySettings", request =>
            {
                Process.Start("desk.cpl");
                request.PostSucceeded();
            }, false);
            apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "isScalingActive",
                                                      request => IsScalingActive(),
                                                      null, true);
        }
예제 #26
0
 public void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointHandler("toolbox/enabledTools", HandleEnabledToolsRequest, true);
     apiHandler.RegisterEndpointHandler("toolbox/fileExists", HandleFileExistsRequest, true);
 }
예제 #27
0
        public void RegisterWithApiHandler(BloomApiHandler apiHandler)
        {
            apiHandler.RegisterEndpointLegacy("uiLanguages", HandleUiLanguages, false);                               // App
            apiHandler.RegisterEndpointLegacy("currentUiLanguage", HandleCurrentUiLanguage, false);                   // App
            apiHandler.RegisterEndpointLegacy("bubbleLanguages", HandleBubbleLanguages, false);                       // Move to EditingViewApi
            apiHandler.RegisterEndpointLegacy("authorMode", HandleAuthorMode, false);                                 // Move to EditingViewApi
            apiHandler.RegisterEndpointLegacy("topics", HandleTopics, false);                                         // Move to EditingViewApi
            apiHandler.RegisterEndpointLegacy("common/error", HandleJavascriptError, false);                          // Common
            apiHandler.RegisterEndpointLegacy("common/preliminaryError", HandlePreliminaryJavascriptError, false);    // Common
            apiHandler.RegisterEndpointLegacy("common/saveChangesAndRethinkPageEvent", RethinkPageAndReloadIt, true); // Move to EditingViewApi
            apiHandler.RegisterEndpointLegacy("common/chooseFolder", HandleChooseFolder, true);
            apiHandler.RegisterEndpointLegacy("common/showInFolder", HandleShowInFolderRequest, true);                // Common
            apiHandler.RegisterEndpointLegacy("common/canModifyCurrentBook", HandleCanModifyCurrentBook, true);
            apiHandler.RegisterEndpointLegacy("common/showSettingsDialog", HandleShowSettingsDialog, false);          // Common
            apiHandler.RegisterEndpointLegacy("common/problemWithBookMessage", request =>
            {
                request.ReplyWithText(CommonMessages.GetProblemWithBookMessage(Path.GetFileName(_bookSelection.CurrentSelection?.FolderPath)));
            }, false);
            apiHandler.RegisterEndpointLegacy("common/clickHereForHelp", request =>
            {
                var problemFilePath = UrlPathString.CreateFromUrlEncodedString(request.RequiredParam("problem")).NotEncoded;
                request.ReplyWithText(CommonMessages.GetPleaseClickHereForHelpMessage(problemFilePath));
            }, false);
            // Used when something in JS land wants to copy text to or from the clipboard. For POST, the text to be put on the
            // clipboard is passed as the 'text' property of a JSON requestData.
            // Somehow the get version of this fires while initializing a page (probably hooking up CkEditor, an unwanted
            // invocation of the code that decides whether to enable the paste hyperlink button). This causes a deadlock
            // unless we make this endpoint requiresSync:false. I think this is safe as it doesn't interact with any other
            // Bloom objects.
            apiHandler.RegisterEndpointLegacy("common/clipboardText",
                                              request =>
            {
                if (request.HttpMethod == HttpMethods.Get)
                {
                    string result = "";                             // initial value is not used, delegate will set it.
                    Program.MainContext.Send(o =>
                    {
                        try
                        {
                            result = PortableClipboard.GetText();
                        }
                        catch (Exception e)
                        {
                            // Need to make sure to handle exceptions.
                            // If the worker thread dies with an unhandled exception,
                            // it causes the whole program to immediately crash without opportunity for error reporting
                            NonFatalProblem.Report(ModalIf.All, PassiveIf.None, "Error pasting text", exception: e);
                        }
                    }, null);
                    request.ReplyWithText(result);
                }
                else
                {
                    // post
                    var requestData = DynamicJson.Parse(request.RequiredPostJson());
                    string content  = requestData.text;
                    if (!string.IsNullOrEmpty(content))
                    {
                        Program.MainContext.Post(o =>
                        {
                            try
                            {
                                PortableClipboard.SetText(content);
                            }
                            catch (Exception e)
                            {
                                // Need to make sure to handle exceptions.
                                // If the worker thread dies with an unhandled exception,
                                // it causes the whole program to immediately crash without opportunity for error reporting
                                NonFatalProblem.Report(ModalIf.All, PassiveIf.None, "Error copying text", exception: e);
                            }
                        }, null);
                    }
                    request.PostSucceeded();
                }
            }, false, false);
            apiHandler.RegisterEndpointLegacy("common/checkForUpdates",
                                              request =>
            {
                WorkspaceView.CheckForUpdates();
                request.PostSucceeded();
            }, false);
            apiHandler.RegisterEndpointLegacy("common/channel",
                                              request =>
            {
                request.ReplyWithText(ApplicationUpdateSupport.ChannelName);
            }, false);
            // This is useful for debugging TypeScript code, especially on Linux.  I wouldn't necessarily expect
            // to see it used anywhere in code that gets submitted and merged.
            apiHandler.RegisterEndpointLegacy("common/debugMessage",
                                              request =>
            {
                var message = request.RequiredPostString();
                Debug.WriteLine("FROM JS: " + message);
                request.PostSucceeded();
            }, false);

            apiHandler.RegisterEndpointLegacy("common/loginData",
                                              request =>
            {
                var requestData = DynamicJson.Parse(request.RequiredPostJson());
                string token    = requestData.sessionToken;
                string email    = requestData.email;
                string userId   = requestData.userId;
                //Debug.WriteLine("Got login data " + email + " with token " + token + " and id " + userId);
                _parseClient.SetLoginData(email, userId, token, BookUpload.Destination);
                _doWhenLoggedIn?.Invoke();
                request.PostSucceeded();
            }, false);

            // At this point we open dialogs from c# code; if we opened dialogs from javascript, we wouldn't need this
            // api to do it. We just need a way to close a c#-opened dialog from javascript (e.g. the Close button of the dialog).
            //
            // This must set requiresSync:false because the API call which opened the dialog may already have
            // the lock in which case we would be deadlocked.
            // ErrorReport.NotifyUserOfProblem is a particularly problematic case. We tried to come up with some
            // other solutions for that including opening the dialog on Application.Idle. But the dialog needs
            // to give a real-time result so callers can know what do with button presses. Since some of those
            // callers are in libpalaso, we can't just ignore the result and handle the actions ourselves.
            apiHandler.RegisterEndpointLegacy("common/closeReactDialog", request =>
            {
                ReactDialog.CloseCurrentModal(request.GetPostStringOrNull());
                request.PostSucceeded();
            }, true, requiresSync: false);

            // TODO: move to the new App API (BL-9635)
            apiHandler.RegisterEndpointLegacy("common/reloadCollection", HandleReloadCollection, true);
        }
예제 #28
0
        public void RegisterWithApiHandler(BloomApiHandler apiHandler)
        {
            apiHandler.RegisterEndpointHandler(kApiUrlPart + "requestState", request =>
            {
                if (request.HttpMethod == HttpMethods.Get)
                {
                    request.ReplyWithJson(CurrentStateString);
                }
                else                 // post
                {
                    Debug.Fail("We shouldn't ever be using the 'post' version.");
                    request.PostSucceeded();
                }
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "addPage", request =>
            {
                AddPageButton_Click();
                request.PostSucceeded();
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "duplicatePage", request =>
            {
                _editingModel.OnDuplicatePage();
                request.PostSucceeded();
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "deletePage", request =>
            {
                if (ConfirmRemovePageDialog.Confirm())
                {
                    _editingModel.OnDeletePage();
                }
                request.PostSucceeded();
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "lockBook", request =>
            {
                _editingModel.SaveNow();                 // BL-5421 lock and unlock lose typing
                _editingModel.CurrentBook.TemporarilyUnlocked = false;
                request.PostSucceeded();
                UpdateState();                 // because we aren't selecting a new page
                _editingModel.RefreshDisplayOfCurrentPage();
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "unlockBook", request =>
            {
                _editingModel.SaveNow();                 // BL-5421 lock and unlock lose typing
                _editingModel.CurrentBook.TemporarilyUnlocked = true;
                request.PostSucceeded();
                UpdateState();                 // because we aren't selecting a new page
                _editingModel.RefreshDisplayOfCurrentPage();
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "cleanup", request =>
            {
                SendCleanupState();
                request.PostSucceeded();
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "zoomMinus", request =>
            {
                _editingModel.AdjustPageZoom(-10);
                request.PostSucceeded();
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "zoomPlus", request =>
            {
                _editingModel.AdjustPageZoom(10);
                request.PostSucceeded();
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "requestVideoPlaceHolder", request =>
            {
                _editingModel.RequestVideoPlaceHolder();
                request.PostSucceeded();
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "requestWidgetPlaceHolder", request =>
            {
                _editingModel.RequestWidgetPlaceHolder();
                request.PostSucceeded();
            }, true);
        }
예제 #29
0
        public void RegisterWithApiHandler(BloomApiHandler apiHandler)
        {
            // This is just for storing the user preference of method
            // If we had a couple of these, we could just have a generic preferences api
            // that browser-side code could use.
            apiHandler.RegisterEndpointLegacy(kApiUrlPart + "method", request =>
            {
                if (request.HttpMethod == HttpMethods.Get)
                {
                    var method = Settings.Default.PublishAndroidMethod;
                    if (!new string[] { "wifi", "usb", "file" }.Contains(method))
                    {
                        method = "wifi";
                    }
                    request.ReplyWithText(method);
                }
                else                 // post
                {
                    Settings.Default.PublishAndroidMethod = request.RequiredPostString();
#if __MonoCS__
                    if (Settings.Default.PublishAndroidMethod == "usb")
                    {
                        _progress.MessageWithoutLocalizing("Sorry, this method is not available on Linux yet.");
                    }
#endif
                    request.PostSucceeded();
                }
            }, true);

            apiHandler.RegisterEndpointLegacy(kApiUrlPart + "backColor", request =>
            {
                if (request.HttpMethod == HttpMethods.Get)
                {
                    if (request.CurrentBook != _coverColorSourceBook)
                    {
                        _coverColorSourceBook = request.CurrentBook;
                        ImageUtils.TryCssColorFromString(request.CurrentBook?.GetCoverColor() ?? "", out _thumbnailBackgroundColor);
                    }
                    request.ReplyWithText(ToCssColorString(_thumbnailBackgroundColor));
                }
                else                 // post
                {
                    // ignore invalid colors (very common while user is editing hex)
                    Color newColor;
                    var newColorAsString = request.RequiredPostString();
                    if (ImageUtils.TryCssColorFromString(newColorAsString, out newColor))
                    {
                        _thumbnailBackgroundColor = newColor;
                        request.CurrentBook.SetCoverColor(newColorAsString);
                    }
                    request.PostSucceeded();
                }
            }, true);

            apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "motionBookMode",
                                                      readRequest =>
            {
                // If the user has taken off all possible motion, force not having motion in the
                // Bloom Reader book.  See https://issues.bloomlibrary.org/youtrack/issue/BL-7680.
                if (!readRequest.CurrentBook.HasMotionPages)
                {
                    readRequest.CurrentBook.BookInfo.PublishSettings.BloomPub.Motion = false;
                }
                return(readRequest.CurrentBook.BookInfo.PublishSettings.BloomPub.Motion);
            },
                                                      (writeRequest, value) =>
            {
                writeRequest.CurrentBook.BookInfo.PublishSettings.BloomPub.Motion = value;
                writeRequest.CurrentBook.BookInfo.SavePublishSettings();
                _webSocketServer.SendEvent("publish", "motionChanged");
            }
                                                      , true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "updatePreview", request =>
            {
                MakeBloompubPreview(request, false);
            }, false);


            apiHandler.RegisterEndpointLegacy(kApiUrlPart + "thumbnail", request =>
            {
                var coverImage = request.CurrentBook.GetCoverImagePath();
                if (coverImage == null)
                {
                    request.Failed("no cover image");
                }
                else
                {
                    // We don't care as much about making it resized as making its background transparent.
                    using (var thumbnail = TempFile.CreateAndGetPathButDontMakeTheFile())
                    {
                        if (_thumbnailBackgroundColor == Color.Transparent)
                        {
                            ImageUtils.TryCssColorFromString(request.CurrentBook?.GetCoverColor(), out _thumbnailBackgroundColor);
                        }
                        RuntimeImageProcessor.GenerateEBookThumbnail(coverImage, thumbnail.Path, 256, 256, _thumbnailBackgroundColor);
                        request.ReplyWithImage(thumbnail.Path);
                    }
                }
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "usb/start", request =>
            {
#if !__MonoCS__
                SetState("UsbStarted");
                UpdatePreviewIfNeeded(request);
                _usbPublisher.Connect(request.CurrentBook, _thumbnailBackgroundColor, GetSettings());
#endif
                request.PostSucceeded();
            }, true);

            apiHandler.RegisterEndpointHandler(kApiUrlPart + "usb/stop", request =>
            {
#if !__MonoCS__
                _usbPublisher.Stop(disposing: false);
                SetState("stopped");
#endif
                request.PostSucceeded();
            }, true);
            apiHandler.RegisterEndpointLegacy(kApiUrlPart + "wifi/start", request =>
            {
                SetState("ServingOnWifi");
                UpdatePreviewIfNeeded(request);
                _wifiPublisher.Start(request.CurrentBook, request.CurrentCollectionSettings, _thumbnailBackgroundColor, GetSettings());

                request.PostSucceeded();
            }, true);

            apiHandler.RegisterEndpointLegacy(kApiUrlPart + "wifi/stop", request =>
            {
                _wifiPublisher.Stop();
                SetState("stopped");
                request.PostSucceeded();
            }, true);

            apiHandler.RegisterEndpointLegacy(kApiUrlPart + "file/save", request =>
            {
                UpdatePreviewIfNeeded(request);
                FilePublisher.Save(request.CurrentBook, _bookServer, _thumbnailBackgroundColor, _progress, GetSettings());
                SetState("stopped");
                request.PostSucceeded();
            }, true);

            apiHandler.RegisterEndpointLegacy(kApiUrlPart + "file/bulkSaveBloomPubsParams", request =>
            {
                request.ReplyWithJson(JsonConvert.SerializeObject(_collectionSettings.BulkPublishBloomPubSettings));
            }, true);

            apiHandler.RegisterEndpointLegacy(kApiUrlPart + "file/bulkSaveBloomPubs", request =>
            {
                // update what's in the collection so that we remember for next time
                _collectionSettings.BulkPublishBloomPubSettings = request.RequiredPostObject <BulkBloomPubPublishSettings>();
                _collectionSettings.Save();

                _bulkBloomPubCreator.PublishAllBooks(_collectionSettings.BulkPublishBloomPubSettings);
                SetState("stopped");
                request.PostSucceeded();
            }, true);

            apiHandler.RegisterEndpointLegacy(kApiUrlPart + "textToClipboard", request =>
            {
                PortableClipboard.SetText(request.RequiredPostString());
                request.PostSucceeded();
            }, true);

            apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "canHaveMotionMode",
                                                      request =>
            {
                return(request.CurrentBook.HasMotionPages);
            },
                                                      null,  // no write action
                                                      false,
                                                      true); // we don't really know, just safe default

            apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "canRotate",
                                                      request =>
            {
                return(request.CurrentBook.BookInfo.PublishSettings.BloomPub.Motion && request.CurrentBook.HasMotionPages);
            },
                                                      null,  // no write action
                                                      false,
                                                      true); // we don't really know, just safe default

            apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "defaultLandscape",
                                                      request =>
            {
                return(request.CurrentBook.GetLayout().SizeAndOrientation.IsLandScape);
            },
                                                      null,  // no write action
                                                      false,
                                                      true); // we don't really know, just safe default
            apiHandler.RegisterEndpointLegacy(kApiUrlPart + "languagesInBook", request =>
            {
                try
                {
                    InitializeLanguagesInBook(request);

                    Dictionary <string, InclusionSetting> textLangsToPublish  = request.CurrentBook.BookInfo.PublishSettings.BloomPub.TextLangs;
                    Dictionary <string, InclusionSetting> audioLangsToPublish = request.CurrentBook.BookInfo.PublishSettings.BloomPub.AudioLangs;

                    var result = "[" + string.Join(",", _allLanguages.Select(kvp =>
                    {
                        string langCode = kvp.Key;

                        bool includeText = false;
                        if (textLangsToPublish != null && textLangsToPublish.TryGetValue(langCode, out InclusionSetting includeTextSetting))
                        {
                            includeText = includeTextSetting.IsIncluded();
                        }

                        bool includeAudio = false;
                        if (audioLangsToPublish != null && audioLangsToPublish.TryGetValue(langCode, out InclusionSetting includeAudioSetting))
                        {
                            includeAudio = includeAudioSetting.IsIncluded();
                        }

                        var value = new LanguagePublishInfo()
                        {
                            code             = kvp.Key,
                            name             = request.CurrentBook.PrettyPrintLanguage(langCode),
                            complete         = kvp.Value,
                            includeText      = includeText,
                            containsAnyAudio = _languagesWithAudio.Contains(langCode),
                            includeAudio     = includeAudio
                        };
                        var json = JsonConvert.SerializeObject(value);
                        return(json);
                    })) + "]";

                    request.ReplyWithText(result);
                }
예제 #30
0
 public static void RegisterWithApiHandler(BloomApiHandler apiHandler)
 {
     apiHandler.RegisterEndpointHandler("toolbox/settings", HandleSettings, false);
 }