Пример #1
0
        private void Recorder_Stopped(IAudioRecorder arg1, ErrorEventArgs arg2)
        {
            Recorder.Stopped -= Recorder_Stopped;
            Directory.CreateDirectory(System.IO.Path.GetDirectoryName(PathToCurrentAudioSegment));             // make sure audio directory exists
            int millisecondsToTrimFromEndForMouseClick = 100;

            try
            {
                var minimum = TimeSpan.FromMilliseconds(300);           // this is arbitrary
                AudioRecorder.TrimWavFile(PathToTemporaryWav, PathToCurrentAudioSegment, new TimeSpan(), TimeSpan.FromMilliseconds(millisecondsToTrimFromEndForMouseClick), minimum);
                RobustFile.Delete(PathToTemporaryWav);                  // Otherwise, these continue to clutter up the temp directory.
            }
            catch (Exception error)
            {
                Logger.WriteEvent(error.Message);
                RobustFile.Copy(PathToTemporaryWav, PathToCurrentAudioSegment, true);
            }

            //We don't actually need the mp3 now, so let people play with recording even without LAME (previously it could crash BL-3159).
            //We could put this off entirely until we make the ePUB.
            //I'm just gating this for now because maybe the thought was that it's better to do it a little at a time?
            //That's fine so long as it doesn't make the UI unresponsive on slow machines.
            if (LameEncoder.IsAvailable())
            {
                _mp3Encoder.Encode(PathToCurrentAudioSegment, PathToCurrentAudioSegment.Substring(0, PathToCurrentAudioSegment.Length - 4), new NullProgress());
                // Note: we need to keep the .wav file as well as the mp3 one. The mp3 format (or alternative mp4)
                // is required for ePUB. The wav file is a better permanent record of the recording; also,
                // it is used for playback.
            }
        }
        private static void AddRequisiteJsFiles(string path)
        {
            const string bloomPlayerFileName = "bloomPlayer.js";
            var          bloomLibraryJsPath  = FileLocator.GetFileDistributedWithApplication(bloomPlayerFileName);

            RobustFile.Copy(bloomLibraryJsPath, Path.Combine(path, bloomPlayerFileName), true);
        }
        public void OneTimeSetUp()
        {
            var dom = new HtmlDom(imageBook, true);

            _spreadsheetFolder = new TemporaryFolder("SpreadsheetImagesTests");
            _bookFolder        = new TemporaryFolder("SpreadsheetImagesTests_Book");

            var mockLangDisplayNameResolver = new Mock <ILanguageDisplayNameResolver>();

            mockLangDisplayNameResolver.Setup(x => x.GetLanguageDisplayName("en")).Returns("English");

            _exporter = new SpreadsheetExporter(mockLangDisplayNameResolver.Object);
            var path = SIL.IO.FileLocationUtilities.GetDirectoryDistributedWithApplication(_pathToTestImages);

            // We need all these files in one place so we can verify that all of them get copied except placeHolder.png
            foreach (var name in new [] { "BloomWithTaglineAgainstLight.svg", "man.jpg", "Mars 2.png", "lady24b.png", "empty-file.jpg" })
            {
                RobustFile.Copy(Path.Combine(path, name), Path.Combine(_bookFolder.FolderPath, name));
            }
            var placeHolderSource = Path.Combine(BloomFileLocator.FactoryCollectionsDirectory, "template books", "Basic Book", "placeHolder.png");

            RobustFile.Copy(placeHolderSource, Path.Combine(_bookFolder.FolderPath, "placeHolder.png"));

            _progressSpy     = new ProgressSpy();
            _sheetFromExport =
                _exporter.ExportToFolder(dom, _bookFolder.FolderPath, _spreadsheetFolder.FolderPath, out string outputPath, _progressSpy, OverwriteOptions.Overwrite);
            _rowsFromExport = _sheetFromExport.ContentRows.ToList();
            _sheetFromFile  = InternalSpreadsheet.ReadFromFile(outputPath);
            _rowsFromFile   = _sheetFromFile.ContentRows.ToList();
        }
Пример #4
0
        private static void HandleAppUpdate(UpdateManager mgr)
        {
            mgr.CreateShortcutForThisExe();

            // See BL-4590 where an upgrade from a clean 3.7.22 to 3.8 either would get no Bloom.exe stub, or get one of 0KB.
            // This is nominally because the installer in 3.7.22 did not use this stub technique... though we don't know why the upgrade
            // process gave us a 0kb attempt at the stub. So we're fixing it here because we need to push this out quickly.
            var stubPath = Application.ExecutablePath.Replace(".exe", "_ExecutionStub.exe");

            // If the move succeeds, then the stub file won't be in our main bin directory anymore... it will already be moved up to the parent
            // directory. So basically we're just "trying again" here, sigh...
            if (File.Exists(stubPath))
            {
                try
                {
                    // the target is the parent directory, and the file name without the "_ExecutionStub" part of the name.
                    var targetPath = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(Application.ExecutablePath)),
                                                  Path.GetFileName(Application.ExecutablePath));
                    RobustFile.Copy(stubPath, targetPath, true);
                }
                catch (Exception e)
                {
                    throw new ApplicationException("Bloom failed to copy the execution stub: " + e.Message, e);
                }
            }
        }
