I have to create a translated audio version for a YouTube video so I'm using YoutubeExplode to download the audio file:
var youtubeClient = new YoutubeClient();
var video = await youtubeClient.Videos.GetAsync(videoUrl);
var streamManifest = await youtubeClient.Videos.Streams.GetManifestAsync(video.Id);
var audioStreamInfo = streamManifest.GetAudioOnlyStreams().GetWithHighestBitrate();
var stream = await youtubeClient.Videos.Streams.GetAsync(audioStreamInfo);
Then I've created a Speech Azure Cognitive Service to generate the translated audio file and here is my code:
var speechTranslateConfig = SpeechTranslationConfig.FromSubscription("key", "region");
var text = await SpeechToText(speechTranslateConfig, stream);
async Task<string> SpeechToText(SpeechTranslationConfig config, Stream stream)
{
config.SpeechRecognitionLanguage = "en-US";
config.AddTargetLanguage("ro");
using var audioInputStream = AudioInputStream.CreatePushStream();
using var audioConfig = AudioConfig.FromStreamInput(audioInputStream);
using var recognizer = new TranslationRecognizer(config, audioConfig);
var bytes = streamToByteArray(stream);
audioInputStream.Write(bytes);
var result = await recognizer.RecognizeOnceAsync();
return result.Text;
}
private static byte[] streamToByteArray(Stream input)
{
MemoryStream ms = new MemoryStream();
input.CopyTo(ms);
return ms.ToArray();
}
I'm trying to use Stream because I don't want to save the original audio file, but the impediment I'm facing is that the translation result is always an empty string.
I also tried to save the original file and translate it (instead of converting the stream to a byte array) and like this, all works fine.
I can't understand what I'm missing, because I followed the documentation.
Related
I'm working on a Blazor WASM App and I want my users to easily open pdf files on specific pages that contain additional information.
I cannot distribute those files myself or upload them to any kind of server. Each user has to provide them themselves.
Because the files are up to 60MB big I cannot convert the uploaded file to base64 and display them as described here.
However I don't have to display the whole file and could just load the needed page +- some pages around them.
For that I tried using iText7 ExtractPageRange(). This answer indicates, that I have to override the GetNextPdfWriter() Method and to store all streams in an collection.
class ByteArrayPdfSplitter : PdfSplitter {
public ByteArrayPdfSplitter(PdfDocument pdfDocument) : base(pdfDocument) {
}
protected override PdfWriter GetNextPdfWriter(PageRange documentPageRange) {
CurrentMemoryStream = new MemoryStream();
UsedStreams.Add(CurrentMemoryStream);
return new PdfWriter(CurrentMemoryStream);
}
public MemoryStream CurrentMemoryStream { get; private set; }
public List<MemoryStream> UsedStreams { get; set; } = new List<MemoryStream>();
Then I thought I could merge those streams and convert them to base64
var file = loadedFiles.First();
using (MemoryStream ms = new MemoryStream())
{
var rs = file.OpenReadStream(maxFileSize);
await rs.CopyToAsync(ms);
ms.Position = 0;
//rs needed to be converted to ms, because the PdfReader constructer uses a
//synchronious read that isn't supported by rs and throws an exception.
PdfReader pdfReader = new PdfReader(ms);
var document = new PdfDocument(pdfReader);
var splitter = new ByteArrayPdfSplitter(document);
var range = new PageRange();
range.AddPageSequence(1, 10);
var splitDoc = splitter.ExtractPageRange(range);
//Edit commented this out, shouldn't have been here at all leads to an exception
//splitDoc.Close();
var outputMs = new MemoryStream();
foreach (var usedMs in splitter.UsedStreams)
{
usedMs.Position = 0;
outputMs.Position = outputMs.Length;
await usedMs.CopyToAsync(outputMs);
}
var data = outputMs.ToArray();
currentPdfContent = "data:application/pdf;base64,";
currentPdfContent += Convert.ToBase64String(data);
pdfLoaded = true;
}
This however doesn't work.
Has anyone a suggestion how to get this working? Or maybe a simpler solution I could try.
Edit:
I took a closer look in debug and it seems like, the resulting stream outputMs is always empty. So it is probably a problem in how I split the pdf.
After at least partially clearing up my misconception of what it means to not being able to access the file system from blazor WASM I managed to find a working solution.
await using MemoryStream ms = new MemoryStream();
var rs = file.OpenReadStream(maxFileSize);
await using var fs = new FileStream("test.pdf", FileMode.Create)
fs.Position = 0;
await rs.CopyToAsync(fs);
fs.Close();
string path = "test.pdf";
string range = "10 - 15";
var pdfDocument = new PdfDocument(new PdfReader("test.pdf"));
var split = new MySplitter(pdfDocument);
var result = split.ExtractPageRange(new PageRange(range));
result.Close();
await using var splitFs = new FileStream("split.pdf", FileMode.Open))
await splitFs.CopyToAsync(ms);
var data = ms.ToArray();
var pdfContent = "data:application/pdf;base64,";
pdfContent += System.Convert.ToBase64String(data);
Console.WriteLine(pdfContent);
currentPdfContent = pdfContent;
With the MySplitter Class from this answer.
class MySplitter : PdfSplitter
{
public MySplitter(PdfDocument pdfDocument) : base(pdfDocument)
{
}
protected override PdfWriter GetNextPdfWriter(PageRange documentPageRange)
{
String toFile = "split.pdf";
return new PdfWriter(toFile);
}
}
public async Task ExportGraph(string projectName, string html)
{
var bytes = Encoding.Default.GetBytes(html);
using var stream = new MemoryStream(bytes);
stream.Seek(0, SeekOrigin.Begin);
using var streamRef = new DotNetStreamReference(stream: stream);
await JS.InvokeVoidAsync("downloadFileFromStream", $"FazerGraph-{projectName}.jpg", streamRef);
}
I have this method that receives a string containing the html I want to create an image from.
I-m getting this string from this JS method:
function getInnerHTMLElement(element) {
if (element) {
return element.innerHTML;
}
return null;
}
When I download the jpg image and try to open it says:
What I'm doing wrong?
I'm using now html converter like this:
public async Task ExportGraph(string projectName, string html)
{
var converter = new HtmlConverter();
var bytes = converter.FromHtmlString(html);
using var stream = new MemoryStream(bytes);
stream.Seek(0, SeekOrigin.Begin);
using var streamRef = new DotNetStreamReference(stream: stream);
await JS.InvokeVoidAsync("downloadFileFromStream", $"FazerGraph-{projectName}.jpg", streamRef);
}
and the result image I get is this:
What can I do to make it the same look like the html (shown bellow)?
I am attempting to download a list of files from urls stored in my database, and then upload them to my Azure FileStorage account. I am successfully downloading the files and can turn them into files on my local storage or convert them to text and upload them. However I lose data when converting something like a pdf to a text and I do not want to have to store the files on the Azure app that this endpoint is hosted on as I do not need to manipulate the files in any way.
I have attempted to upload the files from the Stream I get from the HttpContent object using the UploadFromStream method on the CloudFile. Whenever this command is run I get an InvalidOperationException with the message "Operation is not valid due to the current state of the object."
I've tried converting the original Stream to a MemoryStream as well but this just writes a blank file to the FileStorage account, even if I set the position to the beginning of the MemoryStream. My code is below and if anyone could point out what information I am missing to make this work I would appreciate it.
public DownloadFileResponse DownloadFile(FileLink fileLink)
{
string fileName = string.Format("{0}{1}{2}", fileLink.ExpectedFileName, ".", fileLink.ExpectedFileType);
HttpStatusCode status;
string hash = "";
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromSeconds(10); // candidate for .config setting
client.DefaultRequestHeaders.Add("User-Agent", USER_AGENT);
var request = new HttpRequestMessage(HttpMethod.Get, fileLink.ExpectedURL);
var sendTask = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
var response = sendTask.Result; // not ensuring success here, going to handle error codes without exceptions
status = response.StatusCode;
if (status == HttpStatusCode.OK)
{
var httpStream = response.Content.ReadAsStreamAsync().Result;
fileStorage.WriteFile(fileLink.ExpectedFileType, fileName, httpStream);
hash = HashGenerator.GetMD5HashFromStream(httpStream);
}
}
return new DownloadFileResponse(status, fileName, hash);
}
public void WriteFile(string targetDirectory, string targetFilePath, Stream fileStream)
{
var options = SetOptions();
var newFile = GetTargetCloudFile(targetDirectory, targetFilePath);
newFile.UploadFromStream(fileStream, options: options);
}
public FileRequestOptions SetOptions()
{
FileRequestOptions options = new FileRequestOptions();
options.ServerTimeout = TimeSpan.FromSeconds(10);
options.RetryPolicy = new NoRetry();
return options;
}
public CloudFile GetTargetCloudFile(string targetDirectory, string targetFilePath)
{
if (!shareConnector.share.Exists())
{
throw new Exception("Cannot access Azure File Storage share");
}
CloudFileDirectory rootDirectory = shareConnector.share.GetRootDirectoryReference();
CloudFileDirectory directory = rootDirectory.GetDirectoryReference(targetDirectory);
if (!directory.Exists())
{
throw new Exception("Target Directory does not exist");
}
CloudFile newFile = directory.GetFileReference(targetFilePath);
return newFile;
}
Had the same problem, the only way it worked is by reading the coming stream (in your case it is httpStream in DownloadFile(FileLink fileLink) method) to a byte array and using UploadFromByteArray (byte[] buffer, int index, int count) instead of UploadFromStream
So your WriteFile(FileLink fileLink) method will look like:
public void WriteFile(string targetDirectory, string targetFilePath, Stream fileStream)
{
var options = SetOptions();
var newFile = GetTargetCloudFile(targetDirectory, targetFilePath);
const int bufferLength= 600;
byte[] buffer = new byte[bufferLength];
// Buffer to read from stram This size is just an example
List<byte> byteArrayFile = new List<byte>(); // all your file will be here
int count = 0;
try
{
while ((count = fileStream.Read(buffer, 0, bufferLength)) > 0)
{
byteArrayFile.AddRange(buffer);
}
fileStream.Close();
}
catch (Exception ex)
{
throw; // you need to change this
}
file.UploadFromByteArray(allFile.ToArray(), 0, byteArrayFile.Count);
// Not sure about byteArrayFile.Count.. it should work
}
According to your description and codes, I suggest you could use Steam.CopyTo to copy the stream to the local memoryStream firstly, then upload the MemoryStream to azure file storage.
More details, you could refer to below codes:
I just change the DownloadFile method to test it.
HttpStatusCode status;
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromSeconds(10); // candidate for .config setting
// client.DefaultRequestHeaders.Add("User-Agent", USER_AGENT);
//here I use my blob file to test it
var request = new HttpRequestMessage(HttpMethod.Get, "https://xxxxxxxxxx.blob.core.windows.net/media/secondblobtest-eypt.txt");
var sendTask = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
var response = sendTask.Result; // not ensuring success here, going to handle error codes without exceptions
status = response.StatusCode;
if (status == HttpStatusCode.OK)
{
MemoryStream ms = new MemoryStream();
var httpStream = response.Content.ReadAsStreamAsync().Result;
httpStream.CopyTo(ms);
ms.Position = 0;
WriteFile("aaa", "testaa", ms);
// hash = HashGenerator.GetMD5HashFromStream(httpStream);
}
}
I had a similar problem and got to find out that the UploadFromStream method only works with buffered streams. Nevertheless I was able to successfully upload files to azure storage by using a MemoryStream. I don't think this to be a very good solution as you are using up your memory resources by copying the content of the file stream to memory before handing it to the azure stream. What I have come up with is a way of writing directly to an azure stream by using instead the OpenWriteAsync method to create the stream and then a simple CopyToAsync from the source stream.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse( "YourAzureStorageConnectionString" );
CloudFileClient fileClient = storageAccount.CreateCloudFileClient();
CloudFileShare share = fileClient.GetShareReference( "YourShareName" );
CloudFileDirectory root = share.GetRootDirectoryReference();
CloudFile file = root.GetFileReference( "TheFileName" );
using (CloudFileStream fileWriteStream = await file.OpenWriteAsync( fileMetadata.FileSize, new AccessCondition(),
new FileRequestOptions { StoreFileContentMD5 = true },
new OperationContext() ))
{
await fileContent.CopyToAsync( fileWriteStream, 128 * 1024 );
}
I'm building a Windows Store App including a local folder of Images.
I want to protect all the Images so they can't be accessed from:
C:\Users[username]\AppData\Local\Packages\LocalState\Settings\settings.dat
I know I should encrypt and decrypt the Images using the DataProtectionProvider class, but the documentation only shows how to encrypt/decrypt strings...
How should I convert a Bitmap image into a byte array? or should I encode it with Base64? Is there any tutorial or sample using this process?
It's easiest if the images you want to encrypt are loaded from files and written back out to files. Then you can do:
async void EncryptFile(IStorageFile fileToEncrypt, IStorageFile encryptedFile)
{
IBuffer buffer = await FileIO.ReadBufferAsync(fileToEncrypt);
DataProtectionProvider dataProtectionProvider =
new DataProtectionProvider(ENCRYPTION_DESCRIPTOR);
IBuffer encryptedBuffer =
await dataProtectionProvider.ProtectAsync(buffer);
await FileIO.WriteBufferAsync(encryptedFile, encryptedBuffer);
}
DataProtectionProvider.ProtectStreamAsync is another alternative if you can get stream instances from your inputs and outputs. For example, if you have a byte[] containing your image data then you can create an in-memory input stream from it:
byte[] imageData = ...
using (var inputMemoryStream = new MemoryStream(imageData).AsInputStream())
{
...
}
Edit: Then for example to decrypt the file and display it in an Image control you could do:
var encryptedBuffer = await FileIO.ReadBufferAsync(encryptedFile);
var dataProtectionProvider = new DataProtectionProvider();
var buffer = await dataProtectionProvider.UnprotectAsync(encryptedBuffer);
var bmp = new BitmapImage();
await bmp.SetSourceAsync(buffer.AsStream().AsRandomAccessStream());
imageControl.Source = bmp;
public async void Protect()
{
for (int i = 1; i < 24; i++)
{
string imageFile = ImagePages[i];
var fileToEncrypt = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(imageFile);
var encryptedFile1 = await ApplicationData.Current.LocalFolder.CreateFileAsync("encryptedPage" + i);
var encryptedFile2 = await EncryptFile(fileToEncrypt, encryptedFile1);
IBuffer buffer = await DecryptFile(encryptedFile2);
//(2.) It goes here and throw the 'System.ArgumentException' having the encryptedFile's ContentType=""
var bmp = new BitmapImage();
await bmp.SetSourceAsync(buffer.AsStream().AsRandomAccessStream());
//Fill the List responsible for the Portrait View
MyPortrait mp = new MyPortrait();
mp.onlyImage = bmp;
PImageList.Add(mp);
}
}
public async Task<IStorageFile> EncryptFile(IStorageFile fileToEncrypt, IStorageFile encryptedFile)
{
IBuffer buffer = await FileIO.ReadBufferAsync(fileToEncrypt);
//I have no more exceptions here
DataProtectionProvider dataProtectionProvider = new DataProtectionProvider("LOCAL=user");
IBuffer encryptedBuffer = await dataProtectionProvider.ProtectAsync(buffer);
//(1.) After arriving here when deploying it goes to (2.)
await FileIO.WriteBufferAsync(encryptedFile, encryptedBuffer);
return encryptedFile;
}
public async Task<IBuffer> DecryptFile(IStorageFile encryptedFile)
{
var protectedBuffer = await FileIO.ReadBufferAsync(encryptedFile);
var dataProtectionProvider = new DataProtectionProvider();
var buffer = await dataProtectionProvider.UnprotectAsync(protectedBuffer);
return buffer;
}
I am using a SpeechSynthesizer class in my Windows Phone 8.1 Store app (XAML app/ windows runtime app/ universal app). It outputs a SpeechSynthesisStream which i need to save as a mp3/audio file in phone's local storage. Here's the code that i am using to generate the stream. How to save it as an audio file?
using (var speech = new SpeechSynthesizer())
{
var voiceStream = await speech.SynthesizeTextToStreamAsync(text);
}
Didn't see you there on twitter. Kindly pardon me for that. I think the first thing you should do is save your audio in a wav file as that
var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();
SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync("Hello World");
using (var reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
IBuffer buffer = reader.ReadBuffer((uint)stream.Size);
await FileIO.WriteBufferAsync(outputFile, buffer);
}
After you're done with that you can transcode this one to mp3. For that I believe this:
http://msdn.microsoft.com/library/windows/apps/hh452795
and http://go.microsoft.com/fwlink/p/?linkid=242136
is the place to look into. ;)
A complete example,
var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();
StorageFile sampleFile = await localfolder.CreateFileAsync("sample.wav", CreationCollisionOption.ReplaceExisting);
SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync("Hello World");
using (var reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
IBuffer buffer = reader.ReadBuffer((uint)stream.Size);
await FileIO.WriteBufferAsync(sampleFile, buffer);
}