private void UpdatePreview(ApiRequest request)
 {
     InitializeLanguagesInBook(request);
     _lastSettings = GetSettings();
     _lastThumbnailBackgroundColor = _thumbnailBackgroundColor;
     PreviewUrl = StageBloomD(request.CurrentBook, _bookServer, _progress, _thumbnailBackgroundColor, _lastSettings);
     _webSocketServer.SendString(kWebSocketContext, kWebsocketEventId_Preview, PreviewUrl);
 }
Exemple #2
0
        // Create a BloomReader book while also creating the temporary folder for it (according to the specified parameter) and disposing of it
        public static void CreateBloomPub(string outputPath, string bookFolderPath, BookServer bookServer,

                                          IWebSocketProgress progress, bool isTemplateBook, string tempFolderName = BRExportFolder,
                                          string creator = kCreatorBloom, AndroidPublishSettings settings = null)
        {
            using (var temp = new TemporaryFolder(tempFolderName))
            {
                CreateBloomPub(outputPath, bookFolderPath, bookServer, progress, temp, creator, isTemplateBook, settings);
            }
        }
Exemple #3
0
        /// <summary>
        /// Create a Bloom Digital book (the zipped .bloompub file) as used by BloomReader (and Bloom Library etc)
        /// </summary>
        /// <param name="outputPath">The path to create the zipped .bloompub output file at</param>
        /// <param name="bookFolderPath">The path to the input book</param>
        /// <param name="bookServer"></param>
        /// <param name="backColor"></param>
        /// <param name="progress"></param>
        /// <param name="tempFolder">A temporary folder. This function will not dispose of it when done</param>
        /// <param name="creator">value for &lt;meta name="creator" content="..."/&gt; (defaults to "bloom")</param>
        /// <param name="isTemplateBook"></param>
        /// <param name="settings"></param>
        /// <returns>Path to the unzipped .bloompub</returns>
        public static string CreateBloomPub(string outputPath, string bookFolderPath, BookServer bookServer,
                                            IWebSocketProgress progress, TemporaryFolder tempFolder, string creator = kCreatorBloom, bool isTemplateBook = false,
                                            AndroidPublishSettings settings = null)
        {
            var modifiedBook = PrepareBookForBloomReader(bookFolderPath, bookServer, tempFolder, progress, isTemplateBook, creator, settings);

            // We want at least 256 for Bloom Reader, because the screens have a high pixel density. And (at the moment) we are asking for
            // 64dp in Bloom Reader.

            BookCompressor.MakeSizedThumbnail(modifiedBook, modifiedBook.FolderPath, 256);

            BookCompressor.CompressBookDirectory(outputPath, modifiedBook.FolderPath, "", reduceImages: true, omitMetaJson: false, wrapWithFolder: false,
                                                 pathToFileForSha: BookStorage.FindBookHtmlInFolder(bookFolderPath));

            return(modifiedBook.FolderPath);
        }
Exemple #4
0
        /// <summary>
        /// Add a `.distribution` file to the zip which will be reported on for analytics from Bloom Reader.
        /// See https://issues.bloomlibrary.org/youtrack/issue/BL-8875.
        /// </summary>
        private static void AddDistributionFile(string bookFolder, string creator, AndroidPublishSettings settings = null)
        {
            string distributionValue;

            switch (creator)
            {
            case kCreatorHarvester:
                distributionValue = kDistributionBloomWeb;
                break;

            case kCreatorBloom:
                distributionValue = kDistributionBloomDirect;
                if (settings != null && !string.IsNullOrEmpty(settings.DistributionTag))
                {
                    distributionValue = settings.DistributionTag;
                }
                break;

            default: throw new ArgumentException("Unknown creator", creator);
            }
            RobustFile.WriteAllText(Path.Combine(bookFolder, kDistributionFileName), distributionValue);
        }
 private AndroidPublishSettings GetSettings()
 {
     return(AndroidPublishSettings.FromBookInfo(_bookForLanguagesToPublish.BookInfo));
 }
