├── .gitattributes ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── Binaries ├── Steam Library Manager.exe └── Version.xml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Extras ├── Choco │ ├── steamlibrarymanager.nuspec │ ├── steamlibrarymanager.portable.1.6.0.3.nupkg │ └── tools │ │ ├── LICENSE.txt │ │ ├── Steam.Library.Manager.zip │ │ ├── SteamLibraryManager.exe.gui │ │ ├── VERIFICATION.txt │ │ └── chocolateyinstall.ps1 ├── Icons │ ├── resharper.png │ └── slm.png ├── Logo │ ├── SLM_BANNER.png │ ├── slm.png │ └── slm.psd └── Screenshots │ ├── LibraryCleanerTab.png │ ├── LibraryTab.png │ ├── LibraryTab_ListView.png │ ├── SettingsTab.png │ ├── TaskManagerTab.png │ ├── TaskManagerTab_ListView.png │ └── Wiki │ ├── LibraryCleanerTab.png │ ├── LibraryTab.png │ └── TaskManagerTab.png ├── LICENSE ├── README.md ├── Source ├── Steam Library Manager.sln ├── Steam Library Manager.sln.DotSettings.user └── Steam Library Manager │ ├── App.xaml │ ├── App.xaml.cs │ ├── Definitions │ ├── App.cs │ ├── ContextMenuItem.cs │ ├── Directories.cs │ ├── Enums │ │ └── Enums.cs │ ├── ExtensionMethods.cs │ ├── Global.cs │ ├── Library.cs │ ├── List.cs │ ├── OriginAppInfo.cs │ ├── OriginLibrary.cs │ ├── SLM.cs │ ├── Settings.cs │ ├── SteamAppInfo.cs │ ├── SteamLibrary.cs │ ├── Updater.cs │ ├── UplayAppInfo.cs │ ├── UplayConfigurationDb.cs │ └── UplayLibrary.cs │ ├── FodyWeavers.xml │ ├── FodyWeavers.xsd │ ├── Forms │ ├── AppView.xaml │ ├── AppView.xaml.cs │ ├── HamburgerMenuControl.xaml │ ├── HamburgerMenuControl.xaml.cs │ ├── InstallationWizard │ │ ├── Final.xaml │ │ ├── Final.xaml.cs │ │ ├── Library.xaml │ │ ├── Library.xaml.cs │ │ ├── Welcome.xaml │ │ ├── Welcome.xaml.cs │ │ ├── Wizard.xaml │ │ └── Wizard.xaml.cs │ ├── LibraryCleanerView.xaml │ ├── LibraryCleanerView.xaml.cs │ ├── LibraryView.xaml │ ├── LibraryView.xaml.cs │ ├── Main.xaml │ ├── Main.xaml.cs │ ├── SettingsView.xaml │ ├── SettingsView.xaml.cs │ ├── TaskManagerView.xaml │ └── TaskManagerView.xaml.cs │ ├── Framework │ ├── CachedImage │ │ ├── FileCache.cs │ │ └── Image.cs │ ├── KeyValue.cs │ ├── LocalizedDescriptionAttribute.cs │ ├── SteamIDConvert.cs │ ├── StringFormat.cs │ └── WPF │ │ ├── EnumBindingSourceExtension.cs │ │ ├── EnumDescriptionTypeConverter.cs │ │ ├── PortableSettingsProvider.cs │ │ └── SettingBindingExtension.cs │ ├── Functions │ ├── App.cs │ ├── FileSystem.cs │ ├── Origin.cs │ ├── SLM.cs │ ├── Steam.cs │ ├── TaskManager.cs │ └── Uplay.cs │ ├── GlobalSuppressions.cs │ ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.en.resx │ ├── Resources.fr.resx │ ├── Resources.nl.resx │ ├── Resources.pl.resx │ ├── Resources.resx │ ├── Resources.ru.resx │ ├── Resources.tr.resx │ ├── Settings.Designer.cs │ └── Settings.settings │ ├── Resources │ ├── configurations │ ├── fa │ │ └── FontAwesome.otf │ ├── no_image_available.gif │ ├── no_image_available_origin.jpg │ ├── no_image_available_uplay.jpg │ ├── origin-icon.ico │ ├── slm-icon.ico │ ├── steam-icon.ico │ └── uplay-icon.ico │ ├── Settings.cs │ ├── Steam Library Manager.csproj │ ├── Steam Library Manager.csproj.DotSettings.user │ ├── Steam Library Manager.csproj.user │ └── app.config └── crowdin.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: RevoLand 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Additional context** 24 | Add any other context about the problem here. 25 | -------------------------------------------------------------------------------- /.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 | Binaries/*.settings 2 | Binaries/*.config 3 | Binaries/*.dll 4 | Binaries/*.xml 5 | !Binaries/Version.xml 6 | Binaries/*.pdb 7 | Binaries/*vshost* 8 | Binaries/Logs/* 9 | Binaries/.slmcache/* 10 | *.suo 11 | Source/*.vs/ 12 | Source/packages/* 13 | Source/Steam Library Manager/obj/* 14 | .csproj.user 15 | /.vs 16 | -------------------------------------------------------------------------------- /Binaries/Steam Library Manager.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Binaries/Steam Library Manager.exe -------------------------------------------------------------------------------- /Binaries/Version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.7.2.0 4 | http://github.com/RevoLand/Steam-Library-Manager/releases/download/v1.7.2.0/Steam.Library.Manager.zip 5 | https://github.com/RevoLand/Steam-Library-Manager/releases 6 | false 7 | -------------------------------------------------------------------------------- /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 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at admin@mertercan.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /Extras/Choco/steamlibrarymanager.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | steamlibrarymanager.portable 6 | 1.6.0.3 7 | https://github.com/RevoLand/Steam-Library-Manager/tree/master/Extras/Choco 8 | Mert Ercan 9 | Steam Library Manager (Portable) 10 | Mert Ercan 11 | https://rawcdn.githack.com/RevoLand/Steam-Library-Manager/17422b3cb67384387dcb8ac76d97942bdf0f4068/Extras/Icons/slm.png 12 | https://github.com/RevoLand/Steam-Library-Manager 13 | https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/master/LICENSE 14 | false 15 | https://github.com/RevoLand/Steam-Library-Manager 16 | https://github.com/RevoLand/Steam-Library-Manager/wiki 17 | https://github.com/RevoLand/Steam-Library-Manager/issues 18 | steam origin uplay games library manager steamlibrarymanager 19 | Open source utility to manage Steam, Origin and Uplay libraries in ease of use with multi library support 20 | Steam Library Manager is a tool to manage your Steam, Origin and Uplay Libraries quick and easy. With SLM you can administrate all of your games and backups from one place. Drag and drop between libraries and backup folders with ease. Works with existing Steam Backups or opt to use SLM's open system for fast updates and quick access to game files. 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Extras/Choco/steamlibrarymanager.portable.1.6.0.3.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Choco/steamlibrarymanager.portable.1.6.0.3.nupkg -------------------------------------------------------------------------------- /Extras/Choco/tools/LICENSE.txt: -------------------------------------------------------------------------------- 1 | From: https://github.com/RevoLand/Steam-Library-Manager/blob/master/LICENSE 2 | 3 | LICENSE 4 | 5 | The MIT License (MIT) 6 | 7 | Copyright (c) 2019 Mert Ercan 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. -------------------------------------------------------------------------------- /Extras/Choco/tools/Steam.Library.Manager.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Choco/tools/Steam.Library.Manager.zip -------------------------------------------------------------------------------- /Extras/Choco/tools/SteamLibraryManager.exe.gui: -------------------------------------------------------------------------------- 1 | ## Summary 2 | How do I create packages? See https://chocolatey.org/docs/create-packages 3 | 4 | If you are submitting packages to the community feed (https://chocolatey.org) 5 | always try to ensure you have read, understood and adhere to the create 6 | packages wiki link above. 7 | 8 | ## Automatic Packaging Updates? 9 | Consider making this package an automatic package, for the best 10 | maintainability over time. Read up at https://chocolatey.org/docs/automatic-packages 11 | 12 | ## Shim Generation 13 | Any executables you include in the package or download (but don't call 14 | install against using the built-in functions) will be automatically shimmed. 15 | 16 | This means those executables will automatically be included on the path. 17 | Shim generation runs whether the package is self-contained or uses automation 18 | scripts. 19 | 20 | By default, these are considered console applications. 21 | 22 | If the application is a GUI, you should create an empty file next to the exe 23 | named 'name.exe.gui' e.g. 'bob.exe' would need a file named 'bob.exe.gui'. 24 | See https://chocolatey.org/docs/create-packages#how-do-i-set-up-shims-for-applications-that-have-a-gui 25 | 26 | If you want to ignore the executable, create an empty file next to the exe 27 | named 'name.exe.ignore' e.g. 'bob.exe' would need a file named 28 | 'bob.exe.ignore'. 29 | See https://chocolatey.org/docs/create-packages#how-do-i-exclude-executables-from-getting-shims 30 | 31 | ## Self-Contained? 32 | If you have a self-contained package, you can remove the automation scripts 33 | entirely and just include the executables, they will automatically get shimmed, 34 | which puts them on the path. Ensure you have the legal right to distribute 35 | the application though. See https://chocolatey.org/docs/legal. 36 | 37 | You should read up on the Shim Generation section to familiarize yourself 38 | on what to do with GUI applications and/or ignoring shims. 39 | 40 | ## Automation Scripts 41 | You have a powerful use of Chocolatey, as you are using PowerShell. So you 42 | can do just about anything you need. Choco has some very handy built-in 43 | functions that you can use, these are sometimes called the helpers. 44 | 45 | ### Built-In Functions 46 | https://chocolatey.org/docs/helpers-reference 47 | 48 | A note about a couple: 49 | * Get-BinRoot - this is a horribly named function that doesn't do what new folks think it does. It gets you the 'tools' root, which by default is set to 'c:\tools', not the chocolateyInstall bin folder - see https://chocolatey.org/docs/helpers-get-tools-location 50 | * Install-BinFile - used for non-exe files - executables are automatically shimmed... - see https://chocolatey.org/docs/helpers-install-bin-file 51 | * Uninstall-BinFile - used for non-exe files - executables are automatically shimmed - see https://chocolatey.org/docs/helpers-uninstall-bin-file 52 | 53 | ### Getting package specific information 54 | Use the package parameters pattern - see https://chocolatey.org/docs/how-to-parse-package-parameters-argument 55 | 56 | ### Need to mount an ISO? 57 | https://chocolatey.org/docs/how-to-mount-an-iso-in-chocolatey-package 58 | 59 | ### Environment Variables 60 | Chocolatey makes a number of environment variables available (You can access any of these with $env:TheVariableNameBelow): 61 | 62 | * TEMP/TMP - Overridden to the CacheLocation, but may be the same as the original TEMP folder 63 | * ChocolateyInstall - Top level folder where Chocolatey is installed 64 | * ChocolateyPackageName - The name of the package, equivalent to the `` field in the nuspec (0.9.9+) 65 | * ChocolateyPackageTitle - The title of the package, equivalent to the `` field in the nuspec (0.10.1+) 66 | * ChocolateyPackageVersion - The version of the package, equivalent to the `<version />` field in the nuspec (0.9.9+) 67 | * ChocolateyPackageFolder - The top level location of the package folder - the folder where Chocolatey has downloaded and extracted the NuGet package, typically `C:\ProgramData\chocolatey\lib\packageName`. 68 | 69 | #### Advanced Environment Variables 70 | The following are more advanced settings: 71 | 72 | * ChocolateyPackageParameters - Parameters to use with packaging, not the same as install arguments (which are passed directly to the native installer). Based on `--package-parameters`. (0.9.8.22+) 73 | * CHOCOLATEY_VERSION - The version of Choco you normally see. Use if you are 'lighting' things up based on choco version. (0.9.9+) - Otherwise take a dependency on the specific version you need. 74 | * ChocolateyForceX86 = If available and set to 'true', then user has requested 32bit version. (0.9.9+) - Automatically handled in built in Choco functions. 75 | * OS_PLATFORM - Like Windows, OSX, Linux. (0.9.9+) 76 | * OS_VERSION - The version of OS, like 6.1 something something for Windows. (0.9.9+) 77 | * OS_NAME - The reported name of the OS. (0.9.9+) 78 | * USER_NAME = The user name (0.10.6+) 79 | * USER_DOMAIN = The user domain name (could also be local computer name) (0.10.6+) 80 | * IS_PROCESSELEVATED = Is the process elevated? (0.9.9+) 81 | * IS_SYSTEM = Is the user the system account? (0.10.6+) 82 | * IS_REMOTEDESKTOP = Is the user in a terminal services session? (0.10.6+) 83 | * ChocolateyToolsLocation - formerly 'ChocolateyBinRoot' ('ChocolateyBinRoot' will be removed with Chocolatey v2.0.0), this is where tools being installed outside of Chocolatey packaging will go. (0.9.10+) 84 | 85 | #### Set By Options and Configuration 86 | Some environment variables are set based on options that are passed, configuration and/or features that are turned on: 87 | 88 | * ChocolateyEnvironmentDebug - Was `--debug` passed? If using the built-in PowerShell host, this is always true (but only logs debug messages to console if `--debug` was passed) (0.9.10+) 89 | * ChocolateyEnvironmentVerbose - Was `--verbose` passed? If using the built-in PowerShell host, this is always true (but only logs verbose messages to console if `--verbose` was passed). (0.9.10+) 90 | * ChocolateyForce - Was `--force` passed? (0.9.10+) 91 | * ChocolateyForceX86 - Was `-x86` passed? (CHECK) 92 | * ChocolateyRequestTimeout - How long before a web request will time out. Set by config `webRequestTimeoutSeconds` (CHECK) 93 | * ChocolateyResponseTimeout - How long to wait for a download to complete? Set by config `commandExecutionTimeoutSeconds` (CHECK) 94 | * ChocolateyPowerShellHost - Are we using the built-in PowerShell host? Set by `--use-system-powershell` or the feature `powershellHost` (0.9.10+) 95 | 96 | #### Business Edition Variables 97 | 98 | * ChocolateyInstallArgumentsSensitive - Encrypted arguments passed from command line `--install-arguments-sensitive` that are not logged anywhere. (0.10.1+ and licensed editions 1.6.0+) 99 | * ChocolateyPackageParametersSensitive - Package parameters passed from command line `--package-parameters-senstivite` that are not logged anywhere. (0.10.1+ and licensed editions 1.6.0+) 100 | * ChocolateyLicensedVersion - What version is the licensed edition on? 101 | * ChocolateyLicenseType - What edition / type of the licensed edition is installed? 102 | * USER_CONTEXT - The original user context - different when self-service is used (Licensed v1.10.0+) 103 | 104 | #### Experimental Environment Variables 105 | The following are experimental or use not recommended: 106 | 107 | * OS_IS64BIT = This may not return correctly - it may depend on the process the app is running under (0.9.9+) 108 | * CHOCOLATEY_VERSION_PRODUCT = the version of Choco that may match CHOCOLATEY_VERSION but may be different (0.9.9+) - based on git describe 109 | * IS_ADMIN = Is the user an administrator? But doesn't tell you if the process is elevated. (0.9.9+) 110 | * IS_REMOTE = Is the user in a remote session? (0.10.6+) 111 | 112 | #### Not Useful Or Anti-Pattern If Used 113 | 114 | * ChocolateyInstallOverride = Not for use in package automation scripts. Based on `--override-arguments` being passed. (0.9.9+) 115 | * ChocolateyInstallArguments = The installer arguments meant for the native installer. You should use chocolateyPackageParameters instead. Based on `--install-arguments` being passed. (0.9.9+) 116 | * ChocolateyIgnoreChecksums - Was `--ignore-checksums` passed or the feature `checksumFiles` turned off? (0.9.9.9+) 117 | * ChocolateyAllowEmptyChecksums - Was `--allow-empty-checksums` passed or the feature `allowEmptyChecksums` turned on? (0.10.0+) 118 | * ChocolateyAllowEmptyChecksumsSecure - Was `--allow-empty-checksums-secure` passed or the feature `allowEmptyChecksumsSecure` turned on? (0.10.0+) 119 | * ChocolateyCheckLastExitCode - Should Chocolatey check LASTEXITCODE? Is the feature `scriptsCheckLastExitCode` turned on? (0.10.3+) 120 | * ChocolateyChecksum32 - Was `--download-checksum` passed? (0.10.0+) 121 | * ChocolateyChecksumType32 - Was `--download-checksum-type` passed? (0.10.0+) 122 | * ChocolateyChecksum64 - Was `--download-checksum-x64` passed? (0.10.0)+ 123 | * ChocolateyChecksumType64 - Was `--download-checksum-type-x64` passed? (0.10.0)+ 124 | * ChocolateyPackageExitCode - The exit code of the script that just ran - usually set by `Set-PowerShellExitCode` (CHECK) 125 | * ChocolateyLastPathUpdate - Set by Chocolatey as part of install, but not used for anything in particular in packaging. 126 | * ChocolateyProxyLocation - The explicit proxy location as set in the configuration `proxy` (0.9.9.9+) 127 | * ChocolateyDownloadCache - Use available download cache? Set by `--skip-download-cache`, `--use-download-cache`, or feature `downloadCache` (0.9.10+ and licensed editions 1.1.0+) 128 | * ChocolateyProxyBypassList - Explicitly set locations to ignore in configuration `proxyBypassList` (0.10.4+) 129 | * ChocolateyProxyBypassOnLocal - Should the proxy bypass on local connections? Set based on configuration `proxyBypassOnLocal` (0.10.4+) 130 | * http_proxy - Set by original `http_proxy` passthrough, or same as `ChocolateyProxyLocation` if explicitly set. (0.10.4+) 131 | * https_proxy - Set by original `https_proxy` passthrough, or same as `ChocolateyProxyLocation` if explicitly set. (0.10.4+) 132 | * no_proxy- Set by original `no_proxy` passthrough, or same as `ChocolateyProxyBypassList` if explicitly set. (0.10.4+) 133 | 134 | -------------------------------------------------------------------------------- /Extras/Choco/tools/VERIFICATION.txt: -------------------------------------------------------------------------------- 1 | VERIFICATION 2 | 3 | Verification is intended to assist the Chocolatey moderators and community 4 | in verifying that this package's contents are trustworthy. 5 | 6 | Package can be verified like this: 7 | 8 | 1. Go to 9 | 10 | : https://github.com/RevoLand/Steam-Library-Manager/releases/download/v1.6.0.3/Steam.Library.Manager.zip 11 | 12 | to download the archive. 13 | 14 | 2. You can use one of the following methods to obtain the SHA256 checksum: 15 | - Use powershell function 'Get-FileHash' 16 | - Use Chocolatey utility 'checksum.exe' 17 | 18 | checksum: 42EF820F24BC8A4D8F8C6A281ACE26B1643F58E11ED3407E6268E235C7C41CA6 19 | 20 | Using AU: 21 | 22 | Get-RemoteChecksum https://github.com/RevoLand/Steam-Library-Manager/releases/download/v1.6.0.3/Steam.Library.Manager.zip 23 | 24 | File 'LICENSE.txt' obtained from: 25 | https://github.com/RevoLand/Steam-Library-Manager/blob/master/LICENSE -------------------------------------------------------------------------------- /Extras/Choco/tools/chocolateyinstall.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = 'Stop' 2 | 3 | $toolsPath = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" 4 | 5 | $packageArgs = @{ 6 | PackageName = "steamlibrarymanager" 7 | File = "$toolsPath\Steam.Library.Manager.zip" 8 | Destination = $toolsPath 9 | } 10 | Get-ChocolateyUnzip @packageArgs 11 | 12 | Remove-Item -force "$toolsPath\*.zip" -ea 0 -------------------------------------------------------------------------------- /Extras/Icons/resharper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Icons/resharper.png -------------------------------------------------------------------------------- /Extras/Icons/slm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Icons/slm.png -------------------------------------------------------------------------------- /Extras/Logo/SLM_BANNER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Logo/SLM_BANNER.png -------------------------------------------------------------------------------- /Extras/Logo/slm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Logo/slm.png -------------------------------------------------------------------------------- /Extras/Logo/slm.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Logo/slm.psd -------------------------------------------------------------------------------- /Extras/Screenshots/LibraryCleanerTab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Screenshots/LibraryCleanerTab.png -------------------------------------------------------------------------------- /Extras/Screenshots/LibraryTab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Screenshots/LibraryTab.png -------------------------------------------------------------------------------- /Extras/Screenshots/LibraryTab_ListView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Screenshots/LibraryTab_ListView.png -------------------------------------------------------------------------------- /Extras/Screenshots/SettingsTab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Screenshots/SettingsTab.png -------------------------------------------------------------------------------- /Extras/Screenshots/TaskManagerTab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Screenshots/TaskManagerTab.png -------------------------------------------------------------------------------- /Extras/Screenshots/TaskManagerTab_ListView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Screenshots/TaskManagerTab_ListView.png -------------------------------------------------------------------------------- /Extras/Screenshots/Wiki/LibraryCleanerTab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Screenshots/Wiki/LibraryCleanerTab.png -------------------------------------------------------------------------------- /Extras/Screenshots/Wiki/LibraryTab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Screenshots/Wiki/LibraryTab.png -------------------------------------------------------------------------------- /Extras/Screenshots/Wiki/TaskManagerTab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Extras/Screenshots/Wiki/TaskManagerTab.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Mert Ercan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | <p>Note: Even tho the repository is no longer actively maintained, there are no known bugs and <strong>SLM can be safely used like always</strong>.<br/> 2 | If you like to support me to get back to work on SLM back, you can make a donation via <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=SMB7YGBQQSGD6&item_name=Steam+Library+Manager¤cy_code=EUR&source=url" title="PayPal Donations">PayPal</a>.<br /><br/> 3 | Feel free to contact with me in case of an urgent bug, thanks. Discord: RevoLand#3385 4 | </p> 5 | <p align="center"><img src="/Extras/Logo/slm.png?raw=true" alt="Steam Library Manager" width="550px" height="280px" /> 6 | <br /> 7 | <a href="https://github.com/RevoLand/Steam-Library-Manager/releases/latest"> <img src="https://img.shields.io/github/release/RevoLand/Steam-Library-Manager.svg?style=for-the-badge" alt="Latest Release" /> </a> 8 | <a href="https://github.com/RevoLand/Steam-Library-Manager/releases/latest"> 9 | <img src="https://img.shields.io/github/downloads/RevoLand/Steam-Library-Manager/total.svg?style=for-the-badge" alt="Total Downloads" /> </a> 10 | <a href="https://github.com/RevoLand/Steam-Library-Manager/blob/master/LICENSE"> <img src="https://img.shields.io/badge/license-MIT-blue.svg?style=for-the-badge" alt="License" /> </a> 11 | <a href="https://github.com/RevoLand/Steam-Library-Manager/issues"> <img src="https://img.shields.io/github/issues/RevoLand/Steam-Library-Manager.svg?style=for-the-badge" alt="Issues" /> </a> 12 | <a href="https://github.com/RevoLand/Steam-Library-Manager/wiki"> <img src="https://img.shields.io/badge/SLM-Wiki-blue.svg?style=for-the-badge" alt="Wiki" /> </a> 13 | <a href="https://github.com/RevoLand/Steam-Library-Manager/blob/master/CHANGELOG.md"> <img src="https://img.shields.io/badge/SLM-Changelog-red.svg?style=for-the-badge" alt="License" /> </a> 14 | </p> 15 | <h1>Steam Library Manager</h1> 16 | <p>is a tool to manage your Steam, Origin and Uplay Libraries quick and easy. With SLM you can administrate all of your games and backups from one place. Drag and drop between libraries and backup folders with ease. Works with existing Steam Backups or opt to use SLM's open system for fast updates and quick access to game files.</p> 17 | <p><strong>Benefits to using SLM over Steam Backup:</strong></p> 18 | <ul> 19 | <li>Backups can be updated quickly. No need to recreate the entire backup from scratch.</li> 20 | <li>Backup files are open and easily accessible.</li> 21 | <li>Workshop content and mods such as ENB, ReShade, and SweetFX get backed up automatically.</li> 22 | <li>Faster backups, faster restores, works with or without the Clients running.</li> 23 | <li>Compression is available for those who want to keep things lean.</li> 24 | <li>Built-in library cleaner for leftovers.</li> 25 | <li>Compact both backups and installed games for even more hard disk space.</li> 26 | </ul> 27 | <p>SLM is licensed under MIT license which means it is completely free and open source!</p> 28 | <p>All suggestions are welcome and will help further development of SLM.</p> 29 | <p> 30 | <em>Steam Library Manager (SLM) is not affiliated with, sponsored by, approved by, or otherwise related to Valve 31 | Software, Steam, Electronic Arts, or Ubisoft. 32 | </em> 33 | </p> 34 | <p align="center"> 35 | <a href="https://www.jetbrains.com/?from=SteamLibraryManager"> 36 | <img src="/Extras/Icons/resharper.png?raw=true" width="128px" height="128px" alt="Steam Library Manager" /> 37 | </a> 38 | </p> 39 | -------------------------------------------------------------------------------- /Source/Steam Library Manager.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28917.182 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steam Library Manager", "Steam Library Manager\Steam Library Manager.csproj", "{1E4D6DFF-D115-441D-AEA8-F22F60B2CBE4}" 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 | {1E4D6DFF-D115-441D-AEA8-F22F60B2CBE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {1E4D6DFF-D115-441D-AEA8-F22F60B2CBE4}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {1E4D6DFF-D115-441D-AEA8-F22F60B2CBE4}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {1E4D6DFF-D115-441D-AEA8-F22F60B2CBE4}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | RESX_TaskErrorCategory = Warning 24 | RESX_MoveToResources = {"Items":[{"Extensions":".cs,.vb","Patterns":"Functions.SLM.Translate(nameof(Properties.$File.$Key))|Framework.StringFormat.Format(Functions.SLM.Translate(nameof(Properties.$File.$Key)), new { })|$Key"},{"Extensions":".cshtml,.vbhtml","Patterns":"@$Namespace.$File.$Key|@$File.$Key|@StringResourceKey.$Key|@$Namespace.StringResourceKey.$Key"},{"Extensions":".cpp,.c,.hxx,.h","Patterns":"$File::$Key"},{"Extensions":".aspx,.ascx","Patterns":"<%$ Resources:$File,$Key %>|<%= $File.$Key %>|<%= $Namespace.$File.$Key %>"},{"Extensions":".xaml","Patterns":"{l:Static p:$File.$Key}|\"{l:Static p:$File.$Key}\""}]} 25 | SolutionGuid = {BAC111FB-A259-47CA-987C-ECC3D96BDA53} 26 | RESX_AutoCreateNewLanguageFiles = False 27 | RESX_ShowErrorsInErrorList = True 28 | RESX_DuplicateKeyHandling = Fail 29 | EndGlobalSection 30 | EndGlobal 31 | -------------------------------------------------------------------------------- /Source/Steam Library Manager.sln.DotSettings.user: -------------------------------------------------------------------------------- 1 | <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> 2 | <s:Boolean x:Key="/Default/UserDictionary/Words/=Uplay/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> -------------------------------------------------------------------------------- /Source/Steam Library Manager/App.xaml: -------------------------------------------------------------------------------- 1 | <Application x:Class="Steam_Library_Manager.App" 2 | xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 | xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 | StartupUri="Forms/Main.xaml"> 5 | <Application.Resources> 6 | <ResourceDictionary> 7 | <ResourceDictionary.MergedDictionaries> 8 | <!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! --> 9 | <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /> 10 | <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" /> 11 | <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" /> 12 | 13 | <!-- Accent and AppTheme setting --> 14 | <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" /> 15 | <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" /> 16 | </ResourceDictionary.MergedDictionaries> 17 | </ResourceDictionary> 18 | </Application.Resources> 19 | </Application> -------------------------------------------------------------------------------- /Source/Steam Library Manager/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using MahApps.Metro; 2 | using System; 3 | using System.Diagnostics; 4 | using System.Windows; 5 | using System.Windows.Threading; 6 | 7 | namespace Steam_Library_Manager 8 | { 9 | /// <summary> 10 | /// Interaction logic for App.xaml 11 | /// </summary> 12 | public partial class App 13 | { 14 | protected override void OnStartup(StartupEventArgs e) 15 | { 16 | try 17 | { 18 | ThemeManager.ChangeAppStyle(Current, 19 | ThemeManager.GetAccent(Steam_Library_Manager.Properties.Settings.Default.ThemeAccent) ?? ThemeManager.GetAccent("Blue"), 20 | ThemeManager.GetAppTheme(Steam_Library_Manager.Properties.Settings.Default.BaseTheme) ?? ThemeManager.GetAppTheme("BaseLight")); 21 | 22 | base.OnStartup(e); 23 | 24 | Dispatcher.UnhandledException += OnDispatcherUnhandledException; 25 | } 26 | catch (UnauthorizedAccessException ex) 27 | { 28 | base.OnStartup(e); 29 | MessageBox.Show(ex.ToString()); 30 | } 31 | catch (Exception ex) 32 | { 33 | MessageBox.Show(ex.ToString()); 34 | } 35 | } 36 | 37 | private static void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) 38 | { 39 | //MessageBox.Show($"{e.Exception}\n\n{Environment.StackTrace}"); 40 | Debug.WriteLine(e.Exception); 41 | Debug.WriteLine(Environment.StackTrace); 42 | e.Handled = true; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/ContextMenuItem.cs: -------------------------------------------------------------------------------- 1 | using ControlzEx; 2 | 3 | namespace Steam_Library_Manager.Definitions 4 | { 5 | public class ContextMenuItem 6 | { 7 | public readonly System.Collections.Generic.List<Enums.LibraryType> AllowedLibraryTypes = new System.Collections.Generic.List<Enums.LibraryType>(); 8 | public bool IsActive = true; 9 | public string Header; 10 | public string Action; 11 | public PackIconBase Icon; 12 | public bool ShowToNormal = true; 13 | public bool ShowToSteamBackup = true; 14 | public bool ShowToCompressed = true; 15 | public bool ShowToOffline = true; 16 | public bool IsSeparator; 17 | } 18 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/Directories.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Alphaleonis.Win32.Filesystem; 3 | 4 | namespace Steam_Library_Manager.Definitions 5 | { 6 | // Definitions about directories 7 | internal static class Directories 8 | { 9 | // SLM directory definitions 10 | public static class SLM 11 | { 12 | // Current running directory of SLM 13 | public static string Current = AppDomain.CurrentDomain.BaseDirectory; 14 | 15 | public static string Log = Path.Combine(Current, "logs"); 16 | public static string Cache = Path.Combine(Current, ".slmcache"); 17 | } 18 | 19 | public static class Origin 20 | { 21 | public static string LocalContentDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Origin", "LocalContent"); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/Enums/Enums.cs: -------------------------------------------------------------------------------- 1 | using Steam_Library_Manager.Framework; 2 | using System.ComponentModel; 3 | 4 | namespace Steam_Library_Manager.Definitions.Enums 5 | { 6 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 7 | public enum AppSortingMethod 8 | { 9 | [LocalizedDescription("Enums_Name")] 10 | appName, 11 | 12 | [LocalizedDescription("Enums_AppID")] 13 | appID, 14 | 15 | [LocalizedDescription("Enums_SizeOnDisk")] 16 | sizeOnDisk, 17 | 18 | [LocalizedDescription("Enums_BackupType")] 19 | backupType, 20 | 21 | [LocalizedDescription("Enums_LastUpdate")] 22 | LastUpdated, 23 | 24 | [LocalizedDescription("Enums_LastPlayed")] 25 | LastPlayed 26 | } 27 | 28 | public enum AppSizeCalculationMethod 29 | { 30 | ACF, 31 | Enumeration 32 | } 33 | 34 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 35 | public enum ArchiveSizeCalculationMethod 36 | { 37 | [LocalizedDescription("Enums_ArchiveSize")] 38 | compressed, 39 | 40 | [LocalizedDescription("Enums_ArchiveFileSize")] 41 | Uncompressed 42 | } 43 | 44 | public enum CompressionLevel 45 | { 46 | [LocalizedDescription("Enums_Optimal")] 47 | Optimal = 0, 48 | 49 | [LocalizedDescription("Enums_Fastest")] 50 | Fastest = 1, 51 | 52 | [LocalizedDescription("Enums_Store")] 53 | NoCompression = 2 54 | } 55 | 56 | public enum CompactLevel 57 | { 58 | XPRESS4K, 59 | XPRESS8K, 60 | XPRESS16K, 61 | LZX 62 | } 63 | 64 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 65 | public enum LibraryStyle 66 | { 67 | [LocalizedDescription("Enums_GridView")] 68 | Grid, 69 | 70 | [LocalizedDescription("Enums_ListView")] 71 | Listview 72 | } 73 | 74 | public enum LibraryType 75 | { 76 | Steam, 77 | Origin, 78 | Uplay, 79 | SLM 80 | } 81 | 82 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 83 | public enum TaskType 84 | { 85 | [LocalizedDescription("Enums_Copy")] 86 | Copy, 87 | 88 | [LocalizedDescription("Enums_Delete")] 89 | Delete, 90 | 91 | [LocalizedDescription("Enums_Compress")] 92 | Compress, 93 | 94 | [LocalizedDescription("Enums_Compact")] 95 | Compact 96 | } 97 | 98 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 99 | public enum JunkType 100 | { 101 | [LocalizedDescription("HeadlessFolder")] 102 | HeadlessFolder, 103 | 104 | [LocalizedDescription("HeadlessWorkshopFolder")] 105 | HeadlessWorkshopFolder, 106 | 107 | [LocalizedDescription("CorruptedDataFile")] 108 | CorruptedDataFile, 109 | 110 | [LocalizedDescription("HeadlessDataFile")] 111 | HeadlessDataFile 112 | } 113 | 114 | public enum ThemeAccents 115 | { 116 | Red, 117 | Green, 118 | Blue, 119 | Purple, 120 | Orange, 121 | Lime, 122 | Emerald, 123 | Teal, 124 | Cyan, 125 | Cobalt, 126 | Indigo, 127 | Violet, 128 | Pink, 129 | Magenta, 130 | Crimson, 131 | Amber, 132 | Yellow, 133 | Brown, 134 | Olive, 135 | Steel, 136 | Mauve, 137 | Taupe, 138 | Sienna 139 | } 140 | 141 | [TypeConverter(typeof(EnumDescriptionTypeConverter))] 142 | public enum BaseTheme 143 | { 144 | [LocalizedDescription("Enums_Light")] 145 | BaseLight, 146 | 147 | [LocalizedDescription("Enums_Dark")] 148 | BaseDark 149 | } 150 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/ExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using DirectoryInfo = Alphaleonis.Win32.Filesystem.DirectoryInfo; 4 | using File = Alphaleonis.Win32.Filesystem.File; 5 | using FileInfo = Alphaleonis.Win32.Filesystem.FileInfo; 6 | 7 | namespace Steam_Library_Manager 8 | { 9 | public static class ExtensionMethods 10 | { 11 | public static T ParseEnum<T>(this string value) 12 | { 13 | return (T)Enum.Parse(typeof(T), value, ignoreCase: true); 14 | } 15 | 16 | // https://stackoverflow.com/a/937558 17 | public static bool IsFileLocked(this FileInfo file) 18 | { 19 | FileStream stream = null; 20 | 21 | try 22 | { 23 | stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None); 24 | } 25 | catch (IOException) 26 | { 27 | //the file is unavailable because it is: 28 | //still being written to 29 | //or being processed by another thread 30 | //or does not exist (has already been processed) 31 | return true; 32 | } 33 | finally 34 | { 35 | stream?.Close(); 36 | } 37 | 38 | //file is not locked 39 | return false; 40 | } 41 | 42 | public static bool IsFileLocked(this string file) 43 | { 44 | FileStream stream = null; 45 | 46 | try 47 | { 48 | stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.None); 49 | } 50 | catch (IOException) 51 | { 52 | //the file is unavailable because it is: 53 | //still being written to 54 | //or being processed by another thread 55 | //or does not exist (has already been processed) 56 | return true; 57 | } 58 | finally 59 | { 60 | stream?.Close(); 61 | } 62 | 63 | //file is not locked 64 | return false; 65 | } 66 | 67 | public static long ToUnixTimestamp(this DateTime d) => (long)(d - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds; 68 | 69 | public static bool IsDirectoryAccessible(this DirectoryInfo directory) 70 | { 71 | try 72 | { 73 | directory.GetAccessControl(); 74 | return true; 75 | } 76 | catch (UnauthorizedAccessException) 77 | { 78 | return true; 79 | } 80 | catch 81 | { 82 | return false; 83 | } 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/Global.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Steam_Library_Manager.Definitions 4 | { 5 | internal static class Global 6 | { 7 | public static class Steam 8 | { 9 | public const string RegistryKeyPath = @"HKEY_CURRENT_USER\SOFTWARE\Valve\Steam"; 10 | 11 | public static string VdfFilePath = Alphaleonis.Win32.Filesystem.Path.Combine(Properties.Settings.Default.steamInstallationPath, "config", "config.vdf"); 12 | public static string LibraryFoldersPath = Alphaleonis.Win32.Filesystem.Path.Combine(Properties.Settings.Default.steamInstallationPath, "config", "libraryfolders.vdf"); 13 | 14 | public static bool IsStateChanging, Loaded; 15 | } 16 | 17 | public static class Origin 18 | { 19 | public static readonly string ConfigFilePath = Alphaleonis.Win32.Filesystem.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), "Origin", "local.xml"); 20 | public static List<KeyValuePair<string, string>> AppIds = new List<KeyValuePair<string, string>>(); 21 | 22 | public static bool IsStateChanging, Loaded; 23 | } 24 | 25 | public static class Uplay 26 | { 27 | public const string LauncherRegistryPath = @"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Ubisoft\Launcher"; 28 | public const string InstallationsRegistryPath = @"SOFTWARE\Ubisoft\Launcher\Installs"; 29 | 30 | public static readonly string ConfigFilePath = Alphaleonis.Win32.Filesystem.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), "Ubisoft Game Launcher", "settings.yml"); 31 | 32 | public static bool IsStateChanging, Loaded; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/Library.cs: -------------------------------------------------------------------------------- 1 | using Alphaleonis.Win32.Filesystem; 2 | using Steam_Library_Manager.Definitions.Enums; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Linq; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | 10 | namespace Steam_Library_Manager.Definitions 11 | { 12 | public abstract class Library : INotifyPropertyChanged 13 | { 14 | public readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); 15 | public LibraryType Type { get; set; } 16 | public bool IsMain { get; set; } 17 | public bool IsUpdatingAppList { get; set; } 18 | public DirectoryInfo DirectoryInfo { get; set; } 19 | private string _fullPath; 20 | 21 | public string FullPath 22 | { 23 | get => _fullPath; 24 | set 25 | { 26 | _fullPath = value; 27 | Functions.FileSystem.GetDiskFreeSpaceEx(_fullPath, out var freeSpace, out var totalSpace, out var totalFreeSpace); 28 | 29 | FreeSpace = (long)freeSpace; 30 | TotalSize = (long)totalSpace; 31 | } 32 | } 33 | 34 | public System.Collections.ObjectModel.ObservableCollection<dynamic> Apps { get; set; } = new System.Collections.ObjectModel.ObservableCollection<dynamic>(); 35 | public Dictionary<string, DirectoryInfo> DirectoryList { get; set; } = new Dictionary<string, DirectoryInfo>(); 36 | public List<LibraryType> AllowedAppTypes = new List<LibraryType>(); 37 | 38 | public long FreeSpace { get; set; } 39 | public long TotalSize { get; set; } 40 | public string PrettyFreeSpace => DirectoryInfo.Exists && !DirectoryInfo.FullName.StartsWith(Path.DirectorySeparatorChar.ToString()) ? $"{Functions.FileSystem.FormatBytes(FreeSpace)} / {Functions.FileSystem.FormatBytes(TotalSize)}" : ""; 41 | public int FreeSpacePerc => DirectoryInfo.Exists && !DirectoryInfo.FullName.StartsWith(Path.DirectorySeparatorChar.ToString()) ? 100 - ((int)Math.Round((double)(100 * FreeSpace) / TotalSize)) : 0; 42 | 43 | public List<FrameworkElement> ContextMenu => _contextMenuElements ?? (_contextMenuElements = GenerateCMenuItems()); 44 | private List<FrameworkElement> _contextMenuElements; 45 | 46 | private List<FrameworkElement> GenerateCMenuItems() 47 | { 48 | var cMenu = new List<FrameworkElement>(); 49 | try 50 | { 51 | foreach (var cMenuItem in List.LibraryCMenuItems.Where(x => x.IsActive && x.AllowedLibraryTypes.Contains(Type)).ToList()) 52 | { 53 | if (!cMenuItem.ShowToNormal && IsMain) 54 | { 55 | continue; 56 | } 57 | 58 | if (!DirectoryInfo.Exists && !cMenuItem.ShowToOffline) 59 | { 60 | continue; 61 | } 62 | 63 | if (cMenuItem.IsSeparator) 64 | { 65 | cMenu.Add(new Separator()); 66 | } 67 | else 68 | { 69 | var menuItem = new MenuItem() 70 | { 71 | Tag = cMenuItem.Action, 72 | Header = Framework.StringFormat.Format(cMenuItem.Header, new { LibraryFullPath = DirectoryInfo.FullName, FreeDiskSpace = PrettyFreeSpace }), 73 | Icon = cMenuItem.Icon, 74 | HorizontalContentAlignment = HorizontalAlignment.Left, 75 | VerticalContentAlignment = VerticalAlignment.Center 76 | }; 77 | 78 | menuItem.Click += Main.FormAccessor.LibraryCMenuItem_Click; 79 | 80 | cMenu.Add(menuItem); 81 | } 82 | } 83 | 84 | return cMenu; 85 | } 86 | catch (FormatException ex) 87 | { 88 | MessageBox.Show(Framework.StringFormat.Format(Functions.SLM.Translate(nameof(Properties.Resources.FormatException)), new { ExceptionMessage = ex.Message })); 89 | return cMenu; 90 | } 91 | } 92 | 93 | public abstract void UpdateAppList(); 94 | 95 | public abstract void ParseMenuItemActionAsync(string action); 96 | 97 | public abstract void RemoveLibraryAsync(bool withFiles); 98 | 99 | public abstract void UpdateJunks(); 100 | 101 | public abstract void UpdateDupes(); 102 | 103 | public void UpdateDiskDetails() 104 | { 105 | Functions.FileSystem.GetDiskFreeSpaceEx(_fullPath, out var freeSpace, out var totalSpace, out var totalFreeSpace); 106 | 107 | FreeSpace = (long)freeSpace; 108 | TotalSize = (long)totalSpace; 109 | 110 | OnPropertyChanged("DirectoryInfo"); 111 | OnPropertyChanged("FreeSpace"); 112 | OnPropertyChanged("PrettyFreeSpace"); 113 | OnPropertyChanged("FreeSpacePerc"); 114 | } 115 | 116 | public event PropertyChangedEventHandler PropertyChanged; 117 | 118 | protected void OnPropertyChanged(string info) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info)); 119 | } 120 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/List.cs: -------------------------------------------------------------------------------- 1 | using Steam_Library_Manager.Definitions.Enums; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Collections.ObjectModel; 5 | using System.ComponentModel; 6 | using System.Threading; 7 | 8 | namespace Steam_Library_Manager.Definitions 9 | { 10 | // Our Library and Game definitions exists there 11 | public static class List 12 | { 13 | // Make a new list for Library details 14 | public static ObservableCollection<Library> Libraries { get; set; } = new ObservableCollection<Library>(); 15 | 16 | public static ObservableCollection<JunkInfo> JunkItems { get; set; } = new ObservableCollection<JunkInfo>(); 17 | public static ObservableCollection<DupeInfo> DupeItems { get; set; } = new ObservableCollection<DupeInfo>(); 18 | public static ObservableCollection<string> IgnoredJunkItems { get; set; } = new ObservableCollection<string>(); 19 | 20 | public static readonly IProgress<Library> LibraryProgress = new Progress<Library>(library => Libraries.Add(library)); 21 | public static readonly IProgress<JunkInfo> LcProgress = new Progress<JunkInfo>(junk => JunkItems.Add(junk)); 22 | public static readonly IProgress<DupeInfo> DupeItemsRemove = new Progress<DupeInfo>(dupe => DupeItems.Remove(dupe)); 23 | 24 | public static ObservableCollection<ContextMenuItem> LibraryCMenuItems { get; set; } = new ObservableCollection<ContextMenuItem>(); 25 | public static ObservableCollection<ContextMenuItem> AppCMenuItems { get; set; } = new ObservableCollection<ContextMenuItem>(); 26 | 27 | public static readonly List<Tuple<string, string>> SteamUserIdList = new List<Tuple<string, string>>(); 28 | public static readonly Dictionary<int, DateTime> SteamAppsLastPlayedDic = new Dictionary<int, DateTime>(); 29 | public static readonly List<UplayConfigurationDb> UplayConfigurations = new List<UplayConfigurationDb>(); 30 | public static readonly Dictionary<string, int> UplayAppIds = new Dictionary<string, int>(); 31 | 32 | public class TaskInfo : INotifyPropertyChanged 33 | { 34 | public TaskType TaskType { get; set; } 35 | public App App { get; set; } 36 | public Library TargetLibrary { get; set; } 37 | public CompactLevel CompactLevel { get; set; } = (CompactLevel)Enum.Parse(typeof(CompactLevel), Properties.Settings.Default.DefaultCompactLevel); 38 | public bool Compact { get; set; } = true; 39 | public bool ForceCompact { get; set; } 40 | 41 | public bool ErrorHappened { get; set; } 42 | public bool Active { get; set; } 43 | public bool Completed { get; set; } 44 | public bool AutoInstall { get; set; } 45 | public bool Compress { get; set; } = Properties.Settings.Default.Global_Compress; 46 | public bool RemoveOldFiles { get; set; } = Properties.Settings.Default.Global_RemoveOldFiles; 47 | public bool ReportFileMovement { get; set; } = Properties.Settings.Default.Global_ReportFileMovement; 48 | public System.Diagnostics.Stopwatch ElapsedTime = new System.Diagnostics.Stopwatch(); 49 | public ManualResetEvent mre = new ManualResetEvent(!Functions.TaskManager.Paused); 50 | 51 | private long _movedFileSize; 52 | public string TaskProgressInfo => (_movedFileSize == 0) ? "" : $"{_movedFileSize / 1024000} MB / {TotalFileSize / 1024000} MB"; 53 | 54 | public string TaskStatusInfo { get; set; } 55 | 56 | public int TotalFileCount { get; set; } 57 | 58 | public long MovedFileSize 59 | { 60 | get => _movedFileSize; 61 | set 62 | { 63 | _movedFileSize = value; 64 | OnPropertyChanged("MovedFileSize"); 65 | OnPropertyChanged("ProgressBarPerc"); 66 | OnPropertyChanged("TaskProgressInfo"); 67 | } 68 | } 69 | 70 | public long TotalFileSize { get; set; } 71 | 72 | public double ProgressBarPerc 73 | { 74 | get 75 | { 76 | double perc = 0; 77 | if (_movedFileSize != 0) 78 | { 79 | perc = Math.Floor((double)(100 * _movedFileSize) / TotalFileSize); 80 | } 81 | 82 | return _movedFileSize == 0 ? 0 : perc; 83 | } 84 | } 85 | 86 | public event PropertyChangedEventHandler PropertyChanged; 87 | 88 | protected void OnPropertyChanged(string info) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info)); 89 | } 90 | 91 | public class TmInfo : INotifyPropertyChanged 92 | { 93 | public int PendingTasks { get; set; } 94 | public int CompletedTasks { get; set; } 95 | public int TotalTasks { get; set; } 96 | 97 | public event PropertyChangedEventHandler PropertyChanged; 98 | } 99 | 100 | public class JunkInfo 101 | { 102 | public Alphaleonis.Win32.Filesystem.FileSystemInfo FSInfo { get; set; } 103 | public Library Library { get; set; } 104 | public App App { get; set; } 105 | public string Size { get; set; } 106 | public JunkType Tag { get; set; } 107 | } 108 | 109 | public class DupeInfo 110 | { 111 | public App App1 { get; set; } 112 | public App App2 { get; set; } 113 | public string Size { get; set; } 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/OriginAppInfo.cs: -------------------------------------------------------------------------------- 1 | using MahApps.Metro.Controls.Dialogs; 2 | using System; 3 | using System.Diagnostics; 4 | using Alphaleonis.Win32.Filesystem; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace Steam_Library_Manager.Definitions 9 | { 10 | public class OriginAppInfo : App 11 | { 12 | public string[] Locales { get; set; } 13 | 14 | public string InstalledLocale { get; set; } 15 | public FileInfo TouchupFile { get; set; } 16 | public string InstallationParameter { get; set; } 17 | public string UpdateParameter { get; set; } 18 | public string RepairParameter { get; set; } 19 | public Version AppVersion { get; set; } 20 | 21 | public OriginAppInfo(Library library, string appName, int appId, DirectoryInfo installationDirectory, Version appVersion, string[] locales, string installedLocale, bool isCompressed, string touchupFile, string installationParameter, string updateParameter = null, string repairParameter = null) 22 | { 23 | Library = library; 24 | AppName = appName; 25 | AppId = appId; 26 | Locales = locales; 27 | InstalledLocale = installedLocale; 28 | InstallationDirectory = installationDirectory; 29 | TouchupFile = new FileInfo(installationDirectory.FullName + touchupFile); 30 | InstallationParameter = installationParameter; 31 | UpdateParameter = updateParameter; 32 | RepairParameter = repairParameter; 33 | AppVersion = appVersion; 34 | LastUpdated = InstallationDirectory.LastWriteTime; 35 | IsCompressed = isCompressed; 36 | CompressedArchivePath = new FileInfo(Path.Combine(Library.FullPath, AppId + ".zip")); 37 | SizeOnDisk = (!IsCompressed) ? Functions.FileSystem.GetDirectorySize(InstallationDirectory, true) : CompressedArchivePath.Length; 38 | IsCompacted = CompactStatus().Result; 39 | } 40 | 41 | public override async void ParseMenuItemActionAsync(string action) 42 | { 43 | try 44 | { 45 | switch (action.ToLowerInvariant()) 46 | { 47 | case "disk": 48 | InstallationDirectory.Refresh(); 49 | 50 | if (InstallationDirectory.Exists) 51 | { 52 | Process.Start(InstallationDirectory.FullName); 53 | } 54 | 55 | break; 56 | 57 | case "compress": 58 | if (Functions.TaskManager.TaskList.Count(x => x.App == this && x.TargetLibrary == Library && x.TaskType == Enums.TaskType.Compress) == 0) 59 | { 60 | Functions.TaskManager.AddTask(new List.TaskInfo 61 | { 62 | App = this, 63 | TargetLibrary = Library, 64 | TaskType = Enums.TaskType.Compress, 65 | Compress = !IsCompressed 66 | }); 67 | } 68 | break; 69 | 70 | case "compact": 71 | if (Functions.TaskManager.TaskList.Count(x => x.App == this && x.TargetLibrary == Library && x.TaskType == Enums.TaskType.Compact) == 0) 72 | { 73 | Functions.TaskManager.AddTask(new List.TaskInfo 74 | { 75 | App = this, 76 | TargetLibrary = Library, 77 | TaskType = Enums.TaskType.Compact 78 | }); 79 | } 80 | break; 81 | 82 | case "install": 83 | 84 | await InstallAsync().ConfigureAwait(true); 85 | 86 | break; 87 | 88 | case "repair": 89 | 90 | await InstallAsync(true).ConfigureAwait(true); 91 | 92 | break; 93 | 94 | case "deleteappfiles": 95 | await Task.Run(async () => await DeleteFilesAsync()).ConfigureAwait(true); 96 | 97 | Library.Apps.Remove(this); 98 | if (SLM.CurrentSelectedLibrary == Library) 99 | Functions.App.UpdateAppPanel(Library); 100 | 101 | break; 102 | 103 | case "deleteappfilestm": 104 | Functions.TaskManager.AddTask(new List.TaskInfo 105 | { 106 | App = this, 107 | TargetLibrary = Library, 108 | TaskType = Enums.TaskType.Delete 109 | }); 110 | break; 111 | } 112 | } 113 | catch (Exception ex) 114 | { 115 | Logger.Error(ex); 116 | } 117 | } 118 | 119 | public async Task InstallAsync(bool repair = false) 120 | { 121 | try 122 | { 123 | TouchupFile.Refresh(); 124 | 125 | if (TouchupFile.Exists && !string.IsNullOrEmpty(InstallationParameter)) 126 | { 127 | if (repair && string.IsNullOrEmpty(RepairParameter)) 128 | { 129 | return; 130 | } 131 | 132 | await Main.FormAccessor.AppView.AppPanel.Dispatcher.Invoke(async delegate 133 | { 134 | var progressInformationMessage = await Main.FormAccessor.ShowProgressAsync(Functions.SLM.Translate(nameof(Properties.Resources.PleaseWait)), Framework.StringFormat.Format(Functions.SLM.Translate(nameof(Properties.Resources.OriginInstallation_Start)), new { AppName })).ConfigureAwait(true); 135 | progressInformationMessage.SetIndeterminate(); 136 | 137 | var process = Process.Start(TouchupFile.FullName, ((repair) ? RepairParameter : InstallationParameter).Replace("{locale}", InstalledLocale).Replace("{installLocation}", InstallationDirectory.FullName)); 138 | 139 | Debug.WriteLine(InstallationParameter.Replace("{locale}", InstalledLocale).Replace("{installLocation}", InstallationDirectory.FullName)); 140 | 141 | progressInformationMessage.SetMessage(Framework.StringFormat.Format(Functions.SLM.Translate(nameof(Properties.Resources.OriginInstallation_Ongoing)), new { AppName })); 142 | 143 | while (!process.HasExited) 144 | { 145 | await Task.Delay(100).ConfigureAwait(true); 146 | } 147 | 148 | await progressInformationMessage.CloseAsync().ConfigureAwait(true); 149 | 150 | var installLog = File.ReadAllLines(Path.Combine(InstallationDirectory.FullName, "__Installer", "InstallLog.txt")).Reverse().ToList(); 151 | if (installLog.Any(x => x.IndexOf("Installer finished with exit code:", StringComparison.OrdinalIgnoreCase) != -1)) 152 | { 153 | var installerResult = installLog.FirstOrDefault(x => x.IndexOf("Installer finished with exit code:", StringComparison.OrdinalIgnoreCase) != -1); 154 | 155 | await Main.FormAccessor.ShowMessageAsync(Functions.SLM.Translate(nameof(Properties.Resources.OriginInstallation)), Framework.StringFormat.Format(Functions.SLM.Translate(nameof(Properties.Resources.OriginInstallation_Completed)), new { installerResult })).ConfigureAwait(true); 156 | } 157 | }).ConfigureAwait(true); 158 | } 159 | } 160 | catch (Exception ex) 161 | { 162 | Logger.Error(ex); 163 | } 164 | } 165 | } 166 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/OriginLibrary.cs: -------------------------------------------------------------------------------- 1 | using Dasync.Collections; 2 | using Newtonsoft.Json.Linq; 3 | using System; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.IO.Compression; 7 | using System.Linq; 8 | using System.Net; 9 | using System.Windows; 10 | using Directory = Alphaleonis.Win32.Filesystem.Directory; 11 | using DirectoryInfo = Alphaleonis.Win32.Filesystem.DirectoryInfo; 12 | 13 | namespace Steam_Library_Manager.Definitions 14 | { 15 | public class OriginLibrary : Library 16 | { 17 | public OriginLibrary(string fullPath, bool isMain = false) 18 | { 19 | FullPath = fullPath; 20 | IsMain = isMain; 21 | Type = Enums.LibraryType.Origin; 22 | DirectoryInfo = new DirectoryInfo(fullPath); 23 | 24 | AllowedAppTypes.Add(Enums.LibraryType.Origin); 25 | } 26 | 27 | public override async void UpdateAppList() 28 | { 29 | try 30 | { 31 | if (IsUpdatingAppList) 32 | return; 33 | 34 | IsUpdatingAppList = true; 35 | 36 | Apps.Clear(); 37 | 38 | if (!Directory.Exists(FullPath)) 39 | { 40 | IsUpdatingAppList = false; 41 | return; 42 | } 43 | 44 | await Directory.EnumerateFiles(FullPath, "installerdata.xml", SearchOption.AllDirectories) 45 | .ParallelForEachAsync( 46 | async filePath => 47 | { 48 | await Functions.Origin.ParseAppDetailsAsync(new StreamReader(filePath).BaseStream, filePath, this); 49 | }); 50 | 51 | await Directory.EnumerateFiles(FullPath, "*.zip", SearchOption.TopDirectoryOnly).ParallelForEachAsync(async originCompressedArchive => 52 | { 53 | using (var archive = ZipFile.OpenRead(originCompressedArchive)) 54 | { 55 | if (archive.Entries.Count > 0) 56 | { 57 | foreach (var archiveEntry in archive.Entries.Where(x => x.Name.Contains("installerdata.xml"))) 58 | { 59 | await Functions.Origin.ParseAppDetailsAsync(archiveEntry.Open(), originCompressedArchive, this, true); 60 | } 61 | } 62 | } 63 | }); 64 | 65 | if (SLM.CurrentSelectedLibrary != null && SLM.CurrentSelectedLibrary == this) 66 | { 67 | Functions.App.UpdateAppPanel(this); 68 | } 69 | 70 | IsUpdatingAppList = false; 71 | } 72 | catch (Exception ex) 73 | { 74 | MessageBox.Show(Framework.StringFormat.Format(Functions.SLM.Translate(nameof(Properties.Resources.OriginUpdateAppListException)), new { FullPath, ex })); 75 | Logger.Fatal(ex); 76 | } 77 | } 78 | 79 | public override void ParseMenuItemActionAsync(string action) 80 | { 81 | switch (action.ToLowerInvariant()) 82 | { 83 | case "disk": 84 | if (Directory.Exists(FullPath)) 85 | { 86 | Process.Start(FullPath); 87 | } 88 | break; 89 | 90 | case "remove": 91 | RemoveLibraryAsync(false); 92 | break; 93 | } 94 | } 95 | 96 | public override void RemoveLibraryAsync(bool withFiles) 97 | { 98 | if (withFiles) 99 | { 100 | throw new NotImplementedException(); 101 | } 102 | else 103 | { 104 | List.Libraries.Remove(this); 105 | } 106 | } 107 | 108 | public JObject GetGameLocalData(string gameId) 109 | { 110 | try 111 | { 112 | var client = new WebClient(); 113 | 114 | return JObject.Parse(client.DownloadString($"https://api1.origin.com/ecommerce2/public/{gameId}/en_US")); 115 | } 116 | catch (Exception ex) 117 | { 118 | Logger.Fatal(ex); 119 | Debug.WriteLine(ex); 120 | return null; 121 | } 122 | } 123 | 124 | public override void UpdateJunks() 125 | { 126 | throw new NotImplementedException(); 127 | } 128 | 129 | public override void UpdateDupes() 130 | { 131 | throw new NotImplementedException(); 132 | } 133 | } 134 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/SLM.cs: -------------------------------------------------------------------------------- 1 | namespace Steam_Library_Manager.Definitions 2 | { 3 | // Definitions related to Steam Library Manager (SLM) 4 | public static class SLM 5 | { 6 | public static Library CurrentSelectedLibrary; 7 | } 8 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/Settings.cs: -------------------------------------------------------------------------------- 1 | using Steam_Library_Manager.Definitions.Enums; 2 | using System; 3 | 4 | namespace Steam_Library_Manager.Definitions 5 | { 6 | public class Settings 7 | { 8 | public AppSortingMethod Setting_AppSortingMethod 9 | { 10 | get => (AppSortingMethod)Enum.Parse(typeof(AppSortingMethod), Properties.Settings.Default.defaultGameSortingMethod); 11 | set => Properties.Settings.Default.defaultGameSortingMethod = value.ToString(); 12 | } 13 | 14 | public AppSizeCalculationMethod Setting_AppSizeCalculationMethod 15 | { 16 | get => (AppSizeCalculationMethod)Enum.Parse(typeof(AppSizeCalculationMethod), Properties.Settings.Default.gameSizeCalculationMethod); 17 | set => Properties.Settings.Default.gameSizeCalculationMethod = value.ToString(); 18 | } 19 | 20 | public ArchiveSizeCalculationMethod Setting_ArchiveSizeCalculationMethod 21 | { 22 | get => (ArchiveSizeCalculationMethod)Enum.Parse(typeof(ArchiveSizeCalculationMethod), Properties.Settings.Default.archiveSizeCalculationMethod); 23 | set => Properties.Settings.Default.archiveSizeCalculationMethod = value.ToString(); 24 | } 25 | 26 | public CompressionLevel Setting_CompressionLevel 27 | { 28 | get => (CompressionLevel)Enum.Parse(typeof(CompressionLevel), Properties.Settings.Default.CompressionLevel); 29 | set => Properties.Settings.Default.CompressionLevel = value.ToString(); 30 | } 31 | 32 | public LibraryStyle Setting_LibraryStyle 33 | { 34 | get => (LibraryStyle)Enum.Parse(typeof(LibraryStyle), Properties.Settings.Default.LibraryStyle); 35 | set => Properties.Settings.Default.LibraryStyle = value.ToString(); 36 | } 37 | 38 | public ThemeAccents Setting_ThemeAccent 39 | { 40 | get => (ThemeAccents)Enum.Parse(typeof(ThemeAccents), Properties.Settings.Default.ThemeAccent); 41 | set => Properties.Settings.Default.ThemeAccent = value.ToString(); 42 | } 43 | 44 | public BaseTheme Setting_BaseTheme 45 | { 46 | get => (BaseTheme)Enum.Parse(typeof(BaseTheme), Properties.Settings.Default.BaseTheme); 47 | set => Properties.Settings.Default.BaseTheme = value.ToString(); 48 | } 49 | 50 | public CompactLevel Setting_CompactLevel 51 | { 52 | get => (CompactLevel)Enum.Parse(typeof(CompactLevel), Properties.Settings.Default.DefaultCompactLevel); 53 | set => Properties.Settings.Default.DefaultCompactLevel = value.ToString(); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/SteamAppInfo.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using DirectoryInfo = Alphaleonis.Win32.Filesystem.DirectoryInfo; 3 | using FileInfo = Alphaleonis.Win32.Filesystem.FileInfo; 4 | using Path = Alphaleonis.Win32.Filesystem.Path; 5 | 6 | namespace Steam_Library_Manager.Definitions 7 | { 8 | public class SteamAppInfo : App 9 | { 10 | public bool IsSteamBackup { get; set; } 11 | 12 | public SteamAppInfo(int appId, Library library, DirectoryInfo installationDirectory) 13 | { 14 | AppId = appId; 15 | Library = library; 16 | InstallationDirectory = installationDirectory; 17 | GameHeaderImage = $"http://cdn.akamai.steamstatic.com/steam/apps/{AppId}/header.jpg"; 18 | 19 | CompressedArchivePath = new FileInfo(Path.Combine(Library.DirectoryList["SteamApps"].FullName, AppId + ".zip")); 20 | 21 | AdditionalDirectories.Add((new DirectoryInfo(Path.Combine(Library.DirectoryList["Download"].FullName, InstallationDirectory.Name)), "*", SearchOption.AllDirectories)); 22 | AdditionalDirectories.Add((new DirectoryInfo(Path.Combine(Library.DirectoryList["Workshop"].FullName, "content", AppId.ToString())), "*", SearchOption.AllDirectories)); 23 | AdditionalDirectories.Add((Library.DirectoryList["Download"], $"*{AppId}*.patch", SearchOption.TopDirectoryOnly)); 24 | 25 | AdditionalFiles.Add(new FileInfo(Path.Combine(Library.DirectoryList["SteamApps"].FullName, $"appmanifest_{AppId}.acf"))); 26 | AdditionalFiles.Add(new FileInfo(Path.Combine(Library.DirectoryList["Workshop"].FullName, $"appworkshop_{AppId}.acf"))); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/Updater.cs: -------------------------------------------------------------------------------- 1 | namespace Steam_Library_Manager.Definitions 2 | { 3 | internal static class Updater 4 | { 5 | // Update control URL 6 | public static string VersionControlUrl = "https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/master/Binaries/Version.xml"; 7 | } 8 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/UplayAppInfo.cs: -------------------------------------------------------------------------------- 1 | using MahApps.Metro.Controls.Dialogs; 2 | using Microsoft.Win32; 3 | using System; 4 | using System.Diagnostics; 5 | using Alphaleonis.Win32.Filesystem; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | namespace Steam_Library_Manager.Definitions 10 | { 11 | public class UplayAppInfo : App 12 | { 13 | public string SpaceId { get; set; } 14 | 15 | public UplayAppInfo(Library library, string appName, string spaceId, DirectoryInfo installationDirectory, string headerImage, bool isCompressed) 16 | { 17 | Library = library; 18 | AppName = appName; 19 | SpaceId = spaceId; 20 | InstallationDirectory = installationDirectory; 21 | 22 | if (List.UplayAppIds.ContainsKey(AppName)) 23 | { 24 | AppId = List.UplayAppIds[AppName]; 25 | 26 | Debug.WriteLine($"AppId ({AppId}) set for Uplay game: {AppName}"); 27 | } 28 | 29 | if (!string.IsNullOrEmpty(Properties.Settings.Default.UplayExePath)) 30 | { 31 | var fileInfo = new FileInfo(Properties.Settings.Default.UplayExePath); 32 | 33 | if (fileInfo.Exists) 34 | { 35 | var assetsDirectoryInfo = new DirectoryInfo(Path.Combine(fileInfo.DirectoryName, "cache", "assets")); 36 | 37 | if (assetsDirectoryInfo.Exists) 38 | { 39 | Framework.CachedImage.FileCache.HitAsync(Path.Combine(assetsDirectoryInfo.FullName, headerImage), $"{headerImage.Replace(".jpg", "")}_u") 40 | .ConfigureAwait(false); 41 | 42 | GameHeaderImage = $"{Directories.SLM.Cache}\\{headerImage.Replace(".jpg", "")}_u.jpg"; 43 | } 44 | else 45 | { 46 | Logger.Warn($"Cache/Assets directory doesn't exists: {assetsDirectoryInfo.FullName}"); 47 | } 48 | } 49 | else 50 | { 51 | Logger.Warn($"Uplay Executable Path doesn't exists: {Properties.Settings.Default.UplayExePath}"); 52 | } 53 | } 54 | else 55 | { 56 | Logger.Warn($"Uplay Executable Path not set."); 57 | } 58 | 59 | IsCompressed = isCompressed; 60 | 61 | LastUpdated = InstallationDirectory.LastWriteTime; 62 | CompressedArchivePath = new FileInfo(Path.Combine(Library.FullPath, AppName + ".zip")); 63 | SizeOnDisk = (!IsCompressed) ? Functions.FileSystem.GetDirectorySize(InstallationDirectory, true) : CompressedArchivePath.Length; 64 | IsCompacted = CompactStatus().Result; 65 | } 66 | 67 | public override async void ParseMenuItemActionAsync(string action) 68 | { 69 | try 70 | { 71 | switch (action.ToLowerInvariant()) 72 | { 73 | default: 74 | if (AppId != 0) 75 | { 76 | Process.Start(string.Format(action, AppId)); 77 | } 78 | 79 | break; 80 | 81 | case "disk": 82 | InstallationDirectory.Refresh(); 83 | 84 | if (InstallationDirectory.Exists) 85 | { 86 | Process.Start(InstallationDirectory.FullName); 87 | } 88 | 89 | break; 90 | 91 | case "install": 92 | await InstallAsync(); 93 | break; 94 | 95 | case "compress": 96 | if (Functions.TaskManager.TaskList.Count(x => x.App == this && x.TargetLibrary == Library && x.TaskType == Enums.TaskType.Compress) == 0) 97 | { 98 | Functions.TaskManager.AddTask(new List.TaskInfo 99 | { 100 | App = this, 101 | TargetLibrary = Library, 102 | TaskType = Enums.TaskType.Compress, 103 | Compress = !IsCompressed 104 | }); 105 | } 106 | break; 107 | 108 | case "compact": 109 | if (Functions.TaskManager.TaskList.Count(x => x.App == this && x.TargetLibrary == Library && x.TaskType == Enums.TaskType.Compact) == 0) 110 | { 111 | Functions.TaskManager.AddTask(new List.TaskInfo 112 | { 113 | App = this, 114 | TargetLibrary = Library, 115 | TaskType = Enums.TaskType.Compact 116 | }); 117 | } 118 | break; 119 | 120 | case "deleteappfiles": 121 | await Task.Run(async () => await DeleteFilesAsync()).ConfigureAwait(false); 122 | 123 | Library.Apps.Remove(this); 124 | if (SLM.CurrentSelectedLibrary == Library) 125 | Functions.App.UpdateAppPanel(Library); 126 | 127 | break; 128 | 129 | case "deleteappfilestm": 130 | Functions.TaskManager.AddTask(new List.TaskInfo 131 | { 132 | App = this, 133 | TargetLibrary = Library, 134 | TaskType = Enums.TaskType.Delete 135 | }); 136 | break; 137 | } 138 | } 139 | catch (Exception ex) 140 | { 141 | Logger.Error(ex); 142 | } 143 | } 144 | 145 | public async Task InstallAsync() 146 | { 147 | try 148 | { 149 | if (AppId <= 0) return; 150 | 151 | var installationsRegistry = 152 | RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32) 153 | .OpenSubKey(Global.Uplay.InstallationsRegistryPath) ?? RegistryKey 154 | .OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) 155 | .OpenSubKey(Global.Uplay.InstallationsRegistryPath); 156 | 157 | using (var registry = installationsRegistry) 158 | { 159 | using (var appRegistry = registry?.OpenSubKey(AppId.ToString(), RegistryKeyPermissionCheck.ReadWriteSubTree)) 160 | { 161 | if (appRegistry?.GetValue("InstallDir") != null) 162 | { 163 | appRegistry.SetValue("InstallDir", !InstallationDirectory.FullName.EndsWith(Path.DirectorySeparatorChar.ToString()) ? string.Join("", InstallationDirectory.FullName, Path.DirectorySeparatorChar).Replace(Path.DirectorySeparatorChar, '/') : InstallationDirectory.FullName.Replace(Path.DirectorySeparatorChar, '/')); 164 | } 165 | } 166 | } 167 | } 168 | catch (UnauthorizedAccessException ex) 169 | { 170 | await Main.FormAccessor.AppView.AppPanel.Dispatcher.Invoke(async delegate 171 | { 172 | await Main.FormAccessor.ShowMessageAsync( 173 | Functions.SLM.Translate(nameof(Properties.Resources.Uplay_UnauthorizedAccessExceptionTitle)), 174 | Framework.StringFormat.Format( 175 | Functions.SLM.Translate(nameof(Properties.Resources.Uplay_UnauthorizedAccessExceptionMessage)), 176 | new { AppName, ExceptionMessage = ex.Message })).ConfigureAwait(true); 177 | }, System.Windows.Threading.DispatcherPriority.Normal).ConfigureAwait(true); 178 | 179 | Logger.Fatal(ex); 180 | } 181 | catch (Exception ex) 182 | { 183 | Logger.Fatal(ex); 184 | } 185 | } 186 | } 187 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/UplayConfigurationDb.cs: -------------------------------------------------------------------------------- 1 | namespace Steam_Library_Manager.Definitions 2 | { 3 | public class UplayConfigurationDb 4 | { 5 | public string Name, ThumbImage, SpaceId; 6 | public bool Legacy; 7 | } 8 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Definitions/UplayLibrary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Windows; 5 | using Directory = Alphaleonis.Win32.Filesystem.Directory; 6 | using DirectoryInfo = Alphaleonis.Win32.Filesystem.DirectoryInfo; 7 | using File = Alphaleonis.Win32.Filesystem.File; 8 | using FileInfo = Alphaleonis.Win32.Filesystem.FileInfo; 9 | using Path = Alphaleonis.Win32.Filesystem.Path; 10 | 11 | namespace Steam_Library_Manager.Definitions 12 | { 13 | public class UplayLibrary : Library 14 | { 15 | public UplayLibrary(string fullPath, bool isMain = false) 16 | { 17 | FullPath = fullPath; 18 | IsMain = isMain; 19 | Type = Enums.LibraryType.Uplay; 20 | DirectoryInfo = new DirectoryInfo(fullPath); 21 | 22 | AllowedAppTypes.Add(Enums.LibraryType.Uplay); 23 | } 24 | 25 | public override void UpdateAppList() 26 | { 27 | try 28 | { 29 | if (IsUpdatingAppList) 30 | return; 31 | 32 | IsUpdatingAppList = true; 33 | 34 | Apps.Clear(); 35 | 36 | if (!Directory.Exists(FullPath)) 37 | { 38 | IsUpdatingAppList = false; 39 | return; 40 | } 41 | 42 | foreach (var directoryPath in Directory.EnumerateDirectories(FullPath, "*", 43 | SearchOption.TopDirectoryOnly)) 44 | { 45 | var dirInfo = new DirectoryInfo(directoryPath); 46 | 47 | if (!File.Exists(Path.Combine(dirInfo.FullName, "uplay_install.state"))) 48 | { 49 | if (List.IgnoredJunkItems.Contains(dirInfo.FullName)) 50 | { 51 | continue; 52 | } 53 | 54 | List.LcProgress.Report(new List.JunkInfo 55 | { 56 | FSInfo = dirInfo, 57 | Size = Functions.FileSystem.FormatBytes(Functions.FileSystem.GetDirectorySize(dirInfo, true)), 58 | Library = this, 59 | Tag = Enums.JunkType.HeadlessFolder 60 | }); 61 | continue; 62 | } 63 | 64 | Functions.Uplay.ParseAppDetails(dirInfo.Name, dirInfo, this); 65 | } 66 | 67 | foreach (var archivePath in Directory.EnumerateFiles(FullPath, "*.zip", SearchOption.TopDirectoryOnly)) 68 | { 69 | var fileInfo = new FileInfo(archivePath); 70 | Functions.Uplay.ParseAppDetails(fileInfo.Name.Replace(".zip", ""), fileInfo.Directory, this, true); 71 | } 72 | 73 | if (SLM.CurrentSelectedLibrary != null && SLM.CurrentSelectedLibrary == this) 74 | { 75 | Functions.App.UpdateAppPanel(this); 76 | } 77 | 78 | IsUpdatingAppList = false; 79 | } 80 | catch (Exception ex) 81 | { 82 | MessageBox.Show(Framework.StringFormat.Format(Functions.SLM.Translate(nameof(Properties.Resources.Uplay_UpdateAppListError)), new { FullPath, ex })); 83 | Logger.Fatal(ex); 84 | } 85 | } 86 | 87 | public override void ParseMenuItemActionAsync(string action) 88 | { 89 | switch (action.ToLowerInvariant()) 90 | { 91 | case "disk": 92 | if (Directory.Exists(FullPath)) 93 | { 94 | Process.Start(FullPath); 95 | } 96 | break; 97 | 98 | case "remove": 99 | RemoveLibraryAsync(false); 100 | break; 101 | } 102 | } 103 | 104 | public override void RemoveLibraryAsync(bool withFiles) 105 | { 106 | if (withFiles) 107 | { 108 | throw new NotImplementedException(); 109 | } 110 | else 111 | { 112 | List.Libraries.Remove(this); 113 | } 114 | } 115 | 116 | public override void UpdateJunks() 117 | { 118 | throw new NotImplementedException(); 119 | } 120 | 121 | public override void UpdateDupes() 122 | { 123 | throw new NotImplementedException(); 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> 3 | <Costura /> 4 | <PropertyChanged/> 5 | </Weavers> -------------------------------------------------------------------------------- /Source/Steam Library Manager/FodyWeavers.xsd: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> 3 | <!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> 4 | <xs:element name="Weavers"> 5 | <xs:complexType> 6 | <xs:all> 7 | <xs:element name="PropertyChanged" minOccurs="0" maxOccurs="1"> 8 | <xs:complexType> 9 | <xs:attribute name="InjectOnPropertyNameChanged" type="xs:boolean"> 10 | <xs:annotation> 11 | <xs:documentation>Used to control if the On_PropertyName_Changed feature is enabled.</xs:documentation> 12 | </xs:annotation> 13 | </xs:attribute> 14 | <xs:attribute name="TriggerDependentProperties" type="xs:boolean"> 15 | <xs:annotation> 16 | <xs:documentation>Used to control if the Dependent properties feature is enabled.</xs:documentation> 17 | </xs:annotation> 18 | </xs:attribute> 19 | <xs:attribute name="EnableIsChangedProperty" type="xs:boolean"> 20 | <xs:annotation> 21 | <xs:documentation>Used to control if the IsChanged property feature is enabled.</xs:documentation> 22 | </xs:annotation> 23 | </xs:attribute> 24 | <xs:attribute name="EventInvokerNames" type="xs:string"> 25 | <xs:annotation> 26 | <xs:documentation>Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form.</xs:documentation> 27 | </xs:annotation> 28 | </xs:attribute> 29 | <xs:attribute name="CheckForEquality" type="xs:boolean"> 30 | <xs:annotation> 31 | <xs:documentation>Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project.</xs:documentation> 32 | </xs:annotation> 33 | </xs:attribute> 34 | <xs:attribute name="CheckForEqualityUsingBaseEquals" type="xs:boolean"> 35 | <xs:annotation> 36 | <xs:documentation>Used to control if equality checks should use the Equals method resolved from the base class.</xs:documentation> 37 | </xs:annotation> 38 | </xs:attribute> 39 | <xs:attribute name="UseStaticEqualsFromBase" type="xs:boolean"> 40 | <xs:annotation> 41 | <xs:documentation>Used to control if equality checks should use the static Equals method resolved from the base class.</xs:documentation> 42 | </xs:annotation> 43 | </xs:attribute> 44 | <xs:attribute name="SuppressWarnings" type="xs:boolean"> 45 | <xs:annotation> 46 | <xs:documentation>Used to turn off build warnings from this weaver.</xs:documentation> 47 | </xs:annotation> 48 | </xs:attribute> 49 | <xs:attribute name="SuppressOnPropertyNameChangedWarning" type="xs:boolean"> 50 | <xs:annotation> 51 | <xs:documentation>Used to turn off build warnings about mismatched On_PropertyName_Changed methods.</xs:documentation> 52 | </xs:annotation> 53 | </xs:attribute> 54 | </xs:complexType> 55 | </xs:element> 56 | <xs:element name="Costura" minOccurs="0" maxOccurs="1"> 57 | <xs:complexType> 58 | <xs:all> 59 | <xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string"> 60 | <xs:annotation> 61 | <xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation> 62 | </xs:annotation> 63 | </xs:element> 64 | <xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string"> 65 | <xs:annotation> 66 | <xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation> 67 | </xs:annotation> 68 | </xs:element> 69 | <xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string"> 70 | <xs:annotation> 71 | <xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation> 72 | </xs:annotation> 73 | </xs:element> 74 | <xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string"> 75 | <xs:annotation> 76 | <xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation> 77 | </xs:annotation> 78 | </xs:element> 79 | <xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string"> 80 | <xs:annotation> 81 | <xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation> 82 | </xs:annotation> 83 | </xs:element> 84 | </xs:all> 85 | <xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean"> 86 | <xs:annotation> 87 | <xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation> 88 | </xs:annotation> 89 | </xs:attribute> 90 | <xs:attribute name="IncludeDebugSymbols" type="xs:boolean"> 91 | <xs:annotation> 92 | <xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation> 93 | </xs:annotation> 94 | </xs:attribute> 95 | <xs:attribute name="DisableCompression" type="xs:boolean"> 96 | <xs:annotation> 97 | <xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation> 98 | </xs:annotation> 99 | </xs:attribute> 100 | <xs:attribute name="DisableCleanup" type="xs:boolean"> 101 | <xs:annotation> 102 | <xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation> 103 | </xs:annotation> 104 | </xs:attribute> 105 | <xs:attribute name="LoadAtModuleInit" type="xs:boolean"> 106 | <xs:annotation> 107 | <xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation> 108 | </xs:annotation> 109 | </xs:attribute> 110 | <xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean"> 111 | <xs:annotation> 112 | <xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation> 113 | </xs:annotation> 114 | </xs:attribute> 115 | <xs:attribute name="ExcludeAssemblies" type="xs:string"> 116 | <xs:annotation> 117 | <xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation> 118 | </xs:annotation> 119 | </xs:attribute> 120 | <xs:attribute name="IncludeAssemblies" type="xs:string"> 121 | <xs:annotation> 122 | <xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation> 123 | </xs:annotation> 124 | </xs:attribute> 125 | <xs:attribute name="Unmanaged32Assemblies" type="xs:string"> 126 | <xs:annotation> 127 | <xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation> 128 | </xs:annotation> 129 | </xs:attribute> 130 | <xs:attribute name="Unmanaged64Assemblies" type="xs:string"> 131 | <xs:annotation> 132 | <xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation> 133 | </xs:annotation> 134 | </xs:attribute> 135 | <xs:attribute name="PreloadOrder" type="xs:string"> 136 | <xs:annotation> 137 | <xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation> 138 | </xs:annotation> 139 | </xs:attribute> 140 | </xs:complexType> 141 | </xs:element> 142 | </xs:all> 143 | <xs:attribute name="VerifyAssembly" type="xs:boolean"> 144 | <xs:annotation> 145 | <xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> 146 | </xs:annotation> 147 | </xs:attribute> 148 | <xs:attribute name="VerifyIgnoreCodes" type="xs:string"> 149 | <xs:annotation> 150 | <xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> 151 | </xs:annotation> 152 | </xs:attribute> 153 | <xs:attribute name="GenerateXsd" type="xs:boolean"> 154 | <xs:annotation> 155 | <xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> 156 | </xs:annotation> 157 | </xs:attribute> 158 | </xs:complexType> 159 | </xs:element> 160 | </xs:schema> -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/AppView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Windows.Controls; 4 | using System.Windows.Input; 5 | 6 | namespace Steam_Library_Manager.Forms 7 | { 8 | /// <summary> 9 | /// Interaction logic for AppView.xaml 10 | /// </summary> 11 | public partial class AppView 12 | { 13 | private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); 14 | 15 | public AppView() => InitializeComponent(); 16 | 17 | private void Grid_MouseDown(object sender, MouseButtonEventArgs e) 18 | { 19 | try 20 | { 21 | if (e.ChangedButton != MouseButton.Left || e.ClickCount != 2) return; 22 | 23 | switch (((Grid)sender)?.DataContext) 24 | { 25 | default: 26 | { 27 | var appInfo = (Definitions.App)((Grid)sender)?.DataContext; 28 | if (appInfo?.InstallationDirectory.Exists == true) 29 | { 30 | Process.Start(appInfo?.InstallationDirectory.FullName); 31 | } 32 | 33 | break; 34 | } 35 | } 36 | } 37 | catch (Exception ex) 38 | { 39 | Logger.Error(ex); 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/HamburgerMenuControl.xaml: -------------------------------------------------------------------------------- 1 | <UserControl x:Class="Steam_Library_Manager.Forms.HamburgerMenuControl" 2 | xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 | xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" 4 | xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" 5 | xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 | xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 7 | xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 8 | xmlns:enums="clr-namespace:Steam_Library_Manager.Definitions.Enums" 9 | xmlns:p="clr-namespace:Steam_Library_Manager.Properties" 10 | xmlns:l="http://gu.se/Localization" 11 | mc:Ignorable="d"> 12 | <Grid> 13 | <Grid.Resources> 14 | <DataTemplate x:Key="MenuItemTemplate" DataType="{x:Type controls:HamburgerMenuIconItem}"> 15 | <Grid Height="64"> 16 | <Grid.ColumnDefinitions> 17 | <ColumnDefinition Width="48" /> 18 | <ColumnDefinition /> 19 | </Grid.ColumnDefinitions> 20 | <Image Grid.Column="0" Width="32" Height="32" HorizontalAlignment="Center" VerticalAlignment="Center" Source="{Binding Icon}" Focusable="False" /> 21 | <TextBlock Grid.Column="1" 22 | VerticalAlignment="Center" 23 | FontSize="18" 24 | FontWeight="SemiBold" 25 | Foreground="{DynamicResource TextBrush}" 26 | Text="{Binding Label}" /> 27 | <Grid.ToolTip> 28 | <TextBlock Text="{Binding Label}" /> 29 | </Grid.ToolTip> 30 | </Grid> 31 | </DataTemplate> 32 | <DataTemplate x:Key="MenuOptionsItemTemplate" DataType="{x:Type controls:HamburgerMenuIconItem}"> 33 | <Grid Height="64"> 34 | <Grid.ColumnDefinitions> 35 | <ColumnDefinition Width="48" /> 36 | <ColumnDefinition /> 37 | </Grid.ColumnDefinitions> 38 | <ContentControl 39 | Grid.Column="0" 40 | Content="{Binding Icon}" 41 | Focusable="False" 42 | HorizontalAlignment="Center" 43 | VerticalAlignment="Center" 44 | Foreground="{DynamicResource TextBrush}" /> 45 | <TextBlock Grid.Column="1" 46 | VerticalAlignment="Center" 47 | FontSize="18" 48 | FontWeight="SemiBold" 49 | Foreground="{DynamicResource TextBrush}" 50 | Text="{Binding Label}" /> 51 | <Grid.ToolTip> 52 | <TextBlock Text="{Binding Label}" /> 53 | </Grid.ToolTip> 54 | </Grid> 55 | </DataTemplate> 56 | <DataTemplate x:Key="HamburgerContentTemplate" DataType="{x:Type Grid}"> 57 | <Grid Height="1" Width="1" Visibility="Collapsed" /> 58 | </DataTemplate> 59 | </Grid.Resources> 60 | 61 | <controls:HamburgerMenu x:Name="Control" 62 | PaneBackground="{DynamicResource AccentColorBrush}" 63 | Foreground="{DynamicResource TextBrush}" 64 | IsPaneOpen="False" 65 | ItemTemplate="{StaticResource MenuItemTemplate}" 66 | OptionsItemTemplate="{StaticResource MenuOptionsItemTemplate}" 67 | Margin="3,10,0,50" DisplayMode="CompactInline" HorizontalAlignment="Left" VerticalAlignment="Stretch" Width="200" Content="" ContentTemplate="{StaticResource HamburgerContentTemplate}"> 68 | <controls:HamburgerMenu.ItemsSource> 69 | <controls:HamburgerMenuItemCollection> 70 | <controls:HamburgerMenuIconItem Label="{l:Static p:Resources.HamburgerMenuControl_AllAvailable}" Tag="All" Icon="/Steam Library Manager;component/Resources/slm-icon.ico" /> 71 | <controls:HamburgerMenuIconItem Label="{l:Static p:Resources.SteamSLM}" Icon="/Steam Library Manager;component/Resources/steam-icon.ico"> 72 | <controls:HamburgerMenuIconItem.Tag> 73 | <enums:LibraryType>Steam</enums:LibraryType> 74 | </controls:HamburgerMenuIconItem.Tag> 75 | </controls:HamburgerMenuIconItem> 76 | <controls:HamburgerMenuIconItem Label="{l:Static p:Resources.Origin}" Icon="/Steam Library Manager;component/Resources/origin-icon.ico"> 77 | <controls:HamburgerMenuIconItem.Tag> 78 | <enums:LibraryType>Origin</enums:LibraryType> 79 | </controls:HamburgerMenuIconItem.Tag> 80 | </controls:HamburgerMenuIconItem> 81 | <controls:HamburgerMenuIconItem Label="{l:Static p:Resources.Uplay}" Icon="/Steam Library Manager;component/Resources/uplay-icon.ico"> 82 | <controls:HamburgerMenuIconItem.Tag> 83 | <enums:LibraryType>Uplay</enums:LibraryType> 84 | </controls:HamburgerMenuIconItem.Tag> 85 | </controls:HamburgerMenuIconItem> 86 | </controls:HamburgerMenuItemCollection> 87 | </controls:HamburgerMenu.ItemsSource> 88 | <controls:HamburgerMenu.OptionsItemsSource> 89 | <controls:HamburgerMenuItemCollection> 90 | <controls:HamburgerMenuIconItem Label="{l:Static p:Resources.Settings}" Tag="Settings"> 91 | <controls:HamburgerMenuIconItem.Icon> 92 | <iconPacks:PackIconFontAwesome Kind="CogsSolid" Width="32" Height="32" /> 93 | </controls:HamburgerMenuIconItem.Icon> 94 | </controls:HamburgerMenuIconItem> 95 | </controls:HamburgerMenuItemCollection> 96 | </controls:HamburgerMenu.OptionsItemsSource> 97 | </controls:HamburgerMenu> 98 | </Grid> 99 | </UserControl> -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/HamburgerMenuControl.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Steam_Library_Manager.Forms 2 | { 3 | /// <summary> 4 | /// Interaction logic for HamburgerMenuControl.xaml 5 | /// </summary> 6 | public partial class HamburgerMenuControl 7 | { 8 | public HamburgerMenuControl() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/InstallationWizard/Final.xaml: -------------------------------------------------------------------------------- 1 | <UserControl x:Class="Steam_Library_Manager.Forms.InstallationWizard.Final" 2 | xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 | xmlns:l="http://gu.se/Localization" 4 | xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" 5 | xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 | xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 7 | xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 8 | xmlns:p="clr-namespace:Steam_Library_Manager.Properties" 9 | mc:Ignorable="d" 10 | d:DesignHeight="600" d:DesignWidth="500"> 11 | <StackPanel Orientation="Vertical"> 12 | <StackPanel Orientation="Horizontal"> 13 | <iconPacks:PackIconMaterial Kind="CheckAll" Height="48" Width="48" Margin="5, 0" /> 14 | <TextBlock TextWrapping="Wrap" FontSize="28" Text="{l:Static p:Resources.InstallationWizard_Completed}" /> 15 | </StackPanel> 16 | <Button Name="CloseButton" HorizontalAlignment="Stretch" Content="{l:Static p:Resources.Close}" Height="50" Margin="0,10" Style="{StaticResource AccentedSquareButtonStyle}" Click="CloseButton_OnClick" /> 17 | </StackPanel> 18 | </UserControl> -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/InstallationWizard/Final.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Windows; 4 | 5 | namespace Steam_Library_Manager.Forms.InstallationWizard 6 | { 7 | /// <summary> 8 | /// Interaction logic for Final.xaml 9 | /// </summary> 10 | public partial class Final 11 | { 12 | public Final() 13 | { 14 | InitializeComponent(); 15 | } 16 | 17 | private void CloseButton_OnClick(object sender, RoutedEventArgs e) 18 | { 19 | try 20 | { 21 | Window.GetWindow(this)?.Close(); 22 | } 23 | catch (Exception) 24 | { 25 | Debug.WriteLine("Failed to get window for installation wizard?"); 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/InstallationWizard/Library.xaml: -------------------------------------------------------------------------------- 1 | <UserControl x:Class="Steam_Library_Manager.Forms.InstallationWizard.Library" 2 | xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 | xmlns:l="http://gu.se/Localization" 4 | xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" 5 | xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 | xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 7 | xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 8 | xmlns:SLM="clr-namespace:Steam_Library_Manager" 9 | xmlns:p="clr-namespace:Steam_Library_Manager.Properties" 10 | mc:Ignorable="d" 11 | d:DesignHeight="500" d:DesignWidth="800"> 12 | <GroupBox Header="{l:Static p:Resources.LibrarySettings}"> 13 | <StackPanel Orientation="Vertical"> 14 | <GroupBox Header="Steam"> 15 | <WrapPanel Orientation="Vertical"> 16 | <mah:ToggleSwitch ThumbIndicatorBrush="{DynamicResource AccentColorBrush}" Margin="0, 5" Header="{l:Static p:Resources.SteamLibrarySupport}" IsChecked="{SLM:SettingBinding Steam_IsEnabled}" Style="{StaticResource MahApps.Metro.Styles.ToggleSwitch.Win10}"> 17 | <mah:ToggleSwitch.ToolTip> 18 | <ToolTip> 19 | <StackPanel> 20 | <TextBlock FontWeight="Bold" Text="{l:Static p:Resources.SteamLibrarySupport}" /> 21 | <TextBlock Text="{l:Static p:Resources.SteamLibrarySupport_Tooltip}" /> 22 | </StackPanel> 23 | </ToolTip> 24 | </mah:ToggleSwitch.ToolTip> 25 | </mah:ToggleSwitch> 26 | </WrapPanel> 27 | </GroupBox> 28 | <GroupBox Header="Origin"> 29 | <mah:ToggleSwitch ThumbIndicatorBrush="{DynamicResource AccentColorBrush}" Margin="5" Header="{l:Static p:Resources.OriginLibrarySupport}" IsChecked="{SLM:SettingBinding Origin_IsEnabled}" Style="{StaticResource MahApps.Metro.Styles.ToggleSwitch.Win10}"> 30 | <mah:ToggleSwitch.ToolTip> 31 | <ToolTip> 32 | <StackPanel> 33 | <TextBlock FontWeight="Bold" Text="{l:Static p:Resources.OriginLibrarySupport}" /> 34 | <TextBlock Text="{l:Static p:Resources.OriginLibrarySupport_Tooltip}" /> 35 | </StackPanel> 36 | </ToolTip> 37 | </mah:ToggleSwitch.ToolTip> 38 | </mah:ToggleSwitch> 39 | </GroupBox> 40 | <GroupBox Header="Uplay"> 41 | <WrapPanel Orientation="Vertical"> 42 | <mah:ToggleSwitch ThumbIndicatorBrush="{DynamicResource AccentColorBrush}" Margin="5" Header="{l:Static p:Resources.UplayLibrarySupport}" IsChecked="{SLM:SettingBinding Uplay_IsEnabled}" Style="{StaticResource MahApps.Metro.Styles.ToggleSwitch.Win10}"> 43 | <mah:ToggleSwitch.ToolTip> 44 | <ToolTip> 45 | <StackPanel> 46 | <TextBlock FontWeight="Bold" Text="{l:Static p:Resources.UplayLibrarySupport}" /> 47 | <TextBlock Text="{l:Static p:Resources.UplayLibrarySupport_Tooltip}" /> 48 | </StackPanel> 49 | </ToolTip> 50 | </mah:ToggleSwitch.ToolTip> 51 | </mah:ToggleSwitch> 52 | </WrapPanel> 53 | </GroupBox> 54 | </StackPanel> 55 | </GroupBox> 56 | </UserControl> -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/InstallationWizard/Library.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Steam_Library_Manager.Forms.InstallationWizard 2 | { 3 | /// <summary> 4 | /// Interaction logic for Steam.xaml 5 | /// </summary> 6 | public partial class Library 7 | { 8 | public Library() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/InstallationWizard/Welcome.xaml: -------------------------------------------------------------------------------- 1 | <UserControl x:Class="Steam_Library_Manager.Forms.InstallationWizard.Welcome" 2 | xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 | xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" 4 | xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 | xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 6 | xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 7 | xmlns:localization="clr-namespace:Gu.Localization;assembly=Gu.Localization" 8 | xmlns:l="clr-namespace:Gu.Wpf.Localization;assembly=Gu.Wpf.Localization" 9 | xmlns:slm="clr-namespace:Steam_Library_Manager" 10 | xmlns:enums="clr-namespace:Steam_Library_Manager.Definitions.Enums" 11 | xmlns:p="clr-namespace:Steam_Library_Manager.Properties" 12 | mc:Ignorable="d" 13 | d:DesignHeight="600" d:DesignWidth="500"> 14 | <GroupBox Header="{l:Static p:Resources.GeneralSettings}"> 15 | <WrapPanel> 16 | <TextBlock TextWrapping="Wrap" Text="{l:Static p:Resources.Welcome_Text}" /> 17 | <TextBlock TextWrapping="Wrap" Text="{l:Static p:Resources.Welcome_Text2}" /> 18 | <Separator Width="20" Height="30" Background="Transparent" /> 19 | <ComboBox BorderBrush="{DynamicResource AccentColorBrush}" Margin="0, 0, 5, 0" mah:TextBoxHelper.Watermark="{l:Static p:Resources.ThemeBase}" mah:TextBoxHelper.UseFloatingWatermark="True" HorizontalAlignment="Left" Height="50" 20 | VerticalContentAlignment="Center" VerticalAlignment="Top" Width="240" 21 | SelectedItem="{Binding Setting_BaseTheme}" ItemsSource="{slm:EnumBindingSource {x:Type enums:BaseTheme}}"> 22 | </ComboBox> 23 | 24 | <ComboBox BorderBrush="{DynamicResource AccentColorBrush}" mah:TextBoxHelper.Watermark="{l:Static p:Resources.ThemeAccent}" mah:TextBoxHelper.UseFloatingWatermark="True" HorizontalAlignment="Left" Height="50" 25 | VerticalContentAlignment="Center" VerticalAlignment="Top" Width="240" SelectedItem="{Binding Setting_ThemeAccent}" 26 | ItemsSource="{slm:EnumBindingSource {x:Type enums:ThemeAccents}}"> 27 | </ComboBox> 28 | 29 | <ComboBox BorderBrush="{DynamicResource AccentColorBrush}" Margin="0, 5" mah:TextBoxHelper.Watermark="{l:Static p:Resources.Language}" mah:TextBoxHelper.UseFloatingWatermark="True" 30 | VerticalContentAlignment="Center" VerticalAlignment="Top" Height="50" Width="240" 31 | SelectedItem="{Binding Path=(localization:Translator.Culture)}" ItemsSource="{Binding Path=(localization:Translator.Cultures)}" SelectionChanged="Selector_OnSelectionChanged"> 32 | </ComboBox> 33 | <!-- Check for Updates at Startup --> 34 | <mah:ToggleSwitch ThumbIndicatorBrush="{DynamicResource AccentColorBrush}" Margin="5" Header="{l:Static p:Resources.CheckForUpdatesAtStartup}" OnLabel="{l:Static p:Resources.Yes}" OffLabel="{l:Static p:Resources.No}" 35 | IsChecked="{slm:SettingBinding CheckforUpdatesAtStartup}" 36 | HorizontalAlignment="Left" VerticalAlignment="Top" Style="{StaticResource MahApps.Metro.Styles.ToggleSwitch.Win10}"> 37 | <mah:ToggleSwitch.ToolTip> 38 | <ToolTip> 39 | <StackPanel> 40 | <TextBlock FontWeight="Bold" Text="{l:Static p:Resources.CheckForUpdatesAtStartup}" /> 41 | <TextBlock Text="{l:Static p:Resources.CheckForUpdatesAtStartup_Tooltip}" /> 42 | </StackPanel> 43 | </ToolTip> 44 | </mah:ToggleSwitch.ToolTip> 45 | </mah:ToggleSwitch> 46 | </WrapPanel> 47 | </GroupBox> 48 | </UserControl> -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/InstallationWizard/Welcome.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Steam_Library_Manager.Forms.InstallationWizard 4 | { 5 | /// <summary> 6 | /// Interaction logic for Welcome.xaml 7 | /// </summary> 8 | public partial class Welcome 9 | { 10 | public Welcome() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e) 16 | { 17 | Properties.Settings.Default.Language = Gu.Localization.Translator.CurrentCulture.TwoLetterISOLanguageName; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/InstallationWizard/Wizard.xaml: -------------------------------------------------------------------------------- 1 | <mah:MetroWindow x:Class="Steam_Library_Manager.Forms.InstallationWizard.Wizard" 2 | xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 | xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 | xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 | xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 | xmlns:local="clr-namespace:Steam_Library_Manager.Forms.InstallationWizard" 7 | xmlns:controls="clr-namespace:MvvmWizard.Controls;assembly=MvvmWizard" 8 | xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" 9 | xmlns:l="http://gu.se/Localization" 10 | xmlns:p="clr-namespace:Steam_Library_Manager.Properties" 11 | mc:Ignorable="d" 12 | MinHeight="650" MinWidth="500" Height="650" Width="500" Closing="Wizard_OnClosing" 13 | WindowStyle="None" ShowMaxRestoreButton="False" ShowTitleBar="True" ShowMinButton="False" WindowStartupLocation="CenterScreen" 14 | Title="{l:Static p:Resources.SteamLibraryManagerInstallationWizard}" TitleCharacterCasing="Normal"> 15 | <controls:Wizard Name="WizardControl" SummaryVisibility="Visible" AllowNavigationOnSummaryItemClick="True" TransitionButtonsHorizontalAlignment="Center" SummaryHorizontalAlignment="Center" SummaryMargin="10,0"> 16 | <controls:WizardStep BackButtonVisibility="Collapsed"> 17 | <local:Welcome /> 18 | </controls:WizardStep> 19 | 20 | <controls:WizardStep> 21 | <local:Library /> 22 | </controls:WizardStep> 23 | 24 | <controls:WizardStep SkipButtonVisibility="Collapsed" ForwardButtonVisibility="Collapsed"> 25 | <local:Final /> 26 | </controls:WizardStep> 27 | </controls:Wizard> 28 | </mah:MetroWindow> -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/InstallationWizard/Wizard.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace Steam_Library_Manager.Forms.InstallationWizard 4 | { 5 | /// <summary> 6 | /// Interaction logic for Wizard.xaml 7 | /// </summary> 8 | public partial class Wizard 9 | { 10 | public Wizard() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | private void Wizard_OnClosing(object sender, CancelEventArgs e) 16 | { 17 | Properties.Settings.Default.InstallationWizardShown = true; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/LibraryView.xaml.cs: -------------------------------------------------------------------------------- 1 | using MahApps.Metro.Controls.Dialogs; 2 | using System; 3 | using System.Diagnostics; 4 | using Alphaleonis.Win32.Filesystem; 5 | using System.Linq; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Input; 9 | using Steam_Library_Manager.Definitions.Enums; 10 | 11 | namespace Steam_Library_Manager.Forms 12 | { 13 | /// <summary> 14 | /// Interaction logic for LibraryView.xaml 15 | /// </summary> 16 | public partial class LibraryView 17 | { 18 | private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); 19 | 20 | public LibraryView() => InitializeComponent(); 21 | 22 | private async void LibraryGrid_Drop(object sender, DragEventArgs e) 23 | { 24 | try 25 | { 26 | if (Main.FormAccessor.AppView.AppPanel.SelectedItems.Count == 0 || !(((Grid)sender).DataContext is Definitions.Library library)) 27 | { 28 | return; 29 | } 30 | 31 | library.DirectoryInfo.Refresh(); 32 | if (!library.DirectoryInfo.Exists) 33 | { 34 | return; 35 | } 36 | 37 | foreach (var app in Main.FormAccessor.AppView.AppPanel.SelectedItems.Cast<dynamic>().ToList()) 38 | { 39 | if (app is Definitions.SteamAppInfo && app.IsSteamBackup) 40 | { 41 | Process.Start(Path.Combine(Properties.Settings.Default.steamInstallationPath, "Steam.exe"), $"-install \"{app.InstallationDirectory}\""); 42 | } 43 | else 44 | { 45 | if (library == app.Library || !library.AllowedAppTypes.Contains(app.Library.Type)) 46 | { 47 | Logger.Warn($"Tried to move an app to the same library OR a library that doesn't support the current app type. App Library: {app.Library.FullPath} - Target Library: {library.FullPath} - App Type: {app.Library.Type} - Target Library Type: {library.Type}"); 48 | continue; 49 | } 50 | 51 | if (Functions.TaskManager.TaskList.Count(x => x.App == app && x.TargetLibrary == library && !x.Completed) == 0) 52 | { 53 | Functions.TaskManager.AddTask(new Definitions.List.TaskInfo 54 | { 55 | App = app, 56 | TargetLibrary = library, 57 | TaskType = Definitions.Enums.TaskType.Copy 58 | }); 59 | } 60 | else 61 | { 62 | await Main.FormAccessor.ShowMessageAsync(Functions.SLM.Translate(nameof(Properties.Resources.TaskManager_AlreadyTasked)), Framework.StringFormat.Format(Functions.SLM.Translate(nameof(Properties.Resources.TaskManager_AlreadyTaskedMessage)), new { app.AppName, LibraryFullPath = library.DirectoryInfo.FullName })).ConfigureAwait(true); 63 | } 64 | } 65 | } 66 | } 67 | catch (Exception ex) 68 | { 69 | Logger.Fatal(ex); 70 | } 71 | } 72 | 73 | private void LibraryGrid_DragEnter(object sender, DragEventArgs e) 74 | { 75 | e.Effects = DragDropEffects.Move; 76 | } 77 | 78 | private void LibraryGrid_MouseDown(object sender, SelectionChangedEventArgs e) 79 | { 80 | try 81 | { 82 | Definitions.SLM.CurrentSelectedLibrary = LibraryPanel.SelectedItem as Definitions.Library; 83 | 84 | if (Definitions.SLM.CurrentSelectedLibrary == null) 85 | { 86 | return; 87 | } 88 | 89 | if (Definitions.SLM.CurrentSelectedLibrary.Type != Definitions.Enums.LibraryType.Steam && Directory.Exists(Definitions.SLM.CurrentSelectedLibrary.DirectoryInfo.FullName) && !Definitions.SLM.CurrentSelectedLibrary.DirectoryInfo.Exists) 90 | { 91 | Functions.SLM.Library.UpdateLibrary(Definitions.SLM.CurrentSelectedLibrary); 92 | } 93 | 94 | // Update app panel with selected library 95 | Functions.App.UpdateAppPanel(Definitions.SLM.CurrentSelectedLibrary); 96 | } 97 | catch (Exception ex) 98 | { 99 | Logger.Fatal(ex); 100 | } 101 | } 102 | 103 | private void Grid_MouseDown(object sender, MouseButtonEventArgs e) 104 | { 105 | try 106 | { 107 | if (e.ChangedButton == MouseButton.Left && e.ClickCount == 2) 108 | { 109 | if (((sender as Grid)?.DataContext as Definitions.Library) != null && Directory.Exists(((sender as Grid)?.DataContext as Definitions.Library)?.FullPath)) 110 | { 111 | Process.Start(((sender as Grid)?.DataContext as Definitions.Library)?.FullPath); 112 | } 113 | } 114 | } 115 | catch (Exception ex) 116 | { 117 | Logger.Error(ex); 118 | } 119 | } 120 | 121 | private void LibraryActionButtons_Click(object sender, RoutedEventArgs e) 122 | { 123 | try 124 | { 125 | switch (((Button)sender).Tag) 126 | { 127 | case "create": 128 | Main.FormAccessor.createLibraryFlyout.IsOpen = true; 129 | break; 130 | 131 | case "remove": 132 | if (Definitions.SLM.CurrentSelectedLibrary != null && !Definitions.SLM.CurrentSelectedLibrary.IsMain && Definitions.SLM.CurrentSelectedLibrary.Type != LibraryType.Steam && Functions.TaskManager.TaskList.Count(x => x.TargetLibrary == Definitions.SLM.CurrentSelectedLibrary || x.App?.Library == Definitions.SLM.CurrentSelectedLibrary) == 0) 133 | { 134 | Definitions.List.Libraries.Remove(Definitions.SLM.CurrentSelectedLibrary); 135 | 136 | Main.FormAccessor.AppView.AppPanel.ItemsSource = null; 137 | } 138 | break; 139 | 140 | case "refresh": 141 | if (Definitions.SLM.CurrentSelectedLibrary != null && Functions.TaskManager.TaskList.Count(x => 142 | x.TargetLibrary == Definitions.SLM.CurrentSelectedLibrary 143 | || x.App?.Library == Definitions.SLM.CurrentSelectedLibrary) == 0) 144 | { 145 | Functions.SLM.Library.UpdateLibrary(Definitions.SLM.CurrentSelectedLibrary); 146 | } 147 | break; 148 | } 149 | } 150 | catch (Exception ex) 151 | { 152 | Logger.Fatal(ex); 153 | Debug.WriteLine(ex); 154 | } 155 | } 156 | } 157 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/SettingsView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Alphaleonis.Win32.Filesystem; 2 | using AutoUpdaterDotNET; 3 | using MahApps.Metro.Controls.Dialogs; 4 | using System; 5 | using System.Diagnostics; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | 9 | namespace Steam_Library_Manager.Forms 10 | { 11 | /// <summary> 12 | /// Interaction logic for SettingsView.xaml 13 | /// </summary> 14 | public partial class SettingsView 15 | { 16 | public SettingsView() => InitializeComponent(); 17 | 18 | private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); 19 | 20 | private void CheckForUpdates_Click(object sender, RoutedEventArgs e) 21 | { 22 | try 23 | { 24 | AutoUpdater.Start(Definitions.Updater.VersionControlUrl, Application.ResourceAssembly); 25 | AutoUpdater.CheckForUpdateEvent += async args => 26 | { 27 | if (!args.IsUpdateAvailable) 28 | { 29 | await Main.FormAccessor 30 | .ShowMessageAsync(Functions.SLM.Translate(nameof(Properties.Resources.AutoUpdater)), 31 | Functions.SLM.Translate(nameof(Properties.Resources.Updater_LatestVersionMessage))) 32 | .ConfigureAwait(true); 33 | } 34 | }; 35 | } 36 | catch (Exception ex) 37 | { 38 | Logger.Error(ex); 39 | } 40 | } 41 | 42 | private void ViewLogsButton(object sender, RoutedEventArgs e) 43 | { 44 | if (Directory.Exists(Definitions.Directories.SLM.Log)) 45 | { 46 | Process.Start(Definitions.Directories.SLM.Log); 47 | } 48 | } 49 | 50 | private async void HeaderImageClearButton_ClickAsync(object sender, RoutedEventArgs e) 51 | { 52 | try 53 | { 54 | if (Directory.Exists(Definitions.Directories.SLM.Cache)) 55 | { 56 | foreach (var file in Directory.EnumerateFiles(Definitions.Directories.SLM.Cache, "*.jpg")) 57 | { 58 | File.Delete(file); 59 | } 60 | } 61 | 62 | await Main.FormAccessor.ShowMessageAsync(Functions.SLM.Translate(nameof(Properties.Resources.Forms_Settings_HeaderImageCache)), Functions.SLM.Translate(nameof(Properties.Resources.Forms_Settings_HeaderImageCacheMessage))).ConfigureAwait(false); 63 | } 64 | catch { } 65 | } 66 | 67 | private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 68 | { 69 | Properties.Settings.Default.Language = Gu.Localization.Translator.CurrentCulture.TwoLetterISOLanguageName; 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Forms/TaskManagerView.xaml.cs: -------------------------------------------------------------------------------- 1 | using MahApps.Metro.Controls.Dialogs; 2 | using System; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Windows; 6 | using System.Windows.Controls; 7 | using System.Windows.Input; 8 | 9 | namespace Steam_Library_Manager.Forms 10 | { 11 | /// <summary> 12 | /// Interaction logic for TaskManagerView.xaml 13 | /// </summary> 14 | public partial class TaskManagerView 15 | { 16 | private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); 17 | 18 | public TaskManagerView() => InitializeComponent(); 19 | 20 | private void TaskManager_Buttons_Click(object sender, RoutedEventArgs e) 21 | { 22 | try 23 | { 24 | switch ((sender as Button)?.Tag) 25 | { 26 | case "Start": 27 | default: 28 | Functions.TaskManager.Start(); 29 | Button_StartTaskManager.IsEnabled = false; 30 | Button_PauseTaskManager.IsEnabled = true; 31 | Button_StopTaskManager.IsEnabled = true; 32 | break; 33 | 34 | case "Pause": 35 | Functions.TaskManager.Pause(); 36 | Button_StartTaskManager.IsEnabled = true; 37 | Button_PauseTaskManager.IsEnabled = false; 38 | Button_StopTaskManager.IsEnabled = true; 39 | break; 40 | 41 | case "Stop": 42 | Functions.TaskManager.Stop(); 43 | Button_StartTaskManager.IsEnabled = true; 44 | Button_PauseTaskManager.IsEnabled = false; 45 | Button_StopTaskManager.IsEnabled = false; 46 | break; 47 | 48 | case "BackupUpdates": 49 | Functions.Steam.Library.CheckForBackupUpdatesAsync(); 50 | Functions.Origin.CheckForBackupUpdatesAsync(); 51 | Functions.Uplay.CheckForBackupUpdatesAsync(); 52 | Main.FormAccessor.TmLogs.Report(Framework.StringFormat.Format(Functions.SLM.Translate(nameof(Properties.Resources.Steam_CheckForBackupUpdates_Completed)), new { CurrentTime = DateTime.Now })); 53 | break; 54 | 55 | case "ClearCompleted": 56 | foreach (var currentTask in Functions.TaskManager.TaskList.Where(x => x.Completed).ToList()) 57 | { 58 | Functions.TaskManager.TaskList.Remove(currentTask); 59 | } 60 | break; 61 | } 62 | } 63 | catch (Exception ex) 64 | { 65 | Logger.Fatal(ex); 66 | } 67 | } 68 | 69 | private async void TaskManager_ContextMenu_Click(object sender, RoutedEventArgs e) 70 | { 71 | try 72 | { 73 | if (TaskPanel.SelectedItems.Count == 0) 74 | { 75 | return; 76 | } 77 | switch ((sender as MenuItem)?.Tag) 78 | { 79 | default: 80 | 81 | foreach (var currentTask in TaskPanel.SelectedItems?.OfType<Definitions.List.TaskInfo>().ToList()) 82 | { 83 | if (currentTask.Active && Functions.TaskManager.Status && !currentTask.Completed) 84 | { 85 | await Main.FormAccessor.ShowMessageAsync(Functions.SLM.Translate(nameof(Properties.Resources.TM_TaskActiveError)), Framework.StringFormat.Format(Functions.SLM.Translate(nameof(Properties.Resources.TM_TaskActiveErrorMessage)), new { currentTask.App?.AppName })).ConfigureAwait(true); 86 | } 87 | else 88 | { 89 | Functions.TaskManager.RemoveTask(currentTask); 90 | } 91 | } 92 | break; 93 | 94 | case "ToggleCompress": 95 | foreach (var currentTask in TaskPanel.SelectedItems?.OfType<Definitions.List.TaskInfo>().Where(x => x.TaskType == Definitions.Enums.TaskType.Copy || x.TaskType == Definitions.Enums.TaskType.Compress).ToList()) 96 | { 97 | currentTask.Compress = !currentTask.Compress; 98 | } 99 | break; 100 | 101 | case "ToggleRemoveFiles": 102 | foreach (var currentTask in TaskPanel.SelectedItems?.OfType<Definitions.List.TaskInfo>().Where(x => x.TaskType == Definitions.Enums.TaskType.Copy || x.TaskType == Definitions.Enums.TaskType.Compress).ToList()) 103 | { 104 | currentTask.RemoveOldFiles = !currentTask.RemoveOldFiles; 105 | } 106 | break; 107 | } 108 | } 109 | catch (Exception ex) 110 | { 111 | MessageBox.Show(ex.ToString()); 112 | Logger.Fatal(ex); 113 | } 114 | } 115 | 116 | private void Grid_MouseDown(object sender, MouseButtonEventArgs e) 117 | { 118 | try 119 | { 120 | if (e.ChangedButton == MouseButton.Left && e.ClickCount == 2 && ((sender as Grid)?.DataContext as Definitions.List.TaskInfo)?.App.InstallationDirectory.Exists == true) 121 | { 122 | Process.Start(((Definitions.List.TaskInfo)((Grid)sender)?.DataContext)?.App.InstallationDirectory.FullName); 123 | } 124 | } 125 | catch (Exception ex) 126 | { 127 | Logger.Fatal(ex); 128 | } 129 | } 130 | 131 | private void TaskManager_LogsView_ScrollChanged(object sender, ScrollChangedEventArgs e) 132 | { 133 | try 134 | { 135 | var scrollViewer = ((ScrollViewer)e.OriginalSource); 136 | 137 | // Content scroll event : autoscroll eventually 138 | if (Properties.Settings.Default.TaskManager_Logs_AutoScroll && e.ExtentHeightChange != 0) 139 | { 140 | scrollViewer.ScrollToVerticalOffset(scrollViewer.ExtentHeight); 141 | } 142 | } 143 | catch { } 144 | } 145 | } 146 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Framework/CachedImage/FileCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Net; 5 | using System.Security.Cryptography; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Directory = Alphaleonis.Win32.Filesystem.Directory; 9 | using File = Alphaleonis.Win32.Filesystem.File; 10 | using Path = Alphaleonis.Win32.Filesystem.Path; 11 | 12 | // https://github.com/frogcrush/CachedImage 13 | 14 | namespace Steam_Library_Manager.Framework.CachedImage 15 | { 16 | public static class FileCache 17 | { 18 | public enum CacheMode 19 | { 20 | WinINet, 21 | Dedicated 22 | } 23 | 24 | // Record whether a file is being written. 25 | private static readonly Dictionary<string, bool> IsWritingFile = new Dictionary<string, bool>(); 26 | 27 | static FileCache() => AppCacheMode = CacheMode.Dedicated; 28 | 29 | /// <summary> 30 | /// Gets or sets the cache mode. WinINet is recommended, it's provided by .Net Framework and uses the Temporary Files 31 | /// of IE and the same cache policy of IE. 32 | /// </summary> 33 | public static CacheMode AppCacheMode { get; set; } 34 | 35 | public static async Task<MemoryStream> HitAsync(string url, string filename = null) 36 | { 37 | if (!Directory.Exists(Definitions.Directories.SLM.Cache)) 38 | { 39 | Directory.CreateDirectory(Definitions.Directories.SLM.Cache); 40 | } 41 | 42 | var uri = new Uri(url); 43 | var fileNameBuilder = new StringBuilder(); 44 | using (var sha1 = new SHA1Managed()) 45 | { 46 | var canonicalUrl = uri.ToString(); 47 | var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(canonicalUrl)); 48 | fileNameBuilder.Append(BitConverter.ToString(hash).Replace("-", "").ToLower()); 49 | if (Path.HasExtension(canonicalUrl)) 50 | fileNameBuilder.Append(Path.GetExtension(canonicalUrl.Split('?')[0])); 51 | } 52 | 53 | var fileName = fileNameBuilder.ToString(); 54 | string localFile; 55 | if (string.IsNullOrEmpty(filename)) 56 | { 57 | if (url.Contains("origin")) 58 | { 59 | localFile = $"{Definitions.Directories.SLM.Cache}\\{uri.Segments[2].Replace("/", "")}.jpg"; 60 | } 61 | else if (url.Contains("http")) 62 | { 63 | localFile = $"{Definitions.Directories.SLM.Cache}\\{uri.Segments[3].Replace("/", "")}.jpg"; 64 | } 65 | else 66 | { 67 | localFile = uri.LocalPath; 68 | } 69 | } 70 | else 71 | { 72 | localFile = $"{Definitions.Directories.SLM.Cache}\\{filename}.jpg"; 73 | } 74 | 75 | var memoryStream = new MemoryStream(); 76 | 77 | FileStream fileStream = null; 78 | if (!IsWritingFile.ContainsKey(fileName) && File.Exists(localFile)) 79 | { 80 | using (fileStream = new FileStream(localFile, FileMode.Open, FileAccess.Read)) 81 | { 82 | await fileStream.CopyToAsync(memoryStream).ConfigureAwait(false); 83 | } 84 | memoryStream.Seek(0, SeekOrigin.Begin); 85 | return memoryStream; 86 | } 87 | 88 | var request = WebRequest.Create(uri); 89 | request.Timeout = 10; 90 | try 91 | { 92 | var response = await request.GetResponseAsync().ConfigureAwait(false); 93 | var responseStream = response.GetResponseStream(); 94 | if (responseStream == null) 95 | return null; 96 | if (!IsWritingFile.ContainsKey(fileName)) 97 | { 98 | IsWritingFile[fileName] = true; 99 | fileStream = new FileStream(localFile, FileMode.Create, FileAccess.Write); 100 | } 101 | 102 | using (responseStream) 103 | { 104 | var bytebuffer = new byte[1024]; 105 | int bytesRead; 106 | do 107 | { 108 | bytesRead = await responseStream.ReadAsync(bytebuffer, 0, 1024).ConfigureAwait(false); 109 | if (fileStream != null) 110 | await fileStream.WriteAsync(bytebuffer, 0, bytesRead).ConfigureAwait(false); 111 | await memoryStream.WriteAsync(bytebuffer, 0, bytesRead).ConfigureAwait(false); 112 | } while (bytesRead > 0); 113 | if (fileStream != null) 114 | { 115 | await fileStream.FlushAsync().ConfigureAwait(false); 116 | fileStream.Dispose(); 117 | IsWritingFile.Remove(fileName); 118 | } 119 | } 120 | memoryStream.Seek(0, SeekOrigin.Begin); 121 | return memoryStream; 122 | } 123 | catch (WebException) 124 | { 125 | return null; 126 | } 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Framework/CachedImage/Image.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Diagnostics; 4 | using System.Net.Cache; 5 | using System.Runtime.CompilerServices; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Media.Imaging; 9 | 10 | // Thank you, Jeroen van Langen - http://stackoverflow.com/a/5175424/218882 and Ivan Leonenko - http://stackoverflow.com/a/12638859/218882 11 | 12 | namespace Steam_Library_Manager.Framework.CachedImage 13 | { 14 | /// <summary> 15 | /// Represents a control that is a wrapper on System.Windows.Controls.Image for enabling filesystem-based caching 16 | /// </summary> 17 | public class Image : System.Windows.Controls.Image, INotifyPropertyChanged 18 | { 19 | static Image() => DefaultStyleKeyProperty.OverrideMetadata(typeof(Image), 20 | new FrameworkPropertyMetadata(typeof(Image))); 21 | 22 | public string ImageUrl 23 | { 24 | get => (string)GetValue(ImageUrlProperty); 25 | set => SetValue(ImageUrlProperty, value); 26 | } 27 | 28 | public BitmapImage FailedImage 29 | { 30 | get => (BitmapImage)GetValue(FailedImageProperty); 31 | set => SetValue(FailedImageProperty, value); 32 | } 33 | 34 | public int DecodePixelWidth 35 | { 36 | get => (int)GetValue(DecodePixelWidthProperty); 37 | set => SetValue(DecodePixelWidthProperty, value); 38 | } 39 | 40 | public int DecodePixelHeight 41 | { 42 | get => (int)GetValue(DecodePixelHeightProperty); 43 | set => SetValue(DecodePixelHeightProperty, value); 44 | } 45 | 46 | private bool _isLoading; 47 | 48 | public bool IsLoading 49 | { 50 | get => _isLoading; 51 | private set 52 | { 53 | _isLoading = value; 54 | OnPropertyChanged(); 55 | } 56 | } 57 | 58 | public BitmapCreateOptions CreateOptions 59 | { 60 | get => (BitmapCreateOptions)(GetValue(CreateOptionsProperty)); 61 | set => SetValue(CreateOptionsProperty, value); 62 | } 63 | 64 | private static void FailedImageUrlPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 65 | { 66 | } 67 | 68 | private static async void ImageUrlPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 69 | { 70 | var url = (string)e.NewValue; 71 | var cachedImage = (Image)obj; 72 | 73 | cachedImage.Source = await LoadImageAsync(url, cachedImage).ConfigureAwait(true); 74 | cachedImage.IsLoading = false; 75 | } 76 | 77 | private static async Task<BitmapImage> LoadImageAsync(string url, Image img) 78 | { 79 | if (string.IsNullOrEmpty(url)) 80 | { 81 | switch ((string)img.Tag) 82 | { 83 | default: 84 | return new BitmapImage(new Uri("pack://application:,,,/Resources/no_image_available.gif", 85 | UriKind.Absolute)); 86 | 87 | case "origin": 88 | return new BitmapImage(new Uri("pack://application:,,,/Resources/no_image_available_origin.jpg", 89 | UriKind.Absolute)); 90 | 91 | case "uplay": 92 | return new BitmapImage(new Uri("pack://application:,,,/Resources/no_image_available_uplay.jpg", 93 | UriKind.Absolute)); 94 | } 95 | } 96 | 97 | var bitmapImage = new BitmapImage(); 98 | img.IsLoading = true; 99 | 100 | switch (FileCache.AppCacheMode) 101 | { 102 | case FileCache.CacheMode.WinINet: 103 | bitmapImage.BeginInit(); 104 | bitmapImage.CreateOptions = img.CreateOptions; 105 | 106 | if (img.DecodePixelHeight > 0) 107 | bitmapImage.DecodePixelHeight = img.DecodePixelHeight; 108 | if (img.DecodePixelWidth > 0) 109 | bitmapImage.DecodePixelWidth = img.DecodePixelWidth; 110 | 111 | bitmapImage.UriSource = new Uri(url); 112 | // Enable IE-like cache policy. 113 | bitmapImage.UriCachePolicy = new RequestCachePolicy(RequestCacheLevel.Default); 114 | bitmapImage.EndInit(); 115 | if (bitmapImage.CanFreeze) 116 | bitmapImage.Freeze(); 117 | return bitmapImage; 118 | 119 | case FileCache.CacheMode.Dedicated: 120 | try 121 | { 122 | var memoryStream = await FileCache.HitAsync(url).ConfigureAwait(true); 123 | if (memoryStream == null) 124 | { 125 | Debug.WriteLine("No hit for URL " + url); 126 | 127 | switch ((string)img.Tag) 128 | { 129 | default: 130 | return new BitmapImage(new Uri("pack://application:,,,/Resources/no_image_available.gif", 131 | UriKind.Absolute)); 132 | 133 | case "origin": 134 | return new BitmapImage(new Uri( 135 | "pack://application:,,,/Resources/no_image_available_origin.jpg", 136 | UriKind.Absolute)); 137 | 138 | case "uplay": 139 | return new BitmapImage(new Uri( 140 | "pack://application:,,,/Resources/no_image_available_uplay.jpg", 141 | UriKind.Absolute)); 142 | } 143 | } 144 | 145 | bitmapImage.BeginInit(); 146 | bitmapImage.CreateOptions = img.CreateOptions; 147 | 148 | if (img.DecodePixelHeight > 0) 149 | bitmapImage.DecodePixelHeight = img.DecodePixelHeight; 150 | if (img.DecodePixelWidth > 0) 151 | bitmapImage.DecodePixelWidth = img.DecodePixelWidth; 152 | 153 | bitmapImage.StreamSource = memoryStream; 154 | bitmapImage.EndInit(); 155 | if (bitmapImage.CanFreeze) 156 | bitmapImage.Freeze(); 157 | return bitmapImage; 158 | } 159 | catch (Exception) 160 | { 161 | // ignored, in case the downloaded file is a broken or not an image. 162 | Debug.WriteLine($"Image with url {url} failed to load."); 163 | switch ((string)img.Tag) 164 | { 165 | default: 166 | return new BitmapImage(new Uri("pack://application:,,,/Resources/no_image_available.gif", 167 | UriKind.Absolute)); 168 | 169 | case "origin": 170 | return new BitmapImage(new Uri( 171 | "pack://application:,,,/Resources/no_image_available_origin.jpg", 172 | UriKind.Absolute)); 173 | 174 | case "uplay": 175 | return new BitmapImage(new Uri( 176 | "pack://application:,,,/Resources/no_image_available_uplay.jpg", 177 | UriKind.Absolute)); 178 | } 179 | } 180 | 181 | default: 182 | throw new ArgumentOutOfRangeException(); 183 | } 184 | } 185 | 186 | public static readonly DependencyProperty ImageUrlProperty = DependencyProperty.Register("ImageUrl", 187 | typeof(string), typeof(Image), new PropertyMetadata("", ImageUrlPropertyChanged)); 188 | 189 | public static readonly DependencyProperty FailedImageProperty = DependencyProperty.Register("FailedImage", 190 | typeof(BitmapImage), typeof(Image), new PropertyMetadata(null, FailedImageUrlPropertyChanged)); 191 | 192 | public static readonly DependencyProperty CreateOptionsProperty = DependencyProperty.Register("CreateOptions", 193 | typeof(BitmapCreateOptions), typeof(Image)); 194 | 195 | public static readonly DependencyProperty DecodePixelWidthProperty = DependencyProperty.Register("DecodePixelWidth", 196 | typeof(int), typeof(Image), new PropertyMetadata(-1, FailedImageUrlPropertyChanged)); 197 | 198 | public static readonly DependencyProperty DecodePixelHeightProperty = DependencyProperty.Register("DecodePixelHeight", 199 | typeof(int), typeof(Image), new PropertyMetadata(-1, FailedImageUrlPropertyChanged)); 200 | 201 | public event PropertyChangedEventHandler PropertyChanged; 202 | 203 | protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 204 | { 205 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 206 | } 207 | } 208 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Framework/LocalizedDescriptionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace Steam_Library_Manager.Framework 4 | { 5 | public class LocalizedDescriptionAttribute : DescriptionAttribute 6 | { 7 | private readonly string _resourceKey; 8 | 9 | public LocalizedDescriptionAttribute(string resourceKey) => _resourceKey = resourceKey; 10 | 11 | public override string Description => Functions.SLM.Translate(_resourceKey); 12 | } 13 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Framework/StringFormat.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | 8 | namespace Steam_Library_Manager.Framework 9 | { 10 | /// <summary> 11 | /// The primary class for accessing the functionality of the StringFormat library. 12 | /// </summary> 13 | public static class StringFormat 14 | { 15 | /* 16 | * Explanation: 17 | * (?<=(^|[^\{]|(\{\{)+)) -- This is a lookback, it says that when the next character in the regex is matched, it should 18 | * only be considered a match if it is the start of the line, immediately preceded with a non '{' character, or an even number of '{' characters 19 | * IE: '{one}' and '{{{one}' are both valid (the first two '{' in the second example will result in a single '{' 20 | * but '{{one}' is not a valid because String.Format will combine the first two '{' into a single one 21 | * \{ --Find a '{' character 22 | * (?!\{) --This is a negative look ahead, it says that after you find a the preceding character, 23 | * look to make sure it isn't immediately proceeded with another '{' 24 | *\w --The very next character must be a word character (alpha numeric) 25 | *.* --Continue reading the string for any non-linebreaking character 26 | *?\} --Stop reading at the very first '}' character (don't be greedy) 27 | */ 28 | private const string TokenizeRegex = @"(?<=(^|[^\{]|(\{\{)+))\{(?!\{)\w.*?\}"; 29 | 30 | /// <summary> 31 | /// Formats the string using the placeholder for the property names. 32 | /// </summary> 33 | /// <param name="format">The string to format.</param> 34 | /// <param name="values">The object to pull the values from. Usually an anonymous type.</param> 35 | /// <returns>The formatted string.</returns> 36 | public static string Format(string format, object values) 37 | { 38 | return Format(null, format, values); 39 | } 40 | 41 | /// <summary> 42 | /// Formats the string using the placeholder for the property names. 43 | /// </summary> 44 | /// <param name="provider">The provider to use for formatting dates and numeric values.</param> 45 | /// <param name="format">The string to format.</param> 46 | /// <param name="values">The object to pull the values from. Usually an anonymous type.</param> 47 | /// <returns>The formatted string.</returns> 48 | public static string Format(IFormatProvider provider, string format, object values) 49 | { 50 | return Format(provider, format, AnonymousObjectToDictionary(values)); 51 | } 52 | 53 | /// <summary> 54 | /// Formats the string using the placeholder for the property names. 55 | /// </summary> 56 | /// <param name="format">The string to format.</param> 57 | /// <param name="values">The dictionary to pull the values from.</param> 58 | /// <returns>The formatted string.</returns> 59 | public static string Format(string format, IDictionary<string, object> values) 60 | { 61 | return Format(null, format, values); 62 | } 63 | 64 | /// <summary> 65 | /// Formats the string using the placeholder for the property names. 66 | /// </summary> 67 | /// <param name="provider">The provider to use for formatting dates and numeric values.</param> 68 | /// <param name="format">The string to format.</param> 69 | /// <param name="values">The dictionary to pull the values from.</param> 70 | /// <returns>The formatted string.</returns> 71 | public static string Format(IFormatProvider provider, string format, IDictionary<string, object> values) 72 | { 73 | if (values == null) 74 | { 75 | throw new ArgumentNullException(nameof(values)); 76 | } 77 | 78 | var tokenizedString = TokenizeString(format, out IEnumerable<string> tokens); 79 | 80 | return string.Format(provider, tokenizedString, tokens.Select(s => values[s]).ToArray()); 81 | } 82 | 83 | /// <summary> 84 | /// Returns the format string with the tokens replaced as ordinals. Exposed for developer benefit. Most likely used only in debugging. 85 | /// </summary> 86 | /// <param name="format">The string to format.</param> 87 | /// <returns>A string where the tokens are replaced with ordinal values.</returns> 88 | public static string TokenizeString(string format) 89 | { 90 | return TokenizeString(format, out IEnumerable<string> junk); 91 | } 92 | 93 | /// <summary> 94 | /// Returns the format string with the tokens replaced as ordinals. Exposed for developer benefit. Most likely used only in debugging. 95 | /// </summary> 96 | /// <param name="format">The string to format.</param> 97 | /// <param name="tokens">The tokens that were extracted from the format string.</param> 98 | /// <returns>A string where the tokens are replaced with ordinal values.</returns> 99 | public static string TokenizeString(string format, out IEnumerable<string> tokens) 100 | { 101 | if (format == null) 102 | { 103 | throw new ArgumentNullException(nameof(format)); 104 | } 105 | 106 | //performance: minimize the number of times the builder will have to "grow", while keeping the initial size reasonable 107 | var sb = new StringBuilder(format.Length); 108 | 109 | var match = Regex.Match(format, TokenizeRegex, RegexOptions.Compiled); 110 | 111 | var tokenList = new List<string>(); 112 | 113 | var currentIndex = 0; 114 | while (match.Success) 115 | { 116 | sb.Append(format, currentIndex, match.Index - currentIndex); 117 | 118 | var fullToken = match.ToString(); 119 | 120 | var name = ParseName(fullToken); 121 | 122 | var index = IndexOfName(tokenList, name); 123 | 124 | sb.Append(BuildNewToken(fullToken, name, index)); 125 | 126 | currentIndex = match.Index + match.Length; 127 | 128 | match = match.NextMatch(); 129 | } 130 | 131 | tokens = tokenList; 132 | sb.Append(format.Substring(currentIndex)); 133 | 134 | return sb.ToString(); 135 | } 136 | 137 | #region Private Methods 138 | 139 | private static string ParseName(string fullToken) 140 | { 141 | var token = fullToken.Substring(1, fullToken.Length - 2); 142 | 143 | var colonIndex = token.IndexOf(':'); 144 | 145 | if (colonIndex >= 0) token = token.Substring(0, colonIndex); 146 | 147 | return token.TrimEnd(); 148 | } 149 | 150 | private static int IndexOfName(IList<string> names, string name) 151 | { 152 | var index = names.IndexOf(name); 153 | 154 | if (index < 0) 155 | { 156 | names.Add(name); 157 | index = names.IndexOf(name); 158 | } 159 | 160 | return index; 161 | } 162 | 163 | private static string BuildNewToken(string fullToken, string name, int index) 164 | { 165 | fullToken = fullToken.Remove(1, name.Length); 166 | 167 | return fullToken.Insert(1, index.ToString()); 168 | } 169 | 170 | private static IDictionary<string, object> AnonymousObjectToDictionary(object values) 171 | { 172 | var valueDictionary = new Dictionary<string, object>(); 173 | if (values != null) 174 | { 175 | foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(values)) 176 | { 177 | valueDictionary.Add(propertyDescriptor.Name, propertyDescriptor.GetValue(values)); 178 | } 179 | } 180 | return valueDictionary; 181 | } 182 | 183 | #endregion Private Methods 184 | } 185 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Framework/WPF/EnumBindingSourceExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Markup; 3 | 4 | namespace Steam_Library_Manager 5 | { 6 | public class EnumBindingSourceExtension : MarkupExtension 7 | { 8 | private Type _enumType; 9 | 10 | public Type EnumType 11 | { 12 | get => _enumType; 13 | set 14 | { 15 | if (value != _enumType) 16 | { 17 | if (value != null) 18 | { 19 | Type enumType = Nullable.GetUnderlyingType(value) ?? value; 20 | 21 | if (!enumType.IsEnum) 22 | { 23 | throw new ArgumentException("Type must be for an Enum."); 24 | } 25 | } 26 | 27 | _enumType = value; 28 | } 29 | } 30 | } 31 | 32 | public EnumBindingSourceExtension() 33 | { 34 | } 35 | 36 | public EnumBindingSourceExtension(Type enumType) => EnumType = enumType; 37 | 38 | public override object ProvideValue(IServiceProvider serviceProvider) 39 | { 40 | if (_enumType == null) 41 | { 42 | throw new InvalidOperationException("The EnumType must be specified."); 43 | } 44 | 45 | Type actualEnumType = Nullable.GetUnderlyingType(_enumType) ?? _enumType; 46 | Array enumValues = Enum.GetValues(actualEnumType); 47 | 48 | if (actualEnumType == _enumType) 49 | { 50 | return enumValues; 51 | } 52 | 53 | Array tempArray = Array.CreateInstance(actualEnumType, enumValues.Length + 1); 54 | enumValues.CopyTo(tempArray, 1); 55 | return tempArray; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Framework/WPF/EnumDescriptionTypeConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Reflection; 4 | 5 | namespace Steam_Library_Manager.Framework 6 | { 7 | public class EnumDescriptionTypeConverter : EnumConverter 8 | { 9 | public EnumDescriptionTypeConverter(Type type) 10 | : base(type) 11 | { 12 | } 13 | 14 | public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 15 | { 16 | if (destinationType == typeof(string)) 17 | { 18 | if (value != null) 19 | { 20 | FieldInfo fi = value.GetType().GetField(value.ToString()); 21 | if (fi != null) 22 | { 23 | var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); 24 | return ((attributes.Length > 0) && (!string.IsNullOrEmpty(attributes[0].Description))) ? attributes[0].Description : value.ToString(); 25 | } 26 | } 27 | 28 | return string.Empty; 29 | } 30 | 31 | return base.ConvertTo(context, culture, value, destinationType); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Source/Steam Library Manager/Framework/WPF/PortableSettingsProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Specialized; 4 | using System.Configuration; 5 | using Alphaleonis.Win32.Filesystem; 6 | using System.Xml; 7 | 8 | // Source: https://github.com/crdx/PortableSettingsProvider 9 | namespace Steam_Library_Manager.Framework 10 | { 11 | public sealed class PortableSettingsProvider : SettingsProvider, IApplicationSettingsProvider 12 | { 13 | private const string _rootNodeName = "settings"; 14 | private const string _localSettingsNodeName = "localSettings"; 15 | private const string _globalSettingsNodeName = "globalSettings"; 16 | private const string _className = "PortableSettingsProvider"; 17 | private XmlDocument _xmlDocument; 18 | 19 | private string _filePath => Path.Combine(Path.GetDirectoryName(Definitions.Directories.SLM.Current) ?? Definitions.Directories.SLM.Current, $"{ApplicationName}.settings"); 20 | 21 | private XmlNode _localSettingsNode 22 | { 23 | get 24 | { 25 | XmlNode settingsNode = GetSettingsNode(_localSettingsNodeName); 26 | XmlNode machineNode = settingsNode.SelectSingleNode(Environment.MachineName.ToLowerInvariant()); 27 | 28 | if (machineNode == null) 29 | { 30 | machineNode = _rootDocument.CreateElement(Environment.MachineName.ToLowerInvariant()); 31 | settingsNode.AppendChild(machineNode); 32 | } 33 | 34 | return machineNode; 35 | } 36 | } 37 | 38 | private XmlNode _globalSettingsNode => GetSettingsNode(_globalSettingsNodeName); 39 | 40 | private XmlNode _rootNode => _rootDocument.SelectSingleNode(_rootNodeName); 41 | 42 | private XmlDocument _rootDocument 43 | { 44 | get 45 | { 46 | if (_xmlDocument == null) 47 | { 48 | try 49 | { 50 | _xmlDocument = new XmlDocument(); 51 | _xmlDocument.Load(_filePath); 52 | } 53 | catch (Exception) 54 | { 55 | 56 | } 57 | 58 | if (_xmlDocument.SelectSingleNode(_rootNodeName) != null) 59 | { 60 | return _xmlDocument; 61 | } 62 | 63 | _xmlDocument = GetBlankXmlDocument(); 64 | } 65 | 66 | return _xmlDocument; 67 | } 68 | } 69 | 70 | public override string ApplicationName 71 | { 72 | get => "SLM"; 73 | set { } 74 | } 75 | 76 | public override string Name => _className; 77 | 78 | public override void Initialize(string name, NameValueCollection config) 79 | { 80 | base.Initialize(Name, config); 81 | } 82 | 83 | public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection) 84 | { 85 | foreach (SettingsPropertyValue propertyValue in collection) 86 | { 87 | SetValue(propertyValue); 88 | } 89 | 90 | try 91 | { 92 | _rootDocument.Save(_filePath); 93 | } 94 | catch (Exception) 95 | { 96 | /* 97 | * If this is a portable application and the device has been 98 | * removed then this will fail, so don't do anything. It's 99 | * probably better for the application to stop saving settings 100 | * rather than just crashing outright. Probably. 101 | */ 102 | } 103 | } 104 | 105 | public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection) 106 | { 107 | SettingsPropertyValueCollection values = new SettingsPropertyValueCollection(); 108 | 109 | foreach (SettingsProperty property in collection) 110 | { 111 | values.Add(new SettingsPropertyValue(property) 112 | { 113 | SerializedValue = GetValue(property) 114 | }); 115 | } 116 | 117 | return values; 118 | } 119 | 120 | private void SetValue(SettingsPropertyValue propertyValue) 121 | { 122 | XmlNode targetNode = IsGlobal(propertyValue.Property) 123 | ? _globalSettingsNode 124 | : _localSettingsNode; 125 | 126 | XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[@name='{0}']", propertyValue.Name)); 127 | 128 | if (settingNode != null) 129 | { 130 | settingNode.InnerText = propertyValue.SerializedValue.ToString(); 131 | } 132 | else 133 | { 134 | settingNode = _rootDocument.CreateElement("setting"); 135 | 136 | XmlAttribute nameAttribute = _rootDocument.CreateAttribute("name"); 137 | nameAttribute.Value = propertyValue.Name; 138 | 139 | settingNode.Attributes.Append(nameAttribute); 140 | settingNode.InnerText = propertyValue.SerializedValue.ToString(); 141 | 142 | targetNode.AppendChild(settingNode); 143 | } 144 | } 145 | 146 | private string GetValue(SettingsProperty property) 147 | { 148 | XmlNode targetNode = IsGlobal(property) ? _globalSettingsNode : _localSettingsNode; 149 | XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[@name='{0}']", property.Name)); 150 | 151 | if (settingNode == null) 152 | { 153 | return property.DefaultValue != null ? property.DefaultValue.ToString() : string.Empty; 154 | } 155 | 156 | return settingNode.InnerText; 157 | } 158 | 159 | private bool IsGlobal(SettingsProperty property) 160 | { 161 | foreach (DictionaryEntry attribute in property.Attributes) 162 | { 163 | if ((Attribute)attribute.Value is SettingsManageabilityAttribute) 164 | { 165 | return true; 166 | } 167 | } 168 | 169 | return false; 170 | } 171 | 172 | private XmlNode GetSettingsNode(string name) 173 | { 174 | XmlNode settingsNode = _rootNode.SelectSingleNode(name); 175 | 176 | if (settingsNode == null) 177 | { 178 | settingsNode = _rootDocument.CreateElement(name); 179 | _rootNode.AppendChild(settingsNode); 180 | } 181 | 182 | return settingsNode; 183 | } 184 | 185 | public XmlDocument GetBlankXmlDocument() 186 | { 187 | XmlDocument blankXmlDocument = new XmlDocument(); 188 | blankXmlDocument.AppendChild(blankXmlDocument.CreateXmlDeclaration("1.0", "utf-8", string.Empty)); 189 | blankXmlDocument.AppendChild(blankXmlDocument.CreateElement(_rootNodeName)); 190 | 191 | return blankXmlDocument; 192 | } 193 | 194 | public void Reset(SettingsContext context) 195 | { 196 | _localSettingsNode.RemoveAll(); 197 | _globalSettingsNode.RemoveAll(); 198 | 199 | _xmlDocument.Save(_filePath); 200 | } 201 | 202 | // do nothing 203 | public SettingsPropertyValue GetPreviousVersion(SettingsContext context, SettingsProperty property) => new SettingsPropertyValue(property); 204 | 205 | public void Upgrade(SettingsContext context, SettingsPropertyCollection properties) 206 | { 207 | } 208 | } 209 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Framework/WPF/SettingBindingExtension.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Data; 2 | 3 | namespace Steam_Library_Manager 4 | { 5 | public class SettingBindingExtension : Binding 6 | { 7 | public SettingBindingExtension() => Initialize(); 8 | 9 | public SettingBindingExtension(string path) : base(path) => Initialize(); 10 | 11 | private void Initialize() 12 | { 13 | Source = Properties.Settings.Default; 14 | Mode = BindingMode.TwoWay; 15 | UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Functions/App.cs: -------------------------------------------------------------------------------- 1 | using MahApps.Metro.Controls.Dialogs; 2 | using Steam_Library_Manager.Definitions.Enums; 3 | using System; 4 | using System.IO; 5 | using System.IO.Compression; 6 | using System.Linq; 7 | using System.Threading; 8 | using DirectoryInfo = Alphaleonis.Win32.Filesystem.DirectoryInfo; 9 | using File = Alphaleonis.Win32.Filesystem.File; 10 | using FileInfo = Alphaleonis.Win32.Filesystem.FileInfo; 11 | using Path = Alphaleonis.Win32.Filesystem.Path; 12 | 13 | namespace Steam_Library_Manager.Functions 14 | { 15 | internal static class App 16 | { 17 | private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); 18 | 19 | public static async System.Threading.Tasks.Task AddSteamAppAsync(int AppID, string AppName, string InstallationPath, int StateFlag, Definitions.Library Library, long SizeOnDisk, long LastUpdated, bool IsCompressed, bool IsSteamBackup = false) 20 | { 21 | try 22 | { 23 | // Make a new definition for app 24 | var appInfo = new Definitions.SteamAppInfo(AppID, Library, new DirectoryInfo(Path.Combine(Library.DirectoryList["Common"].FullName, InstallationPath))) 25 | { 26 | // Set game name 27 | AppName = AppName, 28 | 29 | // Define it is an archive 30 | IsCompressed = IsCompressed, 31 | IsSteamBackup = IsSteamBackup, 32 | LastUpdated = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(LastUpdated) 33 | }; 34 | 35 | if (Definitions.List.SteamAppsLastPlayedDic.ContainsKey(AppID)) 36 | { 37 | appInfo.LastPlayed = Definitions.List.SteamAppsLastPlayedDic[AppID]; 38 | } 39 | 40 | // If app doesn't have a folder in "common" directory and "downloading" directory then skip 41 | if (!appInfo.InstallationDirectory.Exists && StateFlag == 4 && !appInfo.IsCompressed && !appInfo.IsSteamBackup) 42 | { 43 | var acfFile = new FileInfo(Path.Combine(Library.DirectoryList["SteamApps"].FullName, $"appmanifest_{appInfo.AppId}.acf")); 44 | 45 | if (Definitions.List.IgnoredJunkItems.Contains(acfFile.FullName)) 46 | { 47 | return; 48 | } 49 | 50 | Definitions.List.LcProgress.Report(new Definitions.List.JunkInfo 51 | { 52 | FSInfo = acfFile, 53 | Size = FileSystem.FormatBytes(acfFile.Length), 54 | Library = Library, 55 | Tag = JunkType.HeadlessDataFile 56 | }); 57 | 58 | return; // Do not add pre-loads to list 59 | } 60 | 61 | if (IsCompressed) 62 | { 63 | // If user want us to get archive size from real uncompressed size 64 | if (Properties.Settings.Default.archiveSizeCalculationMethod.StartsWith("Uncompressed")) 65 | { 66 | // Open archive to read 67 | using (var archive = ZipFile.OpenRead(appInfo.CompressedArchivePath.FullName)) 68 | { 69 | // For each file in archive 70 | foreach (var entry in archive.Entries) 71 | { 72 | // Add file size to sizeOnDisk 73 | appInfo.SizeOnDisk += entry.Length; 74 | } 75 | } 76 | } 77 | else 78 | { 79 | appInfo.CompressedArchivePath.Refresh(); 80 | 81 | // And set archive size as game size 82 | appInfo.SizeOnDisk = appInfo.CompressedArchivePath?.Length ?? 0; 83 | } 84 | } 85 | else 86 | { 87 | // If SizeOnDisk value from .ACF file is not equals to 0 88 | if (Properties.Settings.Default.gameSizeCalculationMethod != "ACF") 89 | { 90 | var gameFiles = appInfo.GetFileList(); 91 | long gameSize = 0; 92 | 93 | System.Threading.Tasks.Parallel.ForEach(gameFiles, file => Interlocked.Add(ref gameSize, file.Length)); 94 | 95 | appInfo.SizeOnDisk = gameSize; 96 | } 97 | else 98 | { 99 | // Else set game size to size in acf 100 | appInfo.SizeOnDisk = SizeOnDisk; 101 | } 102 | } 103 | 104 | appInfo.IsCompacted = await appInfo.CompactStatus().ConfigureAwait(false); 105 | 106 | // Add our game details to global list 107 | Library.Apps.Add(appInfo); 108 | 109 | if (Definitions.SLM.CurrentSelectedLibrary == Library) 110 | { 111 | UpdateAppPanel(Library); 112 | } 113 | } 114 | catch (Exception ex) 115 | { 116 | Logger.Fatal(ex); 117 | } 118 | } 119 | 120 | public static async void ReadDetailsFromZip(string zipPath, Definitions.Library targetLibrary) 121 | { 122 | try 123 | { 124 | // Open archive for read 125 | using (var archive = ZipFile.OpenRead(zipPath)) 126 | { 127 | if (archive.Entries.Count <= 0) return; 128 | 129 | // For each file in opened archive 130 | foreach (var acfEntry in archive.Entries.Where(x => x.Name.Contains("appmanifest_"))) 131 | { 132 | // If it contains 133 | // Define a KeyValue reader 134 | var keyValReader = new Framework.KeyValue(); 135 | 136 | // Open .acf file from archive as text 137 | keyValReader.ReadAsText(acfEntry.Open()); 138 | 139 | // If acf file has no children, skip this archive 140 | if (keyValReader.Children.Count == 0) 141 | { 142 | continue; 143 | } 144 | 145 | await AddSteamAppAsync(Convert.ToInt32(keyValReader["appID"].Value), !string.IsNullOrEmpty(keyValReader["name"].Value) ? keyValReader["name"].Value : keyValReader["UserConfig"]["name"].Value, keyValReader["installdir"].Value, Convert.ToInt32(keyValReader["StateFlags"].Value), targetLibrary, Convert.ToInt64(keyValReader["SizeOnDisk"].Value), Convert.ToInt64(keyValReader["LastUpdated"].Value), true).ConfigureAwait(true); 146 | } 147 | } 148 | } 149 | catch (IOException IEx) 150 | { 151 | await Main.FormAccessor.AppView.AppPanel.Dispatcher.Invoke(async delegate 152 | { 153 | if (await Main.FormAccessor.ShowMessageAsync(SLM.Translate(nameof(Properties.Resources.ReadZip_IOException)), Framework.StringFormat.Format(SLM.Translate(nameof(Properties.Resources.ReadZip_IOExceptionMessage)), new { ZipPath = zipPath }), MessageDialogStyle.AffirmativeAndNegative, new MetroDialogSettings 154 | { 155 | NegativeButtonText = SLM.Translate(nameof(Properties.Resources.ReadZip_DontDelete)) 156 | }).ConfigureAwait(true) == MessageDialogResult.Affirmative) 157 | { 158 | File.Delete(zipPath); 159 | } 160 | }).ConfigureAwait(true); 161 | 162 | System.Diagnostics.Debug.WriteLine(IEx); 163 | Logger.Fatal(IEx); 164 | } 165 | catch (InvalidDataException IEx) 166 | { 167 | await Main.FormAccessor.AppView.AppPanel.Dispatcher.Invoke(async delegate 168 | { 169 | if (await Main.FormAccessor.ShowMessageAsync(SLM.Translate(nameof(Properties.Resources.ReadZip_InvalidDataException)), Framework.StringFormat.Format(SLM.Translate(nameof(Properties.Resources.ReadZip_InvalidDataExceptionMessage)), new { ZipPath = zipPath }), MessageDialogStyle.AffirmativeAndNegative, new MetroDialogSettings 170 | { 171 | NegativeButtonText = SLM.Translate(nameof(Properties.Resources.ReadZip_DontDelete)) 172 | }).ConfigureAwait(true) == MessageDialogResult.Affirmative) 173 | { 174 | File.Delete(zipPath); 175 | } 176 | }).ConfigureAwait(true); 177 | 178 | System.Diagnostics.Debug.WriteLine(IEx); 179 | Logger.Fatal(IEx); 180 | } 181 | catch (Exception ex) 182 | { 183 | Logger.Fatal(ex); 184 | } 185 | } 186 | 187 | public static void UpdateAppPanel(Definitions.Library library) => Main.FormAccessor.LibraryChange.Report(library); 188 | } 189 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Functions/FileSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Threading.Tasks; 7 | using DirectoryInfo = Alphaleonis.Win32.Filesystem.DirectoryInfo; 8 | using DriveInfo = Alphaleonis.Win32.Filesystem.DriveInfo; 9 | using FileInfo = Alphaleonis.Win32.Filesystem.FileInfo; 10 | using Path = Alphaleonis.Win32.Filesystem.Path; 11 | 12 | namespace Steam_Library_Manager.Functions 13 | { 14 | internal static class FileSystem 15 | { 16 | private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); 17 | 18 | public static async Task RemoveGivenFilesAsync(IEnumerable<string> FileList, List<string> DirectoryList = null, Definitions.List.TaskInfo CurrentTask = null) 19 | { 20 | try 21 | { 22 | if (CurrentTask != null) 23 | { 24 | await Task.Delay(5000); 25 | } 26 | 27 | Parallel.ForEach(FileList, currentFile => 28 | { 29 | FileInfo File = new FileInfo(currentFile); 30 | 31 | if (File.Exists) 32 | { 33 | if (CurrentTask != null) 34 | { 35 | CurrentTask.TaskStatusInfo = Framework.StringFormat.Format(SLM.Translate(nameof(Properties.Resources.TaskStatus_DeletingFile)), new { FileName = File.Name, FormattedFileSize = FormatBytes(File.Length) }); 36 | } 37 | 38 | Alphaleonis.Win32.Filesystem.File.SetAttributes(File.FullName, FileAttributes.Normal); 39 | File.Delete(); 40 | } 41 | }); 42 | 43 | if (DirectoryList != null) 44 | { 45 | Parallel.ForEach(DirectoryList, currentDirectory => 46 | { 47 | DirectoryInfo Directory = new DirectoryInfo(currentDirectory); 48 | 49 | if (Directory.Exists) 50 | { 51 | if (CurrentTask != null) 52 | { 53 | CurrentTask.TaskStatusInfo = Framework.StringFormat.Format(SLM.Translate(nameof(Properties.Resources.TaskStatus_DeletingDirectory)), new { DirectoryName = Directory.Name }); 54 | } 55 | 56 | Directory.Delete(); 57 | } 58 | }); 59 | } 60 | 61 | if (CurrentTask != null) 62 | { 63 | CurrentTask.TaskStatusInfo = ""; 64 | } 65 | } 66 | catch (DirectoryNotFoundException ex) 67 | { 68 | logger.Error(ex); 69 | } 70 | catch (IOException ex) 71 | { 72 | logger.Error(ex); 73 | } 74 | catch (AggregateException ex) 75 | { 76 | logger.Error(ex); 77 | } 78 | catch (UnauthorizedAccessException ex) 79 | { 80 | logger.Error(ex); 81 | } 82 | catch (Exception ex) 83 | { 84 | logger.Fatal(ex); 85 | } 86 | } 87 | 88 | // Get directory size from path, with or without sub directories 89 | public static long GetDirectorySize(DirectoryInfo directoryPath, bool IncludeSubDirectories) 90 | { 91 | try 92 | { 93 | /* 94 | dynamic fso = Activator.CreateInstance(Type.GetTypeFromProgID("Scripting.FileSystemObject")); 95 | var fldr = fso.GetFolder(directoryPath.FullName); 96 | 97 | return Convert.ToInt64((ulong)fldr.size); 98 | */ 99 | 100 | directoryPath.Refresh(); 101 | 102 | if (!directoryPath.Exists || !new DriveInfo(Path.GetPathRoot(directoryPath.Root.FullName)).IsReady) 103 | { 104 | return 0; 105 | } 106 | 107 | // Define a "long" for directory size 108 | long DirectorySize = 0; 109 | 110 | foreach (var CurrentFile in directoryPath.EnumerateFiles("*", (IncludeSubDirectories) ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly).Where(x => x is FileInfo)) 111 | { 112 | DirectorySize += CurrentFile.Length; 113 | } 114 | // and return directory size 115 | return DirectorySize; 116 | } 117 | catch (DirectoryNotFoundException ex) 118 | { 119 | logger.Error(ex); 120 | return 0; 121 | } 122 | // on error, return 0 123 | catch (Exception ex) 124 | { 125 | logger.Fatal(ex); 126 | return 0; 127 | } 128 | } 129 | 130 | // Source: http://stackoverflow.com/a/2082893 131 | public static string FormatBytes(long length) 132 | { 133 | try 134 | { 135 | long B = 0, KB = 1024, MB = KB * 1024, GB = MB * 1024, TB = GB * 1024; 136 | double size = length; 137 | string suffix = nameof(B); 138 | 139 | if (length >= TB) 140 | { 141 | size = Math.Round((double)length / TB, 2); 142 | suffix = nameof(TB); 143 | } 144 | else if (length >= GB) 145 | { 146 | size = Math.Round((double)length / GB, 2); 147 | suffix = nameof(GB); 148 | } 149 | else if (length >= MB) 150 | { 151 | size = Math.Round((double)length / MB, 2); 152 | suffix = nameof(MB); 153 | } 154 | else if (length >= KB) 155 | { 156 | size = Math.Round((double)length / KB, 2); 157 | suffix = nameof(KB); 158 | } 159 | 160 | return $"{size} {suffix}"; 161 | } 162 | catch (Exception ex) 163 | { 164 | logger.Error(ex); 165 | return "0"; 166 | } 167 | } 168 | 169 | // Pinvoke for API function 170 | [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 171 | [return: MarshalAs(UnmanagedType.Bool)] 172 | public static extern bool GetDiskFreeSpaceEx(string lpDirectoryName, 173 | out ulong lpFreeBytesAvailable, 174 | out ulong lpTotalNumberOfBytes, 175 | out ulong lpTotalNumberOfFreeBytes); 176 | } 177 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | -------------------------------------------------------------------------------- /Source/Steam Library Manager/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("Steam Library Manager")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("Steam Library Manager")] 14 | [assembly: AssemblyCopyright("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 | //<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file 25 | //inside a <PropertyGroup>. For example, if you are using US english 26 | //in your source files, set the <UICulture> 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 | [assembly: ThemeInfo( 33 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 34 | //(used if a resource is not found in the page, 35 | // or application resource dictionaries) 36 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 37 | //(used if a resource is not found in the page, 38 | // app, or any theme specific resource dictionaries) 39 | )] 40 | 41 | // Version information for an assembly consists of the following four values: 42 | // 43 | // Major Version 44 | // Minor Version 45 | // Build Number 46 | // Revision 47 | // 48 | // You can specify all the values or you can default the Build and Revision Numbers 49 | // by using the '*' as shown below: 50 | // [assembly: AssemblyVersion("1.0.*")] 51 | [assembly: AssemblyVersion("1.7.2.0")] 52 | [assembly: AssemblyFileVersion("1.7.2.0")] 53 | [assembly: NeutralResourcesLanguage("en")] -------------------------------------------------------------------------------- /Source/Steam Library Manager/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | <?xml version='1.0' encoding='utf-8'?> 2 | <SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Steam_Library_Manager.Properties" GeneratedClassName="Settings"> 3 | <Profiles /> 4 | <Settings> 5 | <Setting Name="steamInstallationPath" Roaming="true" Type="System.String" Scope="User"> 6 | <Value Profile="(Default)" /> 7 | </Setting> 8 | <Setting Name="backupDirectories" Roaming="true" Type="System.Collections.Specialized.StringCollection" Scope="User"> 9 | <Value Profile="(Default)" /> 10 | </Setting> 11 | <Setting Name="defaultGameSortingMethod" Roaming="true" Type="System.String" Scope="User"> 12 | <Value Profile="(Default)">appName</Value> 13 | </Setting> 14 | <Setting Name="gameSizeCalculationMethod" Roaming="true" Type="System.String" Scope="User"> 15 | <Value Profile="(Default)">ACF</Value> 16 | </Setting> 17 | <Setting Name="archiveSizeCalculationMethod" Roaming="true" Type="System.String" Scope="User"> 18 | <Value Profile="(Default)">compressed</Value> 19 | </Setting> 20 | <Setting Name="ParallelAfterSize" Roaming="true" Type="System.Int64" Scope="User"> 21 | <Value Profile="(Default)">20</Value> 22 | </Setting> 23 | <Setting Name="includeSearchResults" Roaming="true" Type="System.Boolean" Scope="User"> 24 | <Value Profile="(Default)">True</Value> 25 | </Setting> 26 | <Setting Name="PlayASoundOnCompletion" Roaming="true" Type="System.Boolean" Scope="User"> 27 | <Value Profile="(Default)">True</Value> 28 | </Setting> 29 | <Setting Name="LibraryStyle" Roaming="true" Type="System.String" Scope="User"> 30 | <Value Profile="(Default)">Grid</Value> 31 | </Setting> 32 | <Setting Name="CheckforUpdatesAtStartup" Roaming="true" Type="System.String" Scope="User"> 33 | <Value Profile="(Default)">True</Value> 34 | </Setting> 35 | <Setting Name="Global_RemoveOldFiles" Roaming="true" Type="System.Boolean" Scope="User"> 36 | <Value Profile="(Default)">False</Value> 37 | </Setting> 38 | <Setting Name="Global_Compress" Roaming="true" Type="System.Boolean" Scope="User"> 39 | <Value Profile="(Default)">False</Value> 40 | </Setting> 41 | <Setting Name="Global_ReportFileMovement" Roaming="true" Type="System.Boolean" Scope="User"> 42 | <Value Profile="(Default)">True</Value> 43 | </Setting> 44 | <Setting Name="Global_StartTaskManagerOnStartup" Roaming="true" Type="System.Boolean" Scope="User"> 45 | <Value Profile="(Default)">False</Value> 46 | </Setting> 47 | <Setting Name="CustomSoundFile" Roaming="true" Type="System.String" Scope="User"> 48 | <Value Profile="(Default)" /> 49 | </Setting> 50 | <Setting Name="SearchText" Roaming="true" Type="System.String" Scope="User"> 51 | <Value Profile="(Default)" /> 52 | </Setting> 53 | <Setting Name="BaseTheme" Roaming="true" Type="System.String" Scope="User"> 54 | <Value Profile="(Default)">BaseLight</Value> 55 | </Setting> 56 | <Setting Name="ThemeAccent" Roaming="true" Type="System.String" Scope="User"> 57 | <Value Profile="(Default)">Blue</Value> 58 | </Setting> 59 | <Setting Name="OriginLibraries" Roaming="true" Type="System.Collections.Specialized.StringCollection" Scope="User"> 60 | <Value Profile="(Default)" /> 61 | </Setting> 62 | <Setting Name="CompressionLevel" Roaming="true" Type="System.String" Scope="User"> 63 | <Value Profile="(Default)">Fastest</Value> 64 | </Setting> 65 | <Setting Name="Language" Roaming="true" Type="System.String" Scope="User"> 66 | <Value Profile="(Default)">en</Value> 67 | </Setting> 68 | <Setting Name="SteamID64" Roaming="true" Type="System.String" Scope="User"> 69 | <Value Profile="(Default)" /> 70 | </Setting> 71 | <Setting Name="TaskManager_Logs_AutoScroll" Roaming="true" Type="System.Boolean" Scope="User"> 72 | <Value Profile="(Default)">False</Value> 73 | </Setting> 74 | <Setting Name="DefaultCompactLevel" Roaming="true" Type="System.String" Scope="User"> 75 | <Value Profile="(Default)">XPRESS8K</Value> 76 | </Setting> 77 | <Setting Name="AdvancedCompactSizeDetection" Roaming="true" Type="System.Boolean" Scope="User"> 78 | <Value Profile="(Default)">False</Value> 79 | </Setting> 80 | <Setting Name="TaskManager_AutoClear" Roaming="true" Type="System.Boolean" Scope="User"> 81 | <Value Profile="(Default)">False</Value> 82 | </Setting> 83 | <Setting Name="IgnoredJunks" Roaming="true" Type="System.Collections.Specialized.StringCollection" Scope="User"> 84 | <Value Profile="(Default)" /> 85 | </Setting> 86 | <Setting Name="CompactDetection" Roaming="true" Type="System.Boolean" Scope="User"> 87 | <Value Profile="(Default)">False</Value> 88 | </Setting> 89 | <Setting Name="TaskManager_ContinueOnError" Roaming="true" Type="System.Boolean" Scope="User"> 90 | <Value Profile="(Default)">False</Value> 91 | </Setting> 92 | <Setting Name="TaskManager_SteamRestartSkip" Roaming="true" Type="System.Boolean" Scope="User"> 93 | <Value Profile="(Default)">False</Value> 94 | </Setting> 95 | <Setting Name="LastUserVersion" Roaming="true" Type="System.String" Scope="User"> 96 | <Value Profile="(Default)" /> 97 | </Setting> 98 | <Setting Name="UplayLibraries" Roaming="true" Type="System.Collections.Specialized.StringCollection" Scope="User"> 99 | <Value Profile="(Default)" /> 100 | </Setting> 101 | <Setting Name="Steam_IsEnabled" Roaming="true" Type="System.Boolean" Scope="User"> 102 | <Value Profile="(Default)">True</Value> 103 | </Setting> 104 | <Setting Name="Origin_IsEnabled" Roaming="true" Type="System.Boolean" Scope="User"> 105 | <Value Profile="(Default)">False</Value> 106 | </Setting> 107 | <Setting Name="Uplay_IsEnabled" Roaming="true" Type="System.Boolean" Scope="User"> 108 | <Value Profile="(Default)">False</Value> 109 | </Setting> 110 | <Setting Name="UplayExePath" Roaming="true" Type="System.String" Scope="User"> 111 | <Value Profile="(Default)" /> 112 | </Setting> 113 | <Setting Name="UplayDbPath" Roaming="true" Type="System.String" Scope="User"> 114 | <Value Profile="(Default)" /> 115 | </Setting> 116 | <Setting Name="InstallationWizardShown" Roaming="true" Type="System.Boolean" Scope="User"> 117 | <Value Profile="(Default)">False</Value> 118 | </Setting> 119 | </Settings> 120 | </SettingsFile> -------------------------------------------------------------------------------- /Source/Steam Library Manager/Resources/configurations: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Source/Steam Library Manager/Resources/configurations -------------------------------------------------------------------------------- /Source/Steam Library Manager/Resources/fa/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Source/Steam Library Manager/Resources/fa/FontAwesome.otf -------------------------------------------------------------------------------- /Source/Steam Library Manager/Resources/no_image_available.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Source/Steam Library Manager/Resources/no_image_available.gif -------------------------------------------------------------------------------- /Source/Steam Library Manager/Resources/no_image_available_origin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Source/Steam Library Manager/Resources/no_image_available_origin.jpg -------------------------------------------------------------------------------- /Source/Steam Library Manager/Resources/no_image_available_uplay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Source/Steam Library Manager/Resources/no_image_available_uplay.jpg -------------------------------------------------------------------------------- /Source/Steam Library Manager/Resources/origin-icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Source/Steam Library Manager/Resources/origin-icon.ico -------------------------------------------------------------------------------- /Source/Steam Library Manager/Resources/slm-icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Source/Steam Library Manager/Resources/slm-icon.ico -------------------------------------------------------------------------------- /Source/Steam Library Manager/Resources/steam-icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Source/Steam Library Manager/Resources/steam-icon.ico -------------------------------------------------------------------------------- /Source/Steam Library Manager/Resources/uplay-icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RevoLand/Steam-Library-Manager/0d5a81c1fb96802b658c26a1088bda9ac0d50610/Source/Steam Library Manager/Resources/uplay-icon.ico -------------------------------------------------------------------------------- /Source/Steam Library Manager/Settings.cs: -------------------------------------------------------------------------------- 1 | using MahApps.Metro; 2 | using MahApps.Metro.Controls.Dialogs; 3 | using Steam_Library_Manager.Definitions.Enums; 4 | using System; 5 | using System.Diagnostics; 6 | using System.Windows; 7 | 8 | namespace Steam_Library_Manager.Properties 9 | { 10 | // This class allows you to handle specific events on the settings class: 11 | // The SettingChanging event is raised before a setting's value is changed. 12 | // The PropertyChanged event is raised after a setting's value is changed. 13 | // The SettingsLoaded event is raised after the setting values are loaded. 14 | // The SettingsSaving event is raised before the setting values are saved. 15 | [System.Configuration.SettingsProvider(typeof(Framework.PortableSettingsProvider))] 16 | internal sealed partial class Settings 17 | { 18 | private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); 19 | 20 | public Settings() 21 | { 22 | PropertyChanged += Settings_PropertyChanged; 23 | SettingChanging += Settings_SettingChanging; 24 | } 25 | 26 | private async void Settings_SettingChanging(object sender, System.Configuration.SettingChangingEventArgs e) 27 | { 28 | try 29 | { 30 | if (e.SettingName == "Steam_IsEnabled") 31 | { 32 | if (Default.Steam_IsEnabled == (bool)e.NewValue) return; 33 | 34 | if (Definitions.Global.Steam.IsStateChanging) 35 | { 36 | Main.FormAccessor.AppView.AppPanel.Dispatcher?.Invoke(async delegate 37 | { 38 | await Main.FormAccessor.ShowMessageAsync("State is already changing!", 39 | "State is already being changed for Steam libraries; please wait.", 40 | MessageDialogStyle.AffirmativeAndNegative); 41 | }, System.Windows.Threading.DispatcherPriority.Normal); 42 | e.Cancel = true; 43 | } 44 | else 45 | { 46 | if ((bool)e.NewValue) 47 | { 48 | Functions.SLM.LoadSteam(); 49 | } 50 | else 51 | { 52 | Functions.SLM.UnloadLibrary(LibraryType.Steam); 53 | Functions.SLM.UnloadLibrary(LibraryType.SLM); 54 | } 55 | 56 | Main.FormAccessor.HamburgerMenuControl.Control.SelectedIndex = 0; 57 | Main.FormAccessor.UpdateLibraryList("All"); 58 | } 59 | } 60 | else if (e.SettingName == "Origin_IsEnabled") 61 | { 62 | if (Default.Origin_IsEnabled == (bool)e.NewValue) return; 63 | 64 | if (Definitions.Global.Origin.IsStateChanging) 65 | { 66 | Main.FormAccessor.AppView.AppPanel.Dispatcher?.Invoke(async delegate 67 | { 68 | await Main.FormAccessor.ShowMessageAsync("State is already changing!", 69 | "State is already being changed for Origin libraries; please wait.", 70 | MessageDialogStyle.AffirmativeAndNegative); 71 | }, System.Windows.Threading.DispatcherPriority.Normal); 72 | e.Cancel = true; 73 | } 74 | else 75 | { 76 | if ((bool)e.NewValue) 77 | { 78 | await Functions.SLM.LoadOriginAsync(); 79 | } 80 | else 81 | { 82 | Functions.SLM.UnloadLibrary(LibraryType.Origin); 83 | } 84 | 85 | Main.FormAccessor.HamburgerMenuControl.Control.SelectedIndex = 0; 86 | Main.FormAccessor.UpdateLibraryList("All"); 87 | } 88 | } 89 | else if (e.SettingName == "Uplay_IsEnabled") 90 | { 91 | if (Default.Uplay_IsEnabled == (bool)e.NewValue) return; 92 | 93 | if (Definitions.Global.Uplay.IsStateChanging) 94 | { 95 | Main.FormAccessor.AppView.AppPanel.Dispatcher?.Invoke(async delegate 96 | { 97 | await Main.FormAccessor.ShowMessageAsync("State is already changing!", 98 | "State is already being changed for Uplay libraries; please wait.", 99 | MessageDialogStyle.AffirmativeAndNegative); 100 | }, System.Windows.Threading.DispatcherPriority.Normal); 101 | e.Cancel = true; 102 | } 103 | else 104 | { 105 | if ((bool)e.NewValue) 106 | { 107 | await Functions.SLM.LoadUplayAsync(); 108 | } 109 | else 110 | { 111 | Functions.SLM.UnloadLibrary(LibraryType.Uplay); 112 | } 113 | 114 | Main.FormAccessor.HamburgerMenuControl.Control.SelectedIndex = 0; 115 | Main.FormAccessor.UpdateLibraryList("All"); 116 | } 117 | } 118 | } 119 | catch (Exception exception) 120 | { 121 | Debug.WriteLine(exception); 122 | Logger.Fatal(exception); 123 | throw; 124 | } 125 | } 126 | 127 | private void Settings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 128 | { 129 | Save(); 130 | 131 | if (e.PropertyName == "BaseTheme" || e.PropertyName == "ThemeAccent") 132 | { 133 | ThemeManager.ChangeAppStyle(Application.Current, 134 | ThemeManager.GetAccent(ThemeAccent), 135 | ThemeManager.GetAppTheme(BaseTheme)); 136 | } 137 | } 138 | } 139 | } -------------------------------------------------------------------------------- /Source/Steam Library Manager/Steam Library Manager.csproj.DotSettings.user: -------------------------------------------------------------------------------- 1 | <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> 2 | <s:Boolean x:Key="/Default/Environment/RuntimeUsedReferences/SolutionImplicitUsedModulesNames/=Costura_002EFody/@EntryIndexedValue">True</s:Boolean> 3 | <s:Boolean x:Key="/Default/Environment/RuntimeUsedReferences/SolutionImplicitUsedModulesNames/=PropertyChanged_002EFody/@EntryIndexedValue">True</s:Boolean> 4 | <s:Boolean x:Key="/Default/Environment/RuntimeUsedReferences/SolutionImplicitUsedModulesNames/=Resource_002EEmbedder/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> -------------------------------------------------------------------------------- /Source/Steam Library Manager/Steam Library Manager.csproj.user: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 3 | <PropertyGroup> 4 | <PublishUrlHistory>publish\</PublishUrlHistory> 5 | <InstallUrlHistory /> 6 | <SupportUrlHistory /> 7 | <UpdateUrlHistory /> 8 | <BootstrapperUrlHistory /> 9 | <ErrorReportUrlHistory /> 10 | <FallbackCulture>en-US</FallbackCulture> 11 | <VerifyUploadedFiles>false</VerifyUploadedFiles> 12 | </PropertyGroup> 13 | <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'"> 14 | <EnableUnmanagedDebugging>false</EnableUnmanagedDebugging> 15 | </PropertyGroup> 16 | </Project> -------------------------------------------------------------------------------- /Source/Steam Library Manager/app.config: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <configuration> 3 | <configSections> 4 | <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 5 | <section name="Steam_Library_Manager.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" /> 6 | </sectionGroup> 7 | </configSections> 8 | <userSettings> 9 | <Steam_Library_Manager.Properties.Settings> 10 | <setting name="steamInstallationPath" serializeAs="String"> 11 | <value /> 12 | </setting> 13 | <setting name="defaultGameSortingMethod" serializeAs="String"> 14 | <value>appName</value> 15 | </setting> 16 | <setting name="gameSizeCalculationMethod" serializeAs="String"> 17 | <value>ACF</value> 18 | </setting> 19 | <setting name="archiveSizeCalculationMethod" serializeAs="String"> 20 | <value>compressed</value> 21 | </setting> 22 | <setting name="ParallelAfterSize" serializeAs="String"> 23 | <value>20</value> 24 | </setting> 25 | <setting name="includeSearchResults" serializeAs="String"> 26 | <value>True</value> 27 | </setting> 28 | <setting name="PlayASoundOnCompletion" serializeAs="String"> 29 | <value>True</value> 30 | </setting> 31 | <setting name="LibraryStyle" serializeAs="String"> 32 | <value>Grid</value> 33 | </setting> 34 | <setting name="CheckforUpdatesAtStartup" serializeAs="String"> 35 | <value>True</value> 36 | </setting> 37 | <setting name="Global_RemoveOldFiles" serializeAs="String"> 38 | <value>False</value> 39 | </setting> 40 | <setting name="Global_Compress" serializeAs="String"> 41 | <value>False</value> 42 | </setting> 43 | <setting name="Global_ReportFileMovement" serializeAs="String"> 44 | <value>True</value> 45 | </setting> 46 | <setting name="Global_StartTaskManagerOnStartup" serializeAs="String"> 47 | <value>False</value> 48 | </setting> 49 | <setting name="CustomSoundFile" serializeAs="String"> 50 | <value /> 51 | </setting> 52 | <setting name="SearchText" serializeAs="String"> 53 | <value /> 54 | </setting> 55 | <setting name="BaseTheme" serializeAs="String"> 56 | <value>BaseLight</value> 57 | </setting> 58 | <setting name="ThemeAccent" serializeAs="String"> 59 | <value>Blue</value> 60 | </setting> 61 | <setting name="CompressionLevel" serializeAs="String"> 62 | <value>Fastest</value> 63 | </setting> 64 | <setting name="Language" serializeAs="String"> 65 | <value>en</value> 66 | </setting> 67 | <setting name="SteamID64" serializeAs="String"> 68 | <value /> 69 | </setting> 70 | <setting name="TaskManager_Logs_AutoScroll" serializeAs="String"> 71 | <value>False</value> 72 | </setting> 73 | <setting name="DefaultCompactLevel" serializeAs="String"> 74 | <value>XPRESS8K</value> 75 | </setting> 76 | <setting name="AdvancedCompactSizeDetection" serializeAs="String"> 77 | <value>False</value> 78 | </setting> 79 | <setting name="TaskManager_AutoClear" serializeAs="String"> 80 | <value>False</value> 81 | </setting> 82 | <setting name="CompactDetection" serializeAs="String"> 83 | <value>False</value> 84 | </setting> 85 | <setting name="TaskManager_ContinueOnError" serializeAs="String"> 86 | <value>False</value> 87 | </setting> 88 | <setting name="TaskManager_SteamRestartSkip" serializeAs="String"> 89 | <value>False</value> 90 | </setting> 91 | <setting name="LastUserVersion" serializeAs="String"> 92 | <value /> 93 | </setting> 94 | <setting name="Steam_IsEnabled" serializeAs="String"> 95 | <value>True</value> 96 | </setting> 97 | <setting name="Origin_IsEnabled" serializeAs="String"> 98 | <value>False</value> 99 | </setting> 100 | <setting name="Uplay_IsEnabled" serializeAs="String"> 101 | <value>False</value> 102 | </setting> 103 | <setting name="UplayExePath" serializeAs="String"> 104 | <value /> 105 | </setting> 106 | <setting name="UplayDbPath" serializeAs="String"> 107 | <value /> 108 | </setting> 109 | <setting name="InstallationWizardShown" serializeAs="String"> 110 | <value>False</value> 111 | </setting> 112 | </Steam_Library_Manager.Properties.Settings> 113 | </userSettings> 114 | <runtime> 115 | <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 116 | <dependentAssembly> 117 | <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" /> 118 | <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" /> 119 | </dependentAssembly> 120 | <dependentAssembly> 121 | <assemblyIdentity name="System.Runtime.InteropServices.RuntimeInformation" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> 122 | <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> 123 | </dependentAssembly> 124 | <dependentAssembly> 125 | <assemblyIdentity name="Sentry.Protocol" publicKeyToken="fba2ec45388e2af0" culture="neutral" /> 126 | <bindingRedirect oldVersion="0.0.0.0-1.0.4.0" newVersion="1.0.4.0" /> 127 | </dependentAssembly> 128 | <dependentAssembly> 129 | <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> 130 | <bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" /> 131 | </dependentAssembly> 132 | <dependentAssembly> 133 | <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /> 134 | <bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" /> 135 | </dependentAssembly> 136 | </assemblyBinding> 137 | </runtime> 138 | <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" /></startup></configuration> 139 | -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: /Source/Steam Library Manager/Properties/Resources.resx 3 | translation: /Source/Steam Library Manager/Properties/Resources.%two_letters_code%.resx 4 | --------------------------------------------------------------------------------