Toplu indirme ve Eklenti Güncellemesi

This commit is contained in:
hOLOlu
2026-05-09 11:33:53 +03:00
parent 729879c693
commit 75bd47c052
349 changed files with 5292 additions and 401 deletions

Binary file not shown.

View File

@@ -2,6 +2,18 @@
"Version": 1,
"WorkspaceRootPath": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|d:\\calismalar\\ai\\hdm\\downloadmanager\\src\\downloadmanager.wpf\\views\\mainwindow.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}",
"RelativeMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|solutionrelative:src\\downloadmanager.wpf\\views\\mainwindow.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}"
},
{
"AbsoluteMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|d:\\calismalar\\ai\\hdm\\downloadmanager\\src\\downloadmanager.wpf\\resources\\icons.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}",
"RelativeMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|solutionrelative:src\\downloadmanager.wpf\\resources\\icons.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}"
},
{
"AbsoluteMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|d:\\calismalar\\ai\\hdm\\downloadmanager\\src\\downloadmanager.wpf\\resources\\appicon.png||{177559E0-D141-11D0-92DF-00A0C9138C45}",
"RelativeMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|solutionrelative:src\\downloadmanager.wpf\\resources\\appicon.png||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|d:\\calismalar\\ai\\hdm\\downloadmanager\\src\\downloadmanager.wpf\\viewmodels\\mainviewmodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|solutionrelative:src\\downloadmanager.wpf\\viewmodels\\mainviewmodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
@@ -10,10 +22,6 @@
"AbsoluteMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|d:\\calismalar\\ai\\hdm\\downloadmanager\\src\\downloadmanager.wpf\\viewmodels\\downloaditemviewmodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|solutionrelative:src\\downloadmanager.wpf\\viewmodels\\downloaditemviewmodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|d:\\calismalar\\ai\\hdm\\downloadmanager\\src\\downloadmanager.wpf\\views\\mainwindow.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}",
"RelativeMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|solutionrelative:src\\downloadmanager.wpf\\views\\mainwindow.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}"
},
{
"AbsoluteMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|d:\\calismalar\\ai\\hdm\\downloadmanager\\src\\downloadmanager.wpf\\converters\\statustoiconconverter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|solutionrelative:src\\downloadmanager.wpf\\converters\\statustoiconconverter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
@@ -34,15 +42,39 @@
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 4,
"SelectedChildIndex": 8,
"Children": [
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "AppIcon.png - PNG [512x512, 32 bit, PNG]",
"DocumentMoniker": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\Resources\\AppIcon.png",
"RelativeDocumentMoniker": "src\\DownloadManager.WPF\\Resources\\AppIcon.png",
"ToolTip": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\Resources\\AppIcon.png - PNG [512x512, 32 bit, PNG]",
"RelativeToolTip": "src\\DownloadManager.WPF\\Resources\\AppIcon.png - PNG [512x512, 32 bit, PNG]",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001533|",
"WhenOpened": "2026-05-06T11:23:28.352Z",
"EditorCaption": " - PNG [512x512, 32 bit, PNG]"
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "Icons.xaml",
"DocumentMoniker": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\Resources\\Icons.xaml",
"RelativeDocumentMoniker": "src\\DownloadManager.WPF\\Resources\\Icons.xaml",
"ToolTip": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\Resources\\Icons.xaml",
"RelativeToolTip": "src\\DownloadManager.WPF\\Resources\\Icons.xaml",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003549|",
"WhenOpened": "2026-05-06T11:23:19.058Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "DownloadItemViewModel.cs",
"DocumentMoniker": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\ViewModels\\DownloadItemViewModel.cs",
"RelativeDocumentMoniker": "src\\DownloadManager.WPF\\ViewModels\\DownloadItemViewModel.cs",
@@ -50,12 +82,11 @@
"RelativeToolTip": "src\\DownloadManager.WPF\\ViewModels\\DownloadItemViewModel.cs",
"ViewState": "AgIAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-04T23:33:33.635Z",
"EditorCaption": ""
"WhenOpened": "2026-05-04T23:33:33.635Z"
},
{
"$type": "Document",
"DocumentIndex": 3,
"DocumentIndex": 5,
"Title": "StatusToIconConverter.cs",
"DocumentMoniker": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\Converters\\StatusToIconConverter.cs",
"RelativeDocumentMoniker": "src\\DownloadManager.WPF\\Converters\\StatusToIconConverter.cs",
@@ -67,7 +98,7 @@
},
{
"$type": "Document",
"DocumentIndex": 5,
"DocumentIndex": 7,
"Title": "App.xaml",
"DocumentMoniker": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\App.xaml",
"RelativeDocumentMoniker": "src\\DownloadManager.WPF\\App.xaml",
@@ -79,7 +110,7 @@
},
{
"$type": "Document",
"DocumentIndex": 0,
"DocumentIndex": 3,
"Title": "MainViewModel.cs",
"DocumentMoniker": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\ViewModels\\MainViewModel.cs",
"RelativeDocumentMoniker": "src\\DownloadManager.WPF\\ViewModels\\MainViewModel.cs",
@@ -87,12 +118,11 @@
"RelativeToolTip": "src\\DownloadManager.WPF\\ViewModels\\MainViewModel.cs",
"ViewState": "AgIAAI4CAAAAAAAAAAAcwOYAAABVAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-03T21:58:25.845Z",
"EditorCaption": ""
"WhenOpened": "2026-05-03T21:58:25.845Z"
},
{
"$type": "Document",
"DocumentIndex": 4,
"DocumentIndex": 6,
"Title": "App.xaml.cs",
"DocumentMoniker": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\App.xaml.cs",
"RelativeDocumentMoniker": "src\\DownloadManager.WPF\\App.xaml.cs",
@@ -104,7 +134,7 @@
},
{
"$type": "Document",
"DocumentIndex": 2,
"DocumentIndex": 0,
"Title": "MainWindow.xaml",
"DocumentMoniker": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\Views\\MainWindow.xaml",
"RelativeDocumentMoniker": "src\\DownloadManager.WPF\\Views\\MainWindow.xaml",

View File

@@ -2,6 +2,10 @@
"Version": 1,
"WorkspaceRootPath": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|d:\\calismalar\\ai\\hdm\\downloadmanager\\src\\downloadmanager.wpf\\views\\mainwindow.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}",
"RelativeMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|solutionrelative:src\\downloadmanager.wpf\\views\\mainwindow.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}"
},
{
"AbsoluteMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|d:\\calismalar\\ai\\hdm\\downloadmanager\\src\\downloadmanager.wpf\\resources\\icons.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}",
"RelativeMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|solutionrelative:src\\downloadmanager.wpf\\resources\\icons.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}"
@@ -18,10 +22,6 @@
"AbsoluteMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|d:\\calismalar\\ai\\hdm\\downloadmanager\\src\\downloadmanager.wpf\\viewmodels\\downloaditemviewmodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|solutionrelative:src\\downloadmanager.wpf\\viewmodels\\downloaditemviewmodel.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|d:\\calismalar\\ai\\hdm\\downloadmanager\\src\\downloadmanager.wpf\\views\\mainwindow.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}",
"RelativeMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|solutionrelative:src\\downloadmanager.wpf\\views\\mainwindow.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}"
},
{
"AbsoluteMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|d:\\calismalar\\ai\\hdm\\downloadmanager\\src\\downloadmanager.wpf\\converters\\statustoiconconverter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{11611D1E-B832-4666-9E37-23014F395F55}|src\\DownloadManager.WPF\\DownloadManager.WPF.csproj|solutionrelative:src\\downloadmanager.wpf\\converters\\statustoiconconverter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
@@ -42,7 +42,7 @@
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 2,
"SelectedChildIndex": 8,
"Children": [
{
"$type": "Bookmark",
@@ -50,7 +50,7 @@
},
{
"$type": "Document",
"DocumentIndex": 1,
"DocumentIndex": 2,
"Title": "AppIcon.png - PNG [512x512, 32 bit, PNG]",
"DocumentMoniker": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\Resources\\AppIcon.png",
"RelativeDocumentMoniker": "src\\DownloadManager.WPF\\Resources\\AppIcon.png",
@@ -62,7 +62,7 @@
},
{
"$type": "Document",
"DocumentIndex": 0,
"DocumentIndex": 1,
"Title": "Icons.xaml",
"DocumentMoniker": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\Resources\\Icons.xaml",
"RelativeDocumentMoniker": "src\\DownloadManager.WPF\\Resources\\Icons.xaml",
@@ -74,7 +74,7 @@
},
{
"$type": "Document",
"DocumentIndex": 3,
"DocumentIndex": 4,
"Title": "DownloadItemViewModel.cs",
"DocumentMoniker": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\ViewModels\\DownloadItemViewModel.cs",
"RelativeDocumentMoniker": "src\\DownloadManager.WPF\\ViewModels\\DownloadItemViewModel.cs",
@@ -110,7 +110,7 @@
},
{
"$type": "Document",
"DocumentIndex": 2,
"DocumentIndex": 3,
"Title": "MainViewModel.cs",
"DocumentMoniker": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\ViewModels\\MainViewModel.cs",
"RelativeDocumentMoniker": "src\\DownloadManager.WPF\\ViewModels\\MainViewModel.cs",
@@ -118,8 +118,7 @@
"RelativeToolTip": "src\\DownloadManager.WPF\\ViewModels\\MainViewModel.cs",
"ViewState": "AgIAAI4CAAAAAAAAAAAcwOYAAABVAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-03T21:58:25.845Z",
"EditorCaption": ""
"WhenOpened": "2026-05-03T21:58:25.845Z"
},
{
"$type": "Document",
@@ -135,14 +134,15 @@
},
{
"$type": "Document",
"DocumentIndex": 4,
"DocumentIndex": 0,
"Title": "MainWindow.xaml",
"DocumentMoniker": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\Views\\MainWindow.xaml",
"RelativeDocumentMoniker": "src\\DownloadManager.WPF\\Views\\MainWindow.xaml",
"ToolTip": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.WPF\\Views\\MainWindow.xaml",
"RelativeToolTip": "src\\DownloadManager.WPF\\Views\\MainWindow.xaml",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003549|",
"WhenOpened": "2026-05-01T23:15:00.129Z"
"WhenOpened": "2026-05-01T23:15:00.129Z",
"EditorCaption": ""
}
]
}

BIN
Down_bridge.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

43
GIZLILIK_POLITIKASI.md Normal file
View File

@@ -0,0 +1,43 @@
# hOLOlu Download Manager (hDM) Gizlilik Politikası
**Son Güncelleme:** 7 Mayıs 2026
hOLOlu Download Manager (hDM), gizliliğinizi korumayı taahhüt eder. Bu Gizlilik Politikası, uygulamamızın ve tarayıcı eklentimizin bilgileri nasıl işlediğini açıklar.
## 1. Bilgi Toplama ve Kullanım
hDM, yerel olarak kurulan bir yazılımdır. Tam gizlilik prensibine inanıyoruz:
- **Kişisel Veri Toplanmaz:** Herhangi bir kişisel bilgiyi, tarama geçmişini veya kimlik verisini toplamaz, saklamaz veya herhangi bir harici sunucuya iletmeyiz.
- **Yerel İşleme:** Tüm indirme bilgileri, URL'ler ve dosya yolları, makinenizdeki özel bir veri tabanında yerel olarak işlenir ve saklanır.
- **Takip Yapılmaz:** Davranışlarınızı izlemek için herhangi bir takip pikseli, analiz aracı veya çerez kullanmayız.
## 2. Tarayıcı Eklentisi İzinleri
hDM Tarayıcı Eklentisi, doğru çalışabilmek için aşağıdaki izinlere ihtiyaç duyar:
- **`downloads`:** Bir indirme başladığında bunu tespit etmek, indirmeyi yakalamak ve hDM tarafından yönetilmesini sağlamak için kullanılır.
- **`nativeMessaging`:** Bilgisayarınızdaki hDM masaüstü uygulamasıyla güvenli bir şekilde iletişim kurmak için kullanılır.
- **`contextMenus`:** Bir bağlantıya sağ tıkladığınızda "hDM ile indir" seçeneğini sunmak için kullanılır.
- **`<all_urls>`:** Eklentinin ziyaret ettiğiniz çeşitli web sitelerindeki indirme bağlantılarını yakalamasına olanak tanımak için gereklidir.
Bu izinler aracılığıyla erişilen verilerin hiçbiri asla hDM'ye veya herhangi bir üçüncü tarafa gönderilmez. Tamamen yerel sisteminizde kalır.
## 3. Veri Depolama
- **Yerel Veri Tabanı:** hDM, indirme geçmişinizi ve ayarlarınızı bilgisayarınızdaki yerel bir SQLite veri tabanında saklar.
- **Loglar (Günlükler):** Sorun gidermeye yardımcı olmak için tanılama günlükleri yerel olarak `%AppData%\DownloadManager\logs` klasörünüzde saklanır. Bu günlükler asla otomatik olarak karşıya yüklenmez.
## 4. Üçüncü Taraf Hizmetleri
hDM, verilerinizi üçüncü taraflarla paylaşmaz. Bir dosya indirdiğinizde, doğrudan o dosyayı barındıran sunucuya bağlanırsınız. hDM, bir proxy veya aracı görevi görmez.
## 5. Güvenlik
Uygulama içinde kaydetmeyi seçebileceğiniz tüm kimlik bilgilerinin korunması dahil olmak üzere, yerel verilerinizi korumak için endüstri standardı güvenlik uygulamalarını kullanıyoruz.
## 6. Bu Politikadaki Değişiklikler
Gizlilik Politikamızı zaman zaman güncelleyebiliriz. Herhangi bir değişiklik, güncellenmiş "Son Güncelleme" tarihi ile bu sayfada yayınlanacaktır.
## 7. Bize Ulaşın
Bu Gizlilik Politikası hakkında herhangi bir sorunuz varsa, resmi proje deposu üzerinden bizimle iletişime geçebilirsiniz.

43
PRIVACY_POLICY.md Normal file
View File

@@ -0,0 +1,43 @@
# Privacy Policy for hOLOlu Download Manager (hDM)
**Last Updated:** May 7, 2026
hOLOlu Download Manager (hDM) is committed to protecting your privacy. This Privacy Policy explains how our application and browser extension handle information.
## 1. Information Collection and Use
hDM is a locally installed software. We believe in total privacy:
- **No Personal Data Collection:** We do not collect, store, or transmit any personal information, browsing history, or identity data to any external servers.
- **Local Processing:** All download information, URLs, and file paths are processed and stored locally on your machine in a private database.
- **No Tracking:** We do not use any tracking pixels, analytics, or cookies to monitor your behavior.
## 2. Browser Extension Permissions
To function correctly, the hDM Browser Extension requires the following permissions:
- **`downloads`:** Used to detect when a download starts so it can be intercepted and managed by hDM.
- **`nativeMessaging`:** Used to securely communicate with the hDM desktop application on your computer.
- **`contextMenus`:** Used to provide the "Download with hDM" option when you right-click on a link.
- **`<all_urls>`:** Necessary to allow the extension to intercept download links from various websites you visit.
None of the data accessed via these permissions is ever sent to hDM or any third party. It stays entirely on your local system.
## 3. Data Storage
- **Local Database:** hDM stores your download history and settings in a local SQLite database on your computer.
- **Logs:** Diagnostic logs are stored locally in your `%AppData%\DownloadManager\logs` folder to help troubleshoot issues. These logs are never automatically uploaded.
## 4. Third-Party Services
hDM does not share your data with third parties. When you download a file, you are connecting directly to the server hosting that file. hDM does not act as a proxy or intermediary.
## 5. Security
We implement industry-standard security practices to protect your local data, including the use of protected storage for any credentials you may choose to save within the application.
## 6. Changes to This Policy
We may update our Privacy Policy from time to time. Any changes will be posted on this page with an updated "Last Updated" date.
## 7. Contact Us
If you have any questions about this Privacy Policy, you can contact us through our official project repository.

View File