Пример #5
0
 private void CopyImageFileToDestination(string destFileName, string fullSpreadsheetPath, XmlElement imgElement = null)
 {
     try
     {
         if (_pathToBookFolder != null && _pathToSpreadsheetFolder != null)
         {
             var dest = Path.Combine(_pathToBookFolder, destFileName);
             if (RobustFile.Exists(fullSpreadsheetPath))
             {
                 RobustFile.Copy(fullSpreadsheetPath, dest, true);
                 if (imgElement != null)
                 {
                     ImageUpdater.UpdateImgMetadataAttributesToMatchImage(_pathToBookFolder, imgElement,
                                                                          new NullProgress());
                 }
             }
             else
             {
                 // Review: I doubt these messages are worth localizing? The sort of people who attempt
                 // spreadsheet import can likely cope with some English?
                 // +1 conversion from zero-based to 1-based counting, further adding header.RowCount
                 // makes it match up with the actual row label in the spreadsheet.
                 Warn(
                     $"Image \"{fullSpreadsheetPath}\" on row {_currentRowIndex + 1 + _sheet.Header.RowCount} was not found.");
             }
         }
     }
     catch (Exception e) when(e is IOException || e is SecurityException ||
                              e is UnauthorizedAccessException)
     {
         Warn(
             $"Bloom had trouble copying the file {fullSpreadsheetPath} to the book folder or retrieving its metadata: " +
             e.Message);
     }
 }
Пример #6
0
        // Request from sign language tool to import a video.
        private void HandleImportVideoRequest(ApiRequest request)
        {
            string path = null;

            View.Invoke((Action)(() => {
                var videoFiles = LocalizationManager.GetString("EditTab.Toolbox.SignLanguage.FileDialogVideoFiles", "Video files");
                var dlg = new DialogAdapters.OpenFileDialogAdapter
                {
                    Multiselect = false,
                    CheckFileExists = true,
                    Filter = $"{videoFiles} (*.mp4)|*.mp4"
                };
                var result = dlg.ShowDialog();
                if (result == DialogResult.OK)
                {
                    path = dlg.FileName;
                }
            }));
            if (!string.IsNullOrEmpty(path))
            {
                _importedVideoIntoBloom = true;
                var newVideoPath = Path.Combine(BookStorage.GetVideoDirectoryAndEnsureExistence(CurrentBook.FolderPath), GetNewVideoFileName());                 // Use a new name to defeat caching.
                RobustFile.Copy(path, newVideoPath);
                var relativePath = BookStorage.GetVideoFolderName + Path.GetFileName(newVideoPath);
                request.ReplyWithText(UrlPathString.CreateFromUnencodedString(relativePath).UrlEncodedForHttpPath);
            }
            else
            {
                // If the user canceled, we didn't exactly succeed, but having the user cancel is such a normal
                // event that posting a failure, which is a nuisance to ignore, is not warranted.
                request.ReplyWithText("");
            }
        }
Пример #7
0
 private static void CopyFolder(string sourcePath, string destinationPath)
 {
     Directory.CreateDirectory(destinationPath);
     foreach (var filePath in Directory.GetFiles(sourcePath))
     {
         //better to not just copy the old thumbnail, as the on in the library may well need to look different
         if (Path.GetFileNameWithoutExtension(filePath).ToLowerInvariant() == "thumbnail")
         {
             continue;
         }
         if (Path.GetFileNameWithoutExtension(filePath).StartsWith("."))                 //.guidsForInstaller.xml
         {
             continue;
         }
         var ext = Path.GetExtension(filePath).ToLowerInvariant();
         // We don't need to copy any backups, and we don't want userPrefs because they are likely
         // to include a page number and we want the new book to open at the cover.
         if (new String[] { ".jade", ".less", ".md", ".bak", ".userprefs" }.Any(ex => ex == ext))
         {
             continue;
         }
         RobustFile.Copy(filePath, Path.Combine(destinationPath, Path.GetFileName(filePath)));
     }
     foreach (var dirPath in Directory.GetDirectories(sourcePath))
     {
         //any files found under "template" will not be copied. At the moment (Aug 2015), this is only
         //thumbnail svgs, but we could move readme's and such in there
         var directoriesToSkip = new[] { "template", Book.ReadMeImagesFolderName.ToLowerInvariant() };
         if (!directoriesToSkip.Contains(Path.GetFileName(dirPath).ToLowerInvariant()))
         {
             CopyFolder(dirPath, Path.Combine(destinationPath, Path.GetFileName(dirPath)));
         }
     }
 }
Пример #8
0
        private void CopyFile(ApiRequest request)
        {
            dynamic jsonData = DynamicJson.Parse(request.RequiredPostJson());

            RobustFile.Copy(jsonData.from, jsonData.to, true);
            request.PostSucceeded();
        }
Пример #9
0
        public void CopyEmptyFile()
        {
            // Create an empty file.
            var emptyFile = Path.GetTempFileName();

            Assert.IsTrue(RobustFile.Exists(emptyFile));
            var info = new FileInfo(emptyFile);

            Assert.AreEqual(0, info.Length);

            var destName = emptyFile + "-xyzzy";

            // This was throwing a System.ArgumentOutOfRangeException exception before being fixed.
            RobustFile.Copy(emptyFile, destName, true);
            Assert.IsTrue(RobustFile.Exists(destName));
            var infoDest = new FileInfo(destName);

            Assert.AreEqual(0, infoDest.Length);

            // Clean up after ourselves.
            RobustFile.Delete(emptyFile);
            Assert.IsFalse(RobustFile.Exists(emptyFile));
            RobustFile.Delete(destName);
            Assert.IsFalse(RobustFile.Exists(destName));
        }
Пример #10
0
        private void CopyFile(ApiRequest request)
        {
            dynamic jsonData;

            try
            {
                jsonData = DynamicJson.Parse(request.RequiredPostJson());
            }
            catch (Exception e)
            {
                request.Failed(HttpStatusCode.BadRequest, $"BadRequest: {e.ToString()}");
                return;
            }

            try
            {
                RobustFile.Copy(jsonData.from, jsonData.to, true);
            }
            catch (Exception e)
            {
                request.Failed(HttpStatusCode.InternalServerError, "InternalServerError while copying file. " + e.ToString());
                return;
            }

            request.PostSucceeded();
        }
        /// <summary>
        /// We keep reader tool settings for each language in %localappdata%/SIL/Bloom.
        /// e.g., for language kaj, we would expect to find
        /// ReaderToolsSettings-kaj.json
        /// ReaderToolsWords-kaj.json
        /// and possibly a folder with allowed words lists for stages:
        /// Allowed Words-kaj.
        /// A typical reader tools BloomPack only has one of each, but we allow for the possibility of more.
        /// </summary>
        /// <param name="newlyAddedFolderOfThePack"></param>
        internal static void CopyReaderToolsSettingsToWhereTheyBelong(string newlyAddedFolderOfThePack)
        {
            var destFolder = ProjectContext.GetBloomAppDataFolder();

            foreach (var readerSettingsFile in Directory.GetFiles(newlyAddedFolderOfThePack, ReaderToolsSettingsPrefix + "*.json")
                     .Concat(Directory.GetFiles(newlyAddedFolderOfThePack, "ReaderToolsWords-*.json")))
            {
                try
                {
                    var readerSettingsFileName = Path.GetFileName(readerSettingsFile);
                    RobustFile.Copy(readerSettingsFile, Path.Combine(destFolder, readerSettingsFileName), true);
                    if (readerSettingsFileName.StartsWith(ReaderToolsSettingsPrefix))
                    {
                        var langCode =
                            Path.GetFileNameWithoutExtension(readerSettingsFileName.Substring(ReaderToolsSettingsPrefix.Length));

                        var allowedWordsSource = Path.Combine(newlyAddedFolderOfThePack, AllowedWordsFolderName);
                        var allowedWordsDest   = Path.Combine(destFolder, AllowedWordsFolderName + "-" + langCode);
                        CopyAllowedWords(allowedWordsSource, allowedWordsDest);
                    }
                }
                catch (IOException e)
                {
                    ProblemReportApi.ShowProblemDialog(null, e,
                                                       "Problem copying Reader Tools Settings from an installed BloomPack.", "nonfatal");
                }
            }
        }
Пример #12
0
        private string GetSampleTextsList(string settingsFilePath)
        {
            var path = Path.Combine(Path.GetDirectoryName(settingsFilePath), "Sample Texts");

            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            var fileList1    = new List <string>();
            var langFileName = String.Format(DecodableReaderToolSettings.kSynphonyLanguageDataFileNameFormat,
                                             CurrentBook.BookData.Language1.Iso639Code);
            var langFile = Path.Combine(path, langFileName);

            // if the Sample Texts directory is empty, check for ReaderToolsWords-<iso>.json in ProjectContext.GetBloomAppDataFolder()
            if (DirectoryHelper.IsEmpty(path, true))
            {
                var bloomAppDirInfo = new DirectoryInfo(ProjectContext.GetBloomAppDataFolder());

                // get the most recent file
                var foundFile = bloomAppDirInfo.GetFiles(langFileName, SearchOption.AllDirectories).OrderByDescending(fi => fi.LastWriteTime).FirstOrDefault();

                if (foundFile != null)
                {
                    // copy it
                    RobustFile.Copy(Path.Combine(foundFile.DirectoryName, foundFile.Name), langFile);
                }

                return(String.Empty);
            }

            // first look for ReaderToolsWords-<iso>.json
            if (RobustFile.Exists(langFile))
            {
                fileList1.Add(langFile);
            }

            // next look for <language_name>_lang_data.js
            foreach (var file in Directory.GetFiles(path, "*" + kSynphonyFileNameSuffix))
            {
                if (!fileList1.Contains(file))
                {
                    fileList1.Add(file);
                }
            }

            // now add the rest
            foreach (var file in Directory.GetFiles(path))
            {
                if (!fileList1.Contains(file))
                {
                    fileList1.Add(file);
                }
            }

            return(String.Join("\r", fileList1.ToArray()));
        }
        /// <summary>
        /// Process the input PDF file by compressing images and/or by converting color to CMYK.  The operations
        /// to perform are established by the constructor.
        /// </summary>
        public void ProcessPdfFile(string inputFile, string outputFile)
        {
            _inputPdfPath  = inputFile;
            _outputPdfPath = outputFile;
            var exePath = "/usr/bin/gs";

            if (SIL.PlatformUtilities.Platform.IsWindows)
            {
                exePath = FindGhostcriptOnWindows();
            }
            if (!String.IsNullOrWhiteSpace(exePath) && File.Exists(exePath))
            {
                if (_worker != null)
                {
                    _worker.ReportProgress(0, GetSpecificStatus());
                }
                using (var tempPdfFile = TempFile.WithExtension(".pdf"))
                {
                    var runner        = new CommandLineRunner();
                    var arguments     = GetArguments(tempPdfFile.Path);
                    var fromDirectory = String.Empty;
                    var progress      = new NullProgress();                     // I can't figure out how to use any IProgress based code, but we show progress okay as is.
                    var res           = runner.Start(exePath, arguments, Encoding.UTF8, fromDirectory, 3600, progress, ProcessGhostcriptReporting);
                    if (res.DidTimeOut || !RobustFile.Exists(tempPdfFile.Path))
                    {
                        if (_inputPdfPath != _outputPdfPath)
                        {
                            RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                        }
                        return;
                    }
                    // If the process made the file larger and didn't change the color scheme, ignore the result.
                    var oldInfo = new FileInfo(_inputPdfPath);
                    var newInfo = new FileInfo(tempPdfFile.Path);
                    if (newInfo.Length < oldInfo.Length || _type == OutputType.Printshop)
                    {
                        RobustFile.Copy(tempPdfFile.Path, _outputPdfPath, true);
                    }
                    else if (_inputPdfPath != _outputPdfPath)
                    {
                        RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                    }
                }
            }
            else
            {
                // This shouldn't happen.  Linux Bloom package depends on the ghostscript package, and we'll include
                // ghostscript files in our installer to ensure it's available on Windows.  But we have this code here
                // as a failsafe fallback reminding the developers to ensure this installation work happens.
                Debug.WriteLine("ghostscript is not installed, so Bloom cannot process the PDF file.");
                if (_inputPdfPath != _outputPdfPath)
                {
                    RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                }
            }
        }
Пример #14
0
        private void MakeCollectionCSSIfMissing()
        {
            string path = Path.Combine(_path, "customCollectionStyles.css");

            if (RobustFile.Exists(path))
            {
                return;
            }
            RobustFile.Copy(BloomFileLocator.GetBrowserFile(false, "bookLayout", "collection styles override template.css"), path);
        }
Пример #15
0
 /// <summary>
 /// Copy a folder's content to another folder, creating the destination folder if needed.
 /// </summary>
 /// <remarks>
 /// It's hard to believe this isn't already standard somewhere.
 /// </remarks>
 public static void CopyFolder(string sourcePath, string destinationPath)
 {
     Directory.CreateDirectory(destinationPath);
     foreach (var filePath in Directory.GetFiles(sourcePath))
     {
         RobustFile.Copy(filePath, Path.Combine(destinationPath, Path.GetFileName(filePath)));
     }
     foreach (var dirPath in Directory.GetDirectories(sourcePath))
     {
         CopyFolder(dirPath, Path.Combine(destinationPath, Path.GetFileName(dirPath)));
     }
 }
Пример #16
0
        /// <summary>
        /// Common routine used in normal upload and bulk upload.
        /// </summary>
        /// <param name="book"></param>
        /// <param name="progressBox"></param>
        /// <param name="publishView"></param>
        /// <param name="languages"></param>
        /// <param name="parseId"></param>
        /// <param name="excludeAudio"></param>
        /// <returns></returns>
        internal string FullUpload(Book.Book book, LogBox progressBox, PublishView publishView, string[] languages, out string parseId, bool excludeAudio = true)
        {
            var bookFolder = book.FolderPath;

            parseId = "";             // in case of early return
            // Set this in the metadata so it gets uploaded. Do this in the background task as it can take some time.
            // These bits of data can't easily be set while saving the book because we save one page at a time
            // and they apply to the book as a whole.
            book.BookInfo.LanguageTableReferences = _parseClient.GetLanguagePointers(book.CollectionSettings.MakeLanguageUploadData(languages));
            book.BookInfo.PageCount = book.GetPages().Count();
            book.BookInfo.Save();
            progressBox.WriteStatus(LocalizationManager.GetString("PublishTab.Upload.MakingThumbnail", "Making thumbnail image..."));
            //the largest thumbnail I found on Amazon was 300px high. Prathambooks.org about the same.
            _thumbnailer.MakeThumbnailOfCover(book, 70);             // this is a sacrificial one to prime the pump, to fix BL-2673
            _thumbnailer.MakeThumbnailOfCover(book, 70);
            if (progressBox.CancelRequested)
            {
                return("");
            }
            _thumbnailer.MakeThumbnailOfCover(book, 256);
            if (progressBox.CancelRequested)
            {
                return("");
            }

            // It is possible the user never went back to the Collection tab after creating/updating the book, in which case
            // the 'normal' thumbnail never got created/updating. See http://issues.bloomlibrary.org/youtrack/issue/BL-3469.
            _thumbnailer.MakeThumbnailOfCover(book);
            if (progressBox.CancelRequested)
            {
                return("");
            }

            var uploadPdfPath = UploadPdfPath(bookFolder);

            // If there is not already a locked preview in the book folder
            // (which we take to mean the user has created a customized one that he prefers),
            // make sure we have a current correct preview and then copy it to the book folder so it gets uploaded.
            if (!FileUtils.IsFileLocked(uploadPdfPath))
            {
                progressBox.WriteStatus(LocalizationManager.GetString("PublishTab.Upload.MakingPdf", "Making PDF Preview..."));
                publishView.MakePublishPreview();
                if (RobustFile.Exists(publishView.PdfPreviewPath))
                {
                    RobustFile.Copy(publishView.PdfPreviewPath, uploadPdfPath, true);
                }
            }
            if (progressBox.CancelRequested)
            {
                return("");
            }
            return(UploadBook(bookFolder, progressBox, out parseId, Path.GetFileName(uploadPdfPath), excludeAudio));
        }
