Skip to content

Commit 11a98a1

Browse files
authored
release: v2.0.8 (#33)
* feat: add download grid from channels chore: bump versions * feat: show channel files * feat: add media streaming from telegram (#32)
1 parent 4290b18 commit 11a98a1

16 files changed

Lines changed: 754 additions & 52 deletions

TelegramDownloader/Controllers/FileController.cs

Lines changed: 232 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@
99
using Syncfusion.Blazor.Inputs;
1010
using Syncfusion.EJ2.FileManager.Base;
1111
using Syncfusion.EJ2.FileManager.PhysicalFileProvider;
12+
using Syncfusion.EJ2.Notifications;
1213
using System;
1314
using System.Collections.Generic;
1415
using System.IO;
1516
using System.IO.Compression;
17+
using System.Linq;
1618
using System.Net;
1719
using System.Net.Http.Headers;
1820
using System.Runtime.Serialization.Formatters.Binary;
21+
using System.Web;
1922
using System.Xml.Linq;
2023
using TelegramDownloader.Data;
2124
using TelegramDownloader.Data.db;
@@ -234,15 +237,15 @@ public async Task<IActionResult> GetImage(string path)
234237
}
235238

236239
[Route("GetFile/{id}")]
237-
public async Task<IActionResult> GetFile(string id, string? idChannel, string? idFile )
240+
public async Task<IActionResult> GetFile(string id, string? idChannel, string? idFile)
238241
{
239242
var fileName = id;
240243
var mimeType = FileService.getMimeType(id.Split(".").Last());
241244
var file = _fs.ExistFileIntempFolder($"{idChannel}-{idFile}-{id}");
242245
if ( file == null )
243246
{
244247
// HttpResponseMessage fullResponse = new HttpResponseMessage(HttpStatusCode.OK); // Request.CreateResponse(HttpStatusCode.OK);
245-
Message idM = await _ts.getMessageFile(idChannel, Convert.ToInt32(idFile));
248+
TL.Message idM = await _ts.getMessageFile(idChannel, Convert.ToInt32(idFile));
246249
ChatMessages cm = new ChatMessages();
247250
cm.message = idM;
248251
file = new FileStream(System.IO.Path.Combine(FileService.TEMPDIR, "_temp", $"{idChannel}-{idFile}-{id}"), FileMode.Create, FileAccess.ReadWrite);
@@ -253,13 +256,240 @@ public async Task<IActionResult> GetFile(string id, string? idChannel, string? i
253256
await _ts.DownloadFileAndReturn(cm, file, model: dm);
254257
file.Position = 0;
255258
}
259+
var request = HttpContext.Request;
260+
var rangeHeader = request.Headers["Range"].ToString();
256261

257262
return new FileStreamResult(file, mimeType)
258263
{
259264
FileDownloadName = fileName,
260265
EnableRangeProcessing = true
261266

262267
};
268+
}
269+
270+
[Route("GetFileStream/{idChannel}/{idFile}/{name}")]
271+
public async Task<IActionResult> GetFileStream(string idChannel, string idFile, string name)
272+
{
273+
var fileName = name;
274+
var mimeType = FileService.getMimeType(name.Split(".").Last());
275+
276+
var request = HttpContext.Request;
277+
var rangeHeader = request.Headers["Range"].ToString();
278+
279+
var file = await _fs.getItemById(idChannel, idFile);
280+
281+
TL.Message idM = await _ts.getMessageFile(idChannel, file.MessageId ?? file.ListMessageId.FirstOrDefault());
282+
283+
long totalLength = 0; // (await _fs.getItemById(idChannel, idFile)).Size;
284+
285+
if(idM.media is MessageMediaDocument { document: Document document })
286+
{
287+
totalLength = document.size;
288+
}
289+
290+
long from = 0;
291+
long initialFrom = 0;
292+
long to = 0;
293+
294+
if (!string.IsNullOrEmpty(rangeHeader) && rangeHeader.StartsWith("bytes="))
295+
{
296+
var range = rangeHeader.Replace("bytes=", "").Split('-');
297+
from = long.Parse(range[0]);
298+
initialFrom = from;
299+
if (range.Length > 1 && !string.IsNullOrEmpty(range[1]))
300+
to = long.Parse(range[1]);
301+
}
302+
303+
if (from > 0)
304+
{
305+
from = (from / 524288) * 524288;
306+
}
307+
308+
Console.WriteLine("Fom:" + from);
309+
310+
if (to == 0)
311+
if (string.IsNullOrEmpty(rangeHeader) || from == 0)
312+
to = (12 * 524288) + from;
313+
else
314+
to = (5 * 524288) + from;
315+
else
316+
to = ((to + 524288) / 524288) * 524288;
317+
318+
if (to > totalLength)
319+
{
320+
to = totalLength;
321+
}
322+
323+
if (totalLength == initialFrom)
324+
{
325+
Response.StatusCode = 416; // Range Not Satisfiable
326+
Response.Headers["Content-Range"] = $"bytes */{totalLength}";
327+
return new EmptyResult();
328+
}
329+
330+
long length = to - from;
331+
//Console.WriteLine("To length: " + to);
332+
//Console.WriteLine("future download length: " + length);
333+
334+
byte[] data = await _ts.DownloadFileStream(idM, from, (int)length);
335+
336+
//Console.WriteLine("Total download length: " + data.Length);
337+
338+
long skipedBytes = initialFrom - from - (length - data.Length);
339+
340+
if (skipedBytes < 0) skipedBytes = 0;
341+
342+
if (skipedBytes > data.Length)
343+
return StatusCode(500, "No hay suficientes bytes en el bloque descargado");
344+
345+
long dataLength = data.Length - skipedBytes;
346+
Response.ContentLength = dataLength; //(dataLength + initialFrom) >= totalLength ? totalLength - initialFrom : dataLength;
347+
// Response.StatusCode = (int)HttpStatusCode.PartialContent; // 206
348+
Response.StatusCode = StatusCodes.Status206PartialContent; // StatusCodes.Status206PartialContent;
349+
Response.ContentType = mimeType;
350+
Response.Headers["Content-Disposition"] = $"inline; filename=\"{HttpUtility.UrlEncode(fileName)}\"";
351+
Response.Headers.Add("Content-Range", $"bytes {(initialFrom >= totalLength ? totalLength - 1 : initialFrom)}-{(initialFrom >= totalLength ? totalLength - 1 : initialFrom + Response.ContentLength - 1)}/{totalLength}");
352+
Response.Headers.Add("Accept-Ranges", "bytes");
353+
354+
//if (Request.Headers.ContainsKey("Range"))
355+
//{
356+
// Console.WriteLine("Range header recibido:");
357+
// Console.WriteLine(Request.Headers["Range"]);
358+
//}
359+
360+
//foreach (var header in Response.Headers)
361+
//{
362+
// Console.WriteLine($"{header.Key}: {header.Value}");
363+
//}
364+
365+
366+
// Console.WriteLine("Skiped bytes: " + skipedBytes);
367+
368+
var stream = new MemoryStream(data, (int)skipedBytes, (int)Response.ContentLength);
369+
stream.Position = 0;
370+
371+
// Console.WriteLine("Real Data length: " + stream.Length);
372+
373+
// Console.WriteLine("---------------------------------------------------");
374+
375+
var cancellationToken = HttpContext.RequestAborted;
376+
377+
try
378+
{
379+
await stream.CopyToAsync(Response.Body, 64 * 1024, cancellationToken);
380+
await Response.Body.FlushAsync(cancellationToken);
381+
382+
return new EmptyResult();
383+
}
384+
catch (OperationCanceledException)
385+
{
386+
Console.WriteLine("❌ El cliente cerró la conexión.");
387+
}
388+
389+
return new EmptyResult();
390+
391+
}
392+
393+
[Route("GetFileStream2/{idChannel}/{idFile}/{name}")]
394+
public async Task<IActionResult> GetFileStream2(string idChannel, string idFile, string name)
395+
{
396+
var fileName = name;
397+
var mimeType = FileService.getMimeType(name.Split(".").Last());
398+
399+
var request = HttpContext.Request;
400+
var rangeHeader = request.Headers["Range"].ToString();
401+
402+
var file = await _fs.getItemById(idChannel, idFile);
403+
404+
// HttpResponseMessage fullResponse = new HttpResponseMessage(HttpStatusCode.OK); // Request.CreateResponse(HttpStatusCode.OK);
405+
TL.Message idM = await _ts.getMessageFile(idChannel, file.MessageId ?? file.ListMessageId.FirstOrDefault());
406+
//byte[] data = await _ts.DownloadFileStream(idM, 0, 512);
407+
//var stream = new MemoryStream(data);
408+
409+
// Supón que puedes obtener el tamaño total del archivo remoto
410+
long totalLength = (await _fs.getItemById(idChannel, idFile)).Size;
411+
412+
long from = 0;
413+
long initialFrom = 0;
414+
long to = 0;
415+
416+
417+
418+
if (!string.IsNullOrEmpty(rangeHeader) && rangeHeader.StartsWith("bytes="))
419+
{
420+
var range = rangeHeader.Replace("bytes=", "").Split('-');
421+
from = long.Parse(range[0]);
422+
initialFrom = from;
423+
if (range.Length > 1 && !string.IsNullOrEmpty(range[1]))
424+
to = long.Parse(range[1]);
425+
}
426+
427+
if (from > 0)
428+
{
429+
from = (from / 524288) * 524288;
430+
}
431+
432+
if (to == 0)
433+
to = (25 * 524288) + from;
434+
else
435+
to = ((to + 524288) / 524288) * 524288;
436+
437+
if (to > totalLength)
438+
{
439+
to = totalLength - 1;
440+
}
441+
442+
long length = to - from;
443+
444+
byte[] data = await _ts.DownloadFileStream(idM, from, (int)length);
445+
446+
long skipedBytes = initialFrom - from; // (data.Length + initialFrom) >= totalLength ? data.Length - (totalLength - initialFrom) : initialFrom - from;
447+
448+
if (skipedBytes < 0) skipedBytes = 0;
449+
450+
if (skipedBytes >= data.Length)
451+
return StatusCode(500, "No hay suficientes bytes en el bloque descargado");
452+
453+
long dataLength = data.Length - skipedBytes;
454+
Response.ContentLength = (dataLength + initialFrom) >= totalLength ? totalLength - initialFrom : dataLength;
455+
// Response.StatusCode = (int)HttpStatusCode.PartialContent; // 206
456+
Response.StatusCode = StatusCodes.Status206PartialContent;
457+
Response.ContentType = mimeType;
458+
Response.Headers.Add("Content-Range", $"bytes {initialFrom}-{(initialFrom + Response.ContentLength - 1)}/{totalLength}");
459+
Response.Headers.Add("Accept-Ranges", "bytes");
460+
461+
if (Request.Headers.ContainsKey("Range"))
462+
{
463+
Console.WriteLine("Range header recibido:");
464+
Console.WriteLine(Request.Headers["Range"]);
465+
}
466+
467+
foreach (var header in Response.Headers)
468+
{
469+
Console.WriteLine($"{header.Key}: {header.Value}");
470+
}
471+
472+
473+
474+
475+
var stream = new MemoryStream(data, (int)skipedBytes, (int)Response.ContentLength);
476+
477+
Console.WriteLine("Real Data length: " + stream.Length);
478+
479+
Console.WriteLine("---------------------------------------------------");
480+
481+
//return new FileStreamResult(stream, mimeType);
482+
var cancellationToken = HttpContext.RequestAborted;
483+
484+
await stream.CopyToAsync(Response.Body, 64 * 1024, cancellationToken);
485+
await Response.Body.FlushAsync(cancellationToken);
486+
487+
return new EmptyResult();
488+
// return File(stream, mimeType, enableRangeProcessing: false);
489+
//return new FileStreamResult(stream, mimeType)
490+
//{
491+
// EnableRangeProcessing = false
492+
//};
263493

264494
}
265495

TelegramDownloader/Data/FileService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public class FileService : IFileService
117117
{"mid", "audio/midi"},
118118
{"midi", "audio/midi"},
119119
{"mif", "application/vnd.mif"},
120-
{"mkv", "video/webm" },
120+
{"mkv", "video/x-matroska" },
121121
{"mov", "video/quicktime"},
122122
{"movie", "video/x-sgi-movie"},
123123
{"mp2", "audio/mpeg"},

TelegramDownloader/Data/ITelegramService.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using TelegramDownloader.Models;
1+
using BlazorBootstrap;
2+
using TelegramDownloader.Models;
23
using TL;
34
using WTelegram;
45

@@ -16,17 +17,21 @@ public interface ITelegramService
1617
Task joinChatInvitationHash(string? hash);
1718
Task<User> CallQrGenerator(Action<string> func, CancellationToken ct, bool logoutFirst = false);
1819
Task<string> DownloadFile(ChatMessages message, string fileName = null, string folder = null, DownloadModel model = null, bool shouldAddToList = false);
20+
Task<Byte[]> DownloadFileStream(Message message, long offset, int limit);
1921
Task<Stream> DownloadFileAndReturn(ChatMessages message, Stream ms = null, string fileName = null, string folder = null, DownloadModel model = null);
2022
Task<List<ChatViewBase>> GetFouriteChannels(bool mustRefresh = true);
2123
Task AddFavouriteChannel(long id);
2224
Task RemoveFavouriteChannel(long id);
2325
Task<List<ChatViewBase>> getAllChats();
2426
Task<List<ChatViewBase>> getAllSavedChats();
25-
Task<List<ChatMessages>> getAllMessages(long id);
27+
Task<List<ChatMessages>> getAllMessages(long id, Boolean onlyFiles = false);
28+
Task<GridDataProviderResult<ChatMessages>> getPaginatedMessages(long id, int page, int size, Boolean onlyFiles = false);
29+
Task<List<ChatMessages>> getAllMediaMessages(long id, Boolean onlyFiles = false);
2630
Task<List<ChatMessages>> getChatHistory(long id, int limit = 30, int addOffset = 0);
2731
string getChatName(long id);
2832
Task<Message> getMessageFile(string chatId, int idMessage);
2933
Task<string> getPhotoThumb(ChatBase chat);
34+
Task<string> downloadPhotoThumb(Photo thumb);
3035
Task logOff();
3136
Task sendVerificationCode(string vc);
3237
Task<Message> uploadFile(string chatId, Stream file, string fileName, string mimeType = null, UploadModel um = null, string caption = null);

0 commit comments

Comments
 (0)