@@ -15,7 +15,9 @@ Modern, hızlı ve kullanıcı dostu, .NET 8 ve WPF tabanlıık kaynaklı bi
* **Sistem Tepsisi (Systray) Desteği:** Uygulama kapandığında sistem tepsisine küçülür, arka planda çalışmaya devam eder.
* **Gelişmiş Sıralama ve Filtreleme:** İndirmeleri tarihe, boyuta, duruma veya isme göre akıllıca sıralar; kategori bazlı filtreleme yapar.
* **Kullanıcı Arayüzü Özelleştirme:**ık/Koyu tema desteği, kategori panelini gizleme/gösterme ve sütun genişliklerini otomatik kaydetme.
* **Türkçe Arayüz ve Loglama:** İndirme durumları ve arka plan motor loglamaları Türkçeye çevrilmiş olup SQL logları minimize edilmiştir.
* **Detaylı Durum Çubuğu:** Toplam, Tamamlanan, Aktif, Duraklatılan ve Hatalı indirme sayılarını anlık olarak gösteren renkli istatistik paneli.
* **Akıllı Kuyruk Yönetimi:** Uygulama açılışında tüm indirmelerin otomatik başlamasını engelleyen, kullanıcı kontrolünde "Bekleyenleri Başlat" ve "Tümünü Duraklat" özellikleri.
* **Tekil Örnek (Single Instance):** Uygulamanın birden fazla kopyasının açılmasını engelleyen Mutex tabanlı koruma.
## 🛠 Teknik Mimari
@@ -24,7 +26,7 @@ Uygulama modern yazılım prensipleri (Clean Architecture) ve MVVM deseni üzeri
* **DownloadManager.Core:** İndirme motoru, Hız Sınırlayıcı (SpeedThrottler), HTTP protokol yönetimi, SQLite veritabanı katmanı ve temel modelleri içerir.
* **DownloadManager.WPF:** CommunityToolkit.Mvvm kullanılarak geliştirilmiş, ModernWpf UI kütüphanesi ile zenginleştirilmiş kullanıcı arayüzü.
* **DownloadManager.BrowserBridge:** Tarayıcı eklentisinden gelen verileri Named Pipe üzerinden ana (`hDM`) uygulamaya aktaran hafif köprü uygulaması.
* **Veritabanı:** Ayarlar ve indirme geçmişi SQLite üzerinde Entity Framework Core ile yönetilir.
* **Veritabanı:** Ayarlar ve indirme geçmişi SQLite üzerinde Entity Framework Core ile yönetilir. Arka plan işlemleri için `Scope` tabanlı asenkron erişim ile yüksek stabilite sağlanmıştır.
## 📦 Kurulum ve Çalıştırma
@@ -52,25 +54,24 @@ Tarayıcının eklenti üzerinden ana uygulama ile konuşabilmesi için "Native
* *Not: Kayıt defterindeki `path` değerinin derlediğiniz `DownloadManager.BrowserBridge.exe` dosyasının gerçek yolu ile eşleştiğinden emin olun.*
#### 2. Eklentiyi Tarayıcıya Yükleme
* Chrome veya Edge tarayıcınızda `chrome://extensions` adresine gidin.
* **Geliştirici Modu (Developer Mode)** seçeneğini aktif hale getirin.
* **Paketlenmemiş öğe yükle (Load unpacked)** butonuna tıklayın.
* Proje içindeki `browser-extension` klasörünü seçerek yükleyin.
* Chrome Web Store üzerinden yükleyebilir veya geliştirici modunda `browser-extension` klasörünü seçerek yükleyebilirsiniz.
* **Chrome Web Store ID:** Eklenti yayınlandığında sabitlenen ID'yi `manifest.json` içindeki `allowed_origins` kısmına eklemeyi unutmayın.
### 🖱 Kullanım
* **Otomatik Yakalama:** Eklenti yüklendikten sonra tarayıcıda sağ tık menüsünden **"hDM ile indir"** diyerek veya desteklenen uzantılara tıklayarak otomatik yakalama sağlayabilirsiniz.
* **Site İncele:** Sayfa içindeyken sağ tıklayıp **"Siteyi hDM ile incele"** diyerek sayfadaki tüm dosyaları topluca analiz edebilirsiniz.
* **Kuyruk Yönetimi:** "Bekleyenleri Başlat" butonu ile duraklatılmış tüm indirmeleri sıraya alabilir, "Tümünü Duraklat" ile ağ trafiğini anında durdurabilirsiniz.
* **Pano Desteği:** Herhangi bir linki kopyalayıp hDM içindeki "Ekle" butonuna bastığınızda link otomatik olarak yapıştırılır.
## 📈 Son Durum ve İyileştirmeler
Son yapılan güncellemeler ile:
- [x] Derleme adı `hDM.exe` olarak güncellendi. Özel ikonlar (`Down_nb-02`) eklendi.
- [x] İndirme hızı limitleme (`SpeedThrottler`) ve otomatik yeniden deneme (`Auto-Retry`) motoru yazıldı.
- [x] İndirme duraklatma ve devam ettirme mekanizmasındaki ilerleme (progress) sıfırlanma hataları giderildi.
- [x] UI Durum bildirimleri ve arka plan logları Türkçeleştirildi. EF Core SQL logları temizlendi.
- [x] Tarayıcı eklentisinden bağlam menüsü entegrasyonu (Context Menu) ile URL'nin doğrudan Site İncele paneline aktarılması sağlandı.
- [x] **Stabilite:** DbContext eşzamanlılık (concurrency) hataları `Transient` servis ömrü ve `Scope` yönetimi ile tamamen çözüldü.
- [x] **Kuyruk Kontrolü:** "Tümünü Duraklat" komutunun ardından indirmelerin kendiliğinden tekrar başlaması sorunu, veritabanı durum kontrolü ile giderildi.
- [x] **Açılış Hızı:** Uygulama ıldığında bekleyen indirmelerin otomatik başlaması engellenerek sistem kaynakları korundu.
- [x] **Görsel Detaylar:** Alt kısma indirme durumlarını (Tamamlanan, Hata, Aktif vb.) özetleyen detaylı bir durum çubuğu eklendi.
- [x] **Tekil Örnek:** Tarayıcıdan gelen çoklu tetiklemelerin arka planda süreç (process) biriktirmesi `Mutex` ile engellendi.
## 🛡 Güvenlik ve Gizlilik
hDM, kullanıcı verilerini sadece yerel SQLite veritabanında saklar. Şifreler ve kimlik bilgileri `ProtectedData` (DPAPI) ile Windows seviyesinde şifrelenerek korunur.

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
browser-extension/16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
browser-extension/48x48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -1,11 +1,5 @@
const NATIVE_HOST = "com.downloadmanager.bridge";
const interceptExtensions = [
"exe","msi","zip","rar","7z","tar","gz","iso",
"mp4","mkv","avi","mp3","flac","wav",
"pdf","docx","xlsx","pptx"
];
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
id: "dm-download-link",
@@ -21,9 +15,6 @@ chrome.runtime.onInstalled.addListener(() => {
});
chrome.downloads.onCreated.addListener((item) => {
const ext = item.filename?.split(".").pop()?.toLowerCase() ?? "";
if (!interceptExtensions.includes(ext)) return;
chrome.downloads.cancel(item.id, () => {
console.log("İndirme yakalandı, bridge'e gönderiliyor:", item.url);
chrome.runtime.sendNativeMessage(NATIVE_HOST, {

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "hOLOlu Download Manager",
"version": "1.0.0",
"version": "1.0.2",
"description": "Bağlantıları hDM ile indir ve sayfaları incele",
"permissions": ["downloads", "contextMenus", "storage", "nativeMessaging"],
"host_permissions": ["<all_urls>"],

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
hdm_bridge.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

View File

@@ -5,6 +5,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<ApplicationIcon>hdm_bridge.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>

View File

@@ -61,32 +61,55 @@ class Program
static async Task SendToMainAppAsync(BridgeMessage msg)
{
string logDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "DownloadManager", "logs");
if (!Directory.Exists(logDir)) Directory.CreateDirectory(logDir);
string logPath = Path.Combine(logDir, "bridge.log");
try
{
// Ana uygulamanın çalışıp çalışmadığını kontrol et
var processes = System.Diagnostics.Process.GetProcessesByName("hDM");
if (processes.Length == 0)
{
// Uygulama çalışmıyorsa başlat (Yolu bulmaya çalışalım)
string appPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "hDM.exe");
// Uygulama çalışmıyorsa başlat
// Önce kök dizine (proje kökü) çıkıp bin/Debug veya bin/Release kontrolü yapalım
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
string appPath = Path.Combine(baseDir, "hDM.exe");
// Geliştirme ortamı için alternatif yollar
// Geliştirme ortamı için alternatifler
if (!File.Exists(appPath))
appPath = @"D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.WPF\bin\Release\net8.0-windows\hDM.exe";
{
// Bridge'den WPF bin klasörüne çıkmaya çalış
var di = new DirectoryInfo(baseDir);
// D:\...\DownloadManager\src\DownloadManager.BrowserBridge\bin\Release\net8.0
// Buradan 4 seviye yukarı çıkarsak src'ye ulaşırız
if (di.Parent?.Parent?.Parent?.Parent != null)
{
string wpfBin = Path.Combine(di.Parent.Parent.Parent.Parent.FullName, "src", "DownloadManager.WPF", "bin", "Debug", "net8.0-windows10.0.19041.0", "hDM.exe");
if (File.Exists(wpfBin)) appPath = wpfBin;
else
{
wpfBin = Path.Combine(di.Parent.Parent.Parent.Parent.FullName, "src", "DownloadManager.WPF", "bin", "Release", "net8.0-windows10.0.19041.0", "hDM.exe");
if (File.Exists(wpfBin)) appPath = wpfBin;
}
}
}
if (File.Exists(appPath))
{
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(appPath) { UseShellExecute = true });
// Uygulamanın açılması ve pipe'ı başlatması için biraz bekleyelim
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(appPath) { UseShellExecute = true, WorkingDirectory = Path.GetDirectoryName(appPath) });
await Task.Delay(3000);
}
else
{
File.AppendAllText(logPath, $"{DateTime.Now}: Uygulama bulunamadı: {appPath}\n");
}
}
using var pipe = new NamedPipeClientStream(".", "DownloadManagerPipe",
PipeDirection.Out, PipeOptions.Asynchronous);
// Timeout'u 10 saniyeye çıkaralım (Uygulama yeni açılıyorsa gerekebilir)
await pipe.ConnectAsync(10000);
await pipe.ConnectAsync(5000);
var json = JsonConvert.SerializeObject(msg);
var data = Encoding.UTF8.GetBytes(json);
@@ -96,7 +119,7 @@ class Program
}
catch (Exception ex)
{
File.AppendAllText("bridge_error.log", $"{DateTime.Now}: Bağlantı hatası ({msg.Url}): {ex.Message}\n");
File.AppendAllText(logPath, $"{DateTime.Now}: Bağlantı hatası ({msg.Url}): {ex.Message}\n");
}
}
}

View File

@@ -0,0 +1,41 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v8.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v8.0": {
"DownloadManager.BrowserBridge/1.0.0": {
"dependencies": {
"Newtonsoft.Json": "13.0.4"
},
"runtime": {
"DownloadManager.BrowserBridge.dll": {}
}
},
"Newtonsoft.Json/13.0.4": {
"runtime": {
"lib/net6.0/Newtonsoft.Json.dll": {
"assemblyVersion": "13.0.0.0",
"fileVersion": "13.0.4.30916"
}
}
}
}
},
"libraries": {
"DownloadManager.BrowserBridge/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"Newtonsoft.Json/13.0.4": {
"type": "package",
"serviceable": true,
"sha512": "sha512-pdgNNMai3zv51W5aq268sujXUyx7SNdE2bj1wZcWjAQrKMFZV260lbqYop1d2GM67JI1huLRwxo9ZqnfF/lC6A==",
"path": "newtonsoft.json/13.0.4",
"hashPath": "newtonsoft.json.13.0.4.nupkg.sha512"
}
}
}