Exemple #6
0
        public static Book.Book PrepareBookForBloomReader(string bookFolderPath, BookServer bookServer,
                                                          TemporaryFolder temp,
                                                          IWebSocketProgress progress, bool isTemplateBook,
                                                          string creator = kCreatorBloom,
                                                          AndroidPublishSettings settings = null)
        {
            // MakeDeviceXmatterTempBook needs to be able to copy customCollectionStyles.css etc into parent of bookFolderPath
            // And bloom-player expects folder name to match html file name.
            var htmPath = BookStorage.FindBookHtmlInFolder(bookFolderPath);
            var tentativeBookFolderPath = Path.Combine(temp.FolderPath,
                                                       // Windows directory names cannot have trailing periods, but FileNameWithoutExtension can have these.  (BH-6097)
                                                       BookStorage.SanitizeNameForFileSystem(Path.GetFileNameWithoutExtension(htmPath)));

            Directory.CreateDirectory(tentativeBookFolderPath);
            var modifiedBook = PublishHelper.MakeDeviceXmatterTempBook(bookFolderPath, bookServer,
                                                                       tentativeBookFolderPath, isTemplateBook);

            modifiedBook.SetMotionAttributesOnBody(settings?.Motion ?? false);

            // Although usually tentativeBookFolderPath and modifiedBook.FolderPath are the same, there are some exceptions
            // In the process of bringing a book up-to-date (called by MakeDeviceXmatterTempBook), the folder path may change.
            // For example, it could change if the original folder path contains punctuation marks now deemed dangerous.
            //    The book will be moved to the sanitized version of the file name instead.
            // It can also happen if we end up picking a different version of the title (i.e. in a different language)
            //    than the one written to the .htm file.
            string modifiedBookFolderPath = modifiedBook.FolderPath;

            if (modifiedBook.CollectionSettings.HaveEnterpriseFeatures)
            {
                ProcessQuizzes(modifiedBookFolderPath, modifiedBook.RawDom);
            }

            // Right here, let's maintain the history of what the BloomdVersion signifies to a reader.
            // Version 1 (as opposed to no BloomdVersion field): the bookFeatures property may be
            // used to report features analytics (with earlier bloompub's, the reader must use its own logic)
            modifiedBook.Storage.BookInfo.MetaData.BloomdVersion = 1;

            modifiedBook.Storage.BookInfo.UpdateOneSingletonTag("distribution", settings?.DistributionTag);
            if (!string.IsNullOrEmpty(settings?.BookshelfTag))
            {
                modifiedBook.Storage.BookInfo.UpdateOneSingletonTag("bookshelf", settings.BookshelfTag);
            }

            if (settings?.RemoveInteractivePages ?? false)
            {
                var activities = modifiedBook.GetPageElements().Cast <XmlNode>()
                                 .Where(x => x is XmlElement elt && HtmlDom.IsActivityPage(elt)).ToArray();
                foreach (var page in activities)
                {
                    page.ParentNode.RemoveChild(page);
                }
            }

            if (settings?.LanguagesToInclude != null)
            {
                PublishModel.RemoveUnwantedLanguageData(modifiedBook.OurHtmlDom, settings.LanguagesToInclude, modifiedBook.BookData.MetadataLanguage1IsoCode);
                PublishModel.RemoveUnwantedLanguageRulesFromCssFiles(modifiedBook.FolderPath, settings.LanguagesToInclude);
            }
            else if (Program.RunningHarvesterMode && modifiedBook.OurHtmlDom.SelectSingleNode(BookStorage.ComicalXpath) != null)
            {
                // This indicates that we are harvesting a book with comic speech bubbles or other overlays (Overlay Tool).
                // For books with overlays, we only publish a single language. It's not currently feasible to
                // allow the reader to switch language in a book with overlays, because typically that requires
                // adjusting the positions of the overlays, and we don't yet support having more than one
                // set of overlay locations in a single book. See BL-7912 for some ideas on how we might
                // eventually improve this. In the meantime, switching language would have bad effects,
                // and if you can't switch language, there's no point in the book containing more than one.
                var languagesToInclude = new string[1] {
                    modifiedBook.BookData.Language1.Iso639Code
                };
                PublishModel.RemoveUnwantedLanguageData(modifiedBook.OurHtmlDom, languagesToInclude, modifiedBook.BookData.MetadataLanguage1IsoCode);
            }

            // Do this after processing interactive pages, as they can satisfy the criteria for being 'blank'
            HashSet <string> fontsUsed = null;

            using (var helper = new PublishHelper())
            {
                helper.ControlForInvoke = ControlForInvoke;
                ISet <string> warningMessages = new HashSet <string>();
                helper.RemoveUnwantedContent(modifiedBook.OurHtmlDom, modifiedBook, false,
                                             warningMessages, keepPageLabels: settings?.WantPageLabels ?? false);
                PublishHelper.SendBatchedWarningMessagesToProgress(warningMessages, progress);
                fontsUsed = helper.FontsUsed;
            }
            if (!modifiedBook.IsTemplateBook)
            {
                modifiedBook.RemoveBlankPages(settings?.LanguagesToInclude);
            }

            // See https://issues.bloomlibrary.org/youtrack/issue/BL-6835.
            RemoveInvisibleImageElements(modifiedBook);
            modifiedBook.Storage.CleanupUnusedSupportFiles(/*isForPublish:*/ true, settings?.AudioLanguagesToExclude);
            if (!modifiedBook.IsTemplateBook && RobustFile.Exists(Path.Combine(modifiedBookFolderPath, "placeHolder.png")))
            {
                RobustFile.Delete(Path.Combine(modifiedBookFolderPath, "placeHolder.png"));
            }
            modifiedBook.RemoveObsoleteAudioMarkup();

            // We want these to run after RemoveUnwantedContent() so that the metadata will more accurately reflect
            // the subset of contents that are included in the .bloompub
            // Note that we generally want to disable features here, but not enable them, especially while
            // running harvester!  See https://issues.bloomlibrary.org/youtrack/issue/BL-8995.
            var enableBlind = modifiedBook.BookInfo.MetaData.Feature_Blind || !Program.RunningHarvesterMode;
            // BloomReader and BloomPlayer are not using the SignLanguage feature, and it's misleading to
            // assume the existence of videos implies sign language.  There is a separate "Video" feature
            // now that gets set automatically.  (Automated setting of the Blind feature is imperfect, but
            // more meaningful than trying to automate sign language just based on one video existing.)
            var enableSignLanguage = modifiedBook.BookInfo.MetaData.Feature_SignLanguage;

            modifiedBook.UpdateMetadataFeatures(
                isBlindEnabled: enableBlind,
                isSignLanguageEnabled: enableSignLanguage,
                isTalkingBookEnabled: true,            // talkingBook is only ever set automatically as far as I can tell.
                allowedLanguages: null                 // allow all because we've already filtered out the unwanted ones from the dom above.
                );

            modifiedBook.SetAnimationDurationsFromAudioDurations();

            modifiedBook.OurHtmlDom.SetMedia("bloomReader");
            modifiedBook.OurHtmlDom.AddOrReplaceMetaElement("bloom-digital-creator", creator);
            EmbedFonts(modifiedBook, progress, fontsUsed, FontFileFinder.GetInstance(Program.RunningUnitTests));

            var bookFile = BookStorage.FindBookHtmlInFolder(modifiedBook.FolderPath);

            StripImgIfWeCannotFindFile(modifiedBook.RawDom, bookFile);
            StripContentEditableAndTabIndex(modifiedBook.RawDom);
            InsertReaderStylesheet(modifiedBook.RawDom);
            RobustFile.Copy(FileLocationUtilities.GetFileDistributedWithApplication(BloomFileLocator.BrowserRoot, "publish", "ReaderPublish", "readerStyles.css"),
                            Path.Combine(modifiedBookFolderPath, "readerStyles.css"));
            ConvertImagesToBackground(modifiedBook.RawDom);

            AddDistributionFile(modifiedBookFolderPath, creator, settings);

            modifiedBook.Save();

            return(modifiedBook);
        }
