├── .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 ` ` 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 | Note: Even tho the repository is no longer actively maintained, there are no known bugs and SLM can be safely used like always .
2 | If you like to support me to get back to work on SLM back, you can make a donation via PayPal .
3 | Feel free to contact with me in case of an urgent bug, thanks. Discord: RevoLand#3385
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Steam Library Manager
16 | 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.
17 | Benefits to using SLM over Steam Backup:
18 |
19 | Backups can be updated quickly. No need to recreate the entire backup from scratch.
20 | Backup files are open and easily accessible.
21 | Workshop content and mods such as ENB, ReShade, and SweetFX get backed up automatically.
22 | Faster backups, faster restores, works with or without the Clients running.
23 | Compression is available for those who want to keep things lean.
24 | Built-in library cleaner for leftovers.
25 | Compact both backups and installed games for even more hard disk space.
26 |
27 | SLM is licensed under MIT license which means it is completely free and open source!
28 | All suggestions are welcome and will help further development of SLM.
29 |
30 | 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 |
33 |
34 |
35 |
36 |
37 |
38 |
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 |
2 | True
--------------------------------------------------------------------------------
/Source/Steam Library Manager/App.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/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 | ///
10 | /// Interaction logic for App.xaml
11 | ///
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 AllowedLibraryTypes = new System.Collections.Generic.List();
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(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> AppIds = new List>();
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 Apps { get; set; } = new System.Collections.ObjectModel.ObservableCollection();
35 | public Dictionary DirectoryList { get; set; } = new Dictionary();
36 | public List AllowedAppTypes = new List();
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 ContextMenu => _contextMenuElements ?? (_contextMenuElements = GenerateCMenuItems());
44 | private List _contextMenuElements;
45 |
46 | private List GenerateCMenuItems()
47 | {
48 | var cMenu = new List();
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 Libraries { get; set; } = new ObservableCollection();
15 |
16 | public static ObservableCollection JunkItems { get; set; } = new ObservableCollection();
17 | public static ObservableCollection DupeItems { get; set; } = new ObservableCollection();
18 | public static ObservableCollection IgnoredJunkItems { get; set; } = new ObservableCollection();
19 |
20 | public static readonly IProgress LibraryProgress = new Progress(library => Libraries.Add(library));
21 | public static readonly IProgress LcProgress = new Progress(junk => JunkItems.Add(junk));
22 | public static readonly IProgress DupeItemsRemove = new Progress(dupe => DupeItems.Remove(dupe));
23 |
24 | public static ObservableCollection LibraryCMenuItems { get; set; } = new ObservableCollection();
25 | public static ObservableCollection AppCMenuItems { get; set; } = new ObservableCollection();
26 |
27 | public static readonly List> SteamUserIdList = new List>();
28 | public static readonly Dictionary SteamAppsLastPlayedDic = new Dictionary();
29 | public static readonly List UplayConfigurations = new List();
30 | public static readonly Dictionary UplayAppIds = new Dictionary();
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 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Source/Steam Library Manager/FodyWeavers.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Used to control if the On_PropertyName_Changed feature is enabled.
12 |
13 |
14 |
15 |
16 | Used to control if the Dependent properties feature is enabled.
17 |
18 |
19 |
20 |
21 | Used to control if the IsChanged property feature is enabled.
22 |
23 |
24 |
25 |
26 | 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.
27 |
28 |
29 |
30 |
31 | Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project.
32 |
33 |
34 |
35 |
36 | Used to control if equality checks should use the Equals method resolved from the base class.
37 |
38 |
39 |
40 |
41 | Used to control if equality checks should use the static Equals method resolved from the base class.
42 |
43 |
44 |
45 |
46 | Used to turn off build warnings from this weaver.
47 |
48 |
49 |
50 |
51 | Used to turn off build warnings about mismatched On_PropertyName_Changed methods.
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks
62 |
63 |
64 |
65 |
66 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.
67 |
68 |
69 |
70 |
71 | A list of unmanaged 32 bit assembly names to include, delimited with line breaks.
72 |
73 |
74 |
75 |
76 | A list of unmanaged 64 bit assembly names to include, delimited with line breaks.
77 |
78 |
79 |
80 |
81 | The order of preloaded assemblies, delimited with line breaks.
82 |
83 |
84 |
85 |
86 |
87 | 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.
88 |
89 |
90 |
91 |
92 | Controls if .pdbs for reference assemblies are also embedded.
93 |
94 |
95 |
96 |
97 | Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.
98 |
99 |
100 |
101 |
102 | As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.
103 |
104 |
105 |
106 |
107 | 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.
108 |
109 |
110 |
111 |
112 | 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.
113 |
114 |
115 |
116 |
117 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |
118 |
119 |
120 |
121 |
122 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.
123 |
124 |
125 |
126 |
127 | A list of unmanaged 32 bit assembly names to include, delimited with |.
128 |
129 |
130 |
131 |
132 | A list of unmanaged 64 bit assembly names to include, delimited with |.
133 |
134 |
135 |
136 |
137 | The order of preloaded assemblies, delimited with |.
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
146 |
147 |
148 |
149 |
150 | A comma-separated list of error codes that can be safely ignored in assembly verification.
151 |
152 |
153 |
154 |
155 | 'false' to turn off automatic generation of the XML Schema file.
156 |
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/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 | ///
9 | /// Interaction logic for AppView.xaml
10 | ///
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 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
45 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
68 |
69 |
70 |
71 |
72 |
73 | Steam
74 |
75 |
76 |
77 |
78 | Origin
79 |
80 |
81 |
82 |
83 | Uplay
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/Source/Steam Library Manager/Forms/HamburgerMenuControl.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace Steam_Library_Manager.Forms
2 | {
3 | ///
4 | /// Interaction logic for HamburgerMenuControl.xaml
5 | ///
6 | public partial class HamburgerMenuControl
7 | {
8 | public HamburgerMenuControl()
9 | {
10 | InitializeComponent();
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/Source/Steam Library Manager/Forms/InstallationWizard/Final.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/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 | ///
8 | /// Interaction logic for Final.xaml
9 | ///
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 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Source/Steam Library Manager/Forms/InstallationWizard/Library.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace Steam_Library_Manager.Forms.InstallationWizard
2 | {
3 | ///
4 | /// Interaction logic for Steam.xaml
5 | ///
6 | public partial class Library
7 | {
8 | public Library()
9 | {
10 | InitializeComponent();
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/Source/Steam Library Manager/Forms/InstallationWizard/Welcome.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
24 |
27 |
28 |
29 |
32 |
33 |
34 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Source/Steam Library Manager/Forms/InstallationWizard/Welcome.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace Steam_Library_Manager.Forms.InstallationWizard
4 | {
5 | ///
6 | /// Interaction logic for Welcome.xaml
7 | ///
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 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Source/Steam Library Manager/Forms/InstallationWizard/Wizard.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace Steam_Library_Manager.Forms.InstallationWizard
4 | {
5 | ///
6 | /// Interaction logic for Wizard.xaml
7 | ///
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 | ///
14 | /// Interaction logic for LibraryView.xaml
15 | ///
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().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 | ///
12 | /// Interaction logic for SettingsView.xaml
13 | ///
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 | ///
12 | /// Interaction logic for TaskManagerView.xaml
13 | ///
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().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().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().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 IsWritingFile = new Dictionary();
26 |
27 | static FileCache() => AppCacheMode = CacheMode.Dedicated;
28 |
29 | ///
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 | ///
33 | public static CacheMode AppCacheMode { get; set; }
34 |
35 | public static async Task 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 | ///
15 | /// Represents a control that is a wrapper on System.Windows.Controls.Image for enabling filesystem-based caching
16 | ///
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 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 | ///
11 | /// The primary class for accessing the functionality of the StringFormat library.
12 | ///
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 | ///
31 | /// Formats the string using the placeholder for the property names.
32 | ///
33 | /// The string to format.
34 | /// The object to pull the values from. Usually an anonymous type.
35 | /// The formatted string.
36 | public static string Format(string format, object values)
37 | {
38 | return Format(null, format, values);
39 | }
40 |
41 | ///
42 | /// Formats the string using the placeholder for the property names.
43 | ///
44 | /// The provider to use for formatting dates and numeric values.
45 | /// The string to format.
46 | /// The object to pull the values from. Usually an anonymous type.
47 | /// The formatted string.
48 | public static string Format(IFormatProvider provider, string format, object values)
49 | {
50 | return Format(provider, format, AnonymousObjectToDictionary(values));
51 | }
52 |
53 | ///
54 | /// Formats the string using the placeholder for the property names.
55 | ///
56 | /// The string to format.
57 | /// The dictionary to pull the values from.
58 | /// The formatted string.
59 | public static string Format(string format, IDictionary values)
60 | {
61 | return Format(null, format, values);
62 | }
63 |
64 | ///
65 | /// Formats the string using the placeholder for the property names.
66 | ///
67 | /// The provider to use for formatting dates and numeric values.
68 | /// The string to format.
69 | /// The dictionary to pull the values from.
70 | /// The formatted string.
71 | public static string Format(IFormatProvider provider, string format, IDictionary values)
72 | {
73 | if (values == null)
74 | {
75 | throw new ArgumentNullException(nameof(values));
76 | }
77 |
78 | var tokenizedString = TokenizeString(format, out IEnumerable tokens);
79 |
80 | return string.Format(provider, tokenizedString, tokens.Select(s => values[s]).ToArray());
81 | }
82 |
83 | ///
84 | /// Returns the format string with the tokens replaced as ordinals. Exposed for developer benefit. Most likely used only in debugging.
85 | ///
86 | /// The string to format.
87 | /// A string where the tokens are replaced with ordinal values.
88 | public static string TokenizeString(string format)
89 | {
90 | return TokenizeString(format, out IEnumerable junk);
91 | }
92 |
93 | ///
94 | /// Returns the format string with the tokens replaced as ordinals. Exposed for developer benefit. Most likely used only in debugging.
95 | ///
96 | /// The string to format.
97 | /// The tokens that were extracted from the format string.
98 | /// A string where the tokens are replaced with ordinal values.
99 | public static string TokenizeString(string format, out IEnumerable 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();
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 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 AnonymousObjectToDictionary(object values)
171 | {
172 | var valueDictionary = new Dictionary();
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 FileList, List 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 | //CultureYouAreCodingWith in your .csproj file
25 | //inside a . For example, if you are using US english
26 | //in your source files, set the to en-US. Then uncomment
27 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
28 | //the line below to match the UICulture setting in the project file.
29 |
30 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
31 |
32 | [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 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | appName
13 |
14 |
15 | ACF
16 |
17 |
18 | compressed
19 |
20 |
21 | 20
22 |
23 |
24 | True
25 |
26 |
27 | True
28 |
29 |
30 | Grid
31 |
32 |
33 | True
34 |
35 |
36 | False
37 |
38 |
39 | False
40 |
41 |
42 | True
43 |
44 |
45 | False
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | BaseLight
55 |
56 |
57 | Blue
58 |
59 |
60 |
61 |
62 |
63 | Fastest
64 |
65 |
66 | en
67 |
68 |
69 |
70 |
71 |
72 | False
73 |
74 |
75 | XPRESS8K
76 |
77 |
78 | False
79 |
80 |
81 | False
82 |
83 |
84 |
85 |
86 |
87 | False
88 |
89 |
90 | False
91 |
92 |
93 | False
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | True
103 |
104 |
105 | False
106 |
107 |
108 | False
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | False
118 |
119 |
120 |
--------------------------------------------------------------------------------
/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 |
2 | True
3 | True
4 | True
--------------------------------------------------------------------------------
/Source/Steam Library Manager/Steam Library Manager.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | publish\
5 |
6 |
7 |
8 |
9 |
10 | en-US
11 | false
12 |
13 |
14 | false
15 |
16 |
--------------------------------------------------------------------------------
/Source/Steam Library Manager/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | appName
15 |
16 |
17 | ACF
18 |
19 |
20 | compressed
21 |
22 |
23 | 20
24 |
25 |
26 | True
27 |
28 |
29 | True
30 |
31 |
32 | Grid
33 |
34 |
35 | True
36 |
37 |
38 | False
39 |
40 |
41 | False
42 |
43 |
44 | True
45 |
46 |
47 | False
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | BaseLight
57 |
58 |
59 | Blue
60 |
61 |
62 | Fastest
63 |
64 |
65 | en
66 |
67 |
68 |
69 |
70 |
71 | False
72 |
73 |
74 | XPRESS8K
75 |
76 |
77 | False
78 |
79 |
80 | False
81 |
82 |
83 | False
84 |
85 |
86 | False
87 |
88 |
89 | False
90 |
91 |
92 |
93 |
94 |
95 | True
96 |
97 |
98 | False
99 |
100 |
101 | False
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | False
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
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 |
--------------------------------------------------------------------------------