├── .gitattributes ├── .gitignore ├── Images ├── main.png ├── qBittorrent_offline_main.png ├── qBittorrent_online_main.png └── utorrent_offline_main.png ├── MyQbt.sln ├── MyQbt ├── AddPrefixWithFileName.cs ├── AddTorrentManual.Designer.cs ├── AddTorrentManual.cs ├── AddTorrentManual.resx ├── App.config ├── Config.cs ├── Helper.cs ├── IconHelper.cs ├── InfoForm.Designer.cs ├── InfoForm.cs ├── InfoForm.resx ├── MyQbt.csproj ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Resources │ └── icon.ico ├── WinForm.Designer.cs ├── WinForm.cs ├── WinForm.resx ├── packages.config ├── µTorrentOfflineUserControl.Designer.cs ├── µTorrentOfflineUserControl.cs └── µTorrentOfflineUserControl.resx ├── QbtWebAPI ├── API │ ├── Additional.cs │ ├── Base.cs │ └── Main.cs ├── Data │ ├── BuildInfo.cs │ ├── Log.cs │ ├── PartialData.cs │ ├── Preferences.cs │ ├── QBTException.cs │ ├── Time.cs │ ├── Torrent.cs │ ├── TorrentContents.cs │ ├── TorrentProperties.cs │ ├── Tracker.cs │ └── TransferInfo.cs ├── Enums │ ├── ConnectionStatus.cs │ ├── DynDnsService.cs │ ├── Encryption.cs │ ├── Key.cs │ ├── Locale.cs │ ├── LogType.cs │ ├── MaxRatioAction.cs │ ├── PieceState.cs │ ├── Priority.cs │ ├── ProxyType.cs │ ├── SchedulerDay.cs │ ├── Status.cs │ ├── TorrentState.cs │ └── TrackerStatus.cs ├── JSON │ ├── BuildInfoJSON.cs │ ├── LogJSON.cs │ ├── PartialDataJSON.cs │ ├── PreferencesJSON.cs │ ├── TorrentJSON.cs │ ├── TorrentPropertiesJSON.cs │ ├── TorrentWebSeedJSON.cs │ ├── TrackerJSON.cs │ └── TransferInfoJSON.cs └── QbtWebAPI.csproj ├── README.md └── Transmission.API.RPC ├── Arguments ├── NewTorrent.cs ├── SessionSettings.cs ├── TorrentFields.cs └── TorrentSettings.cs ├── AsyncExtensions.cs ├── Client.Async.cs ├── Client.cs ├── Common ├── ArgumentsBase.cs ├── CommunicateBase.cs ├── TransmissionRequest.cs └── TransmissionResponse.cs ├── Entity ├── NewTorrentInfo.cs ├── RenameTorrentInfo.cs ├── SessionInfo.cs ├── Statistic.cs ├── TorrentInfo.cs └── Units.cs ├── ITransmissionClient.cs ├── ITransmissionClientAsync.cs ├── Properties └── AssemblyInfo.cs ├── Transmission.API.RPC.csproj └── packages.config /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb -------------------------------------------------------------------------------- /Images/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LetCodeGo/MyQbt/9f1ce9d339fe98b575995de521de7ec5e74f80fd/Images/main.png -------------------------------------------------------------------------------- /Images/qBittorrent_offline_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LetCodeGo/MyQbt/9f1ce9d339fe98b575995de521de7ec5e74f80fd/Images/qBittorrent_offline_main.png -------------------------------------------------------------------------------- /Images/qBittorrent_online_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LetCodeGo/MyQbt/9f1ce9d339fe98b575995de521de7ec5e74f80fd/Images/qBittorrent_online_main.png -------------------------------------------------------------------------------- /Images/utorrent_offline_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LetCodeGo/MyQbt/9f1ce9d339fe98b575995de521de7ec5e74f80fd/Images/utorrent_offline_main.png -------------------------------------------------------------------------------- /MyQbt.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29102.190 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyQbt", "MyQbt\MyQbt.csproj", "{9CAC17DF-D741-4B8C-ACDB-17556038D615}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QbtWebAPI", "QbtWebAPI\QbtWebAPI.csproj", "{92CEB65A-B93C-418E-9462-F55CD080A469}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Transmission.API.RPC", "Transmission.API.RPC\Transmission.API.RPC.csproj", "{0D44D5B1-3317-4624-9C28-7DB1F6DFB018}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {9CAC17DF-D741-4B8C-ACDB-17556038D615}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {9CAC17DF-D741-4B8C-ACDB-17556038D615}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {9CAC17DF-D741-4B8C-ACDB-17556038D615}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {9CAC17DF-D741-4B8C-ACDB-17556038D615}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {92CEB65A-B93C-418E-9462-F55CD080A469}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {92CEB65A-B93C-418E-9462-F55CD080A469}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {92CEB65A-B93C-418E-9462-F55CD080A469}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {92CEB65A-B93C-418E-9462-F55CD080A469}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {0D44D5B1-3317-4624-9C28-7DB1F6DFB018}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {0D44D5B1-3317-4624-9C28-7DB1F6DFB018}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {0D44D5B1-3317-4624-9C28-7DB1F6DFB018}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {0D44D5B1-3317-4624-9C28-7DB1F6DFB018}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {8702D1EF-651F-4FCA-BC0F-42B6DCA0E985} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /MyQbt/AddPrefixWithFileName.cs: -------------------------------------------------------------------------------- 1 | using QbtWebAPI; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Text; 9 | using System.Text.RegularExpressions; 10 | using System.Threading.Tasks; 11 | using Transmission.API.RPC.Entity; 12 | 13 | namespace MyQbt 14 | { 15 | public class AddPrefixWithFileName 16 | { 17 | public static Func> LoginAndCheck = null; 18 | 19 | /// 20 | /// 间隔符是 空格 还是 点 21 | /// 22 | /// 23 | /// 24 | private static string AddDotOrBlank(string torrentCaption) 25 | { 26 | // 连续的算一个 27 | int countOfBlank = 0; 28 | int countOfDot = 0; 29 | bool blankFlag = false, dotFlag = false; 30 | 31 | torrentCaption.Trim(new char[] { ' ', '.' }); 32 | foreach (char ch in torrentCaption) 33 | { 34 | if (ch == ' ') 35 | { 36 | blankFlag = true; 37 | if (dotFlag) 38 | { 39 | countOfDot++; 40 | dotFlag = false; 41 | } 42 | } 43 | else if (ch == '.') 44 | { 45 | dotFlag = true; 46 | if (blankFlag) 47 | { 48 | countOfBlank++; 49 | blankFlag = false; 50 | } 51 | } 52 | else 53 | { 54 | if (dotFlag) countOfDot++; 55 | if (blankFlag) countOfBlank++; 56 | 57 | dotFlag = false; 58 | blankFlag = false; 59 | } 60 | } 61 | 62 | return (countOfDot > countOfBlank ? "." : " "); 63 | } 64 | 65 | /// 66 | /// 添加种子,种子文件名作前缀添加进保存路径,返回保存路径 67 | /// 68 | /// 69 | /// 70 | /// 71 | /// 72 | /// 73 | /// 74 | /// 75 | /// 76 | /// 77 | /// 78 | /// 79 | public static async Task AddTorrent( 80 | string torrentPath, BencodeNET.Torrents.Torrent bencodeTorrent, 81 | string saveFolder, bool skipHashCheck, 82 | bool startTorrent, string category, Config.BTClient btClient, 83 | bool isWindowsPath, 84 | Dictionary actualToVirtualDic = null, 85 | Transmission.API.RPC.Client transmissionClient = null) 86 | { 87 | string strTitle = 88 | bencodeTorrent.FileMode == BencodeNET.Torrents.TorrentFileMode.Single ? 89 | Path.GetFileNameWithoutExtension(bencodeTorrent.DisplayName) : 90 | bencodeTorrent.DisplayName; 91 | 92 | strTitle = Path.GetFileNameWithoutExtension(torrentPath) + 93 | AddDotOrBlank(strTitle) + 94 | strTitle; 95 | 96 | string strSaveFolderPath = saveFolder + (isWindowsPath ? "\\" : "/") + strTitle; 97 | 98 | if (Helper.CheckPath(ref strSaveFolderPath, isWindowsPath)) 99 | { 100 | if (skipHashCheck) 101 | { 102 | Helper.TrySkipCheck(bencodeTorrent, 103 | Helper.GetVirtualPath(strSaveFolderPath, actualToVirtualDic), false); 104 | } 105 | 106 | int loginCount = 1; 107 | bool needTryAgain = true; 108 | string errMsg = ""; 109 | 110 | if (btClient == Config.BTClient.qBittorrent) 111 | { 112 | do 113 | { 114 | try 115 | { 116 | await QbtWebAPI.API.DownloadFromDisk( 117 | new List() { torrentPath }, strSaveFolderPath, 118 | null, string.IsNullOrWhiteSpace(category) ? null : category, 119 | skipHashCheck, !startTorrent, false, strTitle, null, null, null, null); 120 | needTryAgain = false; 121 | } 122 | catch (QBTException ex) 123 | { 124 | needTryAgain = (loginCount > 0 && 125 | WinForm.IsConnectDisconnected && 126 | ex.HttpStatusCode == HttpStatusCode.Forbidden && 127 | LoginAndCheck != null && 128 | (errMsg = await LoginAndCheck.Invoke()) == null); 129 | 130 | if (!needTryAgain) 131 | { 132 | if (loginCount == 0 || 133 | ex.HttpStatusCode != HttpStatusCode.Forbidden || 134 | LoginAndCheck == null || 135 | errMsg == null) 136 | throw new Exception(string.Format( 137 | "HttpStatusCode:{0} {1}", 138 | Convert.ToInt32(ex.HttpStatusCode), 139 | Helper.GetExceptionAllMessage(ex))); 140 | else throw new Exception(errMsg); 141 | } 142 | else loginCount--; 143 | } 144 | catch (Exception ex) { throw ex; } 145 | } 146 | while (needTryAgain); 147 | } 148 | else if (btClient == Config.BTClient.Transmission) 149 | { 150 | Debug.Assert(transmissionClient != null); 151 | var addedTorrent = new NewTorrent 152 | { 153 | Metainfo = Helper.GetTransmissionTorrentAddMetainfo(torrentPath), 154 | DownloadDirectory = ( 155 | bencodeTorrent.FileMode == BencodeNET.Torrents.TorrentFileMode.Single ? 156 | strSaveFolderPath : 157 | Helper.GetDirectoryNameDonntChangeDelimiter(strSaveFolderPath)), 158 | Paused = ( 159 | bencodeTorrent.FileMode == BencodeNET.Torrents.TorrentFileMode.Single ? 160 | (!startTorrent) : true) 161 | }; 162 | var addedTorrentInfo = transmissionClient.TorrentAdd(addedTorrent); 163 | Debug.Assert(addedTorrentInfo != null && addedTorrentInfo.ID != 0); 164 | 165 | if (bencodeTorrent.FileMode == BencodeNET.Torrents.TorrentFileMode.Multi) 166 | { 167 | var result = transmissionClient.TorrentRenamePath( 168 | addedTorrentInfo.ID, 169 | bencodeTorrent.DisplayName, 170 | Path.GetFileName(strSaveFolderPath)); 171 | Debug.Assert(result != null && result.ID != 0); 172 | 173 | if (startTorrent) 174 | { 175 | transmissionClient.TorrentStartNow(new object[] { result.ID }); 176 | } 177 | } 178 | } 179 | 180 | return strSaveFolderPath; 181 | } 182 | else throw new Exception("保存路径包含无效字符"); 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /MyQbt/AddTorrentManual.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | 125 | AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w 126 | LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 127 | ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACk 128 | BwAAAk1TRnQBSQFMAgEBAgEAATgBAAE4AQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo 129 | AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA 130 | AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 131 | AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA 132 | AWYDAAGZAwABzAIAATMDAAIzAgABMwFmAgABMwGZAgABMwHMAgABMwH/AgABZgMAAWYBMwIAAmYCAAFm 133 | AZkCAAFmAcwCAAFmAf8CAAGZAwABmQEzAgABmQFmAgACmQIAAZkBzAIAAZkB/wIAAcwDAAHMATMCAAHM 134 | AWYCAAHMAZkCAALMAgABzAH/AgAB/wFmAgAB/wGZAgAB/wHMAQABMwH/AgAB/wEAATMBAAEzAQABZgEA 135 | ATMBAAGZAQABMwEAAcwBAAEzAQAB/wEAAf8BMwIAAzMBAAIzAWYBAAIzAZkBAAIzAcwBAAIzAf8BAAEz 136 | AWYCAAEzAWYBMwEAATMCZgEAATMBZgGZAQABMwFmAcwBAAEzAWYB/wEAATMBmQIAATMBmQEzAQABMwGZ 137 | AWYBAAEzApkBAAEzAZkBzAEAATMBmQH/AQABMwHMAgABMwHMATMBAAEzAcwBZgEAATMBzAGZAQABMwLM 138 | AQABMwHMAf8BAAEzAf8BMwEAATMB/wFmAQABMwH/AZkBAAEzAf8BzAEAATMC/wEAAWYDAAFmAQABMwEA 139 | AWYBAAFmAQABZgEAAZkBAAFmAQABzAEAAWYBAAH/AQABZgEzAgABZgIzAQABZgEzAWYBAAFmATMBmQEA 140 | AWYBMwHMAQABZgEzAf8BAAJmAgACZgEzAQADZgEAAmYBmQEAAmYBzAEAAWYBmQIAAWYBmQEzAQABZgGZ 141 | AWYBAAFmApkBAAFmAZkBzAEAAWYBmQH/AQABZgHMAgABZgHMATMBAAFmAcwBmQEAAWYCzAEAAWYBzAH/ 142 | AQABZgH/AgABZgH/ATMBAAFmAf8BmQEAAWYB/wHMAQABzAEAAf8BAAH/AQABzAEAApkCAAGZATMBmQEA 143 | AZkBAAGZAQABmQEAAcwBAAGZAwABmQIzAQABmQEAAWYBAAGZATMBzAEAAZkBAAH/AQABmQFmAgABmQFm 144 | ATMBAAGZATMBZgEAAZkBZgGZAQABmQFmAcwBAAGZATMB/wEAApkBMwEAApkBZgEAA5kBAAKZAcwBAAKZ 145 | Af8BAAGZAcwCAAGZAcwBMwEAAWYBzAFmAQABmQHMAZkBAAGZAswBAAGZAcwB/wEAAZkB/wIAAZkB/wEz 146 | AQABmQHMAWYBAAGZAf8BmQEAAZkB/wHMAQABmQL/AQABzAMAAZkBAAEzAQABzAEAAWYBAAHMAQABmQEA 147 | AcwBAAHMAQABmQEzAgABzAIzAQABzAEzAWYBAAHMATMBmQEAAcwBMwHMAQABzAEzAf8BAAHMAWYCAAHM 148 | AWYBMwEAAZkCZgEAAcwBZgGZAQABzAFmAcwBAAGZAWYB/wEAAcwBmQIAAcwBmQEzAQABzAGZAWYBAAHM 149 | ApkBAAHMAZkBzAEAAcwBmQH/AQACzAIAAswBMwEAAswBZgEAAswBmQEAA8wBAALMAf8BAAHMAf8CAAHM 150 | Af8BMwEAAZkB/wFmAQABzAH/AZkBAAHMAf8BzAEAAcwC/wEAAcwBAAEzAQAB/wEAAWYBAAH/AQABmQEA 151 | AcwBMwIAAf8CMwEAAf8BMwFmAQAB/wEzAZkBAAH/ATMBzAEAAf8BMwH/AQAB/wFmAgAB/wFmATMBAAHM 152 | AmYBAAH/AWYBmQEAAf8BZgHMAQABzAFmAf8BAAH/AZkCAAH/AZkBMwEAAf8BmQFmAQAB/wKZAQAB/wGZ 153 | AcwBAAH/AZkB/wEAAf8BzAIAAf8BzAEzAQAB/wHMAWYBAAH/AcwBmQEAAf8CzAEAAf8BzAH/AQAC/wEz 154 | AQABzAH/AWYBAAL/AZkBAAL/AcwBAAJmAf8BAAFmAf8BZgEAAWYC/wEAAf8CZgEAAf8BZgH/AQAC/wFm 155 | AQABIQEAAaUBAANfAQADdwEAA4YBAAOWAQADywEAA7IBAAPXAQAD3QEAA+MBAAPqAQAD8QEAA/gBAAHw 156 | AfsB/wEAAaQCoAEAA4ADAAH/AgAB/wMAAv8BAAH/AwAB/wEAAf8BAAL/AgAD/0EAEBEBFAwRAfQiABAR 157 | AewMEQHvIgAQEQH3DBEBFCIAEBEB7AHtDBEB8iEAEREB8gwRAe0hABERAfMBFAwRAf8gABERAbwB7wwR 158 | AbwgABERAe0B9AwRAW0gABERARIuAB0RIwAdESMACBEB9wcABREBFAH0KQAHEQH3CAAEEQEUAfSqAAFC 159 | AU0BPgcAAT4DAAEoAwABQAMAARADAAEBAQABAQUAAYAXAAP/AQAE/wcAAQMHAAEDBwABAwcAAQEHAAEB 160 | HgABPwH/BwABBwcAAQcFAAF/AQEB/wUAAf8BAwH/BAAE/wQABP8EAAs= 161 | 162 | 163 | -------------------------------------------------------------------------------- /MyQbt/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /MyQbt/Config.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Xml.Serialization; 7 | 8 | namespace MyQbt 9 | { 10 | [XmlRoot("Config")] 11 | public class Config 12 | { 13 | [XmlRoot("Connect")] 14 | public class Connect 15 | { 16 | [XmlAttribute("Url")] 17 | public string Url; 18 | [XmlAttribute("User")] 19 | public string User; 20 | [XmlAttribute("Password")] 21 | public string Password; 22 | } 23 | 24 | [XmlRoot("DomainCategory")] 25 | public class DomainCategory 26 | { 27 | [XmlAttribute("Domain")] 28 | public string Domain; 29 | [XmlAttribute("Category")] 30 | public string Category; 31 | } 32 | 33 | public enum SystemType 34 | { 35 | [XmlEnum("Windows")] 36 | Windows, 37 | [XmlEnum("Linux")] 38 | Linux 39 | } 40 | 41 | public enum BTClient 42 | { 43 | [XmlEnum("qBittorrent")] 44 | qBittorrent, 45 | [XmlEnum("Transmission")] 46 | Transmission 47 | } 48 | [XmlAttribute("BTClientType")] 49 | public BTClient BTClientType; 50 | [XmlAttribute("QbtSystemType")] 51 | public SystemType QbtSystemType; 52 | [XmlAttribute("IsPathMap")] 53 | public bool IsPathMap; 54 | [XmlAttribute("LastUseUrl")] 55 | public string LastUseUrl; 56 | [XmlArray("ConnectList")] 57 | public List ConnectList; 58 | 59 | [XmlAttribute("LastUseCategory")] 60 | public string LastUseCategory; 61 | [XmlArray("CategoryList")] 62 | public List CategoryList; 63 | 64 | [XmlArray("DomainCategoryList")] 65 | public List DomainCategoryList; 66 | 67 | [XmlArray("SaveFolderList")] 68 | public List SaveFolderList; 69 | 70 | [XmlElement("PathMapString")] 71 | public string PathMapString; 72 | 73 | [XmlArray("TrackerFindList")] 74 | public List TrackerFindList; 75 | 76 | [XmlArray("TrackerReplaceList")] 77 | public List TrackerReplaceList; 78 | 79 | [XmlArray("SavePathFindList")] 80 | public List SavePathFindList; 81 | 82 | [XmlArray("SavePathReplaceList")] 83 | public List SavePathReplaceList; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /MyQbt/IconHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Collections; 4 | using System.ComponentModel; 5 | using System.Data; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace MyQbt 9 | { 10 | /// 11 | /// Provides static methods to read system icons for both folders and files. 12 | /// 13 | /// 14 | /// IconReader.GetFileIcon("c:\\general.xls"); 15 | /// 16 | public class IconReader 17 | { 18 | /// 19 | /// Options to specify the size of icons to return. 20 | /// 21 | public enum IconSize 22 | { 23 | /// 24 | /// Specify large icon - 32 pixels by 32 pixels. 25 | /// 26 | Large = 0, 27 | /// 28 | /// Specify small icon - 16 pixels by 16 pixels. 29 | /// 30 | Small = 1 31 | } 32 | 33 | /// 34 | /// Options to specify whether folders should be in the open or closed state. 35 | /// 36 | public enum FolderType 37 | { 38 | /// 39 | /// Specify open folder. 40 | /// 41 | Open = 0, 42 | /// 43 | /// Specify closed folder. 44 | /// 45 | Closed = 1 46 | } 47 | 48 | /// 49 | /// Returns an icon for a given file - indicated by the name parameter. 50 | /// 51 | /// Pathname for file. 52 | /// Large or small 53 | /// Whether to include the link icon 54 | /// System.Drawing.Icon 55 | public static System.Drawing.Icon GetFileIcon(string name, IconSize size, bool linkOverlay) 56 | { 57 | Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO(); 58 | uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_USEFILEATTRIBUTES; 59 | 60 | if (true == linkOverlay) flags += Shell32.SHGFI_LINKOVERLAY; 61 | 62 | /* Check the size specified for return. */ 63 | if (IconSize.Small == size) 64 | { 65 | flags += Shell32.SHGFI_SMALLICON; 66 | } 67 | else 68 | { 69 | flags += Shell32.SHGFI_LARGEICON; 70 | } 71 | 72 | Shell32.SHGetFileInfo(name, 73 | Shell32.FILE_ATTRIBUTE_NORMAL, 74 | ref shfi, 75 | (uint)System.Runtime.InteropServices.Marshal.SizeOf(shfi), 76 | flags); 77 | 78 | // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly 79 | System.Drawing.Icon icon = (System.Drawing.Icon)System.Drawing.Icon.FromHandle(shfi.hIcon).Clone(); 80 | User32.DestroyIcon(shfi.hIcon); // Cleanup 81 | return icon; 82 | } 83 | 84 | /// 85 | /// Used to access system folder icons. 86 | /// 87 | /// Specify large or small icons. 88 | /// Specify open or closed FolderType. 89 | /// System.Drawing.Icon 90 | public static System.Drawing.Icon GetFolderIcon(IconSize size, FolderType folderType) 91 | { 92 | // Need to add size check, although errors generated at present! 93 | uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_USEFILEATTRIBUTES; 94 | 95 | if (FolderType.Open == folderType) 96 | { 97 | flags += Shell32.SHGFI_OPENICON; 98 | } 99 | 100 | if (IconSize.Small == size) 101 | { 102 | flags += Shell32.SHGFI_SMALLICON; 103 | } 104 | else 105 | { 106 | flags += Shell32.SHGFI_LARGEICON; 107 | } 108 | 109 | // Get the folder icon 110 | Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO(); 111 | Shell32.SHGetFileInfo(null, 112 | Shell32.FILE_ATTRIBUTE_DIRECTORY, 113 | ref shfi, 114 | (uint)System.Runtime.InteropServices.Marshal.SizeOf(shfi), 115 | flags); 116 | 117 | System.Drawing.Icon.FromHandle(shfi.hIcon); // Load the icon from an HICON handle 118 | 119 | // Now clone the icon, so that it can be successfully stored in an ImageList 120 | System.Drawing.Icon icon = (System.Drawing.Icon)System.Drawing.Icon.FromHandle(shfi.hIcon).Clone(); 121 | 122 | User32.DestroyIcon(shfi.hIcon); // Cleanup 123 | return icon; 124 | } 125 | } 126 | 127 | /// 128 | /// Wraps necessary Shell32.dll structures and functions required to retrieve Icon Handles using SHGetFileInfo. Code 129 | /// courtesy of MSDN Cold Rooster Consulting case study. 130 | /// 131 | /// 132 | 133 | // This code has been left largely untouched from that in the CRC example. The main changes have been moving 134 | // the icon reading code over to the IconReader type. 135 | public class Shell32 136 | { 137 | 138 | public const int MAX_PATH = 256; 139 | [StructLayout(LayoutKind.Sequential)] 140 | public struct SHITEMID 141 | { 142 | public ushort cb; 143 | [MarshalAs(UnmanagedType.LPArray)] 144 | public byte[] abID; 145 | } 146 | 147 | [StructLayout(LayoutKind.Sequential)] 148 | public struct ITEMIDLIST 149 | { 150 | public SHITEMID mkid; 151 | } 152 | 153 | [StructLayout(LayoutKind.Sequential)] 154 | public struct BROWSEINFO 155 | { 156 | public IntPtr hwndOwner; 157 | public IntPtr pidlRoot; 158 | public IntPtr pszDisplayName; 159 | [MarshalAs(UnmanagedType.LPTStr)] 160 | public string lpszTitle; 161 | public uint ulFlags; 162 | public IntPtr lpfn; 163 | public int lParam; 164 | public IntPtr iImage; 165 | } 166 | 167 | // Browsing for directory. 168 | public const uint BIF_RETURNONLYFSDIRS = 0x0001; 169 | public const uint BIF_DONTGOBELOWDOMAIN = 0x0002; 170 | public const uint BIF_STATUSTEXT = 0x0004; 171 | public const uint BIF_RETURNFSANCESTORS = 0x0008; 172 | public const uint BIF_EDITBOX = 0x0010; 173 | public const uint BIF_VALIDATE = 0x0020; 174 | public const uint BIF_NEWDIALOGSTYLE = 0x0040; 175 | public const uint BIF_USENEWUI = (BIF_NEWDIALOGSTYLE | BIF_EDITBOX); 176 | public const uint BIF_BROWSEINCLUDEURLS = 0x0080; 177 | public const uint BIF_BROWSEFORCOMPUTER = 0x1000; 178 | public const uint BIF_BROWSEFORPRINTER = 0x2000; 179 | public const uint BIF_BROWSEINCLUDEFILES = 0x4000; 180 | public const uint BIF_SHAREABLE = 0x8000; 181 | 182 | [StructLayout(LayoutKind.Sequential)] 183 | public struct SHFILEINFO 184 | { 185 | public const int NAMESIZE = 80; 186 | public IntPtr hIcon; 187 | public int iIcon; 188 | public uint dwAttributes; 189 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] 190 | public string szDisplayName; 191 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NAMESIZE)] 192 | public string szTypeName; 193 | }; 194 | 195 | public const uint SHGFI_ICON = 0x000000100; // get icon 196 | public const uint SHGFI_DISPLAYNAME = 0x000000200; // get display name 197 | public const uint SHGFI_TYPENAME = 0x000000400; // get type name 198 | public const uint SHGFI_ATTRIBUTES = 0x000000800; // get attributes 199 | public const uint SHGFI_ICONLOCATION = 0x000001000; // get icon location 200 | public const uint SHGFI_EXETYPE = 0x000002000; // return exe type 201 | public const uint SHGFI_SYSICONINDEX = 0x000004000; // get system icon index 202 | public const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon 203 | public const uint SHGFI_SELECTED = 0x000010000; // show icon in selected state 204 | public const uint SHGFI_ATTR_SPECIFIED = 0x000020000; // get only specified attributes 205 | public const uint SHGFI_LARGEICON = 0x000000000; // get large icon 206 | public const uint SHGFI_SMALLICON = 0x000000001; // get small icon 207 | public const uint SHGFI_OPENICON = 0x000000002; // get open icon 208 | public const uint SHGFI_SHELLICONSIZE = 0x000000004; // get shell size icon 209 | public const uint SHGFI_PIDL = 0x000000008; // pszPath is a pidl 210 | public const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute 211 | public const uint SHGFI_ADDOVERLAYS = 0x000000020; // apply the appropriate overlays 212 | public const uint SHGFI_OVERLAYINDEX = 0x000000040; // Get the index of the overlay 213 | 214 | public const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010; 215 | public const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; 216 | 217 | [DllImport("Shell32.dll")] 218 | public static extern IntPtr SHGetFileInfo( 219 | string pszPath, 220 | uint dwFileAttributes, 221 | ref SHFILEINFO psfi, 222 | uint cbFileInfo, 223 | uint uFlags 224 | ); 225 | } 226 | 227 | /// 228 | /// Wraps necessary functions imported from User32.dll. Code courtesy of MSDN Cold Rooster Consulting example. 229 | /// 230 | public class User32 231 | { 232 | /// 233 | /// Provides access to function required to delete handle. This method is used internally 234 | /// and is not required to be called separately. 235 | /// 236 | /// Pointer to icon handle. 237 | /// N/A 238 | [DllImport("User32.dll")] 239 | public static extern int DestroyIcon(IntPtr hIcon); 240 | } 241 | } -------------------------------------------------------------------------------- /MyQbt/InfoForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace MyQbt 2 | { 3 | partial class InfoForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.richTextBox = new System.Windows.Forms.RichTextBox(); 32 | this.SuspendLayout(); 33 | // 34 | // richTextBox 35 | // 36 | this.richTextBox.DetectUrls = false; 37 | this.richTextBox.Dock = System.Windows.Forms.DockStyle.Fill; 38 | this.richTextBox.Location = new System.Drawing.Point(0, 0); 39 | this.richTextBox.Name = "richTextBox"; 40 | this.richTextBox.ReadOnly = true; 41 | this.richTextBox.Size = new System.Drawing.Size(800, 450); 42 | this.richTextBox.TabIndex = 0; 43 | this.richTextBox.Text = ""; 44 | // 45 | // InfoForm 46 | // 47 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 48 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 49 | this.ClientSize = new System.Drawing.Size(800, 450); 50 | this.Controls.Add(this.richTextBox); 51 | this.Name = "InfoForm"; 52 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 53 | this.Text = "InfoForm"; 54 | this.ResumeLayout(false); 55 | 56 | } 57 | 58 | #endregion 59 | 60 | private System.Windows.Forms.RichTextBox richTextBox; 61 | } 62 | } -------------------------------------------------------------------------------- /MyQbt/InfoForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace MyQbt 12 | { 13 | public partial class InfoForm : Form 14 | { 15 | public InfoForm(string title, string info, Form ownerForm) 16 | { 17 | InitializeComponent(); 18 | 19 | if (ownerForm == null) 20 | { 21 | this.StartPosition = FormStartPosition.CenterParent; 22 | } 23 | else 24 | { 25 | this.StartPosition = FormStartPosition.Manual; 26 | Point topRight = Helper.GetFormRightTopLocation(ownerForm); 27 | this.Location = new Point(topRight.X - this.Width, topRight.Y); 28 | } 29 | 30 | this.Text = title; 31 | this.Icon = Properties.Resources.icon; 32 | this.richTextBox.Text = info; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /MyQbt/InfoForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /MyQbt/MyQbt.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {9CAC17DF-D741-4B8C-ACDB-17556038D615} 8 | WinExe 9 | MyQbt 10 | MyQbt 11 | v4.8 12 | 512 13 | true 14 | true 15 | 16 | 17 | 18 | 19 | 20 | AnyCPU 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | AnyCPU 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | 38 | 39 | Resources\icon.ico 40 | 41 | 42 | MyQbt.Program 43 | 44 | 45 | 46 | ..\packages\BencodeNET.4.0.0\lib\netstandard2.0\BencodeNET.dll 47 | 48 | 49 | ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll 50 | 51 | 52 | 53 | 54 | ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll 55 | 56 | 57 | 58 | 59 | ..\packages\System.IO.Pipelines.6.0.3\lib\net461\System.IO.Pipelines.dll 60 | 61 | 62 | ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll 63 | 64 | 65 | 66 | 67 | ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll 68 | 69 | 70 | ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll 71 | 72 | 73 | ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Form 82 | 83 | 84 | AddTorrentManual.cs 85 | 86 | 87 | 88 | 89 | 90 | Form 91 | 92 | 93 | InfoForm.cs 94 | 95 | 96 | 97 | 98 | Form 99 | 100 | 101 | WinForm.cs 102 | 103 | 104 | UserControl 105 | 106 | 107 | µTorrentOfflineUserControl.cs 108 | 109 | 110 | AddTorrentManual.cs 111 | 112 | 113 | InfoForm.cs 114 | 115 | 116 | ResXFileCodeGenerator 117 | Resources.Designer.cs 118 | Designer 119 | 120 | 121 | True 122 | Resources.resx 123 | True 124 | 125 | 126 | WinForm.cs 127 | 128 | 129 | µTorrentOfflineUserControl.cs 130 | 131 | 132 | 133 | SettingsSingleFileGenerator 134 | Settings.Designer.cs 135 | 136 | 137 | True 138 | Settings.settings 139 | True 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | {92ceb65a-b93c-418e-9462-f55cd080a469} 151 | QbtWebAPI 152 | 153 | 154 | {0d44d5b1-3317-4624-9c28-7db1f6dfb018} 155 | Transmission.API.RPC 156 | 157 | 158 | 159 | 160 | if "$(ConfigurationName)" == "Release" ( 161 | xcopy $(TargetPath) "C:\Users\zhang\Documents\ZX\tools\MyQbt\" /y) 162 | 163 | -------------------------------------------------------------------------------- /MyQbt/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace MyQbt 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// 应用程序的主入口点。 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new WinForm()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /MyQbt/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // 有关程序集的一般信息由以下 7 | // 控制。更改这些特性值可修改 8 | // 与程序集关联的信息。 9 | [assembly: AssemblyTitle("MyQbt")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("MyQbt")] 14 | [assembly: AssemblyCopyright("niconicoflag@gmail.com")] 15 | [assembly: AssemblyTrademark("niconicoflag@gmail.com")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // 将 ComVisible 设置为 false 会使此程序集中的类型 19 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 20 | //请将此类型的 ComVisible 特性设置为 true。 21 | [assembly: ComVisible(false)] 22 | 23 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 24 | [assembly: Guid("9cac17df-d741-4b8c-acdb-17556038d615")] 25 | 26 | // 程序集的版本信息由下列四个值组成: 27 | // 28 | // 主版本 29 | // 次版本 30 | // 生成号 31 | // 修订号 32 | // 33 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 34 | //通过使用 "*",如下所示: 35 | // [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyVersion("1.7")] 37 | [assembly: AssemblyFileVersion("1.7")] 38 | [assembly: NeutralResourcesLanguage("zh")] 39 | -------------------------------------------------------------------------------- /MyQbt/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace MyQbt.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MyQbt.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 重写当前线程的 CurrentUICulture 属性,对 51 | /// 使用此强类型资源类的所有资源查找执行重写。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// 查找类似于 (图标) 的 System.Drawing.Icon 类型的本地化资源。 65 | /// 66 | internal static System.Drawing.Icon icon { 67 | get { 68 | object obj = ResourceManager.GetObject("icon", resourceCulture); 69 | return ((System.Drawing.Icon)(obj)); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /MyQbt/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | -------------------------------------------------------------------------------- /MyQbt/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace MyQbt.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.2.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /MyQbt/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MyQbt/Resources/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LetCodeGo/MyQbt/9f1ce9d339fe98b575995de521de7ec5e74f80fd/MyQbt/Resources/icon.ico -------------------------------------------------------------------------------- /MyQbt/WinForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /MyQbt/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /MyQbt/µTorrentOfflineUserControl.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace MyQbt 2 | { 3 | partial class µTorrentOfflineUserControl 4 | { 5 | /// 6 | /// 必需的设计器变量。 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// 清理所有正在使用的资源。 12 | /// 13 | /// 如果应释放托管资源,为 true;否则为 false。 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region 组件设计器生成的代码 24 | 25 | /// 26 | /// 设计器支持所需的方法 - 不要修改 27 | /// 使用代码编辑器修改此方法的内容。 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.btnSaveResumeData = new System.Windows.Forms.Button(); 32 | this.btnLoadResumeData = new System.Windows.Forms.Button(); 33 | this.groupBoxAction = new System.Windows.Forms.GroupBox(); 34 | this.btnRemoveInvalidTorrentInfo = new System.Windows.Forms.Button(); 35 | this.btnRemoveTorrent = new System.Windows.Forms.Button(); 36 | this.groupBoxAction.SuspendLayout(); 37 | this.SuspendLayout(); 38 | // 39 | // btnSaveResumeData 40 | // 41 | this.btnSaveResumeData.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 42 | | System.Windows.Forms.AnchorStyles.Right))); 43 | this.btnSaveResumeData.Location = new System.Drawing.Point(6, 20); 44 | this.btnSaveResumeData.Name = "btnSaveResumeData"; 45 | this.btnSaveResumeData.Size = new System.Drawing.Size(682, 23); 46 | this.btnSaveResumeData.TabIndex = 11; 47 | this.btnSaveResumeData.Text = "保存 resume.dat"; 48 | this.btnSaveResumeData.UseVisualStyleBackColor = true; 49 | this.btnSaveResumeData.Click += new System.EventHandler(this.BtnSaveResumeData_Click); 50 | // 51 | // btnLoadResumeData 52 | // 53 | this.btnLoadResumeData.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 54 | | System.Windows.Forms.AnchorStyles.Right))); 55 | this.btnLoadResumeData.Location = new System.Drawing.Point(3, 3); 56 | this.btnLoadResumeData.Name = "btnLoadResumeData"; 57 | this.btnLoadResumeData.Size = new System.Drawing.Size(694, 23); 58 | this.btnLoadResumeData.TabIndex = 10; 59 | this.btnLoadResumeData.Text = "执行任何操作前请先加载 resume.data 文件"; 60 | this.btnLoadResumeData.UseVisualStyleBackColor = true; 61 | this.btnLoadResumeData.Click += new System.EventHandler(this.BtnLoadResumeData_Click); 62 | // 63 | // groupBoxAction 64 | // 65 | this.groupBoxAction.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 66 | | System.Windows.Forms.AnchorStyles.Left) 67 | | System.Windows.Forms.AnchorStyles.Right))); 68 | this.groupBoxAction.Controls.Add(this.btnRemoveInvalidTorrentInfo); 69 | this.groupBoxAction.Controls.Add(this.btnRemoveTorrent); 70 | this.groupBoxAction.Controls.Add(this.btnSaveResumeData); 71 | this.groupBoxAction.Location = new System.Drawing.Point(3, 32); 72 | this.groupBoxAction.Name = "groupBoxAction"; 73 | this.groupBoxAction.Size = new System.Drawing.Size(694, 365); 74 | this.groupBoxAction.TabIndex = 12; 75 | this.groupBoxAction.TabStop = false; 76 | // 77 | // btnRemoveInvalidTorrentInfo 78 | // 79 | this.btnRemoveInvalidTorrentInfo.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 80 | | System.Windows.Forms.AnchorStyles.Right))); 81 | this.btnRemoveInvalidTorrentInfo.Location = new System.Drawing.Point(6, 78); 82 | this.btnRemoveInvalidTorrentInfo.Name = "btnRemoveInvalidTorrentInfo"; 83 | this.btnRemoveInvalidTorrentInfo.Size = new System.Drawing.Size(682, 23); 84 | this.btnRemoveInvalidTorrentInfo.TabIndex = 15; 85 | this.btnRemoveInvalidTorrentInfo.Text = "移除UT中实际数据不存在的种子信息(只是移除了 resume.data 中的信息,种子文件还没删)"; 86 | this.btnRemoveInvalidTorrentInfo.UseVisualStyleBackColor = true; 87 | this.btnRemoveInvalidTorrentInfo.Click += new System.EventHandler(this.BtnRemoveInvalidTorrentInfo_Click); 88 | // 89 | // btnRemoveTorrent 90 | // 91 | this.btnRemoveTorrent.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 92 | | System.Windows.Forms.AnchorStyles.Right))); 93 | this.btnRemoveTorrent.Location = new System.Drawing.Point(6, 136); 94 | this.btnRemoveTorrent.Name = "btnRemoveTorrent"; 95 | this.btnRemoveTorrent.Size = new System.Drawing.Size(682, 23); 96 | this.btnRemoveTorrent.TabIndex = 14; 97 | this.btnRemoveTorrent.Text = "移除指定目录下不关联于UT中的种子(不修改 resume.data)"; 98 | this.btnRemoveTorrent.UseVisualStyleBackColor = true; 99 | this.btnRemoveTorrent.Click += new System.EventHandler(this.BtnRemoveTorrent_Click); 100 | // 101 | // µTorrentOfflineUserControl 102 | // 103 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 104 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 105 | this.Controls.Add(this.groupBoxAction); 106 | this.Controls.Add(this.btnLoadResumeData); 107 | this.Name = "µTorrentOfflineUserControl"; 108 | this.Size = new System.Drawing.Size(700, 400); 109 | this.Load += new System.EventHandler(this.ΜTorrentOfflineUserControl_Load); 110 | this.groupBoxAction.ResumeLayout(false); 111 | this.ResumeLayout(false); 112 | 113 | } 114 | 115 | #endregion 116 | 117 | private System.Windows.Forms.Button btnSaveResumeData; 118 | private System.Windows.Forms.Button btnLoadResumeData; 119 | private System.Windows.Forms.GroupBox groupBoxAction; 120 | private System.Windows.Forms.Button btnRemoveInvalidTorrentInfo; 121 | private System.Windows.Forms.Button btnRemoveTorrent; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /MyQbt/µTorrentOfflineUserControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Data; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | using BencodeNET.Objects; 11 | using BencodeNET.Parsing; 12 | using System.IO; 13 | 14 | namespace MyQbt 15 | { 16 | public partial class µTorrentOfflineUserControl : UserControl 17 | { 18 | private BDictionary utBDictionary = null; 19 | 20 | private static string DefaultDirectory = Path.Combine( 21 | Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "uTorrent"); 22 | 23 | public µTorrentOfflineUserControl() 24 | { 25 | InitializeComponent(); 26 | } 27 | 28 | private void ΜTorrentOfflineUserControl_Load(object sender, EventArgs e) 29 | { 30 | this.groupBoxAction.Enabled = false; 31 | } 32 | 33 | private void BtnLoadResumeData_Click(object sender, EventArgs e) 34 | { 35 | OpenFileDialog dlg = new OpenFileDialog(); 36 | dlg.InitialDirectory = DefaultDirectory; 37 | dlg.RestoreDirectory = true; 38 | dlg.Filter = "dat文件|*.dat"; 39 | 40 | if (dlg.ShowDialog() == DialogResult.OK) 41 | { 42 | var parser = new BencodeParser(); 43 | utBDictionary = parser.Parse(dlg.FileName); 44 | 45 | if (utBDictionary != null) 46 | { 47 | this.groupBoxAction.Enabled = true; 48 | MessageBox.Show(string.Format("已加载 {0}", dlg.FileName)); 49 | } 50 | } 51 | } 52 | 53 | private void BtnSaveResumeData_Click(object sender, EventArgs e) 54 | { 55 | if (utBDictionary == null) 56 | { 57 | MessageBox.Show("请先加载 resume.data 文件!"); 58 | return; 59 | } 60 | 61 | SaveFileDialog dlg = new SaveFileDialog(); 62 | dlg.InitialDirectory = DefaultDirectory; 63 | dlg.RestoreDirectory = true; 64 | dlg.Filter = "dat文件|*.dat"; 65 | 66 | if (dlg.ShowDialog() == DialogResult.OK) 67 | { 68 | using (FileStream fs = new FileStream( 69 | dlg.FileName, FileMode.Create)) 70 | { 71 | byte[] bytes = utBDictionary.EncodeAsBytes(); 72 | fs.Write(bytes, 0, bytes.Length); 73 | fs.Flush(); 74 | 75 | MessageBox.Show(string.Format("已保存为 {0}", dlg.FileName)); 76 | } 77 | } 78 | } 79 | 80 | public bool CheckNeedSaveWhenFormClosing() 81 | { 82 | if (utBDictionary == null) return false; 83 | else 84 | { 85 | DialogResult dr = MessageBox.Show( 86 | "关闭前请确保已保存修改过的 resume.dat,确实要关闭吗?", 87 | "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question); 88 | 89 | if (DialogResult.Yes == dr) return false; 90 | else return true; 91 | } 92 | } 93 | 94 | private void BtnRemoveInvalidTorrentInfo_Click(object sender, EventArgs e) 95 | { 96 | if (utBDictionary == null) 97 | { 98 | MessageBox.Show("请先加载 resume.data 文件!"); 99 | return; 100 | } 101 | 102 | BString bpath = new BString("path"); 103 | BString blabel = new BString("label"); 104 | BString bcompleded = new BString("completed_on"); 105 | 106 | List exceptedCatagoryList = 107 | new List { "GGN", "OpenCD", "ORPHEUS", "Redacted" }; 108 | 109 | // 待删列表 110 | List deleteList = new List(); 111 | 112 | foreach (KeyValuePair kv in utBDictionary) 113 | { 114 | if (kv.Key.ToString().ToLower().EndsWith(".torrent")) 115 | { 116 | var tbd = kv.Value as BDictionary; 117 | 118 | if (exceptedCatagoryList.Contains(tbd[blabel].ToString())) continue; 119 | 120 | string tpath = tbd[bpath].ToString(); 121 | 122 | if (tbd[bcompleded].ToString() != "0") 123 | { 124 | if (!(Directory.Exists(tpath) || File.Exists(tpath))) 125 | { 126 | deleteList.Add(kv.Key); 127 | } 128 | } 129 | } 130 | } 131 | 132 | foreach (BString bKey in deleteList) utBDictionary.Remove(bKey); 133 | 134 | MessageBox.Show(string.Format( 135 | "完成,共删除{0}项", deleteList.Count), 136 | "提示", MessageBoxButtons.OK); 137 | } 138 | 139 | private void BtnRemoveTorrent_Click(object sender, EventArgs e) 140 | { 141 | if (utBDictionary == null) 142 | { 143 | MessageBox.Show("请先加载 resume.data 文件!"); 144 | return; 145 | } 146 | 147 | FolderBrowserDialog dlg = new FolderBrowserDialog(); 148 | dlg.SelectedPath = DefaultDirectory; 149 | 150 | if (dlg.ShowDialog() == DialogResult.OK) 151 | { 152 | string strSelectFolder = dlg.SelectedPath; 153 | List torrentNameList = new List(); 154 | 155 | foreach (KeyValuePair kv in utBDictionary) 156 | { 157 | string tName = kv.Key.ToString(); 158 | if (tName.ToLower().EndsWith(".torrent")) 159 | { 160 | torrentNameList.Add(tName); 161 | } 162 | } 163 | 164 | string[] torrentList = Directory.GetFiles( 165 | strSelectFolder, "*.torrent", SearchOption.TopDirectoryOnly); 166 | 167 | string newFolder = Path.Combine(Environment.CurrentDirectory, 168 | string.Format("T-{0}", DateTime.Now.ToString("yyyy-MM-dd"))); 169 | if (!Directory.Exists(newFolder)) Directory.CreateDirectory(newFolder); 170 | 171 | foreach (string torrentPath in torrentList) 172 | { 173 | string torrentName = torrentPath.Substring(torrentPath.LastIndexOf('\\') + 1); 174 | if (!torrentNameList.Contains(torrentName)) 175 | { 176 | string newPath = Path.Combine(newFolder, torrentName); 177 | File.Move(torrentPath, newPath); 178 | } 179 | } 180 | 181 | MessageBox.Show("完成", "提示", MessageBoxButtons.OK); 182 | } 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /MyQbt/µTorrentOfflineUserControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /QbtWebAPI/API/Additional.cs: -------------------------------------------------------------------------------- 1 | using QbtWebAPI.Enums; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | 6 | namespace QbtWebAPI 7 | { 8 | public static partial class API 9 | { 10 | /// 11 | /// Deletes torrents that have seeded longer than maximum time. 12 | /// 13 | /// Maximum time of seeding. 14 | /// Delete data if True. 15 | public static async Task DeleteAfterMaxSeedTime(TimeSpan maxSeedTime, bool deleteData) 16 | { 17 | var torrents = await GetTorrents(); 18 | 19 | if (torrents == null) 20 | return; 21 | 22 | if (torrents.Count == 0) 23 | return; 24 | 25 | var hashes = new List(); 26 | 27 | foreach (var torrent in torrents) 28 | { 29 | var torrentProperties = await GetTorrentProperties(torrent.Hash); 30 | 31 | if (torrentProperties != null) 32 | { 33 | var seedingTimeSpan = torrentProperties.Seeding_Time; 34 | if (seedingTimeSpan != null) 35 | { 36 | if (seedingTimeSpan > maxSeedTime) 37 | { 38 | hashes.Add(torrent.Hash); 39 | } 40 | } 41 | } 42 | } 43 | 44 | if (hashes.Count != 0) 45 | await DeleteTorrents(hashes, deleteData); 46 | } 47 | 48 | /// 49 | /// Deletes torrents that have seeded longer than maximum time. 50 | /// 51 | /// Maximum ratio when seeding. 52 | /// Delete data if True. 53 | public static async Task DeleteAfterMaxRatio(float maxRatio, bool deleteData) 54 | { 55 | var torrents = await GetTorrents(); 56 | 57 | if (torrents == null) 58 | return; 59 | 60 | if (torrents.Count == 0) 61 | return; 62 | 63 | var hashes = new List(); 64 | 65 | foreach (var torrent in torrents) 66 | { 67 | var ratio = torrent.Ratio; 68 | if (ratio > maxRatio) 69 | { 70 | hashes.Add(torrent.Hash); 71 | } 72 | } 73 | 74 | if (hashes.Count != 0) 75 | await DeleteTorrents(hashes, deleteData); 76 | } 77 | 78 | /// 79 | /// Checks if all torrents are paused. 80 | /// 81 | /// 82 | /// Returns false if any torrents are not paused. 83 | /// 84 | public static async Task AreAllTorrentsPaused() 85 | { 86 | var torrents = await GetTorrents(); 87 | 88 | if (torrents == null) 89 | return null; 90 | 91 | 92 | foreach (var torrent in torrents) 93 | if (torrent.State == TorrentState.QueuedUP 94 | || torrent.State == TorrentState.QueuedDL 95 | || torrent.State == TorrentState.QueuedUP 96 | || torrent.State == TorrentState.Uploading 97 | || torrent.State == TorrentState.CheckingUP 98 | || torrent.State == TorrentState.CheckingDL 99 | || torrent.State == TorrentState.Downloading 100 | || torrent.State == TorrentState.StalledDL 101 | || torrent.State == TorrentState.StalledUP 102 | || torrent.State == TorrentState.MetaDL 103 | || torrent.State == TorrentState.ForcedDL 104 | || torrent.State == TorrentState.ForcedUP) 105 | return false; 106 | 107 | return true; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /QbtWebAPI/API/Base.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net.Http; 4 | using System.Threading.Tasks; 5 | using System.Net; 6 | 7 | namespace QbtWebAPI 8 | { 9 | public static partial class API 10 | { 11 | private static async Task Get( 12 | HttpClient client, string requestUri) 13 | { 14 | try 15 | { 16 | var reply = await client.GetAsync(requestUri); 17 | if (!reply.IsSuccessStatusCode) 18 | { 19 | if (reply.StatusCode != HttpStatusCode.Unauthorized) 20 | RaiseDisconnectedEvent(); 21 | throw new QBTException( 22 | reply.StatusCode, await reply.Content.ReadAsStringAsync()); 23 | } 24 | return reply; 25 | } 26 | 27 | catch (HttpRequestException) 28 | { 29 | return null; 30 | } 31 | 32 | catch (TaskCanceledException) 33 | { 34 | RaiseDisconnectedEvent(); 35 | return null; 36 | } 37 | } 38 | 39 | private static async Task Post( 40 | HttpClient client, string requestUri, StringContent content = null) 41 | { 42 | try 43 | { 44 | var reply = await client.PostAsync(requestUri, content); 45 | if (!reply.IsSuccessStatusCode) 46 | { 47 | if (reply.StatusCode != HttpStatusCode.Unauthorized) 48 | RaiseDisconnectedEvent(); 49 | throw new QBTException( 50 | reply.StatusCode, await reply.Content.ReadAsStringAsync()); 51 | } 52 | return reply; 53 | } 54 | 55 | catch (HttpRequestException ex) 56 | { 57 | throw ex; 58 | } 59 | 60 | catch (TaskCanceledException ex) 61 | { 62 | RaiseDisconnectedEvent(); 63 | throw ex; 64 | } 65 | } 66 | 67 | private static async Task Post( 68 | HttpClient client, string requestUri, MultipartFormDataContent content) 69 | { 70 | try 71 | { 72 | var reply = await client.PostAsync(requestUri, content); 73 | if (!reply.IsSuccessStatusCode) 74 | { 75 | if (reply.StatusCode != HttpStatusCode.Unauthorized) 76 | RaiseDisconnectedEvent(); 77 | throw new QBTException( 78 | reply.StatusCode, await reply.Content.ReadAsStringAsync()); 79 | } 80 | return reply; 81 | } 82 | 83 | catch (HttpRequestException ex) 84 | { 85 | throw ex; 86 | } 87 | 88 | catch (TaskCanceledException ex) 89 | { 90 | RaiseDisconnectedEvent(); 91 | throw ex; 92 | } 93 | } 94 | 95 | private static string ListToString(List stringList, char separator) 96 | { 97 | string returnString = ""; 98 | foreach (string element in stringList) 99 | returnString += element + separator; 100 | returnString = returnString.Remove(returnString.Length - 1); 101 | 102 | return returnString; 103 | } 104 | 105 | private static string ListToString(List uris, char separator) 106 | { 107 | string returnString = ""; 108 | foreach (Uri element in uris) 109 | returnString += element.ToString() + separator; 110 | returnString = returnString.Remove(returnString.Length - 1); 111 | 112 | return returnString; 113 | } 114 | 115 | private static StringContent ToStringContent(string text) 116 | { 117 | return new StringContent( 118 | text, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded"); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /QbtWebAPI/Data/BuildInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QbtWebAPI.Data 8 | { 9 | public class BuildInfo 10 | { 11 | public string qt { get; set; } 12 | public string libtorrent { get; set; } 13 | public string boost { get; set; } 14 | public string openssl { get; set; } 15 | public string bitness { get; set; } 16 | 17 | public BuildInfo() { } 18 | 19 | internal BuildInfo(JSON.BuildInfoJSON b) 20 | { 21 | qt = b.qt; 22 | libtorrent = b.libtorrent; 23 | boost = b.boost; 24 | openssl = b.openssl; 25 | bitness = b.bitness; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /QbtWebAPI/Data/Log.cs: -------------------------------------------------------------------------------- 1 | using QbtWebAPI.Enums; 2 | using QbtWebAPI.JSON; 3 | using System; 4 | 5 | namespace QbtWebAPI.Data 6 | { 7 | /// 8 | /// Log. 9 | /// 10 | public class Log 11 | { 12 | /// 13 | /// ID of the message. 14 | /// 15 | public int Id { get; set; } 16 | /// 17 | /// Text of the message. 18 | /// 19 | public string Message { get; set; } 20 | /// 21 | /// Time since epoch. 22 | /// 23 | public TimeSpan Timestamp { get; set; } 24 | /// 25 | /// Type of the message. 26 | /// 27 | public LogType Type { get; set; } 28 | 29 | /// 30 | /// Initializes a new instance of the class. 31 | /// 32 | public Log() { } 33 | 34 | internal Log(LogJSON l) 35 | { 36 | Id = l.id; 37 | Message = l.message; 38 | Timestamp = TimeSpan.FromMilliseconds(l.timestamp); 39 | Type = (LogType)l.type; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /QbtWebAPI/Data/PartialData.cs: -------------------------------------------------------------------------------- 1 | using QbtWebAPI.JSON; 2 | using System.Collections.Generic; 3 | 4 | namespace QbtWebAPI.Data 5 | { 6 | /// 7 | /// Partial data. Changes since last request. 8 | /// 9 | public class PartialData 10 | { 11 | /// 12 | /// Response ID. 13 | /// 14 | public int Rid { get; set; } 15 | /// 16 | /// Whether the response contains all the data or partial data. 17 | /// 18 | public bool Full_Update { get; set; } 19 | /// 20 | /// Torrent list. 21 | /// 22 | public List Torrents { get; set; } 23 | /// 24 | /// List of hashes of torrent removed since last request. 25 | /// 26 | public List Torrents_Removed { get; set; } 27 | /// 28 | /// List of categories added since last request. 29 | /// 30 | public List Categories { get; set; } 31 | /// 32 | /// List of categories removed since last request. 33 | /// 34 | public List Categories_Removed { get; set; } 35 | /// 36 | /// Priority system usage flag. 37 | /// 38 | public bool Queueing { get; set; } 39 | /// 40 | /// Server state. 41 | /// 42 | public TransferInfo Server_State { get; set; } 43 | 44 | /// 45 | /// Initializes a new instance of the class. 46 | /// 47 | public PartialData() { } 48 | 49 | internal PartialData(PartialDataJSON p) 50 | { 51 | Rid = p.rid; 52 | Full_Update = p.full_update; 53 | Torrents = new List(); 54 | foreach(var e in p.torrents) 55 | { 56 | e.Value.hash = e.Key; 57 | Torrents.Add(new Torrent(e.Value)); 58 | } 59 | if (p.torrents_removed != null) 60 | Torrents_Removed = new List(p.torrents_removed); 61 | else 62 | Torrents_Removed = new List(); 63 | if (p.categories != null) 64 | Categories = new List(p.categories); 65 | else 66 | Categories = new List(); 67 | if (p.categories_removed != null) 68 | Categories_Removed = new List(p.categories_removed); 69 | else 70 | Categories_Removed = new List(); 71 | Queueing = p.queueing; 72 | Server_State = new TransferInfo(p.server_state); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /QbtWebAPI/Data/QBTException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace QbtWebAPI 5 | { 6 | /// 7 | /// Represents an exception thrown by API. 8 | /// 9 | public class QBTException : ApplicationException 10 | { 11 | /// 12 | /// The . 13 | /// 14 | public HttpStatusCode HttpStatusCode { get; private set; } 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// /// The . 20 | /// The message which describes the reason of throwing this exception. 21 | public QBTException(HttpStatusCode httpStatusCode, string message) 22 | : base(message) 23 | { 24 | HttpStatusCode = httpStatusCode; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /QbtWebAPI/Data/Time.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace QbtWebAPI.Data 4 | { 5 | /// 6 | /// Time, i.e. 18:30. 7 | /// 8 | public class Time 9 | { 10 | /// 11 | /// Hours. 12 | /// 13 | public int Hours { get; set; } 14 | /// 15 | /// Minutes. 16 | /// 17 | public int Minutes { get; set; } 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// Hours needs to be 0-23. 23 | /// Minutes needs to be 0-59. 24 | public Time(int hours, int minutes) 25 | { 26 | if (hours < 0 || hours > 23) 27 | throw new ArgumentOutOfRangeException("Hours needs to be 0-23"); 28 | 29 | if (minutes < 0 || minutes > 59) 30 | throw new ArgumentOutOfRangeException("Minutes needs to be 0-59"); 31 | 32 | Hours = hours; 33 | Minutes = minutes; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /QbtWebAPI/Data/Torrent.cs: -------------------------------------------------------------------------------- 1 | using QbtWebAPI.Enums; 2 | using QbtWebAPI.JSON; 3 | using System; 4 | 5 | namespace QbtWebAPI.Data 6 | { 7 | /// 8 | /// Torrent. 9 | /// 10 | public class Torrent 11 | { 12 | /// 13 | /// When torrent was addes. 14 | /// 15 | public DateTime Added_On { get; set; } 16 | /// 17 | /// Amount of bytes left before completion. 18 | /// 19 | public long Amount_Left { get; set; } 20 | /// 21 | /// Category of the torrent. 22 | /// 23 | public string Category { get; set; } 24 | /// 25 | /// Amount completed bytes. 26 | /// 27 | public long Completed { get; set; } 28 | /// 29 | /// Completetion time. 30 | /// 31 | public DateTime Completion_On { get; set; } 32 | /// 33 | /// Torrent download speed limit in (bytes/s). 34 | /// 35 | public long Dl_Limit { get; set; } 36 | /// 37 | /// Torrent download speed (bytes/s). 38 | /// 39 | public long Dl_Speed { get; set; } 40 | /// 41 | /// Total data downloaded for torrent (bytes). 42 | /// 43 | public long Downloaded { get; set; } 44 | /// 45 | /// Data downloaded this session (bytes). 46 | /// 47 | public long Downloaded_Session { get; set; } 48 | /// 49 | /// Torrent ETA. 50 | /// 51 | public TimeSpan Eta { get; set; } 52 | /// 53 | /// True if first last piece are prioritized. 54 | /// 55 | public bool First_Last_Piece_Prio { get; set; } 56 | /// 57 | /// True if force start is enabled for this torrent. 58 | /// 59 | public bool Force_Start { get; set; } 60 | /// 61 | /// Torrent hash. 62 | /// 63 | public string Hash { get; set; } 64 | /// 65 | /// When last activity was. 66 | /// 67 | public DateTime Last_Activity { get; set; } 68 | /// 69 | /// Torrent name. 70 | /// 71 | public string Name { get; set; } 72 | /// 73 | /// Number of seeds in the swarm. 74 | /// 75 | public int Num_Complete { get; set; } 76 | /// 77 | /// Number of leechers in the swarm. 78 | /// 79 | public int Num_Incomplete { get; set; } 80 | /// 81 | /// Number of leechers connected to. 82 | /// 83 | public int Num_Leechs { get; set; } 84 | /// 85 | /// Number of seeds connected to. 86 | /// 87 | public int Num_Seeds { get; set; } 88 | /// 89 | /// Torrent priority. 90 | /// 91 | public Priority Priority { get; set; } 92 | /// 93 | /// Torrent progress. 94 | /// 95 | public float Progress { get; set; } 96 | /// 97 | /// Torrent share ratio. 98 | /// 99 | public float Ratio { get; set; } 100 | /// 101 | /// Torrent ratio limit. 102 | /// 103 | public float Ratio_Limit { get; set; } 104 | /// 105 | /// Torrent save path. 106 | /// 107 | public string Save_Path { get; set; } 108 | /// 109 | /// When seen complete. 110 | /// 111 | public DateTime Seen_Complete { get; set; } 112 | /// 113 | /// True if sequential download is enabled. 114 | /// 115 | public bool Seq_Dl { get; set; } 116 | /// 117 | /// Total size (bytes) of files selected for download. 118 | /// 119 | public long Size { get; set; } 120 | /// 121 | /// Torrent state. 122 | /// 123 | public TorrentState State { get; set; } 124 | /// 125 | /// True if super seeding is enabled. 126 | /// 127 | public bool Super_Seeding { get; set; } 128 | /// 129 | /// Torrent total size (bytes). 130 | /// 131 | public long Total_Size { get; set; } 132 | /// 133 | /// Torrent tracker. 134 | /// 135 | public Uri Tracker { get; set; } 136 | /// 137 | /// Torrent upload speed limit in (bytes/s). 138 | /// 139 | public long Up_Limit { get; set; } 140 | /// 141 | /// Total data uploaded for torrent (bytes). 142 | /// 143 | public long Uploaded { get; set; } 144 | /// 145 | /// Total data uploaded this session (bytes). 146 | /// 147 | public long Uploaded_Session { get; set; } 148 | /// 149 | /// Torrent upload speed (bytes/s). 150 | /// 151 | public long Up_Speed { get; set; } 152 | 153 | /// 154 | /// Initializes a new instance of the class. 155 | /// 156 | public Torrent() { } 157 | 158 | internal Torrent(TorrentJSON t) 159 | { 160 | Added_On = DateTimeOffset.FromUnixTimeSeconds(t.added_on).DateTime.ToLocalTime(); 161 | Amount_Left = t.amount_left; 162 | Category = t.category; 163 | Completed = t.completed; 164 | Completion_On = DateTimeOffset.FromUnixTimeSeconds(t.completion_on).DateTime.ToLocalTime(); 165 | Dl_Limit = t.dlspeed; 166 | Dl_Speed = t.dl_limit; 167 | Downloaded = t.downloaded; 168 | Downloaded_Session = t.downloaded_session; 169 | Eta = TimeSpan.FromSeconds(t.eta); 170 | First_Last_Piece_Prio = t.f_l_piece_prio; 171 | Force_Start = t.force_start; 172 | Hash = t.hash; 173 | Last_Activity = DateTimeOffset.FromUnixTimeSeconds(t.last_activity).DateTime.ToLocalTime(); 174 | Name = t.name; 175 | Num_Complete = t.num_complete; 176 | Num_Incomplete = t.num_incomplete; 177 | Num_Leechs = t.num_leechs; 178 | Num_Seeds = t.num_seeds; 179 | Priority = (Priority)t.priority; 180 | Progress = t.progress; 181 | Ratio = t.ratio; 182 | Ratio_Limit = t.ratio_limit; 183 | Save_Path = t.save_path; 184 | Seen_Complete = DateTimeOffset.FromUnixTimeSeconds(t.seen_complete).DateTime.ToLocalTime(); 185 | Seq_Dl = t.seq_dl; 186 | Size = t.size; 187 | State = (TorrentState)Enum.Parse(typeof(TorrentState), t.state, true); 188 | Super_Seeding = t.super_seeding; 189 | Total_Size = t.total_size; 190 | if(t.tracker != "") 191 | Tracker = new Uri(t.tracker); 192 | Up_Limit = t.up_limit; 193 | Uploaded = t.uploaded; 194 | Uploaded_Session = t.uploaded_session; 195 | Up_Speed = t.upspeed; 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /QbtWebAPI/Data/TorrentContents.cs: -------------------------------------------------------------------------------- 1 | using QbtWebAPI.Enums; 2 | 3 | namespace QbtWebAPI.Data 4 | { 5 | /// 6 | /// Torrent contents. 7 | /// 8 | public class TorrentContents 9 | { 10 | /// 11 | /// File name (including relative path). 12 | /// 13 | public string Name { get; set; } 14 | /// 15 | /// File size (bytes). 16 | /// 17 | public long Size { get; set; } 18 | /// 19 | /// File progress. 20 | /// 21 | public float Progress { get; set; } 22 | /// 23 | /// File priority. 24 | /// 25 | public Priority Priority { get; set; } 26 | /// 27 | /// True if file is seeding/complete. 28 | /// 29 | public bool Is_Seed { get; set; } 30 | /// 31 | /// The first number is the starting piece index and the second number is the ending piece index (inclusive). 32 | /// 33 | public int[] Piece_Range { get; set; } 34 | 35 | /// 36 | /// Initializes a new instance of the class. 37 | /// 38 | public TorrentContents() { } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /QbtWebAPI/Data/TorrentProperties.cs: -------------------------------------------------------------------------------- 1 | using QbtWebAPI.JSON; 2 | using System; 3 | 4 | namespace QbtWebAPI.Data 5 | { 6 | /// 7 | /// Torrent properties. 8 | /// 9 | public class TorrentProperties 10 | { 11 | /// 12 | /// Torrent save path. 13 | /// 14 | public string Save_Path { get; set; } 15 | /// 16 | /// Torrent creation date. 17 | /// 18 | public DateTime Creation_Date { get; set; } 19 | /// 20 | /// Torrent piece size (bytes). 21 | /// 22 | public long Piece_Size { get; set; } 23 | /// 24 | /// Torrent comment. 25 | /// 26 | public string Comment { get; set; } 27 | /// 28 | /// Total data wasted for torrent (bytes). 29 | /// 30 | public long Total_Wasted { get; set; } 31 | /// 32 | /// Total data uploaded for torrent (bytes). 33 | /// 34 | public long Total_Uploaded { get; set; } 35 | /// 36 | /// Total data uploaded this session (bytes). 37 | /// 38 | public long Total_Uploaded_Session { get; set; } 39 | /// 40 | /// Total data uploaded for torrent (bytes). 41 | /// 42 | public long Total_Downloaded { get; set; } 43 | /// 44 | /// Total data downloaded this session (bytes). 45 | /// 46 | public long Total_Downloaded_Session { get; set; } 47 | /// 48 | /// Torrent upload limit (bytes/s). 49 | /// 50 | public long Up_Limit { get; set; } 51 | /// 52 | /// Torrent download limit (bytes/s). 53 | /// 54 | public long Dl_Limit { get; set; } 55 | /// 56 | /// Torrent elapsed time. 57 | /// 58 | public TimeSpan Time_Elapsed { get; set; } 59 | /// 60 | /// Torrent elapsed time while complete. 61 | /// 62 | public TimeSpan Seeding_Time { get; set; } 63 | /// 64 | /// Torrent connection count. 65 | /// 66 | public int Nb_Connections { get; set; } 67 | /// 68 | /// Torrent connection count limit. 69 | /// 70 | public int Nb_Connections_Limit { get; set; } 71 | /// 72 | /// Torrent share ratio. 73 | /// 74 | public float Share_Ratio { get; set; } 75 | /// 76 | /// When this torrent was added. 77 | /// 78 | public DateTime Addition_Date { get; set; } 79 | /// 80 | /// Torrent completion date. 81 | /// 82 | public DateTime Completion_Date { get; set; } 83 | /// 84 | /// Torrent creator. 85 | /// 86 | public string Created_By { get; set; } 87 | /// 88 | /// Torrent average download speed (bytes/second). 89 | /// 90 | public long Dl_Speed_Avg { get; set; } 91 | /// 92 | /// Torrent download speed (bytes/second). 93 | /// 94 | public long Dl_Speed { get; set; } 95 | /// 96 | /// Torrent ETA. 97 | /// 98 | public TimeSpan Eta { get; set; } 99 | /// 100 | /// Last seen complete date. 101 | /// 102 | public DateTime Last_Seen { get; set; } 103 | /// 104 | /// Number of peers connected to. 105 | /// 106 | public int Peers { get; set; } 107 | /// 108 | /// Number of peers in the swarm. 109 | /// 110 | public int Peers_Total { get; set; } 111 | /// 112 | /// Number of pieces owned. 113 | /// 114 | public int Pieces_Have { get; set; } 115 | /// 116 | /// Number of pieces of the torrent. 117 | /// 118 | public int Pieces_Num { get; set; } 119 | /// 120 | /// Time until the next announce. 121 | /// 122 | public TimeSpan Reannounce { get; set; } 123 | /// 124 | /// Number of seeds connected to. 125 | /// 126 | public int Seeds { get; set; } 127 | /// 128 | /// Number of seeds in the swarm. 129 | /// 130 | public int Seeds_Total { get; set; } 131 | /// 132 | /// Torrent total size (bytes). 133 | /// 134 | public long Total_Size { get; set; } 135 | /// 136 | /// Torrent average upload speed (bytes/second). 137 | /// 138 | public long Up_Speed_Avg { get; set; } 139 | /// 140 | /// Torrent upload speed (bytes/second). 141 | /// 142 | public long Up_Speed { get; set; } 143 | 144 | /// 145 | /// Initializes a new instance of the class. 146 | /// 147 | public TorrentProperties() { } 148 | 149 | internal TorrentProperties(TorrentPropertiesJSON t) 150 | { 151 | Save_Path = t.Save_Path; 152 | Creation_Date = DateTimeOffset.FromUnixTimeSeconds(t.Creation_Date).DateTime.ToLocalTime(); 153 | Piece_Size = t.Piece_Size; 154 | Comment = t.Comment; 155 | Total_Wasted = t.Total_Wasted; 156 | Total_Uploaded = t.Total_Uploaded; 157 | Total_Uploaded_Session = t.Total_Uploaded_Session; 158 | Total_Downloaded = t.Total_Downloaded; 159 | Total_Downloaded_Session = t.Total_Downloaded_Session; 160 | Up_Limit = t.Up_Limit; 161 | Dl_Limit = t.Dl_Limit; 162 | Time_Elapsed = TimeSpan.FromSeconds(t.Time_Elapsed); 163 | Seeding_Time = TimeSpan.FromSeconds(t.Seeding_Time); 164 | Nb_Connections = Nb_Connections; 165 | Nb_Connections_Limit = Nb_Connections_Limit; 166 | Share_Ratio = Share_Ratio; 167 | Addition_Date = DateTimeOffset.FromUnixTimeSeconds(t.Addition_Date).DateTime.ToLocalTime(); 168 | Completion_Date = DateTimeOffset.FromUnixTimeSeconds(t.Completion_Date).DateTime.ToLocalTime(); 169 | Created_By = Created_By; 170 | Dl_Speed_Avg = Dl_Speed_Avg; 171 | Dl_Speed = Dl_Speed; 172 | Eta = TimeSpan.FromSeconds(t.Eta); 173 | Last_Seen = DateTimeOffset.FromUnixTimeSeconds(t.Last_Seen).DateTime.ToLocalTime(); 174 | Peers = Peers; 175 | Peers_Total = Peers_Total; 176 | Pieces_Have = Pieces_Have; 177 | Pieces_Num = Pieces_Num; 178 | Reannounce = TimeSpan.FromSeconds(t.Reannounce); 179 | Seeds = Seeds; 180 | Seeds_Total = Seeds_Total; 181 | Total_Size = Total_Size; 182 | Up_Speed_Avg = Up_Speed_Avg; 183 | Up_Speed = Up_Speed; 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /QbtWebAPI/Data/Tracker.cs: -------------------------------------------------------------------------------- 1 | using QbtWebAPI.JSON; 2 | using QbtWebAPI.Enums; 3 | using System; 4 | using System.Text.RegularExpressions; 5 | 6 | namespace QbtWebAPI.Data 7 | { 8 | /// 9 | /// Torrent tracker. 10 | /// 11 | public class Tracker 12 | { 13 | /// 14 | /// Tracker url 15 | /// 16 | public Uri Url { get; set; } 17 | /// 18 | /// Tracker status. 19 | /// 20 | public Trackerstatus Status { get; set; } 21 | /// 22 | /// Number of peers for current torrent reported by the tracker. 23 | /// 24 | public int Num_Peers { get; set; } 25 | /// 26 | /// Tracker message (there is no way of knowing what this message is - it's up to tracker admins). 27 | /// 28 | public string Msg { get; set; } 29 | 30 | /// 31 | /// Initializes a new instance of the class. 32 | /// 33 | public Tracker() { } 34 | 35 | internal Tracker(TrackerJSON t) 36 | { 37 | Url = t.Url; 38 | Status = (Trackerstatus)Enum.Parse(typeof(Trackerstatus), new Regex(@"\s|[.]").Replace(t.Status, ""), true); 39 | Num_Peers = t.Num_Peers; 40 | Msg = t.Msg; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /QbtWebAPI/Data/TransferInfo.cs: -------------------------------------------------------------------------------- 1 | using QbtWebAPI.Enums; 2 | using QbtWebAPI.JSON; 3 | using System; 4 | 5 | namespace QbtWebAPI.Data 6 | { 7 | /// 8 | /// Transfer info. 9 | /// 10 | public class TransferInfo 11 | { 12 | /// 13 | /// Global download rate (bytes/s). 14 | /// 15 | public long Dl_Info_Speed { get; set; } 16 | /// 17 | /// Data downloaded this session (bytes). 18 | /// 19 | public long Dl_Info_Data { get; set; } 20 | /// 21 | /// Global upload rate (bytes/s). 22 | /// 23 | public long Up_Info_Speed { get; set; } 24 | /// 25 | /// Data uploaded this session (bytes). 26 | /// 27 | public long Up_Info_Data { get; set; } 28 | /// 29 | /// Download rate limit (bytes/s). 30 | /// 31 | public long Dl_Rate_Limit { get; set; } 32 | /// 33 | /// Upload rate limit (bytes/s). 34 | /// 35 | public long Up_Rate_Limit { get; set; } 36 | /// 37 | /// DHT nodes connected to. 38 | /// 39 | public int Dht_Nodes { get; set; } 40 | /// 41 | /// Connection status. 42 | /// 43 | public ConnectionStatus Connection_Status { get; set; } 44 | /// 45 | /// True if torrent queueing is enabled. 46 | /// 47 | public bool Queueing { get; set; } 48 | /// 49 | /// True if alternative speed limits are enabled. 50 | /// 51 | public bool Use_Alt_Speed_Limits { get; set; } 52 | /// 53 | /// Transfer list refresh interval (milliseconds) 54 | /// 55 | public long Refresh_Interval { get; set; } 56 | 57 | /// 58 | /// Initializes a new instance of the class. 59 | /// 60 | public TransferInfo() { } 61 | 62 | internal TransferInfo(TransferInfoJSON t) 63 | { 64 | Dl_Info_Speed = t.dl_info_speed; 65 | Dl_Info_Data = t.dl_info_data; 66 | Up_Info_Speed = t.up_info_speed; 67 | Up_Info_Data = t.up_info_data; 68 | Dl_Rate_Limit = t.dl_rate_limit; 69 | Up_Rate_Limit = t.up_rate_limit; 70 | Dht_Nodes = t.dht_nodes; 71 | Connection_Status = (ConnectionStatus)Enum.Parse(typeof(ConnectionStatus), t.connection_status, true); 72 | Queueing = t.queueing; 73 | Use_Alt_Speed_Limits = t.use_alt_speed_limits; 74 | Refresh_Interval = t.refresh_interval; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/ConnectionStatus.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// Connection status. 5 | /// 6 | public enum ConnectionStatus 7 | { 8 | /// 9 | /// Connected. 10 | /// 11 | Connected, 12 | /// 13 | /// Firewalled. 14 | /// 15 | Firewalled, 16 | /// 17 | /// Disconnected. 18 | /// 19 | Disconnected 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/DynDnsService.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// DynDNS service. 5 | /// 6 | public enum DynDnsService 7 | { 8 | /// 9 | /// Use DyDNS. 10 | /// 11 | UseDyDns = 0, 12 | /// 13 | /// Use NOIP. 14 | /// 15 | UseNoIp = 1 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/Encryption.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// Encryption. 5 | /// 6 | public enum Encryption 7 | { 8 | /// 9 | /// Prefer encryption. 10 | /// 11 | PreferEncryption = 0, 12 | /// 13 | /// Force encryption on. 14 | /// 15 | ForceEncryptionOn = 1, 16 | /// 17 | /// Force encryption off. 18 | /// 19 | ForceEncryptionOff = 2 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/Key.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// Torrent key. 5 | /// 6 | public enum Key 7 | { 8 | /// 9 | /// Torrent hash. 10 | /// 11 | Hash, 12 | /// 13 | /// Torrent name. 14 | /// 15 | Name, 16 | /// 17 | /// Total size of files selected for download. 18 | /// 19 | Size, 20 | /// 21 | /// Torrent progress. 22 | /// 23 | Progress, 24 | /// 25 | /// Torrent download speed. 26 | /// 27 | DlSpeed, 28 | /// 29 | /// Torrent upload speed. 30 | /// 31 | UpSpeed, 32 | /// 33 | /// Torrent priority. 34 | /// 35 | Priority, 36 | /// 37 | /// Number of seeds connected to. 38 | /// 39 | Num_Seeds, 40 | /// 41 | /// Number of seeds in the swarm. 42 | /// 43 | Num_Complete, 44 | /// 45 | /// Number of leechers connected to. 46 | /// 47 | Num_Leechs, 48 | /// 49 | /// Number of leechers in the swarm. 50 | /// 51 | Num_Incomplete, 52 | /// 53 | /// Torrent share ratio. 54 | /// 55 | Ratio, 56 | /// 57 | /// Torrent ETA. 58 | /// 59 | Eta, 60 | /// 61 | /// Torrent state. 62 | /// 63 | State, 64 | /// 65 | /// Sequential download. 66 | /// 67 | Seq_Dl, 68 | /// 69 | /// First last piece prioritized. 70 | /// 71 | F_L_Piece_Prio, 72 | /// 73 | /// Category of the torrent. 74 | /// 75 | Category, 76 | /// 77 | /// Super seeding. 78 | /// 79 | Super_Seeding, 80 | /// 81 | /// Force start. 82 | /// 83 | Force_Start 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/Locale.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// Locale. 5 | /// 6 | public enum Locale 7 | { 8 | /// 9 | /// English 10 | /// 11 | en, 12 | /// 13 | /// English(Australia) 14 | /// 15 | en_AU, 16 | /// 17 | /// English(United Kingdom) 18 | /// 19 | en_GB, 20 | /// 21 | /// Esperanto 22 | /// 23 | eo_EO, 24 | /// 25 | /// Français 26 | /// 27 | fr_FR, 28 | /// 29 | /// Deutsch 30 | /// 31 | de_DE, 32 | /// 33 | /// Magyar 34 | /// 35 | hu_HU, 36 | /// 37 | /// Íslenska 38 | /// 39 | @is, 40 | /// 41 | /// Bahasa Indonesia 42 | /// 43 | id, 44 | /// 45 | /// Italiano 46 | /// 47 | it_IT, 48 | /// 49 | /// Nederlands 50 | /// 51 | nl_NL, 52 | /// 53 | /// Español 54 | /// 55 | es_ES, 56 | /// 57 | /// Català 58 | /// 59 | ca_ES, 60 | /// 61 | /// Galego 62 | /// 63 | gl_ES, 64 | /// 65 | /// lenga d'òc 66 | /// 67 | oc, 68 | /// 69 | /// Português brasileiro 70 | /// 71 | pt_BR, 72 | /// 73 | /// Português 74 | /// 75 | pt_PT, 76 | /// 77 | /// Polski 78 | /// 79 | pl_PL, 80 | /// 81 | /// latviešu valoda 82 | /// 83 | lv_LV, 84 | /// 85 | /// Lietuvių 86 | /// 87 | lt_LT, 88 | /// 89 | /// بهاس ملايو 90 | /// 91 | ms_MY, 92 | /// 93 | /// Čeština 94 | /// 95 | cs_CZ, 96 | /// 97 | /// Slovenčina 98 | /// 99 | sk_SK, 100 | /// 101 | /// Slovenščina 102 | /// 103 | sl_SI, 104 | /// 105 | /// Српски 106 | /// 107 | sr_CS, 108 | /// 109 | /// हिन्दी, हिंदी 110 | /// 111 | hi_IN, 112 | /// 113 | /// Hrvatski 114 | /// 115 | hr_HR, 116 | /// 117 | /// Հայերեն 118 | /// 119 | hy_AM, 120 | /// 121 | /// Română 122 | /// 123 | ro_RO, 124 | /// 125 | /// Türkçe 126 | /// 127 | tr_TR, 128 | /// 129 | /// Ελληνικά 130 | /// 131 | el_GR, 132 | /// 133 | /// Svenska 134 | /// 135 | sv_SE, 136 | /// 137 | /// Suomi 138 | /// 139 | fi_FI, 140 | /// 141 | /// Norsk 142 | /// 143 | nb_NO, 144 | /// 145 | /// Dansk 146 | /// 147 | da_DK, 148 | /// 149 | /// Български 150 | /// 151 | bg_BG, 152 | /// 153 | /// Українська 154 | /// 155 | uk_UA, 156 | /// 157 | /// >أۇزبېك 158 | /// 159 | uz_Latn, // gsdfgdfg --------------- 160 | /// 161 | /// Русский 162 | /// 163 | ru_RU, 164 | /// 165 | /// 日本語 166 | /// 167 | ja_JP, 168 | /// 169 | /// עברית 170 | /// 171 | he_IL, 172 | /// 173 | /// עברית 174 | /// 175 | ar_AE, 176 | /// 177 | /// עברית 178 | /// 179 | ka_GE, 180 | /// 181 | /// Беларуская 182 | /// 183 | be_BY, 184 | /// 185 | /// Euskara 186 | /// 187 | eu_ES, 188 | /// 189 | /// tiếng Việt 190 | /// 191 | vi_VN, 192 | /// 193 | /// 简体中文 194 | /// 195 | zh, 196 | /// 197 | /// 正體中文 198 | /// 199 | zh_TW, 200 | /// 201 | /// 香港正體字 202 | /// 203 | zh_HK, 204 | /// 205 | /// 한글 206 | /// 207 | ko_KR 208 | }; 209 | } 210 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/LogType.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// Log type. 5 | /// 6 | public enum LogType 7 | { 8 | /// 9 | /// Normal. 10 | /// 11 | Normal = 1, 12 | /// 13 | /// Info. 14 | /// 15 | Info = 2, 16 | /// 17 | /// Warning. 18 | /// 19 | Warning = 4, 20 | /// 21 | /// Critical. 22 | /// 23 | Critical = 8 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/MaxRatioAction.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// Action when maximum ratio has been reached. 5 | /// 6 | public enum MaxRatioAction 7 | { 8 | /// 9 | /// Pause torrent. 10 | /// 11 | PauseTorrent = 0, 12 | /// 13 | /// Remove torrent. 14 | /// 15 | RemoveTorrent = 1 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/PieceState.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// State of torrent piece. 5 | /// 6 | public enum PieceState 7 | { 8 | /// 9 | /// Not downloaded yet. 10 | /// 11 | NotDownloadedYet = 0, 12 | /// 13 | /// Now downloading. 14 | /// 15 | NowDownloading = 1, 16 | /// 17 | /// Already downloaded. 18 | /// 19 | AlreadyDownloaded = 2 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/Priority.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// File priority. 5 | /// 6 | public enum Priority 7 | { 8 | /// 9 | /// Do not download. 10 | /// 11 | DoNotDownload = 0, 12 | /// 13 | /// Normal priority. 14 | /// 15 | NormalPriority = 1, 16 | /// 17 | /// High priority. 18 | /// 19 | HighPriority = 6, 20 | /// 21 | /// Maximal priority. 22 | /// 23 | MaximalPriority = 7 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/ProxyType.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// Proxy type. 5 | /// 6 | public enum ProxyType 7 | { 8 | /// 9 | /// Proxy is disabled. 10 | /// 11 | ProxyIsDisabled = -1, 12 | /// 13 | /// HTTP proxy without authentication. 14 | /// 15 | HttpProxyWithoutAuthentication = 1, 16 | /// 17 | /// SOCKS5 proxy without authentication 18 | /// 19 | Socks5ProxyWithoutAuthentication = 2, 20 | /// 21 | /// HTTP proxy with authentication 22 | /// 23 | HttpProxyWithAuthentication = 3, 24 | /// 25 | /// SOCKS5 proxy with authentication 26 | /// 27 | Socks5ProxyWithAuthentication = 4, 28 | /// 29 | /// SOCKS4 proxy without authentication 30 | /// 31 | Socks4ProxyWithoutAuthentication = 5 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/SchedulerDay.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// Scheduler day. 5 | /// 6 | public enum SchedulerDay 7 | { 8 | /// 9 | /// Every day. 10 | /// 11 | EveryDay = 0, 12 | /// 13 | /// Every weekday. 14 | /// 15 | EveryWeekday = 1, 16 | /// 17 | /// Every weekend. 18 | /// 19 | EveryWeekend = 2, 20 | /// 21 | /// Every Monday. 22 | /// 23 | EveryMonday = 3, 24 | /// 25 | /// Every Tuesday. 26 | /// 27 | EveryTuesday = 4, 28 | /// 29 | /// Every Wednesday. 30 | /// 31 | EveryWednesday = 5, 32 | /// 33 | /// Every Thursday. 34 | /// 35 | EveryThursday = 6, 36 | /// 37 | /// Every Friday. 38 | /// 39 | EveryFriday = 7, 40 | /// 41 | /// Every Saturday. 42 | /// 43 | EverySaturday = 8, 44 | /// 45 | /// Every Sunday. 46 | /// 47 | EverySunday = 9 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/Status.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// Torrent status. 5 | /// 6 | public enum Status 7 | { 8 | /// 9 | /// All statuses. 10 | /// 11 | All, 12 | /// 13 | /// Downloading. 14 | /// 15 | Downloading, 16 | /// 17 | /// Completed. 18 | /// 19 | Completed, 20 | /// 21 | /// Paused. 22 | /// 23 | Paused, 24 | /// 25 | /// Active. 26 | /// 27 | Active, 28 | /// 29 | /// Inactive. 30 | /// 31 | Inactive 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/TorrentState.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// Torrent state. 5 | /// 6 | public enum TorrentState 7 | { 8 | /// 9 | /// Some error occurred, applies to paused torrents. 10 | /// 11 | Error, 12 | /// 13 | /// Torrent is paused and has finished downloading. 14 | /// 15 | PausedUP, 16 | /// 17 | /// Torrent is paused and has NOT finished downloading. 18 | /// 19 | PausedDL, 20 | /// 21 | /// Queuing is enabled and torrent is queued for upload. 22 | /// 23 | QueuedUP, 24 | /// 25 | /// Queuing is enabled and torrent is queued for download. 26 | /// 27 | QueuedDL, 28 | /// 29 | /// Torrent is being seeded and data is being transferred. 30 | /// 31 | Uploading, 32 | /// 33 | /// Torrent is being seeded, but no connection were made. 34 | /// 35 | StalledUP, 36 | /// 37 | /// Torrent has finished downloading and is being checked; 38 | /// this status also applies to preallocation (if enabled) and checking resume data on qBt startup. 39 | /// 40 | CheckingUP, 41 | /// 42 | /// Same as checkingUP, but torrent has NOT finished downloading. 43 | /// 44 | CheckingDL, 45 | /// 46 | /// Torrent is being downloaded and data is being transferred. 47 | /// 48 | Downloading, 49 | /// 50 | /// Torrent is being downloaded, but no connection were made. 51 | /// 52 | StalledDL, 53 | /// 54 | /// Torrent has just started downloading and is fetching metadata. 55 | /// 56 | MetaDL, 57 | /// 58 | /// Torrent is being forced downloaded and data is being transferred. 59 | /// 60 | ForcedDL, 61 | /// 62 | /// Torrent is being forced uploaded, but no connection were made. 63 | /// 64 | ForcedUP 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /QbtWebAPI/Enums/TrackerStatus.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.Enums 2 | { 3 | /// 4 | /// Tracker status. 5 | /// 6 | public enum Trackerstatus 7 | { 8 | /// 9 | /// Tracker has been contacted and is working 10 | /// 11 | Working, 12 | /// 13 | /// Tracker is currently being updated 14 | /// 15 | Updating, 16 | /// 17 | /// Tracker has been contacted, but it is not working (or doesn't send proper replies) 18 | /// 19 | NotWorking, 20 | /// 21 | /// Tracker has not been contacted yet 22 | /// 23 | NotContactedYet 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /QbtWebAPI/JSON/BuildInfoJSON.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QbtWebAPI.JSON 8 | { 9 | internal class BuildInfoJSON 10 | { 11 | public string qt { get; set; } 12 | public string libtorrent { get; set; } 13 | public string boost { get; set; } 14 | public string openssl { get; set; } 15 | public string bitness { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /QbtWebAPI/JSON/LogJSON.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.JSON 2 | { 3 | internal class LogJSON 4 | { 5 | public int id { get; set; } 6 | public string message { get; set; } 7 | public long timestamp { get; set; } 8 | public int type { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /QbtWebAPI/JSON/PartialDataJSON.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace QbtWebAPI.JSON 4 | { 5 | internal class PartialDataJSON 6 | { 7 | public int rid { get; set; } 8 | public bool full_update { get; set; } 9 | public Dictionary torrents { get; set; } 10 | public string[] torrents_removed { get; set; } 11 | public string[] categories { get; set; } 12 | public string[] categories_removed { get; set; } 13 | public bool queueing { get; set; } 14 | public TransferInfoJSON server_state { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /QbtWebAPI/JSON/PreferencesJSON.cs: -------------------------------------------------------------------------------- 1 | using QbtWebAPI.Data; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace QbtWebAPI.JSON 6 | { 7 | 8 | internal class PreferencesJSON 9 | { 10 | public string add_trackers { get; set; } 11 | public bool? add_trackers_enabled { get; set; } 12 | public long? alt_dl_limit { get; set; } 13 | public long? alt_up_limit { get; set; } 14 | public bool? anonymous_mode { get; set; } 15 | public bool? autorun_enabled { get; set; } 16 | public string autorun_program { get; set; } 17 | public bool? bypass_local_auth { get; set; } 18 | public bool? dht { get; set; } 19 | public bool? dhtSameAsBT { get; set; } 20 | public bool? dht_port { get; set; } 21 | public long? dl_limit { get; set; } 22 | public bool? dont_count_slow_torrents { get; set; } 23 | public string[] download_in_scan_dirs { get; set; } 24 | public string dyndns_domain { get; set; } 25 | public bool? dyndns_enabled { get; set; } 26 | public string dyndns_password { get; set; } 27 | public int? dyndns_service { get; set; } 28 | public string dyndns_username { get; set; } 29 | public bool? enable_utp { get; set; } 30 | public int? encryption { get; set; } 31 | public string export_dir { get; set; } 32 | public string export_dir_fin { get; set; } 33 | public bool? force_proxy { get; set; } 34 | public bool? incomplete_files_ext { get; set; } 35 | public bool? ip_filter_enabled { get; set; } 36 | public string ip_filter_path { get; set; } 37 | public bool? ip_filter_trackers { get; set; } 38 | public bool? limit_tcp_overhead { get; set; } 39 | public bool? limit_utp_rate { get; set; } 40 | public int? listen_port { get; set; } 41 | public string locale { get; set; } 42 | public bool? lsd { get; set; } 43 | public bool? mail_notification_auth_enabled { get; set; } 44 | public string mail_notification_email { get; set; } 45 | public bool? mail_notification_enabled { get; set; } 46 | public string mail_notification_password { get; set; } 47 | public string mail_notification_smtp { get; set; } 48 | public bool? mail_notification_ssl_enabled { get; set; } 49 | public string mail_notification_username { get; set; } 50 | public int? max_active_downloads { get; set; } 51 | public int? max_active_torrents { get; set; } 52 | public int? max_active_uploads { get; set; } 53 | public int? max_connec { get; set; } 54 | public int? max_connec_per_torrent { get; set; } 55 | public float? max_ratio { get; set; } 56 | public int? max_ratio_act { get; set; } 57 | public bool? max_ratio_enabled { get; set; } 58 | public int? max_uploads { get; set; } 59 | public int? max_uploads_per_torrent { get; set; } 60 | public bool? pex { get; set; } 61 | public bool? preallocate_all { get; set; } 62 | public bool? proxy_auth_enabled { get; set; } 63 | public string proxy_ip { get; set; } 64 | public string proxy_password { get; set; } 65 | public bool? proxy_peer_connections { get; set; } 66 | public int? proxy_port { get; set; } 67 | public int? proxy_type { get; set; } 68 | public string proxy_username { get; set; } 69 | public bool? queueing_enabled { get; set; } 70 | public bool? random_port { get; set; } 71 | public string save_path { get; set; } 72 | public Dictionary scan_dirs { get; set; } 73 | public int? schedule_from_hour { get; set; } 74 | public int? schedule_from_min { get; set; } 75 | public int? schedule_to_hour { get; set; } 76 | public int? schedule_to_min { get; set; } 77 | public int? scheduler_days { get; set; } 78 | public bool? scheduler_enabled { get; set; } 79 | public string ssl_cert { get; set; } 80 | public string ssl_key { get; set; } 81 | public string temp_path { get; set; } 82 | public bool? temp_path_enabled { get; set; } 83 | public long? up_limit { get; set; } 84 | public bool? upnp { get; set; } 85 | public bool? use_https { get; set; } 86 | public string web_ui_domain_list { get; set; } 87 | public string web_ui_password { get; set; } 88 | public int? web_ui_port { get; set; } 89 | public bool? web_ui_upnp { get; set; } 90 | public string web_ui_username { get; set; } 91 | 92 | public PreferencesJSON() { } 93 | 94 | public PreferencesJSON(Preferences p) 95 | { 96 | if (p.Add_Trackers != null) 97 | { 98 | add_trackers = ""; 99 | foreach (var e in p.Add_Trackers) 100 | add_trackers += e.ToString() + "\n"; 101 | add_trackers = add_trackers.Remove(add_trackers.Length - 1); 102 | } 103 | add_trackers_enabled = p.Add_Trackers_Enabled; 104 | alt_dl_limit = p.Alt_Dl_Limit; 105 | alt_up_limit = p.Alt_Up_Limit; 106 | anonymous_mode = p.Anonymous_Mode; 107 | autorun_enabled = p.Autorun_Enabled; 108 | autorun_program = p.Autorun_Program; 109 | bypass_local_auth = p.Bypass_Local_Auth; 110 | dht = p.Dht; 111 | dhtSameAsBT = p.DhtSameAsBT; 112 | dht_port = p.Dht_Port; 113 | dl_limit = p.Dl_Limit; 114 | dont_count_slow_torrents = p.Dont_Count_Slow_Torrents; 115 | dyndns_domain = p.Dyndns_Domain; 116 | dyndns_enabled = p.Dyndns_Enabled; 117 | dyndns_password = p.Dyndns_Password; 118 | if (p.Dyndns_Service != null) 119 | dyndns_service = (int)p.Dyndns_Service; 120 | dyndns_username = p.Dyndns_Username; 121 | enable_utp = p.Enable_Utp; 122 | if (p.Encryption != null) 123 | encryption = (int)p.Encryption; 124 | export_dir = p.Export_Dir; 125 | export_dir_fin = p.Export_Dir_Finished; 126 | force_proxy = p.Force_Proxy; 127 | incomplete_files_ext = p.Incomplete_Files_Ext; 128 | ip_filter_enabled = p.Ip_Filter_Enabled; 129 | ip_filter_path = p.Ip_Filter_Path; 130 | ip_filter_trackers = p.Ip_Filter_Trackers; 131 | limit_tcp_overhead = p.Limit_Tcp_Overhead; 132 | limit_utp_rate = p.Limit_Utp_Rate; 133 | listen_port = p.Listen_Port; 134 | if (p.Locale != null) 135 | locale = p.Locale.ToString(); 136 | lsd = p.Lsd; 137 | mail_notification_auth_enabled = p.Mail_Notification_Auth_Enabled; 138 | mail_notification_email = p.Mail_Notification_Email; 139 | mail_notification_enabled = p.Mail_Notification_Enabled; 140 | mail_notification_password = p.Mail_Notification_Password; 141 | mail_notification_smtp = p.Mail_Notification_Smtp; 142 | mail_notification_ssl_enabled = p.Mail_Notification_Ssl_Enabled; 143 | mail_notification_username = p.Mail_Notification_Username; 144 | max_active_downloads = p.Max_Active_Downloads; 145 | max_active_torrents = p.Max_Active_Torrents; 146 | max_active_uploads = p.Max_Active_Uploads; 147 | max_connec = p.Max_Connec; 148 | max_connec_per_torrent = p.Max_Connec_Per_Torrent; 149 | max_ratio = p.Max_Ratio; 150 | if (p.Max_Ratio_Action != null) 151 | max_ratio_act = (int)p.Max_Ratio_Action; 152 | max_ratio_enabled = p.Max_Ratio_Enabled; 153 | max_uploads = p.Max_Uploads; 154 | max_uploads_per_torrent = p.Max_Uploads_Per_Torrent; 155 | pex = p.Pex; 156 | preallocate_all = p.Preallocate_All; 157 | proxy_auth_enabled = p.Proxy_Auth_Enabled; 158 | proxy_ip = p.Proxy_Ip; 159 | proxy_password = p.Proxy_Password; 160 | proxy_peer_connections = p.Proxy_Peer_Connections; 161 | proxy_port = p.Proxy_Port; 162 | if (p.Proxy_type != null) 163 | proxy_type = (int)p.Proxy_type; 164 | proxy_username = p.Proxy_Username; 165 | queueing_enabled = p.Queueing_Enabled; 166 | random_port = p.Random_Port; 167 | save_path = p.Save_Path; 168 | if (p.Scan_Dirs != null) 169 | { 170 | download_in_scan_dirs = new string[p.Scan_Dirs.Count]; 171 | scan_dirs = new Dictionary(); 172 | int i = 0; 173 | foreach (var e in p.Scan_Dirs) 174 | { 175 | scan_dirs.Add(e.Key, Convert.ToInt32(e.Key)); 176 | download_in_scan_dirs[i] = e.Key; 177 | i++; 178 | } 179 | } 180 | if (p.Scheduler_Days != null) 181 | scheduler_days = (int)p.Scheduler_Days; 182 | scheduler_enabled = p.Scheduler_Enabled; 183 | if (p.Schedule_From != null) 184 | { 185 | schedule_from_hour = p.Schedule_From.Hours; 186 | schedule_from_min = p.Schedule_From.Minutes; 187 | } 188 | if (p.Schedule_To != null) 189 | { 190 | schedule_to_hour = p.Schedule_To.Hours; 191 | schedule_to_min = p.Schedule_To.Minutes; 192 | } 193 | ssl_cert = p.Ssl_Cert; 194 | ssl_key = p.Ssl_Key; 195 | temp_path = p.Temp_Path; 196 | temp_path_enabled = p.Temp_Path_Enabled; 197 | up_limit = p.Up_Limit; 198 | upnp = p.Upnp; 199 | use_https = p.Use_Https; 200 | web_ui_domain_list = p.Web_Ui_Domain_List; 201 | web_ui_password = p.Web_Ui_Password; 202 | web_ui_port = p.Web_Ui_Port; 203 | web_ui_upnp = p.Web_Ui_Upnp; 204 | web_ui_username = p.Web_Ui_Username; 205 | } 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /QbtWebAPI/JSON/TorrentJSON.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.JSON 2 | { 3 | internal class TorrentJSON 4 | { 5 | public int added_on { get; set; } 6 | public long amount_left { get; set; } 7 | public string category { get; set; } 8 | public long completed { get; set; } 9 | public long completion_on { get; set; } 10 | public long dl_limit { get; set; } 11 | public long dlspeed { get; set; } 12 | public long downloaded { get; set; } 13 | public long downloaded_session { get; set; } 14 | public long eta { get; set; } 15 | public bool f_l_piece_prio { get; set; } 16 | public bool force_start { get; set; } 17 | public string hash { get; set; } 18 | public int last_activity { get; set; } 19 | public string name { get; set; } 20 | public int num_complete { get; set; } 21 | public int num_incomplete { get; set; } 22 | public int num_leechs { get; set; } 23 | public int num_seeds { get; set; } 24 | public int priority { get; set; } 25 | public float progress { get; set; } 26 | public float ratio { get; set; } 27 | public float ratio_limit { get; set; } 28 | public string save_path { get; set; } 29 | public long seen_complete { get; set; } 30 | public bool seq_dl { get; set; } 31 | public long size { get; set; } 32 | public string state { get; set; } 33 | public bool super_seeding { get; set; } 34 | public long total_size { get; set; } 35 | public string tracker { get; set; } 36 | public long up_limit { get; set; } 37 | public long uploaded { get; set; } 38 | public long uploaded_session { get; set; } 39 | public long upspeed { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /QbtWebAPI/JSON/TorrentPropertiesJSON.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.JSON 2 | { 3 | internal class TorrentPropertiesJSON 4 | { 5 | public string Save_Path { get; set; } 6 | public long Creation_Date { get; set; } 7 | public long Piece_Size { get; set; } 8 | public string Comment { get; set; } 9 | public long Total_Wasted { get; set; } 10 | public long Total_Uploaded { get; set; } 11 | public long Total_Uploaded_Session { get; set; } 12 | public long Total_Downloaded { get; set; } 13 | public long Total_Downloaded_Session { get; set; } 14 | public long Up_Limit { get; set; } 15 | public long Dl_Limit { get; set; } 16 | public long Time_Elapsed { get; set; } 17 | public long Seeding_Time { get; set; } 18 | public int Nb_Connections { get; set; } 19 | public int Nb_Connections_Limit { get; set; } 20 | public float Share_Ratio { get; set; } 21 | public long Addition_Date { get; set; } 22 | public long Completion_Date { get; set; } 23 | public string Created_By { get; set; } 24 | public long Dl_Speed_Avg { get; set; } 25 | public long Dl_Speed { get; set; } 26 | public long Eta { get; set; } 27 | public int Last_Seen { get; set; } 28 | public int Peers { get; set; } 29 | public int Peers_Total { get; set; } 30 | public int Pieces_Have { get; set; } 31 | public int Pieces_Num { get; set; } 32 | public long Reannounce { get; set; } 33 | public int Seeds { get; set; } 34 | public int Seeds_Total { get; set; } 35 | public long Total_Size { get; set; } 36 | public long Up_Speed_Avg { get; set; } 37 | public long Up_Speed { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /QbtWebAPI/JSON/TorrentWebSeedJSON.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace QbtWebAPI.JSON 4 | { 5 | internal class TorrentWebSeedJSON 6 | { 7 | public Uri Url { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /QbtWebAPI/JSON/TrackerJSON.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace QbtWebAPI.JSON 4 | { 5 | internal class TrackerJSON 6 | { 7 | public Uri Url { get; set; } 8 | public string Status { get; set; } 9 | public int Num_Peers { get; set; } 10 | public string Msg { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /QbtWebAPI/JSON/TransferInfoJSON.cs: -------------------------------------------------------------------------------- 1 | namespace QbtWebAPI.JSON 2 | { 3 | internal class TransferInfoJSON 4 | { 5 | public long dl_info_speed { get; set; } 6 | public long dl_info_data { get; set; } 7 | public long up_info_speed { get; set; } 8 | public long up_info_data { get; set; } 9 | public long dl_rate_limit { get; set; } 10 | public long up_rate_limit { get; set; } 11 | public int dht_nodes { get; set; } 12 | public string connection_status { get; set; } 13 | public bool queueing { get; set; } 14 | public bool use_alt_speed_limits { get; set; } 15 | public long refresh_interval { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /QbtWebAPI/QbtWebAPI.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 主要功能 2 | 3 | 在线添加种子,qBittorrent v4.1+ 或 Transmission v2.8+ 4 | 在执行离线功能时,请先备份文件夹或文件,qBittorrent的为%localappdata%\qBittorrent\BT_backup文件夹,µTorrent的为resume.dat文件 5 | 1、qBittorrent、Transmission在线添加种子,自动在保存文件夹头添加中文(中文名为添加的种子文件名,可同时添加多个)或手动设置 6 | 2、qBittorrent离线操作fastresume文件,对Tracker、保存路径进行字符串替换 7 | 3、辅种功能,只需要使实际文件保存在相同路径,即可辅种(勾选跳过hash检测时,检测文件名及大小是否相同,两项都一致可认为是相同文件) 8 | 4、qBittorrent离线操作fastresume文件,µTorrent离线操作resume.dat文件,移除实际文件已不存在的种子 9 | 10 | # 主界面 11 | 12 | ![image](https://github.com/LetCodeGo/MyQbt/blob/master/Images/main.png) 13 | 14 | # 感谢以下项目 15 | 16 | * [BencodeNET](https://github.com/Krusen/BencodeNET) 17 | * [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) 18 | * [qBittorrentSharp](https://github.com/teug91/qBittorrentSharp) 19 | * [qBittorrent Web API Documentation](https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation) 20 | * [Transmission.API.RPC](https://github.com/Beatlegger/Transmission.API.RPC) 21 | -------------------------------------------------------------------------------- /Transmission.API.RPC/Arguments/NewTorrent.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Transmission.API.RPC.Common; 8 | 9 | namespace Transmission.API.RPC.Entity 10 | { 11 | /// 12 | /// Information about the torrent file, that will be added 13 | /// 14 | public class NewTorrent : ArgumentsBase 15 | { 16 | /// 17 | /// Pointer to a string of one or more cookies. 18 | /// 19 | public string Cookies { get { return GetValue("cookies"); } set { this["cookies"] = value; } } 20 | 21 | /// 22 | /// Path to download the torrent to 23 | /// 24 | public string DownloadDirectory { get { return GetValue("download-dir"); } set { this["download-dir"] = value; } } 25 | 26 | /// 27 | /// filename (relative to the server) or URL of the .torrent file (Priority than the metadata) 28 | /// 29 | public string Filename { get { return GetValue("filename"); } set { this["filename"] = value; } } 30 | 31 | /// 32 | /// base64-encoded .torrent content 33 | /// 34 | public string Metainfo { get { return GetValue("metainfo"); } set { this["metainfo"] = value; } } 35 | 36 | /// 37 | /// if true, don't start the torrent 38 | /// 39 | public bool Paused { get { return GetValue("paused"); } set { this["paused"] = value; } } 40 | 41 | /// 42 | /// maximum number of peers 43 | /// 44 | public int? PeerLimit { get { return GetValue("peer-limit"); } set { this["peer-limit"] = value; } } 45 | 46 | /// 47 | /// Torrent's bandwidth priority 48 | /// 49 | public int? BandwidthPriority { get { return GetValue("bandwidthPriority"); } set { this["bandwidthPriority"] = value; } } 50 | 51 | /// 52 | /// Indices of file(s) to download 53 | /// 54 | public int[] FilesWanted { get { return GetValue("files-wanted"); } set { this["files-wanted"] = value; } } 55 | 56 | /// 57 | /// Indices of file(s) to download 58 | /// 59 | public int[] FilesUnwanted { get { return GetValue("files-unwanted"); } set { this["files-unwanted"] = value; } } 60 | 61 | /// 62 | /// Indices of high-priority file(s) 63 | /// 64 | public int[] PriorityHigh { get { return GetValue("priority-high"); } set { this["priority-high"] = value; } } 65 | 66 | /// 67 | /// Indices of low-priority file(s) 68 | /// 69 | public int[] PriorityLow { get { return GetValue("priority-low"); } set { this["priority-low"] = value; } } 70 | 71 | /// 72 | /// Indices of normal-priority file(s) 73 | /// 74 | public int[] PriorityNormal { get { return GetValue("priority-normal"); } set { this["priority-normal"] = value; } } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Transmission.API.RPC/Arguments/SessionSettings.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Transmission.API.RPC.Common; 8 | using Transmission.API.RPC.Entity; 9 | 10 | namespace Transmission.API.RPC.Arguments 11 | { 12 | public class SessionSettings : ArgumentsBase 13 | { 14 | /// 15 | /// Max global download speed (KBps) 16 | /// 17 | public int? AlternativeSpeedDown { get { return GetValue("alt-speed-down"); } set { this["alt-speed-down"] = value; } } 18 | 19 | /// 20 | /// True means use the alt speeds 21 | /// 22 | public bool? AlternativeSpeedEnabled { get { return GetValue("alt-speed-enabled"); } set { this["alt-speed-enabled"] = value; } } 23 | 24 | /// 25 | /// When to turn on alt speeds (units: minutes after midnight) 26 | /// 27 | public int? AlternativeSpeedTimeBegin { get { return GetValue("alt-speed-time-begin"); } set { this["alt-speed-time-begin"] = value; } } 28 | 29 | /// 30 | /// True means the scheduled on/off times are used 31 | /// 32 | public bool? AlternativeSpeedTimeEnabled { get { return GetValue("alt-speed-time-enabled"); } set { this["bandwidthPriority"] = value; } } 33 | 34 | /// 35 | /// When to turn off alt speeds 36 | /// 37 | public int? AlternativeSpeedTimeEnd { get { return GetValue("alt-speed-time-end"); } set { this["alt-speed-time-end"] = value; } } 38 | 39 | /// 40 | /// What day(s) to turn on alt speeds 41 | /// 42 | public int? AlternativeSpeedTimeDay { get { return GetValue("alt-speed-time-day"); } set { this["alt-speed-time-day"] = value; } } 43 | 44 | /// 45 | /// Max global upload speed (KBps) 46 | /// 47 | public int? AlternativeSpeedUp { get { return GetValue("alt-speed-up"); } set { this["alt-speed-up"] = value; } } 48 | 49 | /// 50 | /// Location of the blocklist to use for "blocklist-update" 51 | /// 52 | public string BlocklistURL { get { return GetValue("blocklist-url"); } set { this["blocklist-url"] = value; } } 53 | 54 | /// 55 | /// True means enabled 56 | /// 57 | public bool? BlocklistEnabled { get { return GetValue("blocklist-enabled"); } set { this["blocklist-enabled"] = value; } } 58 | 59 | /// 60 | /// Maximum size of the disk cache (MB) 61 | /// 62 | public int? CacheSizeMB { get { return GetValue("cache-size-mb"); } set { this["cache-size-mb"] = value; } } 63 | 64 | /// 65 | /// Default path to download torrents 66 | /// 67 | public string DownloadDirectory { get { return GetValue("download-dir"); } set { this["download-dir"] = value; } } 68 | 69 | /// 70 | /// Max number of torrents to download at once (see download-queue-enabled) 71 | /// 72 | public int? DownloadQueueSize { get { return GetValue("download-queue-size"); } set { this["download-queue-size"] = value; } } 73 | 74 | /// 75 | /// If true, limit how many torrents can be downloaded at once 76 | /// 77 | public bool? DownloadQueueEnabled { get { return GetValue("download-queue-enabled"); } set { this["download-queue-enabled"] = value; } } 78 | 79 | /// 80 | /// True means allow dht in public torrents 81 | /// 82 | public bool? DHTEnabled { get { return GetValue("dht-enabled"); } set { this["dht-enabled"] = value; } } 83 | 84 | /// 85 | /// "required", "preferred", "tolerated" 86 | /// 87 | public string Encryption { get { return GetValue("encryption"); } set { this["encryption"] = value; } } 88 | 89 | /// 90 | /// Torrents we're seeding will be stopped if they're idle for this long 91 | /// 92 | public int? IdleSeedingLimit { get { return GetValue("idle-seeding-limit"); } set { this["idle-seeding-limit"] = value; } } 93 | 94 | /// 95 | /// True if the seeding inactivity limit is honored by default 96 | /// 97 | public bool? IdleSeedingLimitEnabled { get { return GetValue("idle-seeding-limit-enabled"); } set { this["idle-seeding-limit-enabled"] = value; } } 98 | 99 | /// 100 | /// Path for incomplete torrents, when enabled 101 | /// 102 | public string IncompleteDirectory { get { return GetValue("incomplete-dir"); } set { this["incomplete-dir"] = value; } } 103 | 104 | /// 105 | /// True means keep torrents in incomplete-dir until done 106 | /// 107 | public bool? IncompleteDirectoryEnabled { get { return GetValue("incomplete-dir-enabled"); } set { this["incomplete-dir-enabled"] = value; } } 108 | 109 | /// 110 | /// True means allow Local Peer Discovery in public torrents 111 | /// 112 | public bool? LPDEnabled { get { return GetValue("lpd-enabled"); } set { this["lpd-enabled"] = value; } } 113 | 114 | /// 115 | /// Maximum global number of peers 116 | /// 117 | public int? PeerLimitGlobal { get { return GetValue("peer-limit-global"); } set { this["peer-limit-global"] = value; } } 118 | 119 | /// 120 | /// Maximum global number of peers 121 | /// 122 | public int? PeerLimitPerTorrent { get { return GetValue("peer-limit-per-torrent"); } set { this["peer-limit-per-torrent"] = value; } } 123 | 124 | /// 125 | /// True means allow pex in public torrents 126 | /// 127 | public bool? PexEnabled { get { return GetValue("pex-enabled"); } set { this["pex-enabled"] = value; } } 128 | 129 | /// 130 | /// Port number 131 | /// 132 | public int? PeerPort { get { return GetValue("peer-port"); } set { this["peer-port"] = value; } } 133 | 134 | /// 135 | /// True means pick a random peer port on launch 136 | /// 137 | public bool? PeerPortRandomOnStart { get { return GetValue("peer-port-random-on-start"); } set { this["peer-port-random-on-start"] = value; } } 138 | 139 | /// 140 | /// true means enabled 141 | /// 142 | public bool? PortForwardingEnabled { get { return GetValue("port-forwarding-enabled"); } set { this["port-forwarding-enabled"] = value; } } 143 | 144 | /// 145 | /// Whether or not to consider idle torrents as stalled 146 | /// 147 | public bool? QueueStalledEnabled { get { return GetValue("queue-stalled-enabled"); } set { this["queue-stalled-enabled"] = value; } } 148 | 149 | /// 150 | /// Torrents that are idle for N minuets aren't counted toward seed-queue-size or download-queue-size 151 | /// 152 | public int? QueueStalledMinutes { get { return GetValue("queue-stalled-minutes"); } set { this["queue-stalled-minutes"] = value; } } 153 | 154 | /// 155 | /// True means append ".part" to incomplete files 156 | /// 157 | public bool? RenamePartialFiles { get { return GetValue("rename-partial-files"); } set { this["rename-partial-files"] = value; } } 158 | 159 | /// 160 | /// Filename of the script to run 161 | /// 162 | public string ScriptTorrentDoneFilename { get { return GetValue("script-torrent-done-filename"); } set { this["script-torrent-done-filename"] = value; } } 163 | 164 | /// 165 | /// Whether or not to call the "done" script 166 | /// 167 | public bool? ScriptTorrentDoneEnabled { get { return GetValue("script-torrent-done-enabled"); } set { this["script-torrent-done-enabled"] = value; } } 168 | 169 | /// 170 | /// The default seed ratio for torrents to use 171 | /// 172 | public double? SeedRatioLimit { get { return GetValue("seedRatioLimit"); } set { this["seedRatioLimit"] = value; } } 173 | 174 | /// 175 | /// True if seedRatioLimit is honored by default 176 | /// 177 | public bool? SeedRatioLimited { get { return GetValue("seedRatioLimited"); } set { this["seedRatioLimited"] = value; } } 178 | 179 | /// 180 | /// Max number of torrents to uploaded at once (see seed-queue-enabled) 181 | /// 182 | public int? SeedQueueSize { get { return GetValue("seed-queue-size"); } set { this["seed-queue-size"] = value; } } 183 | 184 | /// 185 | /// If true, limit how many torrents can be uploaded at once 186 | /// 187 | public bool? SeedQueueEnabled { get { return GetValue("seed-queue-enabled"); } set { this["seed-queue-enabled"] = value; } } 188 | 189 | /// 190 | /// Max global download speed (KBps) 191 | /// 192 | public int? SpeedLimitDown { get { return GetValue("speed-limit-down"); } set { this["speed-limit-down"] = value; } } 193 | 194 | /// 195 | /// True means enabled 196 | /// 197 | public bool? SpeedLimitDownEnabled { get { return GetValue("speed-limit-down-enabled"); } set { this["speed-limit-down-enabled"] = value; } } 198 | 199 | /// 200 | /// max global upload speed (KBps) 201 | /// 202 | public int? SpeedLimitUp { get { return GetValue("speed-limit-up"); } set { this["speed-limit-up"] = value; } } 203 | 204 | /// 205 | /// True means enabled 206 | /// 207 | public bool? SpeedLimitUpEnabled { get { return GetValue("speed-limit-up-enabled"); } set { this["speed-limit-up-enabled"] = value; } } 208 | 209 | /// 210 | /// True means added torrents will be started right away 211 | /// 212 | public bool? StartAddedTorrents { get { return GetValue("start-added-torrents"); } set { this["start-added-torrents"] = value; } } 213 | 214 | /// 215 | /// True means the .torrent file of added torrents will be deleted 216 | /// 217 | public bool? TrashOriginalTorrentFiles { get { return GetValue("trash-original-torrent-files"); } set { this["trash-original-torrent-files"] = value; } } 218 | 219 | public Units Units { get { return GetValue("units"); } set { this["units"] = value; } } 220 | 221 | /// 222 | /// True means allow utp 223 | /// 224 | public bool? UtpEnabled { get { return GetValue ("utp-enabled"); } set { this["utp-enabled"] = value; } } 225 | 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /Transmission.API.RPC/Arguments/TorrentSettings.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Transmission.API.RPC.Common; 8 | 9 | namespace Transmission.API.RPC.Arguments 10 | { 11 | public class TorrentSettings : ArgumentsBase 12 | { 13 | /// 14 | /// This torrent's bandwidth tr_priority_t 15 | /// 16 | public int? BandwidthPriority { get { return GetValue("bandwidthPriority"); } set { this["bandwidthPriority"] = value; } } 17 | 18 | /// 19 | /// Maximum download speed (KBps) 20 | /// 21 | public int? DownloadLimit { get { return GetValue("downloadLimit"); } set { this["downloadLimit"] = value; } } 22 | 23 | /// 24 | /// Download limit is honored 25 | /// 26 | public bool? DownloadLimited { get { return GetValue("downloadLimited"); } set { this["downloadLimited"] = value; } } 27 | 28 | /// 29 | /// Session upload limits are honored 30 | /// 31 | public bool? HonorsSessionLimits { get { return GetValue("honorsSessionLimits"); } set { this["honorsSessionLimits"] = value; } } 32 | 33 | /// 34 | /// Torrent id array 35 | /// 36 | public object[] IDs { get { return GetValue("ids"); } set { this["ids"] = value; } } 37 | 38 | /// 39 | /// New location of the torrent's content 40 | /// 41 | public string Location { get { return GetValue("location"); } set { this["location"] = value; } } 42 | 43 | /// 44 | /// Maximum number of peers 45 | /// 46 | public int? PeerLimit { get { return GetValue("peer-limit"); } set { this["peer-limit"] = value; } } 47 | 48 | /// 49 | /// Position of this torrent in its queue [0...n) 50 | /// 51 | public int? QueuePosition { get { return GetValue("queuePosition"); } set { this["queuePosition"] = value; } } 52 | 53 | /// 54 | /// Torrent-level number of minutes of seeding inactivity 55 | /// 56 | public int? SeedIdleLimit { get { return GetValue("seedIdleLimit"); } set { this["seedIdleLimit"] = value; } } 57 | 58 | /// 59 | /// Which seeding inactivity to use 60 | /// 61 | public int? SeedIdleMode { get { return GetValue("seedIdleMode"); } set { this["seedIdleMode"] = value; } } 62 | 63 | /// 64 | /// Torrent-level seeding ratio 65 | /// 66 | public double? SeedRatioLimit { get { return GetValue("seedRatioLimit"); } set { this["seedRatioLimit"] = value; } } 67 | 68 | /// 69 | /// Which ratio to use. 70 | /// 71 | public int? SeedRatioMode { get { return GetValue("seedRatioMode"); } set { this["seedRatioMode"] = value; } } 72 | 73 | /// 74 | /// Maximum upload speed (KBps) 75 | /// 76 | public int? UploadLimit { get { return GetValue("uploadLimit"); } set { this["uploadLimit"] = value; } } 77 | 78 | /// 79 | /// Upload limit is honored 80 | /// 81 | public bool? UploadLimited { get { return GetValue("uploadLimited"); } set { this["uploadLimited"] = value; } } 82 | 83 | /// 84 | /// Strings of announce URLs to add 85 | /// 86 | public string[] TrackerAdd { get { return GetValue("trackerAdd"); } set { this["trackerAdd"] = value; } } 87 | 88 | /// 89 | /// Ids of trackers to remove 90 | /// 91 | public int[] TrackerRemove { get { return GetValue("trackerRemove"); } set { this["trackerRemove"] = value; } } 92 | 93 | /// 94 | /// Files wanted 95 | /// 96 | public string[] FilesWanted { get { return GetValue("files-wanted"); } set { this["files-wanted"] = value; } } 97 | 98 | /// 99 | /// Files unwanted 100 | /// 101 | public string[] FilesUnwanted { get { return GetValue("files-unwanted"); } set { this["files-unwanted"] = value; } } 102 | 103 | /// 104 | /// High priority files 105 | /// 106 | public string[] PriorityHigh { get { return GetValue("priority-high"); } set { this["priority-high"] = value; } } 107 | 108 | /// 109 | /// Low priority files 110 | /// 111 | public string[] PriorityLow { get { return GetValue("priority-low"); } set { this["priority-low"] = value; } } 112 | 113 | /// 114 | /// Normal priority files 115 | /// 116 | public string[] PriorityNormal { get { return GetValue("priority-normal"); } set { this["priority-normal"] = value; } } 117 | 118 | //TODO: Add and test 119 | //"trackerReplace" | array pairs of 120 | //public [] trackerReplace; 121 | 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /Transmission.API.RPC/AsyncExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Transmission.API.RPC 8 | { 9 | public static class AsyncExtensions 10 | { 11 | public static void WaitAndUnwrapException(this Task task) 12 | { 13 | try 14 | { 15 | task.Wait(); 16 | } catch(Exception e) 17 | { 18 | if (e.InnerException != null) 19 | { 20 | throw e.InnerException; 21 | } 22 | 23 | throw e; 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Transmission.API.RPC/Common/ArgumentsBase.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Transmission.API.RPC.Common 4 | { 5 | /// 6 | /// Absract class for arguments 7 | /// 8 | public abstract class ArgumentsBase 9 | { 10 | internal Dictionary Data = new Dictionary(); 11 | 12 | internal object this[string name] 13 | { 14 | set { SetValue(name, value); } 15 | } 16 | 17 | private void SetValue(string name, object value) 18 | { 19 | if (this.Data.ContainsKey(name)) Data[name] = value; 20 | else Data.Add(name, value); 21 | } 22 | 23 | internal T GetValue(string name) 24 | { 25 | return this.Data.ContainsKey(name) ? (T)Data[name] : default(T); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Transmission.API.RPC/Common/CommunicateBase.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Transmission.API.RPC.Common 9 | { 10 | public abstract class CommunicateBase 11 | { 12 | /// 13 | /// Data 14 | /// 15 | [JsonProperty("arguments")] 16 | public Dictionary Arguments; 17 | 18 | /// 19 | /// Number (id) 20 | /// 21 | [JsonProperty("tag")] 22 | public int Tag; 23 | 24 | /// 25 | /// Convert to JSON string 26 | /// 27 | /// 28 | public virtual string ToJson() 29 | { 30 | return JsonConvert.SerializeObject(this, Formatting.Indented); 31 | } 32 | 33 | /// 34 | /// Deserialize to class 35 | /// 36 | /// 37 | public T Deserialize() 38 | { 39 | var argumentsString = JsonConvert.SerializeObject(this.Arguments); 40 | return JsonConvert.DeserializeObject(argumentsString); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Transmission.API.RPC/Common/TransmissionRequest.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Transmission.API.RPC.Common 9 | { 10 | /// 11 | /// Transmission request 12 | /// 13 | public class TransmissionRequest : CommunicateBase 14 | { 15 | /// 16 | /// Name of the method to invoke 17 | /// 18 | [JsonProperty("method")] 19 | public string Method; 20 | 21 | public TransmissionRequest(string method) 22 | { 23 | this.Method = method; 24 | } 25 | 26 | public TransmissionRequest(string method, ArgumentsBase arguments) 27 | { 28 | this.Method = method; 29 | this.Arguments = arguments.Data; 30 | } 31 | 32 | public TransmissionRequest(string method, Dictionary arguments) 33 | { 34 | this.Method = method; 35 | this.Arguments = arguments; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Transmission.API.RPC/Common/TransmissionResponse.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Transmission.API.RPC.Common 9 | { 10 | /// 11 | /// Transmission response 12 | /// 13 | public class TransmissionResponse : CommunicateBase 14 | { 15 | /// 16 | /// Contains "success" on success, or an error string on failure. 17 | /// 18 | [JsonProperty("result")] 19 | public string Result; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Transmission.API.RPC/Entity/NewTorrentInfo.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Transmission.API.RPC.Entity 9 | { 10 | /// 11 | /// Information of added torrent 12 | /// 13 | public class NewTorrentInfo 14 | { 15 | /// 16 | /// Torrent ID 17 | /// 18 | [JsonProperty("id")] 19 | public int ID { get; set; } 20 | 21 | /// 22 | /// Torrent name 23 | /// 24 | [JsonProperty("name")] 25 | public string Name { get; set; } 26 | 27 | /// 28 | /// Torrent Hash 29 | /// 30 | [JsonProperty("hashString")] 31 | public string HashString { get; set; } 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Transmission.API.RPC/Entity/RenameTorrentInfo.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Transmission.API.RPC.Entity 9 | { 10 | /// 11 | /// Rename torrent result information 12 | /// 13 | public class RenameTorrentInfo 14 | { 15 | /// 16 | /// The torrent's unique Id. 17 | /// 18 | [JsonProperty("id")] 19 | public int ID { get; set; } 20 | 21 | /// 22 | /// File path. 23 | /// 24 | [JsonProperty("path")] 25 | public string Path { get; set; } 26 | 27 | /// 28 | /// File name. 29 | /// 30 | [JsonProperty("name")] 31 | public string Name { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Transmission.API.RPC/Entity/SessionInfo.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Transmission.API.RPC.Arguments; 9 | 10 | namespace Transmission.API.RPC.Entity 11 | { 12 | public class SessionInfo 13 | { 14 | /// 15 | /// Max global download speed (KBps) 16 | /// 17 | [JsonProperty("alt-speed-down")] 18 | public int? AlternativeSpeedDown { get; set; } 19 | 20 | /// 21 | /// True means use the alt speeds 22 | /// 23 | [JsonProperty("alt-speed-enabled")] 24 | public bool? AlternativeSpeedEnabled { get; set; } 25 | 26 | /// 27 | /// When to turn on alt speeds (units: minutes after midnight) 28 | /// 29 | [JsonProperty("alt-speed-time-begin")] 30 | public int? AlternativeSpeedTimeBegin { get; set; } 31 | 32 | /// 33 | /// True means the scheduled on/off times are used 34 | /// 35 | [JsonProperty("alt-speed-time-enabled")] 36 | public bool? AlternativeSpeedTimeEnabled { get; set; } 37 | 38 | /// 39 | /// When to turn off alt speeds 40 | /// 41 | [JsonProperty("alt-speed-time-end")] 42 | public int? AlternativeSpeedTimeEnd { get; set; } 43 | 44 | /// 45 | /// What day(s) to turn on alt speeds 46 | /// 47 | [JsonProperty("alt-speed-time-day")] 48 | public int? AlternativeSpeedTimeDay { get; set; } 49 | 50 | /// 51 | /// Max global upload speed (KBps) 52 | /// 53 | [JsonProperty("alt-speed-up")] 54 | public int? AlternativeSpeedUp { get; set; } 55 | 56 | /// 57 | /// Location of the blocklist to use for "blocklist-update" 58 | /// 59 | [JsonProperty("blocklist-url")] 60 | public string BlocklistURL { get; set; } 61 | 62 | /// 63 | /// True means enabled 64 | /// 65 | [JsonProperty("blocklist-enabled")] 66 | public bool? BlocklistEnabled { get; set; } 67 | 68 | /// 69 | /// Maximum size of the disk cache (MB) 70 | /// 71 | [JsonProperty("cache-size-mb")] 72 | public int? CacheSizeMB { get; set; } 73 | 74 | /// 75 | /// Default path to download torrents 76 | /// 77 | [JsonProperty("download-dir")] 78 | public string DownloadDirectory { get; set; } 79 | 80 | /// 81 | /// Max number of torrents to download at once (see download-queue-enabled) 82 | /// 83 | [JsonProperty("download-queue-size")] 84 | public int? DownloadQueueSize { get; set; } 85 | 86 | /// 87 | /// If true, limit how many torrents can be downloaded at once 88 | /// 89 | [JsonProperty("download-queue-enabled")] 90 | public bool? DownloadQueueEnabled { get; set; } 91 | 92 | /// 93 | /// True means allow dht in public torrents 94 | /// 95 | [JsonProperty("dht-enabled")] 96 | public bool? DHTEnabled { get; set; } 97 | 98 | /// 99 | /// "required", "preferred", "tolerated" 100 | /// 101 | [JsonProperty("encryption")] 102 | public string Encryption { get; set; } 103 | 104 | /// 105 | /// Torrents we're seeding will be stopped if they're idle for this long 106 | /// 107 | [JsonProperty("idle-seeding-limit")] 108 | public int? IdleSeedingLimit { get; set; } 109 | 110 | /// 111 | /// True if the seeding inactivity limit is honored by default 112 | /// 113 | [JsonProperty("idle-seeding-limit-enabled")] 114 | public bool? IdleSeedingLimitEnabled { get; set; } 115 | 116 | /// 117 | /// Path for incomplete torrents, when enabled 118 | /// 119 | [JsonProperty("incomplete-dir")] 120 | public string IncompleteDirectory { get; set; } 121 | 122 | /// 123 | /// True means keep torrents in incomplete-dir until done 124 | /// 125 | [JsonProperty("incomplete-dir-enabled")] 126 | public bool? IncompleteDirectoryEnabled { get; set; } 127 | 128 | /// 129 | /// True means allow Local Peer Discovery in public torrents 130 | /// 131 | [JsonProperty("lpd-enabled")] 132 | public bool? LPDEnabled { get; set; } 133 | 134 | /// 135 | /// Maximum global number of peers 136 | /// 137 | [JsonProperty("peer-limit-global")] 138 | public int? PeerLimitGlobal { get; set; } 139 | 140 | /// 141 | /// Maximum global number of peers 142 | /// 143 | [JsonProperty("peer-limit-per-torrent")] 144 | public int? PeerLimitPerTorrent { get; set; } 145 | 146 | /// 147 | /// True means allow pex in public torrents 148 | /// 149 | [JsonProperty("pex-enabled")] 150 | public bool? PexEnabled { get; set; } 151 | 152 | /// 153 | /// Port number 154 | /// 155 | [JsonProperty("peer-port")] 156 | public int? PeerPort { get; set; } 157 | 158 | /// 159 | /// True means pick a random peer port on launch 160 | /// 161 | [JsonProperty("peer-port-random-on-start")] 162 | public bool? PeerPortRandomOnStart { get; set; } 163 | 164 | /// 165 | /// true means enabled 166 | /// 167 | [JsonProperty("port-forwarding-enabled")] 168 | public bool? PortForwardingEnabled { get; set; } 169 | 170 | /// 171 | /// Whether or not to consider idle torrents as stalled 172 | /// 173 | [JsonProperty("queue-stalled-enabled")] 174 | public bool? QueueStalledEnabled { get; set; } 175 | 176 | /// 177 | /// Torrents that are idle for N minuets aren't counted toward seed-queue-size or download-queue-size 178 | /// 179 | [JsonProperty("queue-stalled-minutes")] 180 | public int? QueueStalledMinutes { get; set; } 181 | 182 | /// 183 | /// True means append ".part" to incomplete files 184 | /// 185 | [JsonProperty("rename-partial-files")] 186 | public bool? RenamePartialFiles { get; set; } 187 | 188 | /// 189 | /// Filename of the script to run 190 | /// 191 | [JsonProperty("script-torrent-done-filename")] 192 | public string ScriptTorrentDoneFilename { get; set; } 193 | 194 | /// 195 | /// Whether or not to call the "done" script 196 | /// 197 | [JsonProperty("script-torrent-done-enabled")] 198 | public bool? ScriptTorrentDoneEnabled { get; set; } 199 | 200 | /// 201 | /// The default seed ratio for torrents to use 202 | /// 203 | [JsonProperty("seedRatioLimit")] 204 | public double? SeedRatioLimit { get; set; } 205 | 206 | /// 207 | /// True if seedRatioLimit is honored by default 208 | /// 209 | [JsonProperty("seedRatioLimited")] 210 | public bool? SeedRatioLimited { get; set; } 211 | 212 | /// 213 | /// Max number of torrents to uploaded at once (see seed-queue-enabled) 214 | /// 215 | [JsonProperty("seed-queue-size")] 216 | public int? SeedQueueSize { get; set; } 217 | 218 | /// 219 | /// If true, limit how many torrents can be uploaded at once 220 | /// 221 | [JsonProperty("seed-queue-enabled")] 222 | public bool? SeedQueueEnabled { get; set; } 223 | 224 | /// 225 | /// Max global download speed (KBps) 226 | /// 227 | [JsonProperty("speed-limit-down")] 228 | public int? SpeedLimitDown { get; set; } 229 | 230 | /// 231 | /// True means enabled 232 | /// 233 | [JsonProperty("speed-limit-down-enabled")] 234 | public bool? SpeedLimitDownEnabled { get; set; } 235 | 236 | /// 237 | /// max global upload speed (KBps) 238 | /// 239 | [JsonProperty("speed-limit-up")] 240 | public int? SpeedLimitUp { get; set; } 241 | 242 | /// 243 | /// True means enabled 244 | /// 245 | [JsonProperty("speed-limit-up-enabled")] 246 | public bool? SpeedLimitUpEnabled { get; set; } 247 | 248 | /// 249 | /// True means added torrents will be started right away 250 | /// 251 | [JsonProperty("start-added-torrents")] 252 | public bool? StartAddedTorrents { get; set; } 253 | 254 | /// 255 | /// True means the .torrent file of added torrents will be deleted 256 | /// 257 | [JsonProperty("trash-original-torrent-files")] 258 | public bool? TrashOriginalTorrentFiles { get; set; } 259 | 260 | [JsonProperty("units")] 261 | public Units Units { get; set; } 262 | 263 | /// 264 | /// True means allow utp 265 | /// 266 | [JsonProperty("utp-enabled")] 267 | public bool? UtpEnabled { get; set; } 268 | 269 | /// 270 | /// Number of rules in the blocklist 271 | /// 272 | [JsonProperty("blocklist-size")] 273 | public int BlocklistSize{ get; set; } 274 | 275 | /// 276 | /// Location of transmission's configuration directory 277 | /// 278 | [JsonProperty("config-dir")] 279 | public string ConfigDirectory{ get; set; } 280 | 281 | /// 282 | /// The current RPC API version 283 | /// 284 | [JsonProperty("rpc-version")] 285 | public int RpcVersion{ get; set; } 286 | 287 | /// 288 | /// The minimum RPC API version supported 289 | /// 290 | [JsonProperty("rpc-version-minimum")] 291 | public int RpcVersionMinimum{ get; set; } 292 | 293 | /// 294 | /// Long version string "$version ($revision)" 295 | /// 296 | [JsonProperty("version")] 297 | public string Version{ get; set; } 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /Transmission.API.RPC/Entity/Statistic.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Transmission.API.RPC.Entity 9 | { 10 | public class Statistic 11 | { 12 | [JsonProperty("activeTorrentCount")] 13 | public int ActiveTorrentCount { get; set; } 14 | 15 | [JsonProperty("downloadSpeed")] 16 | public int downloadSpeed{ get; set; } 17 | 18 | [JsonProperty("pausedTorrentCount")] 19 | public int pausedTorrentCount{ get; set; } 20 | 21 | [JsonProperty("torrentCount")] 22 | public int torrentCount{ get; set; } 23 | 24 | [JsonProperty("uploadSpeed")] 25 | public int uploadSpeed{ get; set; } 26 | 27 | [JsonProperty("cumulative-stats")] 28 | public CommonStatistic CumulativeStats { get; set; } 29 | 30 | [JsonProperty("current-stats")] 31 | public CommonStatistic CurrentStats { get; set; } 32 | } 33 | 34 | public class CommonStatistic 35 | { 36 | [JsonProperty("uploadedBytes")] 37 | public double uploadedBytes{ get; set; } 38 | 39 | [JsonProperty("downloadedBytes")] 40 | public double DownloadedBytes{ get; set; } 41 | 42 | [JsonProperty("filesAdded")] 43 | public int FilesAdded{ get; set; } 44 | 45 | [JsonProperty("SessionCount")] 46 | public int SessionCount{ get; set; } 47 | 48 | [JsonProperty("SecondsActive")] 49 | public int SecondsActive{ get; set; } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Transmission.API.RPC/Entity/Units.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Transmission.API.RPC.Entity 9 | { 10 | public class Units 11 | { 12 | [JsonProperty("speed-units")] 13 | public string[] SpeedUnits { get; set; } 14 | 15 | [JsonProperty("speed-bytes")] 16 | public int? SpeedBytes { get; set; } 17 | 18 | [JsonProperty("size-units")] 19 | public string[] SizeUnits { get; set; } 20 | 21 | [JsonProperty("size-bytes")] 22 | public int? SizeBytes { get; set; } 23 | 24 | [JsonProperty("memory-units")] 25 | public string[] MemoryUnits { get; set; } 26 | 27 | [JsonProperty("memory-bytes")] 28 | public int? MemoryBytes { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Transmission.API.RPC/ITransmissionClient.cs: -------------------------------------------------------------------------------- 1 | using Transmission.API.RPC.Arguments; 2 | using Transmission.API.RPC.Entity; 3 | 4 | namespace Transmission.API.RPC 5 | { 6 | public interface ITransmissionClient 7 | { 8 | int CurrentTag { get; } 9 | string SessionID { get; } 10 | string Url { get; } 11 | 12 | /// 13 | /// Update blocklist (API: blocklist-update) 14 | /// 15 | /// Blocklist size 16 | int BlocklistUpdate(); 17 | 18 | /// 19 | /// Close current session (API: session-close) 20 | /// 21 | void CloseSession(); 22 | 23 | /// 24 | /// Get free space is available in a client-specified folder. 25 | /// 26 | /// The directory to query 27 | long FreeSpace(string path); 28 | 29 | /// 30 | /// Get information of current session (API: session-get) 31 | /// 32 | /// Session information 33 | SessionInfo GetSessionInformation(); 34 | 35 | /// 36 | /// Get session stat 37 | /// 38 | /// Session stat 39 | Statistic GetSessionStatistic(); 40 | 41 | /// 42 | /// See if your incoming peer port is accessible from the outside world (API: port-test) 43 | /// 44 | /// Accessible state 45 | bool PortTest(); 46 | 47 | /// 48 | /// Set information to current session (API: session-set) 49 | /// 50 | /// New session settings 51 | void SetSessionSettings(SessionSettings settings); 52 | 53 | /// 54 | /// Add torrent (API: torrent-add) 55 | /// 56 | /// Torrent info (ID, Name and HashString) 57 | NewTorrentInfo TorrentAdd(NewTorrent torrent); 58 | 59 | /// 60 | /// Get fields of torrents from ids (API: torrent-get) 61 | /// 62 | /// Fields of torrents 63 | /// IDs of torrents (null or empty for get all torrents) 64 | /// Torrents info 65 | TransmissionTorrents TorrentGet(string[] fields, params int[] ids); 66 | 67 | /// 68 | /// Move torrents to bottom in queue (API: queue-move-bottom) 69 | /// 70 | /// 71 | void TorrentQueueMoveBottom(int[] ids); 72 | 73 | /// 74 | /// Move down torrents in queue (API: queue-move-down) 75 | /// 76 | /// 77 | void TorrentQueueMoveDown(int[] ids); 78 | 79 | /// 80 | /// Move torrents in queue on top (API: queue-move-top) 81 | /// 82 | /// Torrents id 83 | void TorrentQueueMoveTop(int[] ids); 84 | 85 | /// 86 | /// Move up torrents in queue (API: queue-move-up) 87 | /// 88 | /// 89 | void TorrentQueueMoveUp(int[] ids); 90 | 91 | /// 92 | /// Remove torrents (API: torrent-remove) 93 | /// 94 | /// Torrents id 95 | /// Remove local data 96 | void TorrentRemove(int[] ids, bool deleteData = false); 97 | 98 | /// 99 | /// Rename a file or directory in a torrent (API: torrent-rename-path) 100 | /// 101 | /// The torrent whose path will be renamed 102 | /// The path to the file or folder that will be renamed 103 | /// The file or folder's new name 104 | RenameTorrentInfo TorrentRenamePath(int id, string path, string name); 105 | 106 | /// 107 | /// Set torrent params (API: torrent-set) 108 | /// 109 | /// New torrent params 110 | void TorrentSet(TorrentSettings settings); 111 | 112 | /// 113 | /// Set new location for torrents files (API: torrent-set-location) 114 | /// 115 | /// Torrent ids 116 | /// The new torrent location 117 | /// Move from previous location 118 | void TorrentSetLocation(int[] ids, string location, bool move); 119 | 120 | /// 121 | /// Start recently active torrents (API: torrent-start) 122 | /// 123 | void TorrentStart(); 124 | 125 | /// 126 | /// Start torrents (API: torrent-start) 127 | /// 128 | /// A list of torrent id numbers, sha1 hash strings, or both 129 | void TorrentStart(object[] ids); 130 | 131 | /// 132 | /// Start now recently active torrents (API: torrent-start-now) 133 | /// 134 | void TorrentStartNow(); 135 | 136 | /// 137 | /// Start now torrents (API: torrent-start-now) 138 | /// 139 | /// A list of torrent id numbers, sha1 hash strings, or both 140 | void TorrentStartNow(object[] ids); 141 | 142 | /// 143 | /// Stop recently active torrents (API: torrent-stop) 144 | /// 145 | /// A list of torrent id numbers, sha1 hash strings, or both 146 | void TorrentStop(); 147 | 148 | /// 149 | /// Stop torrents (API: torrent-stop) 150 | /// 151 | /// A list of torrent id numbers, sha1 hash strings, or both 152 | void TorrentStop(object[] ids); 153 | 154 | /// 155 | /// Verify recently active torrents (API: torrent-verify) 156 | /// 157 | /// Torrents id 158 | void TorrentVerify(); 159 | 160 | /// 161 | /// Verify torrents (API: torrent-verify) 162 | /// 163 | /// A list of torrent id numbers, sha1 hash strings, or both 164 | void TorrentVerify(object[] ids); 165 | } 166 | } -------------------------------------------------------------------------------- /Transmission.API.RPC/ITransmissionClientAsync.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Transmission.API.RPC.Arguments; 3 | using Transmission.API.RPC.Entity; 4 | 5 | namespace Transmission.API.RPC 6 | { 7 | public interface ITransmissionClientAsync 8 | { 9 | 10 | /// 11 | /// Update blocklist (API: blocklist-update) 12 | /// 13 | /// Blocklist size 14 | Task BlocklistUpdateAsync(); 15 | 16 | /// 17 | /// Close current session (API: session-close) 18 | /// 19 | void CloseSessionAsync(); 20 | 21 | /// 22 | /// Get free space is available in a client-specified folder. 23 | /// 24 | /// The directory to query 25 | Task FreeSpaceAsync(string path); 26 | 27 | /// 28 | /// Get information of current session (API: session-get) 29 | /// 30 | /// Session information 31 | Task GetSessionInformationAsync(); 32 | 33 | /// 34 | /// Get session stat 35 | /// 36 | /// Session stat 37 | Task GetSessionStatisticAsync(); 38 | 39 | /// 40 | /// See if your incoming peer port is accessible from the outside world (API: port-test) 41 | /// 42 | /// Accessible state 43 | Task PortTestAsync(); 44 | 45 | /// 46 | /// Set information to current session (API: session-set) 47 | /// 48 | /// New session settings 49 | void SetSessionSettingsAsync(SessionSettings settings); 50 | 51 | /// 52 | /// Add torrent (API: torrent-add) 53 | /// 54 | /// Torrent info (ID, Name and HashString) 55 | Task TorrentAddAsync(NewTorrent torrent); 56 | 57 | /// 58 | /// Get fields of torrents from ids (API: torrent-get) 59 | /// 60 | /// Fields of torrents 61 | /// IDs of torrents (null or empty for get all torrents) 62 | /// Torrents info 63 | Task TorrentGetAsync(string[] fields, params int[] ids); 64 | 65 | /// 66 | /// Move torrents to bottom in queue (API: queue-move-bottom) 67 | /// 68 | /// 69 | void TorrentQueueMoveBottomAsync(int[] ids); 70 | 71 | /// 72 | /// Move down torrents in queue (API: queue-move-down) 73 | /// 74 | /// 75 | void TorrentQueueMoveDownAsync(int[] ids); 76 | 77 | /// 78 | /// Move torrents in queue on top (API: queue-move-top) 79 | /// 80 | /// Torrents id 81 | void TorrentQueueMoveTopAsync(int[] ids); 82 | 83 | /// 84 | /// Move up torrents in queue (API: queue-move-up) 85 | /// 86 | /// 87 | void TorrentQueueMoveUpAsync(int[] ids); 88 | 89 | /// 90 | /// Remove torrents 91 | /// 92 | /// Torrents id 93 | /// Remove local data 94 | void TorrentRemoveAsync(int[] ids, bool deleteData = false); 95 | 96 | /// 97 | /// Rename a file or directory in a torrent (API: torrent-rename-path) 98 | /// 99 | /// The torrent whose path will be renamed 100 | /// The path to the file or folder that will be renamed 101 | /// The file or folder's new name 102 | Task TorrentRenamePathAsync(int id, string path, string name); 103 | 104 | /// 105 | /// Set torrent params (API: torrent-set) 106 | /// 107 | /// New torrent params 108 | void TorrentSetAsync(TorrentSettings settings); 109 | 110 | /// 111 | /// Set new location for torrents files (API: torrent-set-location) 112 | /// 113 | /// Torrent ids 114 | /// The new torrent location 115 | /// Move from previous location 116 | void TorrentSetLocationAsync(int[] ids, string location, bool move); 117 | 118 | /// 119 | /// Start recently active torrents (API: torrent-start) 120 | /// 121 | void TorrentStartAsync(); 122 | 123 | /// 124 | /// Start torrents (API: torrent-start) 125 | /// 126 | /// A list of torrent id numbers, sha1 hash strings, or both 127 | void TorrentStartAsync(object[] ids); 128 | 129 | /// 130 | /// Start now recently active torrents (API: torrent-start-now) 131 | /// 132 | void TorrentStartNowAsync(); 133 | 134 | /// 135 | /// Start now torrents (API: torrent-start-now) 136 | /// 137 | /// A list of torrent id numbers, sha1 hash strings, or both 138 | void TorrentStartNowAsync(object[] ids); 139 | 140 | /// 141 | /// Stop recently active torrents (API: torrent-stop) 142 | /// 143 | void TorrentStopAsync(); 144 | 145 | /// 146 | /// Stop torrents (API: torrent-stop) 147 | /// 148 | /// A list of torrent id numbers, sha1 hash strings, or both 149 | void TorrentStopAsync(object[] ids); 150 | 151 | /// 152 | /// Verify recently active torrents (API: torrent-verify) 153 | /// 154 | void TorrentVerifyAsync(); 155 | 156 | /// 157 | /// Verify torrents (API: torrent-verify) 158 | /// 159 | /// A list of torrent id numbers, sha1 hash strings, or both 160 | void TorrentVerifyAsync(object[] ids); 161 | } 162 | } -------------------------------------------------------------------------------- /Transmission.API.RPC/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Transmission.API.RPC")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Transmission.API.RPC")] 13 | [assembly: AssemblyCopyright("Copyright © 2020")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("0d44d5b1-3317-4624-9c28-7db1f6dfb018")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 33 | //通过使用 "*",如下所示: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Transmission.API.RPC/Transmission.API.RPC.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {0D44D5B1-3317-4624-9C28-7DB1F6DFB018} 8 | Library 9 | Properties 10 | Transmission.API.RPC 11 | Transmission.API.RPC 12 | v4.8 13 | 512 14 | true 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | if "$(ConfigurationName)" == "Release" ( 75 | xcopy $(TargetPath) "C:\Users\zhang\Documents\ZX\tools\MyQbt\" /y) 76 | 77 | -------------------------------------------------------------------------------- /Transmission.API.RPC/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------