Exemple #7
0
 public static void CreateBloomPub(string outputPath, Book.Book book, BookServer bookServer, IWebSocketProgress progress, AndroidPublishSettings settings = null)
 {
     CreateBloomPub(outputPath, book.FolderPath, bookServer, progress, book.IsTemplateBook, settings: settings);
 }
Exemple #8
0
        public static void CreateBloomPub(BookInfo bookInfo, AndroidPublishSettings settings, string outputFolder, BookServer bookServer, IWebSocketProgress progress)
        {
            var outputPath = Path.Combine(outputFolder, Path.GetFileName(bookInfo.FolderPath) + BookCompressor.BloomPubExtensionWithDot);

            BloomPubMaker.CreateBloomPub(outputPath, bookInfo.FolderPath, bookServer, progress, bookInfo.IsSuitableForMakingShells, settings: settings);
        }
        public static string StageBloomD(Book.Book book, BookServer bookServer, WebSocketProgress progress, Color backColor, AndroidPublishSettings settings = null)
        {
            progress.Message("PublishTab.Epub.PreparingPreview", "Preparing Preview");                  // message shared with Epub publishing
            if (settings?.LanguagesToInclude != null)
            {
                var message = new LicenseChecker().CheckBook(book, settings.LanguagesToInclude.ToArray());
                if (message != null)
                {
                    progress.MessageWithoutLocalizing(message, MessageKind.Error);
                    return(null);
                }
            }

            _stagingFolder?.Dispose();
            if (AudioProcessor.IsAnyCompressedAudioMissing(book.FolderPath, book.RawDom))
            {
                progress.Message("CompressingAudio", "Compressing audio files");
                AudioProcessor.TryCompressingAudioAsNeeded(book.FolderPath, book.RawDom);
            }
            // We don't use the folder found here, but this method does some checks we want done.
            BookStorage.FindBookHtmlInFolder(book.FolderPath);
            _stagingFolder = new TemporaryFolder(StagingFolder);
            var modifiedBook = BloomReaderFileMaker.PrepareBookForBloomReader(book.FolderPath, bookServer, _stagingFolder, progress, settings: settings);

            progress.Message("Common.Done", "Shown in a list of messages when Bloom has completed a task.", "Done");
            return(modifiedBook.FolderPath.ToLocalhost());
        }
        /// <summary>
        /// This is the core of sending a book to a device. We need a book and a bookServer in order to come up
        /// with the .bloomd file.
        /// We are either simply saving the .bloomd to destFileName, or else we will make a temporary .bloomd file and
        /// actually send it using sendAction.
        /// We report important progress on the progress control. This includes reporting that we are starting
        /// the actual transmission using startingMessageAction, which is passed the safe file name (for checking pre-existence
        /// in UsbPublisher) and the book title (typically inserted into the message).
        /// If a confirmAction is passed (currently only by UsbPublisher), we use it check for a successful transfer
        /// before reporting completion (except for file save, where the current message is inappropriate).
        /// This is an awkward case where the three ways of publishing are similar enough that
        /// it's annoying and dangerous to have three entirely separate methods but somewhat awkward to combine them.
        /// Possibly we could eventually make them more similar, e.g., it would simplify things if they all said
        /// "Sending X to Y", though I'm not sure that would be good i18n if Y is sometimes a device name
        /// and sometimes a path.
        /// </summary>
        /// <param name="book"></param>
        /// <param name="destFileName"></param>
        /// <param name="sendAction"></param>
        /// <param name="progress"></param>
        /// <param name="bookServer"></param>
        /// <param name="startingMessageFunction"></param>
        public static void SendBook(Book.Book book, BookServer bookServer, string destFileName, Action <string, string> sendAction, WebSocketProgress progress, Func <string, string, string> startingMessageFunction,
                                    Func <string, bool> confirmFunction, Color backColor, AndroidPublishSettings settings = null)
        {
            var bookTitle = book.Title;

            progress.MessageUsingTitle("PackagingBook", "Packaging \"{0}\" for use with Bloom Reader...", bookTitle, MessageKind.Progress);

            // compress audio if needed, with progress message
            if (AudioProcessor.IsAnyCompressedAudioMissing(book.FolderPath, book.RawDom))
            {
                progress.Message("CompressingAudio", "Compressing audio files");
                AudioProcessor.TryCompressingAudioAsNeeded(book.FolderPath, book.RawDom);
            }
            var publishedFileName = bookTitle + BookCompressor.ExtensionForDeviceBloomBook;

            if (startingMessageFunction != null)
            {
                progress.MessageWithoutLocalizing(startingMessageFunction(publishedFileName, bookTitle));
            }
            if (destFileName == null)
            {
                // wifi or usb...make the .bloomd in a temp folder.
                using (var bloomdTempFile = TempFile.WithFilenameInTempFolder(publishedFileName))
                {
                    BloomReaderFileMaker.CreateBloomDigitalBook(bloomdTempFile.Path, book, bookServer, backColor, progress, settings);
                    sendAction(publishedFileName, bloomdTempFile.Path);
                    if (confirmFunction != null && !confirmFunction(publishedFileName))
                    {
                        throw new ApplicationException("Book does not exist after write operation.");
                    }
                    progress.MessageUsingTitle("BookSent", "You can now read \"{0}\" in Bloom Reader!", bookTitle, MessageKind.Note);
                }
            }
            else
            {
                // save file...user has supplied name, there is no further action.
                Debug.Assert(sendAction == null, "further actions are not supported when passing a path name");
                BloomReaderFileMaker.CreateBloomDigitalBook(destFileName, book, bookServer, backColor, progress, settings);
                progress.Message("PublishTab.Epub.Done", "Done", useL10nIdPrefix: false);                       // share message string with epub publishing
            }
        }
        // Precondition: bulkSaveSettings must be non-null
        public void PublishAllBooks(BulkBloomPubPublishSettings bulkSaveSettings)
        {
            BrowserProgressDialog.DoWorkWithProgressDialog(_webSocketServer, "Bulk Save BloomPubs",
                                                           (progress, worker) =>
            {
                var dest = new TemporaryFolder("BloomPubs");
                progress.MessageWithoutLocalizing($"Creating files in {dest.FolderPath}...");

                var filenameWithoutExtension = _collectionModel.CollectionSettings.DefaultBookshelf.SanitizeFilename(' ', true);
                ;
                if (bulkSaveSettings.makeBookshelfFile)
                {
                    // see https://docs.google.com/document/d/1UUvwxJ32W2X5CRgq-TS-1HmPj7gCKH9Y9bxZKbmpdAI

                    progress.MessageWithoutLocalizing($"Creating bloomshelf file...");
                    System.Diagnostics.Debug.Assert(!bulkSaveSettings.bookshelfColor.Contains("\n") && !bulkSaveSettings.bookshelfColor.Contains("\r"), "(BL-10190 Repro) Invalid bookshelfColor setting (contains newline). Please investigate!");
                    var colorString = getBloomReaderColorString(bulkSaveSettings.bookshelfColor);
                    System.Diagnostics.Debug.Assert(!colorString.Contains("\n") && !colorString.Contains("\r"), "(BL-10190 Repro) Invalid computed colorString value (contains newline). Please investigate!");

                    // OK I know this looks lame but trust me, using jsconvert to make that trivial label array is way too verbose.
                    var template =
                        "{ 'label': [{ 'en': 'bookshelf-name'}], 'id': 'id-of-the-bookshelf', 'color': 'hex-color-value'}";
                    var json = template.Replace('\'', '"')
                               .Replace("bookshelf-name", bulkSaveSettings.bookshelfLabel.Replace('"', '\''))
                               .Replace("id-of-the-bookshelf", _collectionModel.CollectionSettings.DefaultBookshelf)
                               .Replace("hex-color-value", colorString);
                    var filename       = $"{filenameWithoutExtension}.bloomshelf";
                    var bloomShelfPath = Path.Combine(dest.FolderPath, filename);
                    RobustFile.WriteAllText(bloomShelfPath, json, Encoding.UTF8);
                }

                foreach (var bookInfo in _collectionModel.TheOneEditableCollection.GetBookInfos())
                {
                    if (worker.CancellationPending)
                    {
                        progress.MessageWithoutLocalizing("Cancelled.");
                        return(true);
                    }
                    progress.MessageWithoutLocalizing($"Making BloomPUB for {bookInfo.QuickTitleUserDisplay}...",
                                                      ProgressKind.Heading);

                    var settings             = AndroidPublishSettings.GetPublishSettingsForBook(_bookServer, bookInfo);
                    settings.DistributionTag = bulkSaveSettings.distributionTag;
                    if (bulkSaveSettings.makeBookshelfFile)
                    {
                        settings.BookshelfTag = _collectionModel.CollectionSettings.DefaultBookshelf;
                    }
                    BloomPubMaker.CreateBloomPub(bookInfo, settings, dest.FolderPath, _bookServer, progress);
                }

                if (bulkSaveSettings.makeBloomBundle)
                {
                    var bloomBundlePath = Path.Combine(dest.FolderPath, $"{filenameWithoutExtension}.bloombundle");

                    var bloomBundleFile = new BloomTarArchive(bloomBundlePath);
                    bloomBundleFile.AddDirectoryContents(dest.FolderPath, new string[] { ".bloombundle" });
                    bloomBundleFile.Save();
                }

                progress.MessageWithoutLocalizing("Done.", ProgressKind.Heading);
                Process.SafeStart(dest.FolderPath);
                // true means wait for the user, don't close automatically
                return(true);
            });
        }
Exemple #12
0
        public static Book.Book PrepareBookForBloomReader(string bookFolderPath, BookServer bookServer, TemporaryFolder temp,
                                                          WebSocketProgress progress, string creator = "bloom", AndroidPublishSettings settings = null)
        {
            // MakeDeviceXmatterTempBook needs to be able to copy customCollectionStyles.css etc into parent of bookFolderPath
            // And bloom-player expects folder name to match html file name.
            var htmPath = BookStorage.FindBookHtmlInFolder(bookFolderPath);
            var tentativeBookFolderPath = Path.Combine(temp.FolderPath, Path.GetFileNameWithoutExtension(htmPath));

            Directory.CreateDirectory(tentativeBookFolderPath);
            var modifiedBook = PublishHelper.MakeDeviceXmatterTempBook(bookFolderPath, bookServer, tentativeBookFolderPath);

            // Although usually tentativeBookFolderPath and modifiedBook.FolderPath are the same, there are some exceptions
            // In the process of bringing a book up-to-date (called by MakeDeviceXmatterTempBook), the folder path may change.
            // For example, it could change if the original folder path contains punctuation marks now deemed dangerous.
            //    The book will be moved to the sanitized version of the file name instead.
            // It can also happen if we end up picking a different version of the title (i.e. in a different language)
            //    than the one written to the .htm file.
            string modifiedBookFolderPath = modifiedBook.FolderPath;

            if (modifiedBook.CollectionSettings.HaveEnterpriseFeatures)
            {
                ProcessQuizzes(modifiedBookFolderPath, modifiedBook.RawDom);
            }

            // Right here, let's maintain the history of what the BloomdVersion signifies to a reader.
            // Version 1 (as opposed to no BloomdVersion field): the bookFeatures property may be
            // used to report features analytics (with earlier bloomd's, the reader must use its own logic)
            modifiedBook.Storage.BookInfo.MetaData.BloomdVersion = 1;

            if (settings?.LanguagesToInclude != null)
            {
                PublishModel.RemoveUnwantedLanguageData(modifiedBook.OurHtmlDom, settings.LanguagesToInclude, modifiedBook.CollectionSettings.Language2.Iso639Code);
            }
            else if (Program.RunningHarvesterMode && modifiedBook.OurHtmlDom.SelectSingleNode(BookStorage.ComicalXpath) != null)
            {
                // This indicates that we are harvesting a book with comic speech bubbles.
                // For comical books, we only publish a single language. It's not currently feasible to
                // allow the reader to switch language in a Comical book, because typically that requires
                // adjusting the positions of the bubbles, and we don't yet support having more than one
                // set of bubble locations in a single book. See BL-7912 for some ideas on how we might
                // eventually improve this. In the meantime, switching language would have bad effects,
                // and if you can't switch language, there's no point in the book containing more than one.
                var languagesToInclude = new string[1] {
                    modifiedBook.CollectionSettings.Language1.Iso639Code
                };
                PublishModel.RemoveUnwantedLanguageData(modifiedBook.OurHtmlDom, languagesToInclude, modifiedBook.CollectionSettings.Language2.Iso639Code);
            }

            // Do this after processing interactive pages, as they can satisfy the criteria for being 'blank'
            HashSet <string> fontsUsed = null;

            using (var helper = new PublishHelper())
            {
                helper.ControlForInvoke = ControlForInvoke;
                ISet <string> warningMessages = new HashSet <string>();
                helper.RemoveUnwantedContent(modifiedBook.OurHtmlDom, modifiedBook, false, warningMessages);
                PublishHelper.SendBatchedWarningMessagesToProgress(warningMessages, progress);
                fontsUsed = helper.FontsUsed;
            }
            modifiedBook.RemoveBlankPages(settings?.LanguagesToInclude);

            // See https://issues.bloomlibrary.org/youtrack/issue/BL-6835.
            RemoveInvisibleImageElements(modifiedBook);
            modifiedBook.Storage.CleanupUnusedImageFiles(keepFilesForEditing: false);
            if (RobustFile.Exists(Path.Combine(modifiedBookFolderPath, "placeHolder.png")))
            {
                RobustFile.Delete(Path.Combine(modifiedBookFolderPath, "placeHolder.png"));
            }

            modifiedBook.Storage.CleanupUnusedAudioFiles(isForPublish: true);
            modifiedBook.RemoveObsoleteAudioMarkup();
            modifiedBook.Storage.CleanupUnusedVideoFiles();

            // We want these to run after RemoveUnwantedContent() so that the metadata will more accurately reflect
            // the subset of contents that are included in the .bloomd
            modifiedBook.UpdateMetadataFeatures(
                isBlindEnabled: true,
                isSignLanguageEnabled: true,
                isTalkingBookEnabled: true);

            modifiedBook.SetAnimationDurationsFromAudioDurations();

            modifiedBook.OurHtmlDom.SetMedia("bloomReader");
            modifiedBook.OurHtmlDom.AddOrReplaceMetaElement("bloom-digital-creator", creator);
            EmbedFonts(modifiedBook, progress, fontsUsed, new FontFileFinder());

            var bookFile = BookStorage.FindBookHtmlInFolder(modifiedBook.FolderPath);

            StripImgIfWeCannotFindFile(modifiedBook.RawDom, bookFile);
            StripContentEditableAndTabIndex(modifiedBook.RawDom);
            InsertReaderStylesheet(modifiedBook.RawDom);
            RobustFile.Copy(FileLocationUtilities.GetFileDistributedWithApplication(BloomFileLocator.BrowserRoot, "publish", "ReaderPublish", "readerStyles.css"),
                            Path.Combine(modifiedBookFolderPath, "readerStyles.css"));
            ConvertImagesToBackground(modifiedBook.RawDom);

            modifiedBook.Save();

            return(modifiedBook);
        }
Exemple #13
0
 // Create a BloomReader book while also creating the temporary folder for it (according to the specified parameter) and disposing of it
 public static void CreateBloomDigitalBook(string outputPath, string bookFolderPath, BookServer bookServer, Color backColor,
                                           WebSocketProgress progress, string tempFolderName = BRExportFolder, AndroidPublishSettings settings = null)
 {
     using (var temp = new TemporaryFolder(tempFolderName))
     {
         CreateBloomDigitalBook(outputPath, bookFolderPath, bookServer, backColor, progress, temp,
                                settings: settings);
     }
 }
Exemple #14
0
 public static void CreateBloomDigitalBook(string outputPath, Book.Book book, BookServer bookServer, Color backColor, WebSocketProgress progress, AndroidPublishSettings settings = null)
 {
     CreateBloomDigitalBook(outputPath, book.FolderPath, bookServer, backColor, progress, settings: settings);
 }