Пример #17
0
        private string ShowSelectAllowedWordsFileDialog()
        {
            var returnVal = "";

            var destPath = Path.Combine(Path.GetDirectoryName(CurrentBook.CollectionSettings.SettingsFilePath), "Allowed Words");

            if (!Directory.Exists(destPath))
            {
                Directory.CreateDirectory(destPath);
            }

            var textFiles = LocalizationManager.GetString("EditTab.Toolbox.DecodableReaderTool.FileDialogTextFiles", "Text files");
            var dlg       = new OpenFileDialog
            {
                Multiselect     = false,
                CheckFileExists = true,
                Filter          = String.Format("{0} (*.txt;*.csv;*.tab)|*.txt;*.csv;*.tab", textFiles)
            };
            var result = dlg.ShowDialog();

            if (result == DialogResult.OK)
            {
                var srcFile  = dlg.FileName;
                var destFile = Path.GetFileName(srcFile);
                if (destFile != null)
                {
                    // if file is in the "Allowed Words" directory, do not try to copy it again.
                    if (Path.GetFullPath(srcFile) != Path.Combine(destPath, destFile))
                    {
                        var i = 0;

                        // get a unique destination file name
                        while (RobustFile.Exists(Path.Combine(destPath, destFile)))
                        {
                            destFile = Path.GetFileName(srcFile);
                            var fileExt = Path.GetExtension(srcFile);
                            destFile = destFile.Substring(0, destFile.Length - fileExt.Length) + " - Copy";
                            if (++i > 1)
                            {
                                destFile += " " + i;
                            }
                            destFile += fileExt;
                        }

                        RobustFile.Copy(srcFile, Path.Combine(destPath, destFile));
                    }

                    returnVal = destFile;
                }
            }

            return(returnVal);
        }
Пример #18
0
        /// <summary>
        /// Copy the versification file from the text bundle to destinationPath
        /// </summary>
        public void CopyVersificationFile(string destinationPath)
        {
            string versificationPath = Path.Combine(PathToUnzippedBundleInnards, DblBundleFileUtils.kVersificationFileName);

            if (!File.Exists(versificationPath))
            {
                throw new ApplicationException(
                          string.Format("Attempted to copy {0} from the bundle but {0} does not exist in this bundle.", DblBundleFileUtils.kVersificationFileName));
            }

            RobustFile.Copy(versificationPath, destinationPath, true);
        }
Пример #19
0
 /// <summary>
 /// Copy a folder's content to another folder, creating the destination folder if needed.
 /// </summary>
 /// <remarks>
 /// It's hard to believe this isn't already standard somewhere.
 /// </remarks>
 public static void CopyFolder(string sourcePath, string destinationPath)
 {
     Utils.LongPathAware.ThrowIfExceedsMaxPath(sourcePath);
     Utils.LongPathAware.ThrowIfExceedsMaxPath(destinationPath);             //example: BL-10353
     Directory.CreateDirectory(destinationPath);
     foreach (var filePath in Directory.GetFiles(sourcePath))
     {
         RobustFile.Copy(filePath, Path.Combine(destinationPath, Path.GetFileName(filePath)));
     }
     foreach (var dirPath in Directory.GetDirectories(sourcePath))
     {
         CopyFolder(dirPath, Path.Combine(destinationPath, Path.GetFileName(dirPath)));
     }
 }
