├── .github └── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── Feature_request.md ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Crunchyroll-Downloader.sln ├── Crunchyroll-Downloader.sln.DotSettings ├── Crunchyroll-Downloader ├── App.config ├── App.xaml ├── App.xaml.cs ├── Crunchyroll-Downloader.csproj ├── DelegateCommand.cs ├── GlobalSuppressions.cs ├── Images │ ├── background.jpg │ ├── crunchy.png │ ├── crunchylogo.png │ └── logo.ico ├── Installer.cs ├── Models │ └── DownloaderModel.cs ├── Progress │ └── TaskManager.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── PropertyChangedObject.cs ├── Quality.cs ├── ViewModelBase.cs ├── ViewModels │ ├── MainWindowViewModel.cs │ └── ProgressViewModel.cs ├── Views │ ├── AboutWindow.xaml │ ├── AboutWindow.xaml.cs │ ├── LoginWindow.xaml │ ├── LoginWindow.xaml.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── ProgressWindow.xaml │ └── ProgressWindow.xaml.cs ├── crunchy.png ├── crunchylogo.png ├── fond.jpg ├── logo.ico └── packages.config ├── FFmpeg ├── README.md ├── ffmpeg.zip ├── ffplay.zip └── ffprobe.zip ├── LICENSE ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── clean.bat └── screenshot.png /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | 10 | 11 | **Checklist** 12 | 13 | - [ ] I checked if my issue is already referenced. 14 | - [ ] I use a release version (from a tag or master branch). 15 | - [ ] Youtube-DL is up to date 16 | - [ ] I use the version of .NET Framework that is recommended or better 17 | 18 | **Describe the bug** 19 | A clear and concise description of what the bug is. 20 | 21 | **To Reproduce** 22 | Steps to reproduce the behavior: 23 | 1. '...' 24 | 2. '....' 25 | 3. '....' 26 | 4. See error 27 | 28 | **Expected behavior** 29 | A clear and concise description of what you expected to happen. 30 | 31 | **Screenshots** 32 | If applicable, add screenshots to help explain your problem. 33 | 34 | **Infos (please complete the following information):** 35 | - OS (from a cmd : winver) : 36 | - Youtube-DL version (from a cmd : "C:\ProgramData\Crunchy-DL\youtube-dl.exe --version" 37 | - Crunchyroll-Downloader version (click on the about button from MainWindow) : 38 | - Region of the Crunchyroll account : 39 | - URL of what you tried to download : 40 | 41 | **Additional context** 42 | Add any other context about the problem here. 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gpg crap 2 | 3 | *.sign 4 | *.unknown 5 | 6 | ## Ignore Visual Studio temporary files, build results, and 7 | ## files generated by popular Visual Studio add-ons. 8 | ## 9 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 10 | 11 | # User-specific files 12 | *.rsuser 13 | *.suo 14 | *.user 15 | *.userosscache 16 | *.sln.docstates 17 | 18 | # User-specific files (MonoDevelop/Xamarin Studio) 19 | *.userprefs 20 | 21 | # Mono auto generated files 22 | mono_crash.* 23 | 24 | # Build results 25 | [Dd]ebug/ 26 | [Dd]ebugPublic/ 27 | [Rr]elease/ 28 | [Rr]eleases/ 29 | x64/ 30 | x86/ 31 | [Aa][Rr][Mm]/ 32 | [Aa][Rr][Mm]64/ 33 | bld/ 34 | [Bb]in/ 35 | [Oo]bj/ 36 | [Ll]og/ 37 | 38 | # Visual Studio 2015/2017 cache/options directory 39 | .vs/ 40 | # Uncomment if you have tasks that create the project's static files in wwwroot 41 | #wwwroot/ 42 | 43 | # Visual Studio 2017 auto generated files 44 | Generated\ Files/ 45 | 46 | # MSTest test Results 47 | [Tt]est[Rr]esult*/ 48 | [Bb]uild[Ll]og.* 49 | 50 | # NUNIT 51 | *.VisualState.xml 52 | TestResult.xml 53 | 54 | # Build Results of an ATL Project 55 | [Dd]ebugPS/ 56 | [Rr]eleasePS/ 57 | dlldata.c 58 | 59 | # Benchmark Results 60 | BenchmarkDotNet.Artifacts/ 61 | 62 | # .NET Core 63 | project.lock.json 64 | project.fragment.lock.json 65 | artifacts/ 66 | 67 | # StyleCop 68 | StyleCopReport.xml 69 | 70 | # Files built by Visual Studio 71 | *_i.c 72 | *_p.c 73 | *_h.h 74 | *.ilk 75 | *.meta 76 | *.obj 77 | *.iobj 78 | *.pch 79 | *.pdb 80 | *.ipdb 81 | *.pgc 82 | *.pgd 83 | *.rsp 84 | *.sbr 85 | *.tlb 86 | *.tli 87 | *.tlh 88 | *.tmp 89 | *.tmp_proj 90 | *_wpftmp.csproj 91 | *.log 92 | *.vspscc 93 | *.vssscc 94 | .builds 95 | *.pidb 96 | *.svclog 97 | *.scc 98 | 99 | # Chutzpah Test files 100 | _Chutzpah* 101 | 102 | # Visual C++ cache files 103 | ipch/ 104 | *.aps 105 | *.ncb 106 | *.opendb 107 | *.opensdf 108 | *.sdf 109 | *.cachefile 110 | *.VC.db 111 | *.VC.VC.opendb 112 | 113 | # Visual Studio profiler 114 | *.psess 115 | *.vsp 116 | *.vspx 117 | *.sap 118 | 119 | # Visual Studio Trace Files 120 | *.e2e 121 | 122 | # TFS 2012 Local Workspace 123 | $tf/ 124 | 125 | # Guidance Automation Toolkit 126 | *.gpState 127 | 128 | # ReSharper is a .NET coding add-in 129 | _ReSharper*/ 130 | *.[Rr]e[Ss]harper 131 | *.DotSettings.user 132 | 133 | # JustCode is a .NET coding add-in 134 | .JustCode 135 | 136 | # TeamCity is a build add-in 137 | _TeamCity* 138 | 139 | # DotCover is a Code Coverage Tool 140 | *.dotCover 141 | 142 | # AxoCover is a Code Coverage Tool 143 | .axoCover/* 144 | !.axoCover/settings.json 145 | 146 | # Visual Studio code coverage results 147 | *.coverage 148 | *.coveragexml 149 | 150 | # NCrunch 151 | _NCrunch_* 152 | .*crunch*.local.xml 153 | nCrunchTemp_* 154 | 155 | # MightyMoose 156 | *.mm.* 157 | AutoTest.Net/ 158 | 159 | # Web workbench (sass) 160 | .sass-cache/ 161 | 162 | # Installshield output folder 163 | [Ee]xpress/ 164 | 165 | # DocProject is a documentation generator add-in 166 | DocProject/buildhelp/ 167 | DocProject/Help/*.HxT 168 | DocProject/Help/*.HxC 169 | DocProject/Help/*.hhc 170 | DocProject/Help/*.hhk 171 | DocProject/Help/*.hhp 172 | DocProject/Help/Html2 173 | DocProject/Help/html 174 | 175 | # Click-Once directory 176 | publish/ 177 | 178 | # Publish Web Output 179 | *.[Pp]ublish.xml 180 | *.azurePubxml 181 | # Note: Comment the next line if you want to checkin your web deploy settings, 182 | # but database connection strings (with potential passwords) will be unencrypted 183 | *.pubxml 184 | *.publishproj 185 | 186 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 187 | # checkin your Azure Web App publish settings, but sensitive information contained 188 | # in these scripts will be unencrypted 189 | PublishScripts/ 190 | 191 | # NuGet Packages 192 | *.nupkg 193 | # The packages folder can be ignored because of Package Restore 194 | **/[Pp]ackages/* 195 | # except build/, which is used as an MSBuild target. 196 | !**/[Pp]ackages/build/ 197 | # Uncomment if necessary however generally it will be regenerated when needed 198 | #!**/[Pp]ackages/repositories.config 199 | # NuGet v3's project.json files produces more ignorable files 200 | *.nuget.props 201 | *.nuget.targets 202 | 203 | # Microsoft Azure Build Output 204 | csx/ 205 | *.build.csdef 206 | 207 | # Microsoft Azure Emulator 208 | ecf/ 209 | rcf/ 210 | 211 | # Windows Store app package directories and files 212 | AppPackages/ 213 | BundleArtifacts/ 214 | Package.StoreAssociation.xml 215 | _pkginfo.txt 216 | *.appx 217 | *.appxbundle 218 | *.appxupload 219 | 220 | # Visual Studio cache files 221 | # files ending in .cache can be ignored 222 | *.[Cc]ache 223 | # but keep track of directories ending in .cache 224 | !?*.[Cc]ache/ 225 | 226 | # Others 227 | ClientBin/ 228 | ~$* 229 | *~ 230 | *.dbmdl 231 | *.dbproj.schemaview 232 | *.jfm 233 | *.pfx 234 | *.publishsettings 235 | orleans.codegen.cs 236 | 237 | # Including strong name files can present a security risk 238 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 239 | #*.snk 240 | 241 | # Since there are multiple workflows, uncomment next line to ignore bower_components 242 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 243 | #bower_components/ 244 | 245 | # RIA/Silverlight projects 246 | Generated_Code/ 247 | 248 | # Backup & report files from converting an old project file 249 | # to a newer Visual Studio version. Backup files are not needed, 250 | # because we have git ;-) 251 | _UpgradeReport_Files/ 252 | Backup*/ 253 | UpgradeLog*.XML 254 | UpgradeLog*.htm 255 | ServiceFabricBackup/ 256 | *.rptproj.bak 257 | 258 | # SQL Server files 259 | *.mdf 260 | *.ldf 261 | *.ndf 262 | 263 | # Business Intelligence projects 264 | *.rdl.data 265 | *.bim.layout 266 | *.bim_*.settings 267 | *.rptproj.rsuser 268 | *- Backup*.rdl 269 | 270 | # Microsoft Fakes 271 | FakesAssemblies/ 272 | 273 | # GhostDoc plugin setting file 274 | *.GhostDoc.xml 275 | 276 | # Node.js Tools for Visual Studio 277 | .ntvs_analysis.dat 278 | node_modules/ 279 | 280 | # Visual Studio 6 build log 281 | *.plg 282 | 283 | # Visual Studio 6 workspace options file 284 | *.opt 285 | 286 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 287 | *.vbw 288 | 289 | # Visual Studio LightSwitch build output 290 | **/*.HTMLClient/GeneratedArtifacts 291 | **/*.DesktopClient/GeneratedArtifacts 292 | **/*.DesktopClient/ModelManifest.xml 293 | **/*.Server/GeneratedArtifacts 294 | **/*.Server/ModelManifest.xml 295 | _Pvt_Extensions 296 | 297 | # Paket dependency manager 298 | .paket/paket.exe 299 | paket-files/ 300 | 301 | # FAKE - F# Make 302 | .fake/ 303 | 304 | # CodeRush personal settings 305 | .cr/personal 306 | 307 | # Python Tools for Visual Studio (PTVS) 308 | __pycache__/ 309 | *.pyc 310 | 311 | # Cake - Uncomment if you are using it 312 | # tools/** 313 | # !tools/packages.config 314 | 315 | # Tabs Studio 316 | *.tss 317 | 318 | # Telerik's JustMock configuration file 319 | *.jmconfig 320 | 321 | # BizTalk build output 322 | *.btp.cs 323 | *.btm.cs 324 | *.odx.cs 325 | *.xsd.cs 326 | 327 | # OpenCover UI analysis results 328 | OpenCover/ 329 | 330 | # Azure Stream Analytics local run output 331 | ASALocalRun/ 332 | 333 | # MSBuild Binary and Structured Log 334 | *.binlog 335 | 336 | # NVidia Nsight GPU debugger configuration file 337 | *.nvuser 338 | 339 | # MFractors (Xamarin productivity tool) working folder 340 | .mfractor/ 341 | 342 | # Local History for Visual Studio 343 | .localhistory/ 344 | 345 | # BeatPulse healthcheck temp database 346 | healthchecksdb 347 | 348 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 349 | MigrationBackup/ 350 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at skid@tuto-craft.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to contribute to Crunchyroll-Downloader 2 | 3 | #### **Did you find a bug?** 4 | 5 | * **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/skid9000/Crunchyroll-Downloader/issues). 6 | 7 | * If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/skid9000/Crunchyroll-Downloader/issues/new/choose). Be sure to include a **title and clear description**, as much relevant information as possible. 8 | 9 | #### **Did you write a patch that fixes a bug?** 10 | 11 | * Open a new GitHub pull request with the patch. 12 | 13 | * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. 14 | 15 | #### **Do you intend to add a new feature or change an existing one?** 16 | 17 | * Suggest your change in a github issue and start writing code. 18 | 19 | * Do not open an PR on GitHub until you have collected positive feedback about the change. 20 | 21 | Thanks! 22 | 23 | Skid 24 | -------------------------------------------------------------------------------- /Crunchyroll-Downloader.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Crunchyroll-Downloader", "Crunchyroll-Downloader\Crunchyroll-Downloader.csproj", "{BFD5A544-E85E-46E7-B6DC-A8900240DE1E}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {BFD5A544-E85E-46E7-B6DC-A8900240DE1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {BFD5A544-E85E-46E7-B6DC-A8900240DE1E}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {BFD5A544-E85E-46E7-B6DC-A8900240DE1E}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {BFD5A544-E85E-46E7-B6DC-A8900240DE1E}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /Crunchyroll-Downloader.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True -------------------------------------------------------------------------------- /Crunchyroll-Downloader/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Crunchyroll-Downloader/App.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Crunchyroll-Downloader/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using CrunchyrollDownloader.Views; 3 | 4 | namespace CrunchyrollDownloader 5 | { 6 | /// 7 | /// Interaction logic for App.xaml 8 | /// 9 | public partial class App : Application 10 | { 11 | private Installer _installer = new Installer(); 12 | protected override async void OnStartup(StartupEventArgs e) 13 | { 14 | if (!_installer.CheckIfInstalled()) 15 | { 16 | await _installer.InstallAll(); 17 | } 18 | var w = new MainWindow(); 19 | w.Closed += (_,__) => Shutdown(); 20 | w.Show(); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Crunchyroll-Downloader.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {BFD5A544-E85E-46E7-B6DC-A8900240DE1E} 8 | WinExe 9 | Properties 10 | CrunchyrollDownloader 11 | Crunchyroll-Downloader 12 | v4.7.2 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | true 17 | 18 | publish\ 19 | true 20 | Disk 21 | false 22 | Foreground 23 | 7 24 | Days 25 | false 26 | false 27 | true 28 | 0 29 | 1.0.0.%2a 30 | false 31 | false 32 | true 33 | 34 | 35 | AnyCPU 36 | true 37 | full 38 | false 39 | bin\Debug\ 40 | DEBUG;TRACE 41 | prompt 42 | 4 43 | 44 | 45 | AnyCPU 46 | pdbonly 47 | true 48 | bin\Release\ 49 | TRACE 50 | prompt 51 | 4 52 | 53 | 54 | Images\logo.ico 55 | 56 | 57 | CrunchyrollDownloader.App 58 | 59 | 60 | false 61 | 62 | 63 | false 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | ..\packages\SharpZipLib.1.1.0\lib\net45\ICSharpCode.SharpZipLib.dll 76 | 77 | 78 | ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 4.0 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | MSBuild:Compile 102 | Designer 103 | 104 | 105 | Designer 106 | MSBuild:Compile 107 | 108 | 109 | Designer 110 | MSBuild:Compile 111 | 112 | 113 | Designer 114 | MSBuild:Compile 115 | 116 | 117 | MSBuild:Compile 118 | Designer 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | AboutWindow.xaml 131 | 132 | 133 | App.xaml 134 | 135 | 136 | ProgressWindow.xaml 137 | 138 | 139 | 140 | LoginWindow.xaml 141 | 142 | 143 | MainWindow.xaml 144 | Code 145 | 146 | 147 | 148 | 149 | Code 150 | 151 | 152 | True 153 | True 154 | Resources.resx 155 | 156 | 157 | True 158 | Settings.settings 159 | True 160 | 161 | 162 | ResXFileCodeGenerator 163 | Resources.Designer.cs 164 | 165 | 166 | 167 | SettingsSingleFileGenerator 168 | Settings.Designer.cs 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | False 184 | Microsoft .NET Framework 4.7.1 %28x86 et x64%29 185 | true 186 | 187 | 188 | False 189 | .NET Framework 3.5 SP1 190 | false 191 | 192 | 193 | 194 | 195 | 202 | -------------------------------------------------------------------------------- /Crunchyroll-Downloader/DelegateCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | using System.Windows.Input; 4 | 5 | namespace CrunchyrollDownloader 6 | { 7 | public class DelegateCommand : ICommand 8 | { 9 | public DelegateCommand(Action action, Func canExecute = null) 10 | { 11 | ActionToExecute = action; 12 | if (canExecute != null) CanExecuteAction = canExecute; 13 | } 14 | 15 | public DelegateCommand(Action act, Func canExecute = null) : this(_ => act(), canExecute) { } 16 | public DelegateCommand(Action act, Func canExecute) : this(act, _ => canExecute()) { } 17 | public Action ActionToExecute { get; set; } 18 | public Func CanExecuteAction { get; set; } = o => true; 19 | public event EventHandler CanExecuteChanged; 20 | 21 | public bool CanExecute(object parameter) 22 | { 23 | return CanExecuteAction(parameter); 24 | } 25 | 26 | public void Execute(object parameter) 27 | { 28 | ActionToExecute(parameter); 29 | } 30 | 31 | public void RaiseCanExecuteChanged() 32 | { 33 | if (Application.Current.Dispatcher.CheckAccess()) 34 | { 35 | CanExecuteChanged?.Invoke(this, new EventArgs()); 36 | } 37 | else 38 | { 39 | Application.Current.Dispatcher.BeginInvoke(new Action(() => 40 | CanExecuteChanged?.Invoke(this, new EventArgs()))); 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /Crunchyroll-Downloader/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 |  2 | // This file is used by Code Analysis to maintain SuppressMessage 3 | // attributes that are applied to this project. 4 | // Project-level suppressions either have no target or are given 5 | // a specific target and scoped to a namespace, type, member, etc. 6 | // lol 7 | 8 | using System.Diagnostics.CodeAnalysis; 9 | 10 | [assembly: SuppressMessage("Minor Code Smell", "S1075:URIs should not be hardcoded", Justification = "", Scope = "member", Target = "~M:CrunchyrollDownloader.MainWindow.button_Click(System.Object,System.Windows.RoutedEventArgs)")] 11 | [assembly: SuppressMessage("Minor Code Smell", "S1075:URIs should not be hardcoded", Justification = "", Scope = "member", Target = "~M:CrunchyrollDownloader.MainWindow.#ctor")] 12 | [assembly: SuppressMessage("Minor Code Smell", "S1075:URIs should not be hardcoded", Justification = "", Scope = "member", Target = "~M:CrunchyrollDownloader.MainWindow.CheckCookie")] 13 | [assembly: SuppressMessage("Minor Code Smell", "S1075:URIs should not be hardcoded", Justification = "", Scope = "member", Target = "~M:CrunchyrollDownloader.MainWindow.InstallAll")] 14 | [assembly: SuppressMessage("Minor Code Smell", "S1075:URIs should not be hardcoded", Justification = "", Scope = "member", Target = "~M:CrunchyrollDownloader.MainWindow.button_logout_Click(System.Object,System.Windows.RoutedEventArgs)")] 15 | 16 | -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Images/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skid9000/Crunchyroll-Downloader/aa4ed8e42b7446e873c4de7daa273c80243194ef/Crunchyroll-Downloader/Images/background.jpg -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Images/crunchy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skid9000/Crunchyroll-Downloader/aa4ed8e42b7446e873c4de7daa273c80243194ef/Crunchyroll-Downloader/Images/crunchy.png -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Images/crunchylogo.png: -------------------------------------------------------------------------------- 1 | �PNG 2 |  3 | IHDR��,�� 4 | !iCCPsRGB display profile with display hardware configuration data derived from calih��}pu�?wm�&MKici������K�۔�B�JSj�$ 5 | ��ۻ,��]w�r EF�F��UQF���aķJ� �� �"S��ʨ�S�ؽ���$�����?7���������|�����h�_��f�}���ȨP��YJ+���e��Q����O�x�~�}�=�1ْ�w�gK�i��"i۰���5�GF�� �M8���c���Zsh 6 | �C�I D��׌ D���5���0T-�U�]���@_�S,C����* i��.��f,-�� �Z\I�L�VtM���(�dS��cB�ԓ�$�ʘ��f� ��8 7 | *1a�0��` ��L #!CGC� 21d$t4�($Ha"b���!�D�� & 8 | 2**r��Z�1��(���Q]�" �#�鴏-O�Qݘ2�ĸ-�I� �p�ЯH�n�q[�ꦡg��Q�9��>��lOnM�m�;�&M®�`�u��s��+�-Rʜp�|�Ա��H�����o����;�����)�|;}������o��������6�9���|w�Ssk�v͝�{�܃�V�;*�4O�'ͻsޫ�-��T>4����]U�U�W�W��Z�~`���<[�Ys��� ��O/�]t�)�S���r�Ջ�:U=��%�%��JK�R�����\��b�ON�gy��V�W����3^8󺕫W>��:k�Y{���ug?��9��>���N�n]���~Q���7^p��w���� �B�C��Dv4\�(7]��ز������W��w<��}k^�P��u���g�_��y��wI���k6\�A��6����Moo^���{�[C�R���ᩑ��H�e����h�80� �u9�j� e��W��Im���o[K��RO_9��.����?��箑�}�S�Ͻ���}v��[>��M7����_�~˹�>�O~-|ۋ_�}ǖo.�c��[�3zg�{�����x��4߻辿�dϮ������c\��u�j�M�����ʽg>���� o~�������^�ܭ��h�����`���+����M��m��������S��̅��p2N�Ba.�F�n�`qo��u�|�_�:&I�"0������$L � 9 |  � �M�z"�`�,��5H�H�A�d&P���G'����jְ�pO�%�866�a!1�L� I$Lt,t����I"��F �4!��a!e- 10 | �j]��>����J��"�DT���Q�Ui$���V$,��$I���B�!�0���,M"�a����枌�c�t�yk� D�m�0�w�0\��PPQ�����B���*O~�[� �$rv_k\t;Bf;�Q*b�;�cRO/�,$Ȭ�t5��d �"-9KCeښ� #�5�ק@� 4NK�Y!�"��<3z9��Ha3���_c�����?��X 11 | �f��9D����r}.�K��~dD,R��$�Ѱ���C�bd��P�1���$�.b�F�,)��X�V�Q��ٌ�����"zh�9O����9r�s� "�g#)�(h褰���$���컋� 2�AHDæ����֗�Y,QA+�/\Bb靅裛-(�ؤQ�zk�X�ƺ�!�� b#��`-��z�4SO����N�4�A�fO�/�Y 12 | �K��������B-w�\�g���m��S ���4$L3F\Vv�;�n4��F�v�M�o��4�����&��w�%OS�vg�҇��첋bM�4�Օ�hj%B�f�49�f�ՍJjZ�"���J��<=^�g�#"�mMa�o\f�F"I��\B�826}�(hlDACF�̮ �3N|�n����G���7�4�J-�@(����!�!7�-O����&�4�9{��ԍRU�����^�x~Q頋"6�뿃ptZ�SOG�fDL�39��B&F�&�y�6�u8��D���Դ6Zh�ōx~��z��fD���|�ڐ�r�];2_����ɹ�������T>��>�Ks���p�D9�ޛ�@z�['D��� ��i��A�N������Ǐ���-�dI;ӤI$M�g�w,�b�~62�� ;�N��/� _F��K$@'[�2���']po+�y��n&P�]d��7��}N+Ǘ���� ��d∤P�g�]���� �}���N�b��Ď1N����1����)����.���Q��M���-yx�>��G87���X~��o��Јyxt{�.93��+��Y���"ޗ�0H 13 | �#��.���y��[,/7wg��%�=����׽�rf���v�R�-�A&�r���ޮ)�����V���=Sng::�� �gR��#b��̠� 14 | "�($ �6sg��Y6=F'Y�̬ �eLJ8R�N�G�B!I 15 | ��l� $g�������0����(Y�2L`Q���a���rw� ���UpIDATx��y�U�ǿ�B%�-Ȧ����C| 1�'�+�&�OAAQ�� �V�(�*� KDv;��@H��$Cd��ܙ��~�[�N�������'��|�3IO�e�u��s�=��X,�1�|ws`<�+0�L�6/�9����겟o����'4%�UH�w��"� _�[l����*|=�x�,�m��FH�wG����}�Ό��&0 x��x����0ZZH�ww&���dۣ�,�<�x�`���N� I?�����>�l{�%����x� Yw�-#$廟N�Fg�k� ����og��ZH�ws�����gܝ4��.u�`Q֝IBS 16 | I�n'2������H���V��7����NB4.��dI��Y���FH�w'��̸+�D?p p���Yw�� I������׀�L;Ӽ�Ns�`j��FfBR���\l�I'Z��A-Ⱥ#�d"$�;7"v�6��Nu�ຬ;RJÅ�|�S� �6 mx�q#�M� ���4PHzI.�"kυ��8^0#�4DHzO�fdS��]�]� ~�e'R���}���w��P�뀓��NUH�w?�xWj��C?0yt,a���������5��5�q�ۮ����k��)5!)�=�K�յ#d>�74N̷qgko�]Q}�/��e�i�5x 17 | 8���)���I���Xd�qR�<���� �5�q�0�ǁ���� 18 | |���օ�|�"�,������_�x��;S��ݱ����N[�U���/,�W�BR��#�|k��K���}��3�O]��n |;n3 ���tY��&ք�|�D���Tf�;���o/X�mW��|�� �̦��w�`��~UÊ��� 19 | ��0�,9]���5��d��(�� ��Z�i�jC�L�Z��0���I��(+=��"�<���gԇ�Q��^�Kb2�F�ہ�Ӳ3 I��x�i`+k=��pp��k3h?���\엠�Վ|�r�!)�< �a�G�x�-��3G��LF\p�����h�O&B������e "��6�ݦD�W�1�u��›HH�w���14���ii��mz��q5�E�"/�ٜ|�6~�y�5�:�A���g�"���7![0�"��k�}�5"i����#�� 8����^K�����; ����+��ѡ<|�= 20 | �G�G�=��x�|# I��4�Q,�G5�i9z�4��4p�I�j`��vXg�B}��/8Ѵ�8B���i�� �j�_��^��[�z"�Z�K���-d'>|��F�m�w]���5.+�/xڤ�HBR���6��"r�9^��)廛��a7(WH1��LM�$��ݝ�G��/"&��V�BR��.�N�)i#������(�� 21 | �"�� ��F2� 22 | ��x�Si4�|w"�Z��Os��ʤmD���6�?:^pB�m�CGw;�ڟ�"����b�v۱)��S�a�k҉wM!��� H���n�F� �#Q'?#��B#��x2\o�h�|wg�q`�*�\�x���]� y:��i�Y�": 23 | lu �-"�Ӑ��5/��*�rɷ�>6U���OMRiD� v�T}����|��4��4۲�t�����m�r� ��\�כ��;��hK�m����ϧT?�w?���|6�6,����gӔ�� 24 | �n�_-�ŵ�U�d��h�FlqfZ"���� �V T�7�-�L$�'�� ����L��d�;{��V7 C� p p�#���i���V�Qo2Pi��i�Zd�}�i�-DVM�ц�'��N���X��(��z�J�_m��.��BR��'�-�_q�`��J���?�-�Va)� � �f� � nC���s|�z*�H�*�� �L�]���~��v�)��T� 25 | �,�}x3� I��|�B��Y��Ѳ����w/C�ҥy��6�f�i�x�26|�m���� �[=M8��rś�[�`�j\�x�Yw�� nGF�R"?�ʅ��c�y�K����S�xܭ�ۤ�oi™�[I�$�GW�uB��ҏ��/@��YۀT�{0�+[�5�_��ذ����8*J��io��B���6�����D�o���8���u'"p6�rP�B�B�T &ֶX���]ds��78^�:�N����U%o��&jR*$�1��;^p����j�&`7�eD3Dj���''���>� 26 | ���>f�3X��Bċ�UY����,F��}Z�#�~�M�7 �~a�hz���2���}Eɿ# ����O6��#�" �ɚdz�@\��x8�N��� 27 | ��U���`2�;՛&��@BB/ �:��PH6=���G��Y�O3Ъ�jo˜�55��K��-6n+J�) �,�-)$��~���BB�ي�܇ ��6��ͻ�44}D�����B��X{���Y ��%�~j�S���B2�@ǚ>ݼ+M�{��@R�����*M'$dw�Ւ�ԣ�G$�d9�)߭�w��Y� F�m7����4i�MH�0RIU��4�1 ���h|j�F`��l��xTՊM!�x�n��fd���d݉��xN�i���a��#,�Ѭ��M� u�������9�h��p6?)Gd�C���Vl�H�,d,l�;���N̺�Lm6�� w!��jUPGH6�mRX��vHz���$�-y���+��>���5�tD�����_j��V��W�-!-4,o#�f�������|7�SwE����X��鈚�8Ð��~/�Nh.�����~akD2�cc�%�wɲ�w�����Z m )���^Tr��:Hj�Q��7CG�v5�/s!!� 6��v9�1����*��0p'Cy�߫o��t"�L1c����Ep���݁�/�1g����8 8���b;�ؑ]I��!g�L1 qlk����"����(ߵ����F�$�[���ڴ%$�a�ѹ?��m�+���w��r��w�C���� �j\jd��Ď�L���6dg�/���w���5������ɓ�=#�i4"u�ÊL�4��jm�"��@��ݗ�H�]��Rdn�#�������h��t� �|w`�xe"$kI[�9�"1��N�~�T����f"��L7�b�=�Bz����Mm��&F�C($S�Z9S��R�jmD!ҳ�=#M\dW�mc㐄9� ��<I1�t�oP���VP����A=���x�*�lӴI���+�/$�y�V�w�1(o��Mr�?�R!M�l�b�Q�-�l�'$�����7(��A�6���~@7�u�Aٿ��()Ţ~�U�s;�Bzx3a]Mz:B�-k?�"P,B�@�� ,zg�E� �|u���"U�\��.����&�4"�(`_���iPv�`���x~�w?�ǔ'S�T��\��`ٚ����X��+���x �;����;i���Q,Š��<�j?�� ��d q6�����ܭȾ�&��,GG���n�!���W��I>�2I��4m{RU��Efw�y��~�.���W�y��WdΛ�+O>��^� �l�����&�oB�Dq����Ԅ�k�@wo�Yo�Y��`���`�=�ko���,$kӉjB�=�N�:�KX����[Y�L&���(ҵ�@�*FY�偻mu���/�.KX�Ir�0t��t@o��k�ϤW�-��iDz�f6�Z�ɮ"��{w廉�8^��{���!���s��|���H�N�It� 28 | Ig;�2a�_NX$뤱]c�Q$��(4R�����tLS���H.ָ���@���������"�� K�ڗ���/֨)$� �1�j)[�H�#���ɖ6�\�C�Pφ4 ˣD;s>�F��O7�2� \��찤#��Z���l� �'٩+$��{z�����\�y�O��'ʥ��}���,�j=" ��L�d�>K���p�`)�');)!a���Qs����"N8�S�|lq��L)���6D ��R�Xu�}��ӬwLYH��.I��/��MP}�}��#5��#��\G�yR�G#���|क़e�b&��"���̏�q� ���XBҖ�c�? ������Y&lsP���:���,�-��k�S�;����o#\�|7n���͕�a�>�I8�~8!Վi�nt��&⻚쏄�K��@���a�:�ԡd��8ܶ�&1qNC����y�wv��$ :^p���3H�вD�! '��_�|�E\��q�� с�[�Txj��v� ����G#)H�� p����ap/�����-O(��E1'������/^�L�ZF!��?���}V�T�V6�(,�~� 29 | ��(� ��v�oa� s 30 | X�S`nW��0���v�Y�S�P���ힾ�ʛ�}���d��$���O�����-0SG1��R�� 31 | ܎ �Q9��k ��Z�ir03��`i��g�3s� �{D9��α�N#���H�m�ɦz�Q,�+ �\{�Z�ZY׹�u��hYx�(D,��r,�U�T�V�аG[)�L%��j廟4hs�t8�y& 32 | "������~潕gٚ����V��f�s�㊗� �����;:"/�s����G"�س�m d?u'�J�"�;^ppv�"��_��~Р�� NB>��X�u�O����� 33 | .�}Ef.��'zyr�o�.�/�I�o���g1� ��ڭN�=�-�D������ ��%qs�n���{pMng*KW��p���B �`� w<����b��T_1�ʭ�^G!���"�9��D��f;"�8^�}� �b� ����- ۽�Bټ���.��բX�wV��K�\�P//��3}�| 8�4�b�牷_�T��8^��Ct/ǽ����۰�Y�m�9��|���" ������v:�Y� |�� ����DS�Բ9^p����{/`����J�>r*M悒�����==����=}���#�O'��V!+�7Hx�"��V�� D�Ö���&�:^p��������[���N�8#�OE 34 | ź�"2יD�L��wa<ߊ�Z7#`��w��J.��?A6��g�C�s���Ƽ��'g����]��FNܮ�d4�ĎT� !�J~I���߁g��i���������K�>�B.��� ���=F��9F���n? ��R&�$4dD*E��9Q���$u��U҇��!s�L�� 35 | �����A�|�������n��A$��O���z��.$�;7F,r'�e��u�̓�E���6��@�W_[����֎]��p�e�M�"��Ǩ2/j !h'�����#�|��+����gDT��-�u�#�ww{�9��NB�pl��n| f ��4�v�O)� )Do�^�䞏��] ��c�ٯ�!��"s���� 36 | � �~=�s�+�W��1��, 37 | vľ� 38 | �}��TXɶ��B��N@���p�"�{���Kt<��#[;���$�Zd�ԭ��T��v�6��9$�W����+�!�s_Â3[)M#$}��$��̸En~�-�-E!��i�k}rb�ƺ��p U�dž��BtR�Ɉ��e��#�?w�`I�}�MAu".��Dv���߫�7�_ �W���D@!M)����Hdr��:��E�x_��IZ�:#ӻ���D��ggt*3�e��Tɍ7�T���O C���M5z��Ui 39 | �MQ�n��B�Ӷ�Q�;�Mx��R��i_��k�F���{.��{6j!����&#��}���� 1j�<�65�b���]d3��j�x1�L����B�������z ������F�yO�9^Pɦ�4��+�ؙ�F�����)"bY��>!��/R�rmS@!�FH��G�DĠ8��U��ϔ���FD����R��mi"� �2 40 | � ��Y���I��4`$ 41 | �B��6*�G�eȰG"_�b`b�^t�� ���.���о�j�ڋl�V�g 42 | ���jԘ7��Ӫ�t���6ɩ���'�i���&A$ڴi�B��mm��~���B[Hm��R+�'ۆ��hM�U6k*��B�K�L� 43 | �C�8CQ�ǡ�@�������59�B�uT(�? ��F��W���ʮ �ۭt]�^���r:w��-${t"ތE8��1�\^:�/'D��+��,V�.C8J�^S���vK�+���c�v�t!�� �1���Ɯ"�#��=��3��"3�c"r�� 44 | �hS�-$;�FF�/"�U��s�1o�@(�����j�����;�+"�l���{?����A� 45 | ��o.l�������m!�SDV3��rJc�&�����#ޕ�R�+q҇�/� 6��a��"B��35���E�m$ ����h�Ya�M1�ݎ �CNņF��M��`Ȑ�;�\24=)7H�eJ��T�w��:J~_�� �һ1H� ��8��G2�l��ԟ�|��4Q�����r�Β���h�^� C¨V_�g���ʆ� �H���"I�r$��*��7m�FN����BIEND�B`� -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Images/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skid9000/Crunchyroll-Downloader/aa4ed8e42b7446e873c4de7daa273c80243194ef/Crunchyroll-Downloader/Images/logo.ico -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Installer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Threading.Tasks; 5 | using System.Windows; 6 | using CrunchyrollDownloader.Progress; 7 | using CrunchyrollDownloader.ViewModels; 8 | using CrunchyrollDownloader.Views; 9 | using ICSharpCode.SharpZipLib.Zip; 10 | 11 | namespace CrunchyrollDownloader 12 | { 13 | public class Installer 14 | { 15 | public const string InstallFolder = @"C:\ProgramData\Crunchy-DL"; 16 | public async Task InstallAll() 17 | { 18 | var data = new ProgressViewModel 19 | { 20 | Progress = new TaskManager(new[] 21 | { 22 | new ProgressTask("Downloading dependencies: Youtube-DL"), 23 | new ProgressTask("Downloading dependencies: FFmpeg-base"), 24 | new ProgressTask("Downloading dependencies: FFmpeg-play"), 25 | new ProgressTask("Downloading dependencies: FFmpeg-probe"), 26 | new ProgressTask("Extracting downloaded files") 27 | }) 28 | { FinalizingText = "Cleaning up..." } 29 | }; 30 | var window = Application.Current.Dispatcher.Invoke(() => new ProgressWindow(data)); 31 | _ = Task.Run(() => Application.Current.Dispatcher.Invoke(() => window.ShowDialog())); 32 | await SetupDependencies(data); 33 | window.Close(); 34 | } 35 | 36 | private static async Task SetupDependencies(ProgressViewModel data) 37 | { 38 | var zip = new FastZip(); 39 | using (var client = new WebClient()) 40 | { 41 | ServicePointManager.Expect100Continue = true; 42 | ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 43 | client.DownloadProgressChanged += (sender, args) => 44 | { 45 | var progress = args.BytesReceived / (double) args.TotalBytesToReceive; 46 | if (progress >= 0.99) return; 47 | data.Progress.CurrentTask.Progress = progress; 48 | }; 49 | Directory.CreateDirectory(@"C:\ProgramData\Crunchy-DL"); 50 | await client.DownloadFileTaskAsync(new Uri("https://yt-dl.org/downloads/latest/youtube-dl.exe"), 51 | @"C:\ProgramData\Crunchy-DL\youtube-dl.exe"); 52 | data.Progress.GoNext(); 53 | 54 | await client.DownloadFileTaskAsync( 55 | new Uri("https://raw.githubusercontent.com/skid9000/Crunchyroll-Downloader/develop/FFmpeg/ffmpeg.zip"), 56 | @"C:\ProgramData\Crunchy-DL\ffmpeg.zip"); 57 | data.Progress.GoNext(); 58 | 59 | await client.DownloadFileTaskAsync( 60 | new Uri("https://raw.githubusercontent.com/skid9000/Crunchyroll-Downloader/develop/FFmpeg/ffplay.zip"), 61 | @"C:\ProgramData\Crunchy-DL\ffplay.zip"); 62 | data.Progress.GoNext(); 63 | 64 | await client.DownloadFileTaskAsync( 65 | new Uri("https://raw.githubusercontent.com/skid9000/Crunchyroll-Downloader/develop/FFmpeg/ffprobe.zip"), 66 | @"C:\ProgramData\Crunchy-DL\ffprobe.zip"); 67 | } 68 | data.Progress.GoNext(); 69 | 70 | await Task.Run(() => zip.ExtractZip(InstallFolder + @"\ffmpeg.zip", InstallFolder, "")); 71 | data.Progress.CurrentTask.Progress = 0.33; 72 | await Task.Run(() => zip.ExtractZip(InstallFolder + @"\ffplay.zip", InstallFolder, "")); 73 | data.Progress.CurrentTask.Progress = 0.66; 74 | await Task.Run(() => zip.ExtractZip(InstallFolder + @"\ffprobe.zip", InstallFolder, "")); 75 | data.Progress.CurrentTask.Progress = 0.99; 76 | data.Progress.GoNext(); 77 | data.IsIndeterminate = true; 78 | await Task.Run(() => 79 | { 80 | File.Delete(@"C:\ProgramData\Crunchy-DL\ffmpeg.zip"); 81 | File.Delete(@"C:\ProgramData\Crunchy-DL\ffplay.zip"); 82 | File.Delete(@"C:\ProgramData\Crunchy-DL\ffprobe.zip"); 83 | }); 84 | } 85 | 86 | private void ShowErrorMessage() => MessageBox.Show("Dependencies seems corrupted or missing, click OK to re-download them.", "Important Note", MessageBoxButton.OK, MessageBoxImage.Information); 87 | public bool CheckIfInstalled() 88 | { 89 | if (Directory.Exists(InstallFolder) && 90 | File.Exists(@"C:\ProgramData\Crunchy-DL\ffmpeg.exe") && 91 | File.Exists(@"C:\ProgramData\Crunchy-DL\ffplay.exe") && 92 | File.Exists(@"C:\ProgramData\Crunchy-DL\ffprobe.exe") && 93 | File.Exists(@"C:\ProgramData\Crunchy-DL\youtube-dl.exe")) 94 | { 95 | return true; 96 | } 97 | ShowErrorMessage(); 98 | if (Directory.Exists(InstallFolder)) 99 | Directory.Delete(InstallFolder, true); 100 | return false; 101 | } 102 | 103 | public void DeleteInstallation() 104 | { 105 | Directory.Delete(InstallFolder, true); 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Models/DownloaderModel.cs: -------------------------------------------------------------------------------- 1 | namespace CrunchyrollDownloader.Models 2 | { 3 | public class DownloaderModel 4 | { 5 | public bool AreSubtitlesEnabled { get; set; } 6 | public string Url { get; set; } 7 | public string Language { get; set; } = "enUS"; 8 | public string Format { get; set; } = "ass"; 9 | public string SavePath { get; set; } 10 | public Quality Quality { get; set; } = Quality.Best; 11 | public bool IsMkv { get; set; } 12 | public string DlStatus { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Progress/TaskManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | 6 | namespace CrunchyrollDownloader.Progress 7 | { 8 | public class TaskManager : PropertyChangedObject 9 | { 10 | public void GoNext() => CurrentTask.Complete(); 11 | public List Tasks { get; } = new List(); 12 | public string FinalizingText { get; set; } = "Finalizing..."; 13 | public double TotalProgress 14 | { 15 | get 16 | { 17 | var totalProgress = Tasks.Sum(t => t.Weight); 18 | var completedProgress = Tasks.Sum(t => t.Weight * t.Progress); 19 | return completedProgress / totalProgress; 20 | } 21 | } 22 | public string CurrentName => CurrentTask?.Name ?? FinalizingText; 23 | public string CurrentDisplay => CurrentTask is null ? FinalizingText : CurrentTask.GetFormattedDisplay(Tasks.IndexOf(CurrentTask) + 1, Tasks.Count); 24 | public ProgressTask CurrentTask => Tasks.FirstOrDefault(p => !p.IsComplete); 25 | public TaskManager(IEnumerable tasks) 26 | { 27 | Tasks.AddRange(tasks); 28 | foreach (var task in Tasks) 29 | { 30 | task.PropertyChanged += UpdateProgress; 31 | } 32 | } 33 | 34 | public TaskManager(string display) 35 | { 36 | FinalizingText = display; 37 | } 38 | 39 | private void UpdateProgress(object sender, PropertyChangedEventArgs e) 40 | { 41 | var task = (ProgressTask) sender; 42 | OnPropertyChanged(nameof(TotalProgress)); 43 | OnPropertyChanged(nameof(CurrentDisplay)); 44 | OnPropertyChanged(nameof(CurrentTask)); 45 | OnPropertyChanged(nameof(CurrentName)); 46 | } 47 | } 48 | 49 | public class ProgressTask : PropertyChangedObject 50 | { 51 | public ProgressTask(string name = "Something", int weight = 100) 52 | { 53 | Name = name; 54 | Weight = weight; 55 | } 56 | public string GetFormattedDisplay(int current, int remaining) 57 | { 58 | return string.Format(Display, current, remaining, Progress.ToString("P"), Name); 59 | } 60 | public string Name { get; set; } 61 | public string Display { get; set; } = "{3}... {2} [{0}/{1}]"; 62 | 63 | public double Weight { get; } = 100; 64 | 65 | private double _progress; 66 | /// 67 | /// Progress, from 0 to 1 68 | /// 69 | public double Progress 70 | { 71 | get => _progress; 72 | set => Set(Math.Min(value, 1), out _progress); 73 | } 74 | 75 | public bool IsComplete => Progress >= 1 - double.Epsilon * 10; 76 | public void Complete() 77 | { 78 | Progress = 1; 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.InteropServices; 4 | using System.Windows; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("Crunchyroll Downloader")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("Skid")] 13 | [assembly: AssemblyProduct("")] 14 | [assembly: AssemblyCopyright("Skid Copyright © 2020")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // Setting ComVisible to false makes the types in this assembly not visible 19 | // to COM components. If you need to access a type in this assembly from 20 | // COM, set the ComVisible attribute to true on that type. 21 | [assembly: ComVisible(false)] 22 | 23 | //In order to begin building localizable applications, set 24 | //CultureYouAreCodingWith in your .csproj file 25 | //inside a . For example, if you are using US english 26 | //in your source files, set the to en-US. Then uncomment 27 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 28 | //the line below to match the UICulture setting in the project file. 29 | 30 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 31 | 32 | 33 | [assembly: ThemeInfo( 34 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 35 | //(used if a resource is not found in the page, 36 | // or application resource dictionaries) 37 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 38 | //(used if a resource is not found in the page, 39 | // app, or any theme specific resource dictionaries) 40 | )] 41 | 42 | 43 | // Version information for an assembly consists of the following four values: 44 | // 45 | // Major Version 46 | // Minor Version 47 | // Build Number 48 | // Revision 49 | // 50 | // You can specify all the values or you can default the Build and Revision Numbers 51 | // by using the '*' as shown below: 52 | // [assembly: AssemblyVersion("1.0.*")] meme 53 | [assembly: AssemblyVersion("2.1.1.0")] 54 | [assembly: AssemblyFileVersion("2.1.1.0")] 55 | [assembly: NeutralResourcesLanguage("en")] 56 | 57 | -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Ce code a été généré par un outil. 4 | // Version du runtime :4.0.30319.42000 5 | // 6 | // Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si 7 | // le code est régénéré. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CrunchyrollDownloader.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées. 17 | /// 18 | // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder 19 | // à l'aide d'un outil, tel que ResGen ou Visual Studio. 20 | // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen 21 | // avec l'option /str ou régénérez votre projet VS. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.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 | /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe. 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("CrunchyrollDownloader.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Remplace la propriété CurrentUICulture du thread actuel pour toutes 51 | /// les recherches de ressources à l'aide de cette classe de ressource fortement typée. 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 | -------------------------------------------------------------------------------- /Crunchyroll-Downloader/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 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Ce code a été généré par un outil. 4 | // Version du runtime :4.0.30319.42000 5 | // 6 | // Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si 7 | // le code est régénéré. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CrunchyrollDownloader.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.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 | -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Crunchyroll-Downloader/PropertyChangedObject.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace CrunchyrollDownloader 5 | { 6 | public class PropertyChangedObject : INotifyPropertyChanged 7 | { 8 | public event PropertyChangedEventHandler PropertyChanged; 9 | 10 | protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 11 | { 12 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 13 | } 14 | protected void Set(TVal value, out TVal output, [CallerMemberName] string propertyName = null) 15 | { 16 | output = value; 17 | OnPropertyChanged(propertyName); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Quality.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace CrunchyrollDownloader 6 | { 7 | public enum Quality 8 | { 9 | Best, 10 | P1080, 11 | P720, 12 | P480, 13 | P360 14 | } 15 | 16 | public class QualityItem 17 | { 18 | public static QualityItem[] AllQualities => Enum.GetValues(typeof(Quality)).Cast().Select(q => new QualityItem(q)).ToArray(); 19 | public QualityItem(Quality innerQuality) 20 | { 21 | InnerQuality = innerQuality; 22 | } 23 | public string DisplayName => InnerQuality.ToDisplay(); 24 | public Quality InnerQuality { get; set; } 25 | 26 | public static bool operator ==(QualityItem i, Quality q) 27 | { 28 | return i?.InnerQuality == q; 29 | } 30 | 31 | public static bool operator !=(QualityItem i, Quality q) 32 | { 33 | return !(i == q); 34 | } 35 | 36 | public override string ToString() => InnerQuality.ToNormalized(); 37 | } 38 | public static class QualityExtensions 39 | { 40 | public static IReadOnlyList Displays { get; } = new[] 41 | { 42 | "Best (recommended)", 43 | "1080p", 44 | "720p", 45 | "480p", 46 | "360p" 47 | }; 48 | 49 | public static IReadOnlyList Normalizations { get; } = new[] 50 | { 51 | "best", 52 | "1080", 53 | "720", 54 | "480", 55 | "360" 56 | }; 57 | public static string ToDisplay(this Quality quality) => Displays[(int) quality]; 58 | public static string ToNormalized(this Quality quality) => Normalizations[(int) quality]; 59 | } 60 | } -------------------------------------------------------------------------------- /Crunchyroll-Downloader/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace CrunchyrollDownloader 6 | { 7 | public class ViewModelBase : PropertyChangedObject where T : class, new() 8 | { 9 | public T Model { get; protected set; } 10 | public ViewModelBase(T model = null) 11 | { 12 | Model = model ?? new T(); 13 | } 14 | 15 | protected void SetModelProperty(object value, [CallerMemberName] string propertyName = null) 16 | { 17 | if (propertyName is null) throw new ArgumentNullException(nameof(propertyName)); 18 | typeof(T).GetProperty(propertyName)?.SetValue(Model, value); 19 | OnPropertyChanged(propertyName); 20 | } 21 | } 22 | 23 | public class UnknownCulture : CultureInfo 24 | { 25 | public override string Name { get; } 26 | public override string NativeName => "Unknown language for Windows (" + Name + ")"; 27 | 28 | public UnknownCulture(string name) : base("en-US") 29 | { 30 | Name = name; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /Crunchyroll-Downloader/ViewModels/MainWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Globalization; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text.RegularExpressions; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using System.Windows; 11 | using CrunchyrollDownloader.Models; 12 | using CrunchyrollDownloader.Progress; 13 | using CrunchyrollDownloader.Views; 14 | using Newtonsoft.Json; 15 | using static System.Globalization.CultureInfo; 16 | using static CrunchyrollDownloader.Quality; 17 | 18 | namespace CrunchyrollDownloader.ViewModels 19 | { 20 | 21 | public class MainWindowViewModel : ViewModelBase 22 | { 23 | readonly static UnknownCulture esla = new UnknownCulture("es-LA"); 24 | readonly static UnknownCulture arme = new UnknownCulture("ar-ME"); 25 | 26 | public MainWindowViewModel() : this(null) 27 | { 28 | } 29 | 30 | public MainWindowViewModel(DownloaderModel model = null) : base(model) 31 | { 32 | } 33 | 34 | public string DlStatus 35 | { 36 | get => Model.DlStatus; 37 | set => SetModelProperty(value); 38 | } 39 | 40 | public string[] AvailableFormats { get; } = 41 | { 42 | "ass" 43 | }; 44 | 45 | public string Format 46 | { 47 | get => Model.Format; 48 | set => SetModelProperty(value); 49 | } 50 | 51 | public string Language 52 | { 53 | get => Model.Language; 54 | set => SetModelProperty(value); 55 | } 56 | 57 | public bool IsMkv 58 | { 59 | get => Model.IsMkv; 60 | set => SetModelProperty(value); 61 | } 62 | 63 | public QualityItem Quality 64 | { 65 | get => new QualityItem(Model.Quality); 66 | set => SetModelProperty(value.InnerQuality); 67 | } 68 | 69 | public string SavePath 70 | { 71 | get => Model.SavePath; 72 | set => SetModelProperty(value); 73 | } 74 | 75 | public bool AreSubtitlesEnabled 76 | { 77 | get => Model.AreSubtitlesEnabled; 78 | set => SetModelProperty(value); 79 | } 80 | 81 | public string Url 82 | { 83 | get => Model.Url; 84 | set => SetModelProperty(value); 85 | } 86 | private int _selectedQualityItemIndex = 0; 87 | 88 | public int SelectedQualityItemIndex 89 | { 90 | get => _selectedQualityItemIndex; 91 | set 92 | { 93 | Set(value, out _selectedQualityItemIndex); 94 | Quality = QualityItem.AllQualities[value]; 95 | } 96 | } 97 | 98 | private QualityItem _selectedQualityItem; 99 | 100 | public QualityItem SelectedQualityItem 101 | { 102 | get => QualityItem.AllQualities[_selectedQualityItemIndex]; 103 | set => SelectedQualityItemIndex = Array.IndexOf(QualityItem.AllQualities, value); 104 | } 105 | 106 | public bool HasLogin => File.Exists(@"C:\ProgramData\Crunchy-DL\login.json"); 107 | public bool HasNoLogin => !HasLogin; 108 | 109 | public List AvailableLanguages { get; } = new List 110 | { 111 | 112 | GetCultureInfo("en-US"), 113 | GetCultureInfo("fr-FR"), 114 | GetCultureInfo("es-ES"), 115 | esla, 116 | GetCultureInfo("pt-BR"), 117 | GetCultureInfo("it-IT"), 118 | GetCultureInfo("de-DE"), 119 | GetCultureInfo("ru-RU"), 120 | arme 121 | }; 122 | private CultureInfo _selectedCultureInfo; 123 | 124 | public CultureInfo SelectedLanguage 125 | { 126 | get 127 | { 128 | if (_selectedCultureInfo is null) 129 | { 130 | _selectedCultureInfo = AvailableLanguages[0]; 131 | } 132 | return _selectedCultureInfo; 133 | } 134 | set 135 | { 136 | Set(value, out _selectedCultureInfo); 137 | Language = new string(_selectedCultureInfo.Name.Where(c => c != '-').ToArray()); 138 | } 139 | } 140 | 141 | public void UpdateLogin() 142 | { 143 | OnPropertyChanged(nameof(HasLogin)); 144 | OnPropertyChanged(nameof(HasNoLogin)); 145 | } 146 | public async Task Download() 147 | { 148 | var process = GetYoutubeDlProcessWithArguments(); 149 | var isIntentional = false; 150 | var data = new ProgressViewModel 151 | { 152 | IsIndeterminate = true, 153 | Progress = new TaskManager(new[] 154 | { 155 | new ProgressTask("Fetching video info", 1) { Display = "{3}..." }, 156 | new ProgressTask("Downloading") { Display = "{3}... {2}" } 157 | }) 158 | { FinalizingText = "Writing to file..." }, 159 | CanClose = () => true, 160 | OnClose = () => 161 | { 162 | isIntentional = true; 163 | process.Kill(); 164 | } 165 | }; 166 | var downloadWindow = new ProgressWindow(data); 167 | _ = Task.Run(() => Application.Current.Dispatcher.Invoke(() => downloadWindow.ShowDialog())); 168 | UpdateWithProcessOutput(process, data); 169 | process.Start(); 170 | process.BeginOutputReadLine(); 171 | process.BeginErrorReadLine(); 172 | await Task.Run(() => process.WaitForExit()); // do not block other threads. 173 | downloadWindow.Close(); 174 | if (!isIntentional) 175 | { 176 | if (process.ExitCode == 0) 177 | MessageBox.Show("Download finished !", "Success !", MessageBoxButton.OK, MessageBoxImage.Information); 178 | else 179 | MessageBox.Show("Something wrong has happened while downloading the video. " + 180 | "Please check your URL or login credentials", "Error", MessageBoxButton.OK, MessageBoxImage.Error); 181 | } 182 | } 183 | 184 | private static void UpdateWithProcessOutput(Process process, ProgressViewModel data) 185 | { 186 | TimeSpan? totalDuration = null; 187 | const string pattern = "([0-9.:]+)"; 188 | process.ErrorDataReceived += (_, e) => 189 | { 190 | Debug.WriteLine("E: " + (e?.Data ?? "[null]")); 191 | if (e?.Data is null) return; 192 | if (totalDuration is null && e.Data.StartsWith(" Duration:")) 193 | { 194 | var value = Regex.Match(e.Data, $"Duration: {pattern}").Groups[1].Value; 195 | if (TimeSpan.TryParse(value, out var d)) 196 | { 197 | totalDuration = d; 198 | data.Progress.GoNext(); 199 | data.IsIndeterminate = false; 200 | } 201 | } 202 | 203 | if (totalDuration is null) return; 204 | if (e.Data.StartsWith("frame=")) 205 | { 206 | var value = Regex.Match(e.Data, $"time={pattern}").Groups[1].Value; 207 | if (TimeSpan.TryParse(value, out var step)) 208 | { 209 | var progress = step.TotalMilliseconds / totalDuration.Value.TotalMilliseconds; 210 | data.Progress.CurrentTask.Progress = progress; 211 | } 212 | } 213 | }; 214 | process.OutputDataReceived += (_, e) => { Debug.WriteLine("O { " + e.Data + " }"); }; 215 | } 216 | 217 | private Process GetYoutubeDlProcessWithArguments() 218 | { 219 | var loginJson = File.ReadAllText(@"C:\ProgramData\Crunchy-DL\login.json"); 220 | dynamic loginIdents = JsonConvert.DeserializeObject(loginJson); 221 | string username = loginIdents.username; 222 | string password = loginIdents.password; 223 | 224 | var currentSavePath = SavePath; 225 | currentSavePath += @"\%(title)s.%(ext)s"; 226 | 227 | var login = $"--username {username} --password {password}"; 228 | var ua = $"--user-agent \"Mozilla / 5.0 (Windows NT 10.0; Win64; x64; rv: 65.0) Gecko / 20100101 Firefox / 65.0\""; 229 | var basicArguments = $"{login} --console-title --newline --no-warnings --no-part -o \"{currentSavePath}\" {ua}"; 230 | var subsArguments = $"--write-sub --sub-lang {Language} --sub-format {Format}"; 231 | var qualityArguments = Quality == Best ? "-f best" : $"-f \"best[height={Quality}]\""; 232 | 233 | var process = new Process 234 | { 235 | StartInfo = 236 | { 237 | FileName = @"C:\ProgramData\Crunchy-DL\youtube-dl.exe", 238 | UseShellExecute = false, 239 | RedirectStandardOutput = true, 240 | RedirectStandardError = true, 241 | CreateNoWindow = true, 242 | } 243 | }; 244 | 245 | if (AreSubtitlesEnabled) 246 | { 247 | process.StartInfo.Arguments = IsMkv 248 | ? $"{qualityArguments} --recode-video mkv --embed-subs --postprocessor-args \"-disposition:s:0 default\" {subsArguments} {basicArguments}" 249 | : $"{qualityArguments} {subsArguments} {basicArguments}"; 250 | } 251 | else 252 | { 253 | process.StartInfo.Arguments = $"{qualityArguments} {basicArguments}"; 254 | } 255 | 256 | process.StartInfo.Arguments += " -v --newline " + Url; 257 | return process; 258 | } 259 | } 260 | } -------------------------------------------------------------------------------- /Crunchyroll-Downloader/ViewModels/ProgressViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using CrunchyrollDownloader.Progress; 4 | 5 | namespace CrunchyrollDownloader.ViewModels 6 | { 7 | public class ProgressViewModel : PropertyChangedObject 8 | { 9 | public TaskManager Progress 10 | { 11 | get => _progress; 12 | set 13 | { 14 | if (_progress != null) 15 | _progress.PropertyChanged -= ProgressOnPropertyChanged; 16 | 17 | _progress = value; 18 | _progress.PropertyChanged += ProgressOnPropertyChanged; 19 | } 20 | } 21 | 22 | private void ProgressOnPropertyChanged(object sender, PropertyChangedEventArgs e) 23 | { 24 | OnPropertyChanged(nameof(IsIndeterminate)); 25 | } 26 | 27 | private bool _isIndeterminate; 28 | private TaskManager _progress; 29 | 30 | public bool IsIndeterminate 31 | { 32 | get => _isIndeterminate || Progress.CurrentTask is null; 33 | set => Set(value, out _isIndeterminate); 34 | } 35 | 36 | public Func CanClose { get; set; } = () => false; 37 | public Action OnClose { get; set; } = () => { }; 38 | } 39 | } -------------------------------------------------------------------------------- /Crunchyroll-Downloader/Views/AboutWindow.xaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |