Skip to content

Commit a84bef5

Browse files
authored
internal: Develop to main (#44)
* feat: add download grid from channels chore: bump versions * feat: show channel files * feat: add media streaming from telegram (#32) * feat: media stream for huge files (#34) * feat: add webdav and export files to strm (#39) feat: improves fix: error on download root files fix: error on download splitted files * chore: dockerfile * chore: dockerfile change * chore: python virtual env * chore: add beta tags * chore: log refresh * feat: add download file before play * chore: python docker repair * feat: add virtual scroll config * chore: add mutex in tasks * fix: repair strm feat: add app controller * fea: add preload files on streaming option * fix: solve download multi part file for stream * fix: multi download problem * chore: add getFileById on download * chore: add ogm as a video extension * feat: improve streaming * feat: download files v2 * feat: add reverse proxy support over https feat: download sync file and return to front * chore: add local file manager routes dynamically * chore: improve navbar * feat: add speedChart chore: add more logs * feat: improve main window (#41) chore: add download and upload info * feat: remove id from task tables * fix: solve some errors 🚑 * chore: improve shared file manager * chore: add start time in download * chore: improve js and css * chore: improve events * chore: navbar changes * chore: change strm export * feat: add new lazy DropDownTree * feat: add custom mobile file manager (#43) * feat: add custom mobile file manager * chore: add strm function on mobileFIleManager * feat: prevent load file manager * feat: add file type filter on mobile * feat: add shared folder to mobile * feat: add preload files * feat: slide bottom bar * feat: bump .net to 10 * feat: versioning * feat: improve version modal * feat: improve refresh data channel * chore: improve audio and video modals * feat: add audio playlist * feat: improve audio player * feat: improve configuration * feat: improve local file upload * feat: improve top row * feat: improve offcanvas * feat: improve task manager * chore: change dockerfile * fix: ensure is dispose * chore: improve tasks list * feat: tasks tab navigation * feat: improve import modal * feat: add multiple audio files to playlist * feat: devices compatibilities * fix: culture error solve * feat: improve video modal
1 parent 4245542 commit a84bef5

54 files changed

Lines changed: 13645 additions & 1099 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/docker-image.yml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Docker Image CI
1+
name: Docker Image CI (Dev)
22

33
on:
44
push:
@@ -12,17 +12,30 @@ jobs:
1212

1313
steps:
1414
- uses: actions/checkout@v4
15+
16+
- name: Generate version
17+
id: version
18+
run: |
19+
# Generate dev version: 0.0.0-dev.YYYYMMDD.HHMMSS.shortsha
20+
DATE_VERSION=$(date +%Y%m%d.%H%M%S)
21+
SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-7)
22+
VERSION="0.0.0-dev.${DATE_VERSION}.${SHORT_SHA}"
23+
echo "version=$VERSION" >> $GITHUB_OUTPUT
24+
echo "Generated version: $VERSION"
25+
1526
- name: 'Login to GitHub Container Registry'
1627
uses: docker/login-action@v3
1728
with:
1829
registry: ghcr.io
1930
username: ${{github.actor}}
2031
password: ${{secrets.GHCR}}
32+
2133
- name: Build and Push the Docker image
2234
run: |
23-
date_ref=$(date +%s)
24-
docker build ./TelegramDownloader -f ./TelegramDownloader/Dockerfile --tag ghcr.io/mateof/telegramfilemanager:dev_$date_ref
25-
IMAGE_ID=$(docker images | grep ghcr.io/mateof/telegramfilemanager | awk '{print $3}')
26-
docker tag $IMAGE_ID ghcr.io/mateof/telegramfilemanager:dev_latest
27-
docker push ghcr.io/mateof/telegramfilemanager:dev_$date_ref
35+
VERSION=${{ steps.version.outputs.version }}
36+
docker build ./TelegramDownloader -f ./TelegramDownloader/Dockerfile \
37+
--build-arg VERSION=$VERSION \
38+
--tag ghcr.io/mateof/telegramfilemanager:dev_$VERSION \
39+
--tag ghcr.io/mateof/telegramfilemanager:dev_latest
40+
docker push ghcr.io/mateof/telegramfilemanager:dev_$VERSION
2841
docker push ghcr.io/mateof/telegramfilemanager:dev_latest

.github/workflows/release-docker-image.yml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Docker Image CI
1+
name: Docker Image CI (Release)
22

33
on:
44
push:
@@ -12,16 +12,28 @@ jobs:
1212

1313
steps:
1414
- uses: actions/checkout@v4
15+
16+
- name: Extract version from tag
17+
id: version
18+
run: |
19+
# Remove 'v' prefix from tag (v1.2.3 -> 1.2.3)
20+
VERSION=${GITHUB_REF_NAME#v}
21+
echo "version=$VERSION" >> $GITHUB_OUTPUT
22+
echo "Extracted version: $VERSION"
23+
1524
- name: 'Login to GitHub Container Registry'
1625
uses: docker/login-action@v3
1726
with:
1827
registry: ghcr.io
1928
username: ${{github.actor}}
2029
password: ${{secrets.GHCR}}
30+
2131
- name: Build and Push the Docker image
2232
run: |
23-
docker build ./TelegramDownloader -f ./TelegramDownloader/Dockerfile --tag ghcr.io/mateof/telegramfilemanager:latest --build-arg tag=${{github.ref_name}}
24-
IMAGE_ID=$(docker images | grep ghcr.io/mateof/telegramfilemanager | awk '{print $3}')
25-
docker tag $IMAGE_ID ghcr.io/mateof/telegramfilemanager:${{github.ref_name}}
26-
docker push ghcr.io/mateof/telegramfilemanager:latest
33+
VERSION=${{ steps.version.outputs.version }}
34+
docker build ./TelegramDownloader -f ./TelegramDownloader/Dockerfile \
35+
--build-arg VERSION=$VERSION \
36+
--tag ghcr.io/mateof/telegramfilemanager:${{github.ref_name}} \
37+
--tag ghcr.io/mateof/telegramfilemanager:latest
2738
docker push ghcr.io/mateof/telegramfilemanager:${{github.ref_name}}
39+
docker push ghcr.io/mateof/telegramfilemanager:latest

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ services:
3838
api_id: ""
3939
hash_id: ""
4040
DOTNET_HOSTBUILDER__RELOADCONFIGONCHANGE: false
41+
DOTNET_CLI_TELEMETRY_OPTOUT: true
4142
restart: unless-stopped
4243
depends_on:
4344
- mongodb_container

TelegramDownloader/Data/FileService.cs

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,52 @@ public async Task oneItemDeleteAsync(string dbName, Syncfusion.Blazor.FileManage
557557

558558
}
559559

560+
public async Task<FileManagerResponse<Syncfusion.Blazor.FileManager.FileManagerDirectoryContent>> CopyOrMoveItems(string dbName, Syncfusion.Blazor.FileManager.FileManagerDirectoryContent[] files, string targetPath, Syncfusion.Blazor.FileManager.FileManagerDirectoryContent targetData, bool isCopy)
561+
{
562+
try
563+
{
564+
FileManagerResponse<Syncfusion.Blazor.FileManager.FileManagerDirectoryContent> fm = new FileManagerResponse<Syncfusion.Blazor.FileManager.FileManagerDirectoryContent>();
565+
var lista = new List<Syncfusion.Blazor.FileManager.FileManagerDirectoryContent>();
566+
foreach (var item in files)
567+
{
568+
if (!item.IsFile)
569+
{
570+
var result = await copyAllDirectoryFiles(dbName, item.Id, targetData, targetPath + item.Name + "/");
571+
lista.Add(result.toFileManagerContentInCopy());
572+
if (!isCopy)
573+
{
574+
await _db.deleteEntry(dbName, item.Id);
575+
}
576+
}
577+
else
578+
{
579+
var result = await _db.copyItem(dbName, item.Id, targetData, targetPath, item.IsFile);
580+
lista.Add(result.toFileManagerContentInCopy());
581+
if (!isCopy)
582+
{
583+
await _db.deleteEntry(dbName, item.Id);
584+
}
585+
}
586+
await _db.addBytesToFolder(dbName, item.ParentId, item.Size);
587+
}
588+
fm.Files = lista;
589+
return fm;
590+
}
591+
catch (Exception e)
592+
{
593+
_logger.LogError(e, "Error on CopyOrMoveItems");
594+
if (e is MongoWriteException ex)
595+
{
596+
if (ex.WriteError.Category == ServerErrorCategory.DuplicateKey)
597+
{
598+
NotificationModel nm = new NotificationModel();
599+
nm.sendEvent(new Notification("The file exist in the directory", "Duplicate", NotificationTypes.Error));
600+
}
601+
}
602+
throw e;
603+
}
604+
}
605+
560606
private async Task<BsonFileManagerModel> copyAllDirectoryFiles(string dbName, string idfolder, Syncfusion.Blazor.FileManager.FileManagerDirectoryContent target, string targetPath, bool isCopy = true)
561607
{
562608
var result = await _db.copyItem(dbName, idfolder, target, targetPath, false);
@@ -1027,6 +1073,11 @@ public async Task importSharedData(ShareFilesModel sfm, GenericNotificationProgr
10271073
return (await _db.createEntry(dbName, await _db.toBasonFile(args.Path, args.FolderName, args.ParentFolder))).Select(x => x.toFileManagerContent()).ToList();
10281074
}
10291075

1076+
public async Task<List<Syncfusion.Blazor.FileManager.FileManagerDirectoryContent>> createFolder(string dbName, string path, string folderName, Syncfusion.Blazor.FileManager.FileManagerDirectoryContent? parentFolder)
1077+
{
1078+
return (await _db.createEntry(dbName, await _db.toBasonFile(path, folderName, parentFolder))).Select(x => x.toFileManagerContent()).ToList();
1079+
}
1080+
10301081
public async Task CreateDatabase(string id)
10311082
{
10321083
if (_ts.checkChannelExist(id))
@@ -1444,10 +1495,11 @@ public async Task UploadFileFromServer(string dbName, string currentPath, List<S
14441495
// if file or folder does not exist, it will be created
14451496
if ((await _db.getFileByPath(dbName, System.IO.Path.Combine(currentPath, file.Name))) == null)
14461497
await _db.createEntry(dbName, model);
1498+
if (!parent.HasChild)
1499+
await _db.setDirectoryHasChild(dbName, parent.Id);
14471500
if (file.IsFile)
14481501
{
14491502
await _db.addBytesToFolder(dbName, model.ParentId, model.Size);
1450-
await _db.setDirectoryHasChild(dbName, parent.Id);
14511503
if (idt != null) idt.AddOne(file.Size);
14521504
}
14531505
else
@@ -1535,6 +1587,7 @@ private string GetMimeType(string fileName)
15351587

15361588
public async Task refreshChannelFIles(string channelId, bool force = false)
15371589
{
1590+
int totalNewMessages = 0;
15381591
refreshMutex.WaitOne();
15391592
refreshChannelList.Add(channelId);
15401593
refreshMutex.ReleaseMutex();
@@ -1590,21 +1643,23 @@ public async Task refreshChannelFIles(string channelId, bool force = false)
15901643
model.isSplit = false;
15911644
model.isEncrypted = false;
15921645
await _db.createEntry(channelId, model);
1646+
totalNewMessages++;
15931647
}
15941648
}
15951649
refreshMutex.WaitOne();
15961650
refreshChannelList.Remove(channelId);
15971651
refreshMutex.ReleaseMutex();
1598-
_logger.LogInformation($"Finish Refresh channel with id: {channelId}");
1652+
_logger.LogInformation($"Finish Refresh channel with id: {channelId} with {totalNewMessages} new files added.");
15991653

16001654
// Fix for CS1739: Removed the invalid 'autoHide' parameter and replaced it with the correct property assignment.
16011655
ToastMessage tm = new ToastMessage
16021656
{
16031657
Type = ToastType.Success,
16041658
IconName = IconName.CheckCircle,
16051659
Title = "Refresh channel files",
1606-
Message = "Files channel has been refreshed",
1660+
Message = $"Files channel has been refreshed with {totalNewMessages} new files added.",
16071661
AutoHide = true
1662+
16081663
};
16091664
_toastService.Notify(tm);
16101665
}
@@ -1769,6 +1824,13 @@ public async Task<List<BsonFileManagerModel>> getTelegramFolders(string dbName,
17691824
return result;
17701825
}
17711826

1827+
public async Task<List<BsonFileManagerModel>> getTelegramFoldersByParentId(string dbName, string? parentId)
1828+
{
1829+
var result = await _db.getFoldersByParentId(dbName, parentId);
1830+
1831+
return result;
1832+
}
1833+
17721834
private async Task<List<FolderModel>> getTelegramSubfolders(string id, List<BsonFileManagerModel> listFolders, string prevPath)
17731835
{
17741836
List<FolderModel> node = new List<FolderModel>();
@@ -1841,9 +1903,20 @@ private async Task<List<ExpandoObject>> AddChildRecords(string id, string parent
18411903
var childItem = fileDetails.Count > 0 && fileDetails[0] != null ? fileDetails[0] : Data
18421904
.Where(x => x.FilePath + "/" == path).First().toFileManagerContent();
18431905
response.CWD = childItem;
1844-
response.Files = Data
1845-
.Where(x => x.ParentId == childItem.Id).Select(x => x.toFileManagerContent()).ToList();
18461906

1907+
// First try to find children in the query result (by ParentId)
1908+
var files = Data.Where(x => x.ParentId == childItem.Id).ToList();
1909+
1910+
// If no children found in query result, do a separate query by ParentId
1911+
// This handles the case where children's FilterPath format doesn't match the query path
1912+
if (files.Count == 0 && !string.IsNullOrEmpty(childItem.Id))
1913+
{
1914+
files = collectionName == null
1915+
? await _db.getFilesByParentId(dbName, childItem.Id)
1916+
: await _db.getFilesByParentId(dbName, childItem.Id, collectionName);
1917+
}
1918+
1919+
response.Files = files.Select(x => x.toFileManagerContent()).ToList();
18471920
}
18481921
await Task.Yield();
18491922
return response;
@@ -1980,5 +2053,10 @@ private async Task mergeFileStreamAsync(List<string> pathList, string destName)
19802053
}
19812054
_logger.LogInformation("File merge completed - DestName: {DestName}", destName);
19822055
}
2056+
2057+
public virtual Task<int> PreloadFilesToTemp(string channelId, List<Syncfusion.Blazor.FileManager.FileManagerDirectoryContent> items)
2058+
{
2059+
throw new NotImplementedException("PreloadFilesToTemp is implemented in FileServiceV2");
2060+
}
19832061
}
19842062
}

TelegramDownloader/Data/FileServiceV2.cs

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,141 @@ public async Task DownloadFileNowV2(string dbName, int messageId, string destPat
170170
{
171171
await _ts.DownloadFileAndReturn(cm, ms: fs, model: model);
172172
}
173-
173+
174+
}
175+
176+
public override async Task<int> PreloadFilesToTemp(string channelId, List<FileManagerDirectoryContent> items)
177+
{
178+
_logger.LogInformation("Starting preload files to temp V2 - ChannelId: {ChannelId}, ItemsCount: {Count}", channelId, items.Count);
179+
NotificationModel nm = new NotificationModel();
180+
int preloadedCount = 0;
181+
string tempPath = System.IO.Path.Combine(TEMPDIR, "_temp");
182+
Directory.CreateDirectory(tempPath);
183+
184+
try
185+
{
186+
nm.sendEvent(new Notification($"Starting preload of {items.Count} items to cache", "Preload", NotificationTypes.Info));
187+
188+
// Collect all files to preload (including files inside folders)
189+
var filesToPreload = new List<BsonFileManagerModel>();
190+
await CollectFilesForPreloadV2(channelId, items, filesToPreload);
191+
192+
_logger.LogInformation("Collected {Count} files to preload", filesToPreload.Count);
193+
nm.sendEvent(new Notification($"Found {filesToPreload.Count} files to preload", "Preload", NotificationTypes.Info));
194+
195+
foreach (var file in filesToPreload)
196+
{
197+
try
198+
{
199+
// Build the temp file name: {channelId}-{MessageId}-{fileName}
200+
string tempFileName = $"{channelId}-{file.MessageId}-{file.Name}";
201+
string tempFilePath = System.IO.Path.Combine(tempPath, tempFileName);
202+
203+
// Check if file already exists and is complete
204+
if (File.Exists(tempFilePath))
205+
{
206+
var existingFile = new System.IO.FileInfo(tempFilePath);
207+
if (existingFile.Length >= file.Size)
208+
{
209+
_logger.LogInformation("File already preloaded: {FileName}", file.Name);
210+
preloadedCount++;
211+
continue;
212+
}
213+
// File exists but incomplete, delete and re-download
214+
File.Delete(tempFilePath);
215+
}
216+
217+
// Download file to temp
218+
_logger.LogInformation("Preloading file: {FileName} (MessageId: {MessageId})", file.Name, file.MessageId);
219+
220+
if (file.isSplit)
221+
{
222+
// Handle split files
223+
await PreloadSplitFilesToTempV2(channelId, file, tempFilePath);
224+
}
225+
else
226+
{
227+
await downloadFromTelegramV2(channelId, (int)file.MessageId, tempFilePath, file);
228+
}
229+
230+
preloadedCount++;
231+
}
232+
catch (Exception ex)
233+
{
234+
_logger.LogError(ex, "Error preloading file: {FileName}", file.Name);
235+
}
236+
}
237+
238+
nm.sendEvent(new Notification($"Preload completed: {preloadedCount} files cached", "Preload", NotificationTypes.Success));
239+
_logger.LogInformation("Preload completed - FilesPreloaded: {Count}", preloadedCount);
240+
}
241+
catch (Exception ex)
242+
{
243+
_logger.LogError(ex, "Error during preload to temp");
244+
nm.sendEvent(new Notification($"Error during preload: {ex.Message}", "Preload Error", NotificationTypes.Error));
245+
}
246+
247+
return preloadedCount;
248+
}
249+
250+
private async Task CollectFilesForPreloadV2(string channelId, List<FileManagerDirectoryContent> items, List<BsonFileManagerModel> filesToPreload)
251+
{
252+
foreach (var item in items)
253+
{
254+
if (item.IsFile)
255+
{
256+
// Get the file details from database
257+
var dbFile = await _db.getFileById(channelId, item.Id);
258+
if (dbFile != null && dbFile.MessageId != null)
259+
{
260+
filesToPreload.Add(dbFile);
261+
}
262+
}
263+
else
264+
{
265+
// It's a folder - get all files inside recursively
266+
await CollectFilesInFolderRecursiveV2(channelId, item.Id, filesToPreload);
267+
}
268+
}
269+
}
270+
271+
private async Task CollectFilesInFolderRecursiveV2(string channelId, string folderId, List<BsonFileManagerModel> filesToPreload)
272+
{
273+
// Get all items in this folder
274+
var children = await _db.getFilesByParentId(channelId, folderId);
275+
276+
foreach (var child in children)
277+
{
278+
if (child.IsFile)
279+
{
280+
if (child.MessageId != null)
281+
{
282+
filesToPreload.Add(child);
283+
}
284+
}
285+
else
286+
{
287+
// Recurse into subfolder
288+
await CollectFilesInFolderRecursiveV2(channelId, child.Id, filesToPreload);
289+
}
290+
}
291+
}
292+
293+
private async Task PreloadSplitFilesToTempV2(string channelId, BsonFileManagerModel file, string destPath)
294+
{
295+
_logger.LogInformation("Preloading split file V2 - FileName: {FileName}, Parts: {Parts}", file.Name, file.ListMessageId?.Count ?? 0);
296+
297+
if (File.Exists(destPath))
298+
{
299+
File.Delete(destPath);
300+
}
301+
302+
int i = 1;
303+
foreach (int messageId in file.ListMessageId)
304+
{
305+
await downloadFromTelegramV2(channelId, messageId, destPath, file, true, destPath, i);
306+
i++;
307+
}
174308
}
175309

176310
}

0 commit comments

Comments
 (0)