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(); }
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); } } }
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); } }
// 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(""); } }
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))); } } }
private void CopyFile(ApiRequest request) { dynamic jsonData = DynamicJson.Parse(request.RequiredPostJson()); RobustFile.Copy(jsonData.from, jsonData.to, true); request.PostSucceeded(); }
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)); }
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"); } } }
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); } } }
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); }
/// <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))); } }
/// <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)); }
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); }
/// <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); }
/// <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))); } }
/// <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); } }
/// <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); }
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); }
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")); } } }
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? } } }
/// <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 } } }
/// <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"); } } }