/// <summary> /// API Handler when the Auto Segment button is clicked /// /// Replies with the text read (with orthography conversion applied) if eSpeak completed successfully, or "' if there was an error. /// </summary> public void ESpeakPreview(ApiRequest request) { Logger.WriteEvent("AudioSegmentationApi.ESpeakPreview(): ESpeakPreview started."); // Parse the JSON containing the text segmentation data. string json = request.RequiredPostJson(); ESpeakPreviewRequest requestParameters = JsonConvert.DeserializeObject <ESpeakPreviewRequest>(json); string requestedLangCode = requestParameters.lang; string langCode = GetBestSupportedLanguage(requestedLangCode); Logger.WriteEvent($"AudioSegmentationApi.ESpeakPreview(): langCode={langCode ?? "null"}"); string text = requestParameters.text; text = SanitizeTextForESpeakPreview(text); string collectionPath = _bookSelection.CurrentSelection.CollectionSettings.FolderPath; string orthographyConversionMappingPath = Path.Combine(collectionPath, $"convert_{requestedLangCode}_to_{langCode}.txt"); if (File.Exists(orthographyConversionMappingPath)) { text = ApplyOrthographyConversion(text, orthographyConversionMappingPath); } // Even though you theoretically can pass the text through on the command line, it's better to write it to file. // The way the command line handles non-ASCII characters is not guaranteed to be the same as when reading from file. // It's more straightforward to just read/write it from file. // This causes the audio to match the audio that Aeneas will hear when it calls its eSpeak dependency. // (Well, actually it was difficult to verify the exact audio that Aeneas hears, but for -v el "άλφα", verified reading from file caused audio duration to match, but passing on command line caused discrepancy in audio duration) string textToSpeakFullPath = Path.GetTempFileName(); File.WriteAllText(textToSpeakFullPath, text, Encoding.UTF8); // No need to wait for espeak before responding. var response = new ESpeakPreviewResponse() { text = text, lang = langCode, filePath = File.Exists(orthographyConversionMappingPath) ? Path.GetFileName(orthographyConversionMappingPath) : "" }; string responseJson = JsonConvert.SerializeObject(response); request.ReplyWithJson(responseJson); string stdout; string command = $"espeak -v {langCode} -f \"{textToSpeakFullPath}\""; bool success = !DoesCommandCauseError(command, out stdout); RobustFile.Delete(textToSpeakFullPath); Logger.WriteEvent("AudioSegmentationApi.ESpeakPreview() Completed with success = " + success); if (!success) { var message = L10NSharp.LocalizationManager.GetString( "EditTab.Toolbox.TalkingBookTool.ESpeakPreview.Error", "eSpeak failed.", "This text is shown if an error occurred while running eSpeak. eSpeak is a piece of software that this program uses to do text-to-speech (have the computer read text out loud)."); NonFatalProblem.Report(ModalIf.None, PassiveIf.All, message, null, null, false); // toast without allowing error report. } }
/// <summary> /// How this page looks has changed, so remove from our cache /// </summary> /// <param name="id"></param> public void PageChanged(string id) { Image image; if (_images.TryGetValue(id, out image)) { _images.Remove(id); if (image.Tag != null) { string thumbnailPath = image.Tag as string; if (!string.IsNullOrEmpty(thumbnailPath)) { if (RobustFile.Exists(thumbnailPath)) { try { RobustFile.Delete(thumbnailPath); } catch (Exception) { Debug.Fail("Could not delete path (would not see this in release version)"); //oh well, couldn't delete it); throw; } } } } image.Dispose(); } }
private string GetPdfPath(string fname) { string path = null; // Sanitize fileName first string fileName = BookStorage.SanitizeNameForFileSystem(fname); for (int i = 0; i < 100; i++) { path = Path.Combine(Path.GetTempPath(), string.Format("{0}-{1}.pdf", fileName, i)); if (!RobustFile.Exists(path)) { break; } try { RobustFile.Delete(path); break; } catch (Exception) { //couldn't delete it? then increment the suffix and try again } } return(path); }
public void DeletedBook_RaisesDeleteRepoBookFileEvent() { var bloomBookPath = Path.Combine(_repoFolder.FolderPath, "Books", "put book to delete.bloom"); // Don't use PutBook here...changing the file immediately after putting it won't work, // because of the code that tries to prevent notifications of our own checkins. RobustFile.WriteAllText(bloomBookPath, @"This is original"); // no, not a zip at all var deletedBookName = ""; _collection.StartMonitoring(); ManualResetEvent bookDeletedRaised = new ManualResetEvent(false); EventHandler <DeleteRepoBookFileEventArgs> monitorFunction = (sender, args) => { deletedBookName = args.BookFileName; bookDeletedRaised.Set(); }; _collection.DeleteRepoBookFile += monitorFunction; // sut (at least, triggers it and waits for it) RobustFile.Delete(bloomBookPath); var waitSucceeded = bookDeletedRaised.WaitOne(1000); // To avoid messing up other tests, clean up before asserting. _collection.DeleteRepoBookFile -= monitorFunction; _collection.StopMonitoring(); Assert.That(waitSucceeded, "book deleted was not raised"); Assert.That(deletedBookName, Is.EqualTo("put book to delete.bloom")); }
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)); }
public static void DeleteFolderThatMayBeInUse(string folder) { if (Directory.Exists(folder)) { try { RobustIO.DeleteDirectory(folder, true); } catch (Exception e) { try { Debug.WriteLine(e.Message); //maybe we can at least clear it out a bit string[] files = Directory.GetFiles(folder, "*.*", SearchOption.AllDirectories); foreach (string s in files) { try { RobustFile.Delete(s); } catch (Exception) { } } //sleep and try again (in case some other thread will let go of them) Thread.Sleep(1000); RobustIO.DeleteDirectory(folder, true); } catch (Exception) { } } } }
/// <summary> /// Merge the specified input files into the specified output file. Returns null if successful, /// a string that may be useful in debugging if not. /// </summary> public static string MergeAudioFiles(IEnumerable <string> mergeFiles, string combinedAudioPath) { var ffmpeg = "/usr/bin/ffmpeg"; // standard Linux location if (SIL.PlatformUtilities.Platform.IsWindows) { ffmpeg = Path.Combine(BloomFileLocator.GetCodeBaseFolder(), "ffmpeg.exe"); } if (RobustFile.Exists(ffmpeg)) { var argsBuilder = new StringBuilder("-i \"concat:"); foreach (var path in mergeFiles) { argsBuilder.Append(path + "|"); } argsBuilder.Length--; argsBuilder.Append($"\" -c copy \"{combinedAudioPath}\""); var result = CommandLineRunner.Run(ffmpeg, argsBuilder.ToString(), "", 60 * 10, new NullProgress()); var output = result.ExitCode != 0 ? result.StandardError : null; if (output != null) { RobustFile.Delete(combinedAudioPath); } return(output); } return("Could not find ffmpeg"); }
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. } }
/// <summary> /// Encode the given file as an .mp3 file in the same directory. /// </summary> /// <returns>Path to the new file</returns> public string Encode(string sourcePath) { string destinationPath = Path.ChangeExtension(sourcePath, AudioRecording.kPublishableExtension); try { if (RobustFile.Exists(destinationPath)) { RobustFile.Delete(destinationPath); } } catch (Exception) { var shortMsg = LocalizationManager.GetString("LameEncoder.DeleteFailedShort", "Cannot replace mp3 file. Check antivirus"); var longMsg = LocalizationManager.GetString("LameEncoder.DeleteFailedLong", "Bloom could not replace an mp3 file. If this continues, check your antivirus."); NonFatalProblem.Report(ModalIf.None, PassiveIf.All, shortMsg, longMsg); return(null); } //-a downmix to mono string arguments = $"-a \"{sourcePath}\" \"{destinationPath}\""; ExecutionResult result = CommandLineRunner.Run(GetLamePath(), arguments, null, 60, new NullProgress()); result.RaiseExceptionIfFailed(""); return(destinationPath); }
public void BulkPublishBloomPubSettings_GivenBulkPublishSettingsInXml_LoadsProperly() { var collectionName = "loadBulkPublishSettingsTest"; var collectionSettingsPath = Path.Combine(_folder.Path, $"{collectionName}.bloomCollection"); if (RobustFile.Exists(collectionSettingsPath)) { RobustFile.Delete(collectionSettingsPath); } string fileContents = @"<?xml version=""1.0"" encoding=""utf-8""?> <Collection version=""0.2""> <BulkPublishBloomPubSettings> <MakeBookshelfFile>False</MakeBookshelfFile> <MakeBloomBundle>False</MakeBloomBundle> <BookshelfColor>#FF0000</BookshelfColor> <DistributionTag>distTag</DistributionTag> <BookshelfLabel>bookshelfLabel</BookshelfLabel> </BulkPublishBloomPubSettings> </Collection>"; RobustFile.WriteAllText(collectionSettingsPath, fileContents); // System under test var collectionSettings = new CollectionSettings(collectionSettingsPath); // Verification var bulkPublishSettings = collectionSettings.BulkPublishBloomPubSettings; Assert.That(bulkPublishSettings.makeBookshelfFile, Is.EqualTo(false), "makeBookshelfFile"); Assert.That(bulkPublishSettings.makeBloomBundle, Is.EqualTo(false), "makeBloomBundle"); Assert.That(bulkPublishSettings.bookshelfColor, Is.EqualTo("#FF0000")); Assert.That(bulkPublishSettings.distributionTag, Is.EqualTo("distTag")); Assert.That(bulkPublishSettings.bookshelfLabel, Is.EqualTo("bookshelfLabel")); }
/// <summary> /// The thing here is that we need to guarantee unique names at the top level, so we wrap the books inside a folder /// with some unique name. As this involves copying the folder it is also a convenient place to omit any PDF files /// except the one we want. /// </summary> /// <param name="storageKeyOfBookFolder"></param> /// <param name="pathToBloomBookDirectory"></param> /// <param name="excludeAudio">If true, audio files are not uploaded.</param> public void UploadBook(string storageKeyOfBookFolder, string pathToBloomBookDirectory, IProgress progress, string pdfToInclude = null, bool excludeAudio = true) { BaseUrl = null; BookOrderUrlOfRecentUpload = null; DeleteBookData(_bucketName, storageKeyOfBookFolder); // In case we're overwriting, get rid of any deleted files. //first, let's copy to temp so that we don't have to worry about changes to the original while we're uploading, //and at the same time introduce a wrapper with the last part of the unique key for this person+book string prefix = ""; // storageKey up to last slash (or empty) string tempFolderName = storageKeyOfBookFolder; // storage key after last slash (or all of it) // storageKeyOfBookFolder typically has a slash in it, email/id. // We only want the id as the temp folder name. // If there is anything before it, though, we want that as a prefix to make a parent 'folder' on parse.com. int index = storageKeyOfBookFolder.LastIndexOf('/'); if (index >= 0) { prefix = storageKeyOfBookFolder.Substring(0, index + 1); // must include the slash tempFolderName = storageKeyOfBookFolder.Substring(index + 1); } var wrapperPath = Path.Combine(Path.GetTempPath(), tempFolderName); //If we previously uploaded the book, but then had a problem, this directory could still be on our harddrive. Clear it out. if (Directory.Exists(wrapperPath)) { DeleteFileSystemInfo(new DirectoryInfo(wrapperPath)); } Directory.CreateDirectory(wrapperPath); var destDirName = Path.Combine(wrapperPath, Path.GetFileName(pathToBloomBookDirectory)); CopyDirectory(pathToBloomBookDirectory, destDirName); if (excludeAudio) { // Don't upload audio. string audioDir = Path.Combine(destDirName, "audio"); if (Directory.Exists(audioDir)) { SIL.IO.RobustIO.DeleteDirectory(audioDir, true); } } var unwantedPdfs = Directory.EnumerateFiles(destDirName, "*.pdf").Where(x => Path.GetFileName(x) != pdfToInclude); foreach (var file in unwantedPdfs) { RobustFile.Delete(file); } // Don't upload corrupt htms that have been repaired foreach (var path in Directory.EnumerateFiles(destDirName, BookStorage.PrefixForCorruptHtmFiles + "*.htm")) { RobustFile.Delete(path); } UploadDirectory(prefix, wrapperPath, progress); DeleteFileSystemInfo(new DirectoryInfo(wrapperPath)); }
private static void SaveBadFile(string filepath) { var savedBadFile = filepath + "-BAD"; if (RobustFile.Exists(savedBadFile)) { RobustFile.Delete(savedBadFile); } RobustFile.Move(filepath, savedBadFile); }
/// <summary> /// Download the files for this project from DBL into sourceDirectory and then /// copy them to the destination directory. /// Install should throw an Exception with an appropriate message if something goes wrong. /// </summary> /// <returns> /// <c>true</c> if fonts were installed; otherwise <c>false</c>. /// </returns> /// <exception cref="ArgumentNullException">DBLEntryUid /// or /// DBLSourceUrl /// or /// Name</exception> public override bool Install() { // Easier to check parameters here than fill the temp directory with files // NOTE: This is not an exhaustive list of the required parameters! // You will need to refer to InstallableResource.Install() for that. if (string.IsNullOrWhiteSpace(this.DBLEntryUid)) { throw new ArgumentNullException(nameof(this.DBLEntryUid)); } else if (string.IsNullOrWhiteSpace(this.DblSourceUrl)) { throw new ArgumentNullException(nameof(this.DblSourceUrl)); } else if (string.IsNullOrWhiteSpace(this.Name)) { throw new ArgumentNullException(nameof(this.Name)); } sourceDirectory = this.CreateTempSourceDirectory(); string filePath = Path.Combine(sourceDirectory, this.Name + ProjectFileManager.resourceFileExtension); if (!this.GetFile(filePath)) { if (RobustFile.Exists(filePath)) { // RobustFile only handles retries... RobustFile.Delete(filePath); } return(false); } bool result; try { result = base.Install(); } catch (UnauthorizedAccessException) { // Treat this like we couldn't get the resource from the DBL - ignore the error and continue. // This maybe caused by the file already being there and in use or the SF Project directory not existing result = false; } if (RobustFile.Exists(filePath)) { RobustFile.Delete(filePath); } return(result); }
public void OneTimeSetup() { _testFolder = new TemporaryFolder("SpreadsheetImporterWithBookTests"); // We need 2 layers of temp folder because BringBookUpToDate will change the name of the book // folder to match an imported title. _bookFolder = new TemporaryFolder(_testFolder, "Book"); var settings = new NewCollectionSettings(); settings.Language1.Iso639Code = "en"; settings.Language1.SetName("English", false); settings.SettingsFilePath = Path.Combine(_bookFolder.FolderPath, "dummy"); var fileLocator = new BloomFileLocator(settings, new XMatterPackFinder(new string[] { }), ProjectContext.GetFactoryFileLocations(), ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations()); var bookFilePath = Path.Combine(_bookFolder.FolderPath, "testBook.htm"); if (File.Exists(bookFilePath)) // Shouldn't ever happen, but... just being careful. { RobustFile.Delete(bookFilePath); } _dom = SetupTestDom(); // Write out our test book File.WriteAllText(bookFilePath, _dom.RawDom.OuterXml.ToString()); var storage = new BookStorage(_bookFolder.FolderPath, fileLocator, new BookRenamedEvent(), settings); var book = new Bloom.Book.Book(new BookInfo(_bookFolder.FolderPath, true), storage, null, settings, new Bloom.Edit.PageSelection(), new PageListChangedEvent(), new BookRefreshEvent()); // Create the regular production importer _importer = new SpreadsheetImporter(null, book, _bookFolder.FolderPath); // Set up the internal spreadsheet rows directly. var ss = new InternalSpreadsheet(); var columnForEn = ss.AddColumnForLang("en", "English"); var columnForImage = ss.GetColumnForTag(InternalSpreadsheet.ImageSourceColumnLabel); var newTitle = "My new book title"; var titleRow = new ContentRow(ss); titleRow.AddCell(InternalSpreadsheet.BookTitleRowLabel); titleRow.SetCell(columnForEn, newTitle); var coverImageRow = new ContentRow(ss); coverImageRow.AddCell(InternalSpreadsheet.CoverImageRowLabel); coverImageRow.SetCell(columnForImage, Path.Combine("images", "Othello 199.jpg")); _importer.Import(ss); _resultElement = ReadResultingBookToXml(newTitle); }
public static void GetUnusedFilenameTests(string basename, string expectedResult) { const string extension = ".txt"; using (var folder = new TemporaryFolder("UnusedFilenameTest")) { var basePath = Path.Combine(folder.Path, basename + extension); RobustFile.Delete(basePath); // just in case RobustFile.WriteAllText(basePath, "test contents"); var filename = ImageUtils.GetUnusedFilename(Path.GetDirectoryName(basePath), basename, extension); Assert.That(Path.GetFileNameWithoutExtension(filename), Is.EqualTo(expectedResult)); } }
internal static void RemoveSimulatedPageFile(string key) { if (key.StartsWith("file://")) { var uri = new Uri(key); RobustFile.Delete(uri.LocalPath); return; } lock (_urlToSimulatedPageContent) { _urlToSimulatedPageContent.Remove(key.FromLocalhost()); } }
private void MakeBloomPackInternal(string path, string dir, int dirNameOffset, string dirNamePrefix, bool forReaderTools) { try { if (RobustFile.Exists(path)) { // UI already got permission for this RobustFile.Delete(path); } using (var pleaseWait = new SimpleMessageDialog("Creating BloomPack...", "Bloom")) { try { pleaseWait.Show(); pleaseWait.BringToFront(); Application.DoEvents(); // actually show it Cursor.Current = Cursors.WaitCursor; Logger.WriteEvent("BloomPack path will be " + path + ", made from " + dir + " with rootName " + Path.GetFileName(dir)); using (var fsOut = RobustFile.Create(path)) { using (ZipOutputStream zipStream = new ZipOutputStream(fsOut)) { zipStream.SetLevel(9); CompressDirectory(dir, zipStream, dirNameOffset, dirNamePrefix, forReaderTools); zipStream.IsStreamOwner = true; // makes the Close() also close the underlying stream zipStream.Close(); } } // show it Logger.WriteEvent("Showing BloomPack on disk"); PathUtilities.SelectFileInExplorer(path); Analytics.Track("Create BloomPack"); } finally { Cursor.Current = Cursors.Default; pleaseWait.Close(); } } } catch (Exception e) { ErrorReport.NotifyUserOfProblem(e, "Could not make the BloomPack at " + path); } }
public void Dispose() { if (RobustFile.Exists(PdfFilePath)) { try { RobustFile.Delete(PdfFilePath); } catch (Exception) { } } GC.SuppressFinalize(this); }
private static bool DeleteFileReportingAnyProblem(string path) { try { RobustFile.Delete(path); return(true); } catch (IOException e) { var msg = string.Format( LocalizationManager.GetString("Errors.ProblemDeletingFile", "Bloom had a problem deleting this file: {0}"), path); ErrorReport.NotifyUserOfProblem(e, msg + Environment.NewLine + e.Message); } return(false); }
/// <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); }
/// <summary> /// If Bloom was launched by a fast splash screen program, signal it to close. /// </summary> private static void CloseFastSplashScreen() { if (SIL.PlatformUtilities.Platform.IsLinux) { RobustFile.Delete("/tmp/BloomLaunching.now"); // (okay if file doesn't exist) } else if (SIL.PlatformUtilities.Platform.IsWindows) { // signal the native process (that launched us) to close the splash screen // (okay if there's nobody there to receive the signal) using (var closeSplashEvent = new EventWaitHandle(false, EventResetMode.ManualReset, "CloseSquirrelSplashScreenEvent")) { closeSplashEvent.Set(); } } }
/// <summary> /// Merge the specified input files into the specified output file. Returns null if successful, /// a string that may be useful in debugging if not. /// </summary> public static string MergeAudioFiles(IEnumerable <string> mergeFiles, string combinedAudioPath) { var ffmpeg = "/usr/bin/ffmpeg"; // standard Linux location if (SIL.PlatformUtilities.Platform.IsWindows) { ffmpeg = Path.Combine(BloomFileLocator.GetCodeBaseFolder(), "ffmpeg.exe"); } if (RobustFile.Exists(ffmpeg)) { // A command something like // ffmpeg -i "concat:stereo1.mp3|monaural2.mp3|stereo3.mp3" -c:a libmp3lame output.mp3 // might work okay except that the output file characteristics appear to depend on the // first file in the list, and stereo recorded on only one side does come out only on // that one side if the file ends up being stereo, but not if the file ends up monaural. // This may or may not be preferable to flattening all of the files to monaural at the // standard recording rate before concatenating them. The current approach at least // has deterministic output for all files. var monoFiles = TryEnsureConsistentInputFiles(ffmpeg, mergeFiles); try { var argsBuilder = new StringBuilder("-i \"concat:"); argsBuilder.Append(string.Join("|", monoFiles)); argsBuilder.Append($"\" -c copy \"{combinedAudioPath}\""); var result = CommandLineRunner.Run(ffmpeg, argsBuilder.ToString(), "", 60 * 10, new NullProgress()); var output = result.ExitCode != 0 ? result.StandardError : null; if (output != null) { RobustFile.Delete(combinedAudioPath); } return(output); } finally { foreach (var file in monoFiles) { if (!mergeFiles.Contains(file)) { RobustFile.Delete(file); } } } } return("Could not find ffmpeg"); }
public void PutBook_DoesNotRaiseBookChangedEvent_OrDeletedEvent() { var folderPath = Path.Combine(_collectionFolder.FolderPath, "put existing book"); var bookPath = Path.Combine(folderPath, "put existing book.htm"); Directory.CreateDirectory(folderPath); RobustFile.WriteAllText(bookPath, "<html><body>This is our newly put book</body></html>"); _collection.PutBook(folderPath); // create test situation without monitoring _collection.StartMonitoring(); ManualResetEvent bookChangedRaised = new ManualResetEvent(false); _collection.OnChangedCalled = () => { bookChangedRaised.Set(); }; bool bookChangedWasCalled = false; bool bookDeletedWasCalled = false; EventHandler <BookRepoChangeEventArgs> monitorFunction = (sender, args) => { bookChangedWasCalled = true; }; _collection.BookRepoChange += monitorFunction; EventHandler <DeleteRepoBookFileEventArgs> monitorFunction2 = (sender, args) => { bookDeletedWasCalled = true; }; _collection.DeleteRepoBookFile += monitorFunction2; //sut: put it again _collection.PutBook(folderPath); var waitSucceeded = bookChangedRaised.WaitOne(1000); // cleanup _collection.BookRepoChange -= monitorFunction; _collection.DeleteRepoBookFile -= monitorFunction2; _collection.StopMonitoring(); var bloomBookPath = Path.Combine(_repoFolder.FolderPath, "put existing book.bloom"); RobustFile.Delete(bloomBookPath); Assert.That(waitSucceeded, "OnChanged was not called"); Assert.That(bookChangedWasCalled, Is.False, "BookChanged wrongly called"); Assert.That(bookDeletedWasCalled, Is.False, "BookDeleted wrongly called"); }
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")); } } }
public void Encode(string sourcePath, string destPathWithoutExtension, IProgress progress) { LocateAndRememberLAMEPath(); if (RobustFile.Exists(destPathWithoutExtension + ".mp3")) { RobustFile.Delete(destPathWithoutExtension + ".mp3"); } progress.WriteMessage(LocalizationManager.GetString("LameEncoder.Progress", " Converting to mp3", "Appears in progress indicator")); //-a downmix to mono string arguments = string.Format("-a \"{0}\" \"{1}.mp3\"", sourcePath, destPathWithoutExtension); //ClipRepository.RunCommandLine(progress, _pathToLAME, arguments); ExecutionResult result = CommandLineRunner.Run(_pathToLAME, arguments, null, 60, progress); result.RaiseExceptionIfFailed(""); }
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? } } }
public void MakePdf_BookNameIsChinese_OutputsPdf() { var maker = new PdfMaker(); using (var input = TempFile.WithFilename("北京.html")) using (var output = TempFile.WithFilename("北京.pdf")) { RobustFile.WriteAllText(input.Path, "<html><body>北京</body></html>"); RobustFile.Delete(output.Path); RunMakePdf(maker, input.Path, output.Path, "A5", false, false, false, PublishModel.BookletLayoutMethod.SideFold, PublishModel.BookletPortions.BookletPages); //we don't actually have a way of knowing it did a booklet Assert.IsTrue(File.Exists(output.Path), "Failed to convert trivial HTML file to PDF (Chinese filenames and content)"); var bytes = File.ReadAllBytes(output.Path); Assert.Less(1000, bytes.Length, "Generated PDF file is way too small! (Chinese filenames and content)"); Assert.IsTrue(bytes [0] == (byte)'%' && bytes [1] == (byte)'P' && bytes [2] == (byte)'D' && bytes [3] == (byte)'F', "Generated PDF file started with the wrong 4-byte signature (Chinese filenames and content)"); } }
/// <summary> /// All we do at this point is make a file with a ".doc" extension and open it. /// </summary> /// <remarks> /// The .doc extension allows the operating system to recognize which program /// should open the file, and the program (whether Microsoft Word or LibreOffice /// or OpenOffice) seems to handle HTML content just fine. /// </remarks> public void ExportDocFormat(string path) { string sourcePath = _bookSelection.CurrentSelection.GetPathHtmlFile(); if (RobustFile.Exists(path)) { RobustFile.Delete(path); } // Linux (Trusty) LibreOffice requires slightly different metadata at the beginning // of the file in order to recognize it as HTML. Otherwise it opens the file as raw // HTML (See https://silbloom.myjetbrains.com/youtrack/issue/BL-2276 if you don't // believe me.) I don't know any perfect way to add this information to the file, // but a simple string replace should be safe. This change works okay for both // Windows and Linux and for all three programs (Word, OpenOffice and Libre Office). string content = RobustFile.ReadAllText(sourcePath); string fixedContent = content.Replace("<meta charset=\"UTF-8\">", "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">"); RobustFile.WriteAllText(path, fixedContent); }
private void HandleChooseWidget(ApiRequest request) { if (!View.Model.CanChangeImages()) { // Enhance: more widget-specific message? MessageBox.Show( LocalizationManager.GetString("EditTab.CantPasteImageLocked", "Sorry, this book is locked down so that images cannot be changed.")); request.ReplyWithText(""); return; } using (var dlg = new DialogAdapters.OpenFileDialogAdapter { Multiselect = false, CheckFileExists = true, Filter = "Widget files|*.wdgt;*.html;*.htm" }) { var result = dlg.ShowDialog(); if (result != DialogResult.OK) { request.ReplyWithText(""); return; } var fullWidgetPath = dlg.FileName; var ext = Path.GetExtension(fullWidgetPath); if (ext.EndsWith("htm") || ext.EndsWith("html")) { fullWidgetPath = EditingModel.CreateWidgetFromHtmlFolder(fullWidgetPath); } string activityName = View.Model.MakeWidget(fullWidgetPath); var url = UrlPathString.CreateFromUnencodedString(activityName); request.ReplyWithText(url.UrlEncodedForHttpPath); // clean up the temporary widget file we created. if (fullWidgetPath != dlg.FileName) { RobustFile.Delete(fullWidgetPath); } } }
/// <summary> /// Make a metadata, usually by just reading the meta.json file in the book folder. /// If some exception is thrown while trying to do that, or if it doesn't exist, /// Try reading a backup (and restore it if successful). /// If that also fails, return null. /// </summary> /// <param name="bookFolderPath"></param> /// <returns></returns> public static BookMetaData FromFolder(string bookFolderPath) { var metaDataPath = MetaDataPath(bookFolderPath); BookMetaData result; if (TryReadMetaData(metaDataPath, out result)) { return(result); } var backupPath = Path.ChangeExtension(metaDataPath, "bak"); if (RobustFile.Exists(backupPath) && TryReadMetaData(backupPath, out result)) { RobustFile.Delete(metaDataPath); // Don't think it's worth saving the corrupt one RobustFile.Move(backupPath, metaDataPath); return(result); } return(null); }