View File

@@ -0,0 +1,12 @@
{
"runtimeOptions": {
"tfm": "net8.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "8.0.0"
},
"configProperties": {
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

View File

@@ -4,6 +4,7 @@
"path": "D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.BrowserBridge\\bin\\Release\\net8.0\\DownloadManager.BrowserBridge.exe",
"type": "stdio",
"allowed_origins": [
"chrome-extension://gnohncemfbplcagkfdhedbkfaogcoobi/"
"chrome-extension://dnpggiajimpjhghjppekgpejplkcbejg",
"chrome-extension://gnohncemfbplcagkfdhedbkfaogcoobi"
]
}

View File

@@ -0,0 +1,22 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("DownloadManager.BrowserBridge")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+561a953b1f10b7ec16bef81fdcd4030ad9d5f1e4")]
[assembly: System.Reflection.AssemblyProductAttribute("DownloadManager.BrowserBridge")]
[assembly: System.Reflection.AssemblyTitleAttribute("DownloadManager.BrowserBridge")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// MSBuild WriteCodeFragment sınıfı tarafından oluşturuldu.

View File

@@ -0,0 +1 @@
113565b263fcdda4a4665ee4bb805cc1b4b99e5585e061be924810699276bedd

View File

@@ -0,0 +1,15 @@
is_global = true
build_property.TargetFramework = net8.0
build_property.TargetPlatformMinVersion =
build_property.UsingMicrosoftNETSdkWeb =
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = DownloadManager.BrowserBridge
build_property.ProjectDir = D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\
build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop =
build_property.EffectiveAnalysisLevelStyle = 8.0
build_property.EnableCodeStyleSeverity =

View File

@@ -0,0 +1 @@
5fd99a422a78009cff8ca33e1127d7f18d84d9f6b01faca46a390be79a246ed9

View File

@@ -0,0 +1,17 @@
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\bin\Debug\net8.0\DownloadManager.BrowserBridge.exe
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\bin\Debug\net8.0\DownloadManager.BrowserBridge.deps.json
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\bin\Debug\net8.0\DownloadManager.BrowserBridge.runtimeconfig.json
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\bin\Debug\net8.0\DownloadManager.BrowserBridge.dll
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\bin\Debug\net8.0\DownloadManager.BrowserBridge.pdb
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\bin\Debug\net8.0\Newtonsoft.Json.dll
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\obj\Debug\net8.0\DownloadManager.BrowserBridge.csproj.AssemblyReference.cache
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\obj\Debug\net8.0\DownloadManager.BrowserBridge.GeneratedMSBuildEditorConfig.editorconfig
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\obj\Debug\net8.0\DownloadManager.BrowserBridge.AssemblyInfoInputs.cache
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\obj\Debug\net8.0\DownloadManager.BrowserBridge.AssemblyInfo.cs
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\obj\Debug\net8.0\DownloadManager.BrowserBridge.csproj.CoreCompileInputs.cache
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\obj\Debug\net8.0\Download.A73557B5.Up2Date
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\obj\Debug\net8.0\DownloadManager.BrowserBridge.dll
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\obj\Debug\net8.0\refint\DownloadManager.BrowserBridge.dll
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\obj\Debug\net8.0\DownloadManager.BrowserBridge.pdb
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\obj\Debug\net8.0\DownloadManager.BrowserBridge.genruntimeconfig.cache
D:\Calismalar\AI\hDM\DownloadManager\src\DownloadManager.BrowserBridge\obj\Debug\net8.0\ref\DownloadManager.BrowserBridge.dll

View File

@@ -0,0 +1 @@
55a289d435d94f5304dfb112e526c2c5fd4f8dced6fb87cc465459bf16bab373

View File

@@ -1,7 +1,6 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -14,10 +13,10 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("DownloadManager.BrowserBridge")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+81faa715a4eb11a2bf648f52891306b46ea7c256")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+561a953b1f10b7ec16bef81fdcd4030ad9d5f1e4")]
[assembly: System.Reflection.AssemblyProductAttribute("DownloadManager.BrowserBridge")]
[assembly: System.Reflection.AssemblyTitleAttribute("DownloadManager.BrowserBridge")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// Generated by the MSBuild WriteCodeFragment class.
// MSBuild WriteCodeFragment sınıfı tarafından oluşturuldu.

View File

@@ -1 +1 @@
c41154c222d4c9aaf2ac34116ff46b068de5b4633ca984a833d7394a42fc99da
f0f25ac1863349e31e231b7ddaa3d27d9e23bc3cc9323375791cbf31e36329ff

View File

@@ -1,7 +1,9 @@
Windows Registry Editor Version 5.00
; Google Chrome için Kayıt
[HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts\com.downloadmanager.bridge]
@="D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.BrowserBridge\\manifest.json"
; Microsoft Edge için Kayıt
[HKEY_CURRENT_USER\Software\Microsoft\Edge\NativeMessagingHosts\com.downloadmanager.bridge]
@="D:\\Calismalar\\AI\\hDM\\DownloadManager\\src\\DownloadManager.BrowserBridge\\manifest.json"

View File

@@ -15,4 +15,30 @@ public class CategoryRepository : ICategoryRepository
public async Task<DownloadCategory?> GetByIdAsync(int id)
=> await _db.Categories.FindAsync(id);
public async Task AddAsync(DownloadCategory category)
{
_db.Categories.Add(category);
await _db.SaveChangesAsync();
}
public async Task UpdateAsync(DownloadCategory category)
{
var existing = await _db.Categories.FindAsync(category.Id);
if (existing != null)
{
_db.Entry(existing).CurrentValues.SetValues(category);
await _db.SaveChangesAsync();
}
}
public async Task DeleteAsync(int id)
{
var category = await _db.Categories.FindAsync(id);
if (category != null)
{
_db.Categories.Remove(category);
await _db.SaveChangesAsync();
}
}
}

View File

@@ -18,6 +18,9 @@ public interface ICategoryRepository
{
Task<IEnumerable<DownloadCategory>> GetAllAsync();
Task<DownloadCategory?> GetByIdAsync(int id);
Task AddAsync(DownloadCategory category);
Task UpdateAsync(DownloadCategory category);
Task DeleteAsync(int id);
}
public interface ISettingsRepository

View File

@@ -52,6 +52,25 @@ public class DownloadEngine
private async Task ProcessDownloadAsync(DownloadItem item, CancellationToken ct)
{
// Kuyruktan çıktıktan sonra güncel durumu veritabanından kontrol et
using (var scope = _serviceProvider.CreateScope())
{
var repo = scope.ServiceProvider.GetRequiredService<Data.Repositories.IDownloadRepository>();
var latest = await repo.GetByIdAsync(item.Id);
if (latest == null || latest.Status == DownloadStatus.Paused)
{
Serilog.Log.Information("İndirme {Id} duraklatılmış veya artık mevcut değil, işlem iptal edildi.", item.Id);
_queue.Release();
return;
}
// Eğer veritabanındaki durum farklıysa (örneğin başka bir yerden güncellendiyse) nesneyi güncelle
item.Status = latest.Status;
item.SavePath = latest.SavePath;
item.FileName = latest.FileName;
}
var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
_activeDownloads[item.Id] = cts;
@@ -73,13 +92,6 @@ public class DownloadEngine
item.DownloadedBytes = 0; // Yeni indirme
}
// DURAKLATILMIŞSA İŞLEME (Kuyruktan yeni çıktıysa ve o sırada durdurulduysa)
if (item.Status == DownloadStatus.Paused)
{
Serilog.Log.Information("İndirme {Id} duraklatıldı, atlanıyor.", item.Id);
return;
}
item.Status = DownloadStatus.Downloading;
// Notify UI that we are starting

View File

@@ -4,7 +4,7 @@ public class EngineOptions
{
public int MaxSegments { get; set; } = 8;
public long MinSegmentBytes { get; set; } = 512 * 1024; // 512 KB
public int MaxRetries { get; set; } = 5;
public int MaxRetries { get; set; } = 30;
public int RetryDelayMs { get; set; } = 2000;
public int ConnectionTimeoutSeconds { get; set; } = 30;
public long SpeedLimitBytesPerSec { get; set; } = 0; // 0 = limitsiz

View File

@@ -128,21 +128,29 @@ public class SegmentedDownloader : IDownloader
private async Task DownloadSegmentAsync(DownloadItem item, DownloadSegment segment, string tempDir, IProgress<DownloadProgressEvent>? progress, CancellationToken ct)
{
int retryCount = 0;
while (true)
Interlocked.Increment(ref _activeSegmentCount);
try
{
try
while (true)
{
await PerformSegmentDownloadAsync(item, segment, tempDir, progress, ct);
break;
}
catch (Exception ex) when (retryCount < _options.MaxRetries && !ct.IsCancellationRequested)
{
retryCount++;
Serilog.Log.Warning("Parça {Index} indirilemedi (Deneme {Count}/{Max}): {Error}",
segment.Index, retryCount, _options.MaxRetries, ex.Message);
await Task.Delay(_options.RetryDelayMs * retryCount, ct);
try
{
await PerformSegmentDownloadAsync(item, segment, tempDir, progress, ct);
break;
}
catch (Exception ex) when (retryCount < _options.MaxRetries && !ct.IsCancellationRequested)
{
retryCount++;
Serilog.Log.Warning("Parça {Index} indirilemedi (Deneme {Count}/{Max}): {Error}",
segment.Index, retryCount, _options.MaxRetries, ex.Message);
await Task.Delay((_options.RetryDelayMs * retryCount) + Random.Shared.Next(1000), ct);
}
}
}
finally
{
Interlocked.Decrement(ref _activeSegmentCount);
}
}
private async Task PerformSegmentDownloadAsync(DownloadItem item, DownloadSegment segment, string tempDir, IProgress<DownloadProgressEvent>? progress, CancellationToken ct)
@@ -168,9 +176,15 @@ public class SegmentedDownloader : IDownloader
var buffer = new byte[8192];
int read;
while ((read = await stream.ReadAsync(buffer, 0, buffer.Length, ct)) > 0)
while (true)
{
await fileStream.WriteAsync(buffer, 0, read, ct);
// Read with timeout to prevent hanging on network loss
read = await stream.ReadAsync(buffer, ct).AsTask()
.WaitAsync(TimeSpan.FromSeconds(_options.ConnectionTimeoutSeconds), ct);
if (read == 0) break;
await fileStream.WriteAsync(buffer.AsMemory(0, read), ct);
segment.Downloaded += read;
lock (_progressLock)
@@ -186,6 +200,8 @@ public class SegmentedDownloader : IDownloader
segment.Status = SegmentStatus.Completed;
}
private int _activeSegmentCount = 0;
private void ReportProgress(DownloadItem item, IProgress<DownloadProgressEvent>? progress)
{
if ((DateTime.UtcNow - _lastReport).TotalMilliseconds < 250) return;
@@ -203,7 +219,8 @@ public class SegmentedDownloader : IDownloader
ProgressPercent = percent,
SpeedBytesPerSec = _speedCalculator.GetBytesPerSecond(),
EstimatedRemaining = _speedCalculator.EstimateRemaining(item.TotalSize - downloaded),
Status = DownloadStatus.Downloading
Status = DownloadStatus.Downloading,
ActiveSegments = _activeSegmentCount
});
}

View File

@@ -43,7 +43,7 @@ public class SingleDownloader : IDownloader
retryCount++;
Serilog.Log.Warning("Tekil indirme başarısız (Deneme {Count}/{Max}): {Error}",
retryCount, _options.MaxRetries, ex.Message);
await Task.Delay(_options.RetryDelayMs * retryCount, ct);
await Task.Delay((_options.RetryDelayMs * retryCount) + Random.Shared.Next(1000), ct);
}
}
}
@@ -87,9 +87,15 @@ public class SingleDownloader : IDownloader
var buffer = new byte[8192];
int read;
while ((read = await contentStream.ReadAsync(buffer, 0, buffer.Length, ct)) > 0)
while (true)
{
await fileStream.WriteAsync(buffer, 0, read, ct);
// Read with timeout to prevent hanging on network loss
read = await contentStream.ReadAsync(buffer, ct).AsTask()
.WaitAsync(TimeSpan.FromSeconds(_options.ConnectionTimeoutSeconds), ct);
if (read <= 0) break;
await fileStream.WriteAsync(buffer.AsMemory(0, read), ct);
item.DownloadedBytes += read;
_speedCalculator.AddSample(read);

View File

@@ -12,4 +12,5 @@ public class DownloadProgressEvent
public long SpeedBytesPerSec { get; set; }
public TimeSpan? EstimatedRemaining { get; set; }
public DownloadStatus Status { get; set; }
public int ActiveSegments { get; set; }
}

View File

@@ -1,6 +1,9 @@
using DownloadManager.Core.Data.Repositories;
using DownloadManager.Core.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace DownloadManager.Core.Services;
@@ -8,6 +11,10 @@ namespace DownloadManager.Core.Services;
public interface ICategoryService
{
Task<IEnumerable<DownloadCategory>> GetCategoriesAsync();
Task AddCategoryAsync(DownloadCategory category);
Task UpdateCategoryAsync(DownloadCategory category);
Task DeleteCategoryAsync(int id);
Task<int> GetCategoryIdByExtensionAsync(string fileName);
}
public class CategoryService : ICategoryService
@@ -17,4 +24,34 @@ public class CategoryService : ICategoryService
public Task<IEnumerable<DownloadCategory>> GetCategoriesAsync()
=> _repository.GetAllAsync();
public Task AddCategoryAsync(DownloadCategory category)
=> _repository.AddAsync(category);
public Task UpdateCategoryAsync(DownloadCategory category)
=> _repository.UpdateAsync(category);
public Task DeleteCategoryAsync(int id)
=> _repository.DeleteAsync(id);
public async Task<int> GetCategoryIdByExtensionAsync(string fileName)
{
var ext = Path.GetExtension(fileName).TrimStart('.').ToLower();
var categories = await _repository.GetAllAsync();
foreach (var cat in categories)
{
if (string.IsNullOrWhiteSpace(cat.Extensions)) continue;
var extensions = cat.Extensions.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim().ToLower());
if (extensions.Contains(ext))
{
return cat.Id;
}
}
var other = categories.FirstOrDefault(c => c.Name == "Other" || c.Name == "Diğer");
return other?.Id ?? 6;
}
}

View File

@@ -45,10 +45,15 @@ public class DownloadService : IDownloadService
await _repository.UpdateAsync(item);
}
public Task PauseDownloadAsync(Guid id)
public async Task PauseDownloadAsync(Guid id)
{
var item = await _repository.GetByIdAsync(id);
if (item != null)
{
item.Status = Enums.DownloadStatus.Paused;
await _repository.UpdateAsync(item);
}
_engine.CancelDownload(id);
return Task.CompletedTask;
}
public async Task ResumeDownloadAsync(Guid id)

View File

@@ -1,4 +1,5 @@
using DownloadManager.Core.Models;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Threading;
@@ -8,15 +9,13 @@ namespace DownloadManager.Core.Services;
public class SchedulerWatchdog
{
private readonly IScheduleService _scheduleService;
private readonly IDownloadService _downloadService;
private readonly IServiceProvider _serviceProvider;
private Timer? _timer;
private bool _isProcessing;
public SchedulerWatchdog(IScheduleService scheduleService, IDownloadService downloadService)
public SchedulerWatchdog(IServiceProvider serviceProvider)
{
_scheduleService = scheduleService;
_downloadService = downloadService;
_serviceProvider = serviceProvider;
}
public void Start()
@@ -39,7 +38,10 @@ public class SchedulerWatchdog
try
{
var jobs = await _scheduleService.GetJobsAsync();
using var scope = _serviceProvider.CreateScope();
var scheduleService = scope.ServiceProvider.GetRequiredService<IScheduleService>();
var jobs = await scheduleService.GetJobsAsync();
var activeJob = jobs.FirstOrDefault(j => j.IsActive);
if (activeJob == null) return;
@@ -49,9 +51,6 @@ public class SchedulerWatchdog
// Gün kontrolü
int dayIndex = (int)now.DayOfWeek; // 0=Pazar, 1=Pazartesi...
// Model Pt=0, Pz=6 şeklinde varsayılmıştı (1111111)
// .NET DayOfWeek: Sunday=0, Monday=1...
// Dönüştürelim: Pt=0 için
int adjustedIndex = dayIndex == 0 ? 6 : dayIndex - 1;
if (activeJob.DaysOfWeek[adjustedIndex] == '0') return;
@@ -60,10 +59,9 @@ public class SchedulerWatchdog
if (activeJob.StartTime.HasValue)
{
var startTime = activeJob.StartTime.Value.TimeOfDay;
// Başlangıç vaktinden sonraki 1 dakika içindeysek başlat (sürekli tetiklenmemesi için)
if (currentTime >= startTime && currentTime < startTime.Add(TimeSpan.FromMinutes(1)))
{
await StartScheduledDownloads();
await StartScheduledDownloads(scope.ServiceProvider.GetRequiredService<IDownloadService>());
}
}
@@ -73,7 +71,7 @@ public class SchedulerWatchdog
var endTime = activeJob.EndTime.Value.TimeOfDay;
if (currentTime >= endTime && currentTime < endTime.Add(TimeSpan.FromMinutes(1)))
{
await StopAllDownloads();
await StopAllDownloads(scope.ServiceProvider.GetRequiredService<IDownloadService>());
}
}
}
@@ -87,27 +85,27 @@ public class SchedulerWatchdog
}
}
private async Task StartScheduledDownloads()
private async Task StartScheduledDownloads(IDownloadService downloadService)
{
Serilog.Log.Information("Zamanlayıcı: İndirmeler başlatılıyor...");
var downloads = await _downloadService.GetAllDownloadsAsync();
var downloads = await downloadService.GetAllDownloadsAsync();
var pending = downloads.Where(d => d.Status == Enums.DownloadStatus.Paused || d.Status == Enums.DownloadStatus.Pending);
foreach (var item in pending)
{
await _downloadService.ResumeDownloadAsync(item.Id);
await downloadService.ResumeDownloadAsync(item.Id);
}
}
private async Task StopAllDownloads()
private async Task StopAllDownloads(IDownloadService downloadService)
{
Serilog.Log.Information("Zamanlayıcı: İndirmeler durduruluyor...");
var downloads = await _downloadService.GetAllDownloadsAsync();
var downloads = await downloadService.GetAllDownloadsAsync();
var active = downloads.Where(d => d.Status == Enums.DownloadStatus.Downloading || d.Status == Enums.DownloadStatus.Queued);
foreach (var item in active)
{
await _downloadService.PauseDownloadAsync(item.Id);
await downloadService.PauseDownloadAsync(item.Id);
}
}
}

View File

@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("DownloadManager.Core")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+81faa715a4eb11a2bf648f52891306b46ea7c256")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+561a953b1f10b7ec16bef81fdcd4030ad9d5f1e4")]
[assembly: System.Reflection.AssemblyProductAttribute("DownloadManager.Core")]
[assembly: System.Reflection.AssemblyTitleAttribute("DownloadManager.Core")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@@ -1 +1 @@
57eee8222b0d77ae6e394591882c8d91daaa59ea38bf4b29e8d5d32072290d1d
355e174528e4d22ee7c251d97b3ad390b2cefbca24bdd6f2d576299a7fce3925

View File

@@ -1,7 +1,6 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -14,10 +13,10 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("DownloadManager.Core")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+81faa715a4eb11a2bf648f52891306b46ea7c256")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+561a953b1f10b7ec16bef81fdcd4030ad9d5f1e4")]
[assembly: System.Reflection.AssemblyProductAttribute("DownloadManager.Core")]
[assembly: System.Reflection.AssemblyTitleAttribute("DownloadManager.Core")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// Generated by the MSBuild WriteCodeFragment class.
// MSBuild WriteCodeFragment sınıfı tarafından oluşturuldu.

View File

@@ -1 +1 @@
86922a9eccfa1e5736aa220690f23d77712e45c8681c90dab58e4b60acfd7921
62c36dfd3abfff411d19bf2d9f22e0bd666e57c1af0629fcae7d4ef188fe9e95

View File

@@ -1,7 +1,6 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -14,10 +13,10 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("DownloadManager.TestConsole")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+81faa715a4eb11a2bf648f52891306b46ea7c256")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+561a953b1f10b7ec16bef81fdcd4030ad9d5f1e4")]
[assembly: System.Reflection.AssemblyProductAttribute("DownloadManager.TestConsole")]
[assembly: System.Reflection.AssemblyTitleAttribute("DownloadManager.TestConsole")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// Generated by the MSBuild WriteCodeFragment class.
// MSBuild WriteCodeFragment sınıfı tarafından oluşturuldu.

Some files were not shown because too many files have changed in this diff Show More