Пример #20
0
        /// <summary>
        /// Save the video file, first processing it with ffmpeg (if possible) to convert the data to a more
        /// common and more compressed format (h264 instead of vp8) and to insert keyframes every half second.
        /// Processing with ffmpeg also has the effect of setting the duration value for the video as a whole,
        /// something which is sadly lacking in the video data coming directly from mozilla browser code.
        /// If ffmpeg is not available, then the file is stored exactly as it comes from the api call.
        /// </summary>
        /// <remarks>
        /// Explicitly setting the frame rate to 30 fps is needed for Geckofx60.  The raw file that comes
        /// directly from the javascript objects claims to be at 1000fps.  This is perhaps due to the high
        /// speed video cameras that claim up to that frame rate.  I can't figure out how to change the frame
        /// rate in javascript.  The video track already claims to be at 30 fps even though the raw file
        /// claims to be at 1000fps.  Interestingly, setting the frame rate explicitly speeds up ffmpeg
        /// processing to what it was with Geckofx45 instead of being much slower.
        /// See https://issues.bloomlibrary.org/youtrack/issue/BL-7934.
        /// </remarks>
        private static void SaveVideoFile(string path, string rawVideoPath)
        {
            var length  = new FileInfo(rawVideoPath).Length;
            var seconds = (int)(length / 312500);             // we're asking for 2.5mpbs, which works out to 312.5K bytes per second.

            if (!string.IsNullOrEmpty(FfmpegProgram))
            {
                // -hide_banner = don't write all the version and build information to the console
                // -y = always overwrite output file
                // -v 16 = verbosity level reports only errors, including ones that can be recovered from
                // -i <path> = specify input file
                // -r 30 = set frame rate to 30 fps
                // -force_key_frames "expr:gte(t,n_forced*0.5)" = insert keyframe every 0.5 seconds in the output file
                var parameters = $"-hide_banner -y -v 16 -i \"{rawVideoPath}\" -r 30 -force_key_frames \"expr:gte(t,n_forced*0.5)\" \"{path}\"";
                // On slowish machines, this compression seems to take about 1/5 as long as the video took to record.
                // Allowing for some possibly being slower still, we're basing the timeout on half the length of the video,
                // plus a minute to be sure.
                var result = CommandLineRunner.Run(FfmpegProgram, parameters, "", seconds / 2 + 60, new NullProgress());
                var msg    = string.Empty;
                if (result.DidTimeOut)
                {
                    msg = LocalizationManager.GetString("EditTab.Toolbox.SignLanguage.Timeout",
                                                        "The initial processing of the video file timed out after one minute.  The raw video output will be stored.");
                }
                else
                {
                    var output = result.StandardError;
                    if (!string.IsNullOrWhiteSpace(output))
                    {
                        // Even though it may be possible to recover from the error, we'll just notify the user and use the raw vp8 output.
                        var format = LocalizationManager.GetString("EditTab.Toolbox.SignLanguage.VideoProcessingError",
                                                                   "Error output from ffmpeg trying to produce {0}: {1}{2}The raw video output will be stored.",
                                                                   "{0} is the path to the video file, {1} is the error message from the ffmpeg program, and {2} is a newline character");
                        msg = string.Format(format, path, output, Environment.NewLine);
                    }
                }
                if (!string.IsNullOrEmpty(msg))
                {
                    Logger.WriteEvent(msg);
                    ErrorReport.NotifyUserOfProblem(msg);
                    RobustFile.Copy(rawVideoPath, path, true);                         // use the original, hoping it's better than nothing.
                }
            }
            else
            {
                RobustFile.Copy(rawVideoPath, path, true);
            }
        }
Пример #21
0
        /// <summary>
        /// Renames the {title}.htm HTM file to index.htm instead
        /// </summary>
        /// <param name="bookDirectory"></param>
        private static CreateArtifactsExitCode RenameBloomDigitalFiles(string bookDirectory)
        {
            string originalHtmFilePath = Bloom.Book.BookStorage.FindBookHtmlInFolder(bookDirectory);

            Debug.Assert(RobustFile.Exists(originalHtmFilePath), "Book HTM not found: " + originalHtmFilePath);
            if (!RobustFile.Exists(originalHtmFilePath))
            {
                return(CreateArtifactsExitCode.BookHtmlNotFound);
            }

            string newHtmFilePath = Path.Combine(bookDirectory, $"index.htm");

            RobustFile.Copy(originalHtmFilePath, newHtmFilePath);
            RobustFile.Delete(originalHtmFilePath);
            return(CreateArtifactsExitCode.Success);
        }
Пример #22
0
        public void ChangeVideo(string bookFolderPath, ElementProxy videoContainer, string videoPath,
                                IProgress progress)
        {
            var videoFileName = Path.GetFileName(videoPath);
            var destPath      = Path.Combine(bookFolderPath, videoFileName);

            if (destPath != videoPath && !File.Exists(destPath))
            {
                RobustFile.Copy(videoPath, destPath);
            }
            // Enhance: if destination exists and content does not match pick a new name and copy to that.

            HtmlDom.SetVideoElementUrl(videoContainer, UrlPathString.CreateFromUnencodedString(videoFileName));
            // Enhance: do we need to do something here about metadata, when we figure out how to handle that
            // for videos?
        }
        /// <summary>
        /// If the collection has no reader tools at all, or if ones that came with the program are newer,
        /// copy the ones that came with the program.
        /// This is language-dependent, we'll typically only overwrite settings for an English collection.
        /// </summary>
        /// <param name="settings"></param>
        public static void CopyRelevantNewReaderSettings(CollectionSettings settings)
        {
            var readerToolsPath = GetReaderToolsSettingsFilePath(settings);
            var bloomFolder     = ProjectContext.GetBloomAppDataFolder();
            var newReaderTools  = Path.Combine(bloomFolder, Path.GetFileName(readerToolsPath));

            if (!RobustFile.Exists(newReaderTools))
            {
                return;
            }
            if (RobustFile.Exists(readerToolsPath) && RobustFile.GetLastWriteTime(readerToolsPath) > RobustFile.GetLastWriteTime(newReaderTools))
            {
                return;                 // don't overwrite newer existing settings?
            }
            RobustFile.Copy(newReaderTools, readerToolsPath, true);
        }
Пример #24
0
 public void Copy()
 {
     using (var temp = new TempFile())
     {
         RobustFile.WriteAllText(temp.Path, "This is a test");
         using (var output = new TempFile())
         {
             RobustFile.Delete(output.Path);                     // apparently we can encounter a left-over temp file
             RobustFile.Copy(temp.Path, output.Path);
             Assert.That(File.ReadAllText(output.Path), Is.EqualTo("This is a test"));
             // output file now exists, w/o 3rd argument can't overwrite
             Assert.Throws <IOException>(() => RobustFile.Copy(temp.Path, output.Path));
             RobustFile.WriteAllText(temp.Path, "This is another test");
             RobustFile.Copy(temp.Path, output.Path, true);                     // overwrite, no exception
             Assert.That(File.ReadAllText(output.Path), Is.EqualTo("This is another test"));
         }
     }
 }
Пример #25
0
        private void CleanUpAfterPressTooShort()
        {
            // Seems sometimes on a very short click the recording actually got started while we were informing the user
            // that he didn't click long enough. Before we try to delete the file where the recording is taking place,
            // we have to stop it; otherwise, we will get an exception trying to delete it.
            while (Recording)
            {
                try
                {
                    Recorder.Stop();
                    Application.DoEvents();
                }
                catch (Exception)
                {
                }
            }
            // Don't kid the user we have a recording for this.
            // Also, the absence of the file is how the UI knows to switch back to the state where 'speak'
            // is the expected action.
            try
            {
                RobustFile.Delete(PathToCurrentAudioSegment);
            }
            catch (Exception error)
            {
                Logger.WriteError("Audio Recording trying to delete " + PathToCurrentAudioSegment, error);
                Debug.Fail("can't delete the recording even after we stopped:" + error.Message);
            }

            // If we had a prior recording, restore it...button press may have been a mistake.
            if (RobustFile.Exists(_backupPath))
            {
                try
                {
                    RobustFile.Copy(_backupPath, PathToCurrentAudioSegment, true);
                }
                catch (IOException e)
                {
                    Logger.WriteError("Audio Recording could not restore backup " + _backupPath, e);
                    // if we can't restore it we can't. Review: are there other exception types we should ignore? Should we bother the user?
                }
            }
        }
Пример #26
0
        /// <summary>
        /// Given a book, typically one in a temporary folder made just for exporting (or testing),
        /// and given the set of fonts found while creating that book and removing hidden elements,
        /// find the files needed for those fonts.
        /// Copy the font file for the normal style of that font family from the system font folder,
        /// if permitted; or post a warning in progress if we can't embed it.
        /// Create an extra css file (fonts.css) which tells the book to find the font files for those font families
        /// in the local folder, and insert a link to it into the book.
        /// </summary>
        /// <param name="fontFileFinder">use new FontFinder() for real, or a stub in testing</param>
        public static void EmbedFonts(Book.Book book, IWebSocketProgress progress, HashSet <string> fontsWanted, IFontFinder fontFileFinder)
        {
            const string defaultFont = "Andika New Basic";             // already in BR, don't need to embed or make rule.

            fontsWanted.Remove(defaultFont);
            PublishHelper.CheckFontsForEmbedding(progress, fontsWanted, fontFileFinder, out List <string> filesToEmbed, out HashSet <string> badFonts);
            foreach (var file in filesToEmbed)
            {
                // Enhance: do we need to worry about problem characters in font file names?
                var dest = Path.Combine(book.FolderPath, Path.GetFileName(file));
                RobustFile.Copy(file, dest);
            }
            // Create the fonts.css file, which tells the browser where to find the fonts for those families.
            var sb = new StringBuilder();

            foreach (var font in fontsWanted)
            {
                if (badFonts.Contains(font))
                {
                    continue;
                }
                var group = fontFileFinder.GetGroupForFont(font);
                if (group != null)
                {
                    EpubMaker.AddFontFace(sb, font, "normal", "normal", group.Normal);
                }
                // We don't need (or want) a rule to use Andika instead.
                // The reader typically WILL use Andika, because we have a rule making it the default font
                // for the whole body of the document, and BloomReader always has it available.
                // However, it's possible that although we aren't allowed to embed the desired font,
                // the device actually has it installed. In that case, we want to use it.
            }
            RobustFile.WriteAllText(Path.Combine(book.FolderPath, "fonts.css"), sb.ToString());
            // Tell the document to use the new stylesheet.
            book.OurHtmlDom.AddStyleSheet("fonts.css");
            // Repair defaultLangStyles.css and other places in the output book if needed.
            if (badFonts.Any())
            {
                PublishHelper.FixCssReferencesForBadFonts(book.FolderPath, defaultFont, badFonts);
                PublishHelper.FixXmlDomReferencesForBadFonts(book.OurHtmlDom.RawDom, defaultFont, badFonts);
            }
        }
        internal static void CopyReaderToolsSettingsToWhereTheyBelong(string newlyAddedFolderOfThePack)
        {
            var destFolder = ProjectContext.GetBloomAppDataFolder();

            foreach (var readerSettingsFile in Directory.GetFiles(newlyAddedFolderOfThePack, ReaderToolsSettingsPrefix + "*.json")
                     .Concat(Directory.GetFiles(newlyAddedFolderOfThePack, "ReaderToolsWords-*.json")))
            {
                try
                {
                    RobustFile.Copy(readerSettingsFile, Path.Combine(destFolder, Path.GetFileName(readerSettingsFile)), true);
                }
                catch (IOException e)
                {
                    // If we can't do it, we can't. Don't worry about it in production.
#if DEBUG
                    Debug.Fail("Some file error copying reader settings");
#endif
                }
            }
        }
Пример #28
0
        /// <summary>
        /// Generates the cover image for a book, e.g. the thumbnail used on Bloom Library
        /// </summary>
        /// <param name="book"></param>
        /// <param name="requestedSize">The maximum size of either dimension</param>
        public static string GenerateCoverImageOfRequestedMaxSize(Book.Book book, int requestedSize)
        {
            if (requestedSize == 256)
            {
                // Use the custom thumbnail file if one is provided.
                var customFile = Path.Combine(book.FolderPath, "custom-thumbnail-256.png");
                if (RobustFile.Exists(customFile))
                {
                    var thumbnailFile = Path.Combine(book.FolderPath, "thumbnail-256.png");
                    RobustFile.Copy(customFile, thumbnailFile, true);
                    return(thumbnailFile);
                }
            }
            var thumbnailOptions = GetCoverThumbnailOptions(requestedSize, new Guid());

            CreateThumbnailOfCoverImage(book, thumbnailOptions);

            var thumbnailDestination = Path.Combine(book.FolderPath, thumbnailOptions.FileName);

            return(thumbnailDestination);
        }
        /// <summary>
        /// If the collection has no reader tools at all, or if ones that came with the program are newer,
        /// copy the ones that came with the program.
        /// This is language-dependent, we'll typically only overwrite settings for an English collection.
        /// Or, if the language came as a bloompack, we may copy updated settings for a newer bloompack.
        /// Basically this copies the same set of files as CopyReaderToolsSettingsToWhereTheyBelong creates
        /// into the book's own folder.
        /// </summary>
        public static void CopyRelevantNewReaderSettings(CollectionSettings settings)
        {
            var readerToolsPath        = GetReaderToolsSettingsFilePath(settings);
            var bloomFolder            = ProjectContext.GetBloomAppDataFolder();
            var readerSettingsFileName = Path.GetFileName(readerToolsPath);
            var newReaderTools         = Path.Combine(bloomFolder, readerSettingsFileName);

            if (!RobustFile.Exists(newReaderTools))
            {
                return;
            }
            if (RobustFile.Exists(readerToolsPath) && RobustFile.GetLastWriteTime(readerToolsPath) > RobustFile.GetLastWriteTime(newReaderTools))
            {
                return;                 // don't overwrite newer existing settings?
            }
            RobustFile.Copy(newReaderTools, readerToolsPath, true);
            // If the settings file is being updated, we should update the corresponding allowed words, if any.
            var langCode = Path.GetFileNameWithoutExtension(readerSettingsFileName.Substring(ReaderToolsSettingsPrefix.Length));

            CopyAllowedWords(Path.Combine(bloomFolder, AllowedWordsFolderName + "-" + langCode), Path.Combine(Path.GetDirectoryName(readerToolsPath), AllowedWordsFolderName));
        }
 private static void CopyAllowedWords(string allowedWordsSource, string allowedWordsDest)
 {
     if (Directory.Exists(allowedWordsSource))
     {
         var sourcePath = "";
         var destPath   = "";
         try
         {
             Directory.CreateDirectory(allowedWordsDest);
             foreach (var allowedWordsFile in Directory.GetFiles(allowedWordsSource))
             {
                 sourcePath = allowedWordsFile;
                 destPath   = Path.Combine(allowedWordsDest, Path.GetFileName(allowedWordsFile));
                 RobustFile.Copy(allowedWordsFile, destPath, true);
             }
         }
         catch (IOException e)
         {
             var msg = $"Cannot copy {sourcePath} to {destPath}.";
             ProblemReportApi.ShowProblemDialog(null, e, msg, "nonfatal");
         }
     }
 }