steam-client 3.0.0.dev0__tar.gz → 4.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. steam_client-4.1.0/PKG-INFO +145 -0
  2. steam_client-4.1.0/README.md +128 -0
  3. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/pyproject.toml +1 -31
  4. steam_client-4.1.0/steam_client/__init__.py +3 -0
  5. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/steam_client/app.py +1 -7
  6. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/steam_client/commands.py +12 -24
  7. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/steam_client/game.py +25 -21
  8. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/steam_client/library.py +22 -20
  9. steam_client-4.1.0/steam_client/library_folder.py +17 -0
  10. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/steam_client/login_users.py +11 -12
  11. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/steam_client/shortcut.py +29 -11
  12. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/steam_client/steam.py +1 -1
  13. steam_client-4.1.0/steam_client.egg-info/PKG-INFO +145 -0
  14. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/steam_client.egg-info/SOURCES.txt +3 -2
  15. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/tests/test_commands.py +4 -12
  16. steam_client-4.1.0/tests/test_game.py +108 -0
  17. steam_client-4.1.0/tests/test_library.py +220 -0
  18. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/tests/test_login_users.py +5 -5
  19. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/tests/test_shortcut.py +14 -15
  20. steam_client-3.0.0.dev0/PKG-INFO +0 -16
  21. steam_client-3.0.0.dev0/steam_client/__init__.py +0 -0
  22. steam_client-3.0.0.dev0/steam_client/library_directory.py +0 -18
  23. steam_client-3.0.0.dev0/steam_client/web_api.py +0 -24
  24. steam_client-3.0.0.dev0/steam_client.egg-info/PKG-INFO +0 -16
  25. steam_client-3.0.0.dev0/tests/test_game.py +0 -61
  26. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/LICENSE +0 -0
  27. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/setup.cfg +0 -0
  28. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/setup.py +0 -0
  29. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/steam_client/py.typed +0 -0
  30. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/steam_client/utils.py +0 -0
  31. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/steam_client.egg-info/dependency_links.txt +0 -0
  32. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/steam_client.egg-info/requires.txt +0 -0
  33. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/steam_client.egg-info/top_level.txt +0 -0
  34. {steam_client-3.0.0.dev0 → steam_client-4.1.0}/tests/test_steam.py +0 -0
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.4
2
+ Name: steam-client
3
+ Version: 4.1.0
4
+ Summary: Steam client library for Python
5
+ Author-email: William McAllister <dev.garulf@gmail.com>
6
+ License: MIT
7
+ Project-URL: Source, https://github.com/garulf/steam-client
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3 :: Only
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: vdf>=3.4
15
+ Requires-Dist: pycrc>=0.10.0
16
+ Dynamic: license-file
17
+
18
+ # Steam Client
19
+
20
+ A Python library for interacting with a locally installed Steam client — enumerate your game library/non-steam games, read game metadata and artwork paths, and send Steam URI commands.
21
+
22
+ [![Docs](https://img.shields.io/badge/docs-mkdocs%20material-0A7BBB?style=flat&logo=materialformkdocs&logoColor=white)](docs/index.md)
23
+
24
+ [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-garulf-FFDD00?style=flat&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/garulf)
25
+ [![Ko-fi](https://img.shields.io/badge/Ko--fi-garulf-FF5E5B?style=flat&logo=ko-fi&logoColor=white)](https://ko-fi.com/garulf)
26
+
27
+ ---
28
+
29
+ ## Installation
30
+
31
+ Requires Python 3.8+.
32
+
33
+ ```bash
34
+ pip install steam-client
35
+ ```
36
+
37
+ Or install from source:
38
+
39
+ ```bash
40
+ pip install -e .
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Quickstart
46
+
47
+ ```python
48
+ from steam_client.steam import Steam
49
+
50
+ steam = Steam() # Uses default path: C:\Program Files (x86)\Steam
51
+
52
+ # On Windows, auto-detect path from registry:
53
+ from steam_client.utils import steam_from_registry
54
+ steam = steam_from_registry()
55
+ ```
56
+
57
+ ---
58
+
59
+ ## Common Operations
60
+
61
+ ### List all installed games
62
+
63
+ ```python
64
+ for game in steam.library.games():
65
+ print(game.appid, game.name)
66
+ ```
67
+
68
+ ### Find a game
69
+
70
+ ```python
71
+ game = steam.library.game_by_id("440") # by app ID
72
+ game = steam.library.game_by_name("Portal 2") # by name (case-insensitive)
73
+ ```
74
+
75
+ ### Artwork paths
76
+
77
+ ```python
78
+ game.header # Path to header image (460×215 jpg)
79
+ game.grid # Path to grid image (600×900 jpg)
80
+ game.hero # Path to hero image
81
+ game.icon # Path to icon file, or None
82
+ ```
83
+
84
+ ### Launch and manage games via Steam URI commands
85
+
86
+ ```python
87
+ from steam_client.commands import Commands, SteamWindows
88
+
89
+ commands = Commands()
90
+ commands.run_game_id("440") # Launch a game
91
+ commands.store("440") # Open store page
92
+ commands.install("440") # Prompt install
93
+ commands.uninstall("440") # Prompt uninstall
94
+ commands.open(SteamWindows.FRIENDS) # Open a Steam window
95
+ commands.open_url("https://store.steampowered.com")
96
+ ```
97
+
98
+ Or launch a game directly from a `SteamGame` object:
99
+
100
+ ```python
101
+ game.run()
102
+ ```
103
+
104
+ ### Users and shortcuts
105
+
106
+ ```python
107
+ for user in steam.users:
108
+ print(user.user.data.PersonaName)
109
+
110
+ for shortcut in steam.library.shortcuts():
111
+ print(shortcut.appname)
112
+ ```
113
+
114
+ ## Platform Notes
115
+
116
+ | Platform | Default path | Registry helper |
117
+ |----------|--------------------------------|-------------------------|
118
+ | Windows | `C:\Program Files (x86)\Steam` | `steam_from_registry()` |
119
+ | Linux | `~/.local/share/steam` | Not available |
120
+
121
+ Pass a custom path to override the default:
122
+
123
+ ```python
124
+ steam = Steam("/custom/steam/path")
125
+ ```
126
+
127
+ Requires read access to local Steam config files (`libraryfolders.vdf`, `shortcuts.vdf`, appmanifest files).
128
+
129
+ ---
130
+
131
+ ## Development
132
+
133
+ ```bash
134
+ pytest # Run tests
135
+ flake8 steam_client # Lint
136
+ mypy steam_client # Type check
137
+ mkdocs serve # Preview docs locally
138
+ mkdocs build --strict # Validate docs build
139
+ tox # Run all environments (lint, type, docs, py311–314)
140
+
141
+ bump-my-version show current_version # Show current version
142
+ bump-my-version bump patch # 4.0.0 → 4.0.1
143
+ bump-my-version bump minor # 4.0.0 → 4.1.0
144
+ bump-my-version bump major # 4.0.0 → 5.0.0
145
+ ```
@@ -0,0 +1,128 @@
1
+ # Steam Client
2
+
3
+ A Python library for interacting with a locally installed Steam client — enumerate your game library/non-steam games, read game metadata and artwork paths, and send Steam URI commands.
4
+
5
+ [![Docs](https://img.shields.io/badge/docs-mkdocs%20material-0A7BBB?style=flat&logo=materialformkdocs&logoColor=white)](docs/index.md)
6
+
7
+ [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-garulf-FFDD00?style=flat&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/garulf)
8
+ [![Ko-fi](https://img.shields.io/badge/Ko--fi-garulf-FF5E5B?style=flat&logo=ko-fi&logoColor=white)](https://ko-fi.com/garulf)
9
+
10
+ ---
11
+
12
+ ## Installation
13
+
14
+ Requires Python 3.8+.
15
+
16
+ ```bash
17
+ pip install steam-client
18
+ ```
19
+
20
+ Or install from source:
21
+
22
+ ```bash
23
+ pip install -e .
24
+ ```
25
+
26
+ ---
27
+
28
+ ## Quickstart
29
+
30
+ ```python
31
+ from steam_client.steam import Steam
32
+
33
+ steam = Steam() # Uses default path: C:\Program Files (x86)\Steam
34
+
35
+ # On Windows, auto-detect path from registry:
36
+ from steam_client.utils import steam_from_registry
37
+ steam = steam_from_registry()
38
+ ```
39
+
40
+ ---
41
+
42
+ ## Common Operations
43
+
44
+ ### List all installed games
45
+
46
+ ```python
47
+ for game in steam.library.games():
48
+ print(game.appid, game.name)
49
+ ```
50
+
51
+ ### Find a game
52
+
53
+ ```python
54
+ game = steam.library.game_by_id("440") # by app ID
55
+ game = steam.library.game_by_name("Portal 2") # by name (case-insensitive)
56
+ ```
57
+
58
+ ### Artwork paths
59
+
60
+ ```python
61
+ game.header # Path to header image (460×215 jpg)
62
+ game.grid # Path to grid image (600×900 jpg)
63
+ game.hero # Path to hero image
64
+ game.icon # Path to icon file, or None
65
+ ```
66
+
67
+ ### Launch and manage games via Steam URI commands
68
+
69
+ ```python
70
+ from steam_client.commands import Commands, SteamWindows
71
+
72
+ commands = Commands()
73
+ commands.run_game_id("440") # Launch a game
74
+ commands.store("440") # Open store page
75
+ commands.install("440") # Prompt install
76
+ commands.uninstall("440") # Prompt uninstall
77
+ commands.open(SteamWindows.FRIENDS) # Open a Steam window
78
+ commands.open_url("https://store.steampowered.com")
79
+ ```
80
+
81
+ Or launch a game directly from a `SteamGame` object:
82
+
83
+ ```python
84
+ game.run()
85
+ ```
86
+
87
+ ### Users and shortcuts
88
+
89
+ ```python
90
+ for user in steam.users:
91
+ print(user.user.data.PersonaName)
92
+
93
+ for shortcut in steam.library.shortcuts():
94
+ print(shortcut.appname)
95
+ ```
96
+
97
+ ## Platform Notes
98
+
99
+ | Platform | Default path | Registry helper |
100
+ |----------|--------------------------------|-------------------------|
101
+ | Windows | `C:\Program Files (x86)\Steam` | `steam_from_registry()` |
102
+ | Linux | `~/.local/share/steam` | Not available |
103
+
104
+ Pass a custom path to override the default:
105
+
106
+ ```python
107
+ steam = Steam("/custom/steam/path")
108
+ ```
109
+
110
+ Requires read access to local Steam config files (`libraryfolders.vdf`, `shortcuts.vdf`, appmanifest files).
111
+
112
+ ---
113
+
114
+ ## Development
115
+
116
+ ```bash
117
+ pytest # Run tests
118
+ flake8 steam_client # Lint
119
+ mypy steam_client # Type check
120
+ mkdocs serve # Preview docs locally
121
+ mkdocs build --strict # Validate docs build
122
+ tox # Run all environments (lint, type, docs, py311–314)
123
+
124
+ bump-my-version show current_version # Show current version
125
+ bump-my-version bump patch # 4.0.0 → 4.0.1
126
+ bump-my-version bump minor # 4.0.0 → 4.1.0
127
+ bump-my-version bump major # 4.0.0 → 5.0.0
128
+ ```
@@ -6,7 +6,7 @@ name = "steam-client"
6
6
  authors = [
7
7
  {name = "William McAllister", email = "dev.garulf@gmail.com"}
8
8
  ]
9
- version = "3.0.0-dev.0"
9
+ version = "4.1.0"
10
10
  description = "Steam client library for Python"
11
11
  readme = "README.md"
12
12
  requires-python = ">=3.8"
@@ -30,34 +30,4 @@ packages = ["steam_client"]
30
30
  [tool.setuptools.package-data]
31
31
  "steam_client" = ["py.typed"]
32
32
 
33
- [tool.bumpversion]
34
- current_version = "3.0.0-dev.0"
35
- search = "version = \"{current_version}\""
36
- replace = "version = \"{new_version}\""
37
- parse = """(?x)
38
- (?P<major>[0-9]+)
39
- \\.(?P<minor>[0-9]+)
40
- \\.(?P<patch>[0-9]+)
41
- (?:
42
- -(?P<label>dev|rc|release)
43
- (?:.(?P<label_n>[0-9]+))?
44
- )?
45
- """
46
- serialize = [
47
- "{major}.{minor}.{patch}-{label}.{label_n}",
48
- "{major}.{minor}.{patch}",
49
- ]
50
- tag = true
51
- allow_dirty = false
52
- commit = true
53
-
54
- [tool.bumpversion.parts.label]
55
- optional_value = "release"
56
- values =[
57
- "dev",
58
- "rc",
59
- "release",
60
- ]
61
33
 
62
- [[tool.bumpversion.files]]
63
- filename = "pyproject.toml"
@@ -0,0 +1,3 @@
1
+ from steam_client.steam import Steam
2
+
3
+ __all__ = ["Steam"]
@@ -1,20 +1,14 @@
1
1
  from __future__ import annotations
2
2
  from abc import ABC, abstractmethod
3
3
  from pathlib import Path
4
- from typing import TYPE_CHECKING
5
-
6
4
 
7
5
  from .commands import Commands
8
6
 
9
- if TYPE_CHECKING:
10
- from .steam import Steam
11
-
12
7
 
13
8
  class App(ABC):
14
9
  """Abstract base class for all Steam apps."""
15
10
 
16
- def __init__(self, steam: Steam):
17
- self._steam = steam
11
+ def __init__(self):
18
12
  self._commands = Commands()
19
13
 
20
14
  @property
@@ -1,8 +1,9 @@
1
- from typing import List
2
1
  import webbrowser
3
2
  from enum import StrEnum
4
3
 
5
- SCHEME = 'steam'
4
+
5
+ def _create_uri(*segments: str) -> str:
6
+ return f'steam://{"/".join(segments)}'
6
7
 
7
8
 
8
9
  class SteamWindows(StrEnum):
@@ -21,49 +22,36 @@ class SteamWindows(StrEnum):
21
22
  CONSOLE = 'console'
22
23
 
23
24
 
24
- class Command():
25
-
26
- def __init__(self, scheme: str):
27
- self._scheme = scheme
28
-
29
- def _create_uri(self, path: List[str], endpoint: str) -> str:
30
- return f'{self._scheme}://{"/".join(path)}/{endpoint}'
31
-
32
- def __call__(self, path: List[str], endpoint: str) -> None:
33
- """Executes the command with the specified endpoint."""
34
- webbrowser.open(self._create_uri(path, endpoint))
35
-
36
-
37
25
  class Commands:
38
26
  """A collection of commands for the Steam client."""
39
27
 
40
- def __init__(self):
41
- self._command = Command(SCHEME)
28
+ def _open(self, *segments: str) -> None:
29
+ webbrowser.open(_create_uri(*segments))
42
30
 
43
31
  def run_game_id(self, app_id: str) -> None:
44
32
  """Launches game with the specified ID in the Steam client."""
45
- self._command(['rungameid'], app_id)
33
+ self._open('rungameid', app_id)
46
34
 
47
35
  def store(self, app_id: str) -> None:
48
36
  """Opens the game's store page in the Steam client."""
49
- self._command(['store'], app_id)
37
+ self._open('store', app_id)
50
38
 
51
39
  def install(self, app_id: str) -> None:
52
40
  """Opens the game's install prompt in the Steam client."""
53
- self._command(['install'], app_id)
41
+ self._open('install', app_id)
54
42
 
55
43
  def uninstall(self, app_id: str) -> None:
56
44
  """Opens the game's uninstall prompt in the Steam client."""
57
- self._command(['uninstall'], app_id)
45
+ self._open('uninstall', app_id)
58
46
 
59
47
  def update_news(self, app_id: str) -> None:
60
48
  """Opens the game's update news in the Steam client."""
61
- self._command(['updatenews'], app_id)
49
+ self._open('updatenews', app_id)
62
50
 
63
51
  def open(self, window: SteamWindows) -> None:
64
52
  """Opens the specified window in the Steam client."""
65
- self._command(['open'], window)
53
+ self._open('open', window)
66
54
 
67
55
  def open_url(self, url: str) -> None:
68
56
  """Opens the specified URL in the Steam client."""
69
- self._command(['openurl'], url)
57
+ self._open('openurl', url)
@@ -1,13 +1,9 @@
1
1
  from __future__ import annotations
2
2
  import functools
3
3
  from pathlib import Path
4
- from typing import TYPE_CHECKING
5
4
 
6
5
  import vdf # type: ignore
7
6
 
8
- if TYPE_CHECKING:
9
- from .steam import Steam
10
-
11
7
  from .app import App
12
8
 
13
9
 
@@ -22,19 +18,20 @@ ASSETS = frozenset({
22
18
  })
23
19
 
24
20
 
25
- class SteamGame(App):
21
+ class Game(App):
26
22
  """Represents a Steam game."""
27
23
 
28
- def __init__(self, steam: Steam, library_path: str, appid: str):
24
+ def __init__(self, library_cache_path: Path, library_path: str, appid: str):
25
+ self._library_cache_path = Path(library_cache_path)
29
26
  self.library_path = library_path
30
27
  self._appid = appid
31
28
  self._icon: Path | None = None
32
29
  self._name: str | None = None
33
- super().__init__(steam)
30
+ super().__init__()
34
31
 
35
32
  def __repr__(self) -> str:
36
33
  return (
37
- f'Game(steam={self._steam.__repr__()}, '
34
+ f'Game(library_cache_path={self._library_cache_path.__repr__()}, '
38
35
  f'library_path={self.library_path.__repr__()}, '
39
36
  f'appid={self.appid.__repr__()})'
40
37
  )
@@ -42,41 +39,44 @@ class SteamGame(App):
42
39
  @property
43
40
  def asset_dir(self) -> Path:
44
41
  """Returns the path to the game's asset directory."""
45
- return Path(self._steam.library_cache).joinpath(self.appid)
42
+ return self._library_cache_path.joinpath(self.appid)
46
43
 
47
44
  @property
48
45
  def icon(self) -> Path | None:
49
46
  """Returns the path to the icon image."""
50
47
  if self._icon is None:
51
- self._icon = next(
52
- (
53
- asset
54
- for asset in self.asset_dir.iterdir()
55
- if asset.is_file() and asset.name not in ASSETS
56
- ),
57
- None,
58
- )
48
+ try:
49
+ self._icon = next(
50
+ (
51
+ asset
52
+ for asset in self.asset_dir.iterdir()
53
+ if asset.is_file() and asset.name not in ASSETS
54
+ ),
55
+ None,
56
+ )
57
+ except (FileNotFoundError, NotADirectoryError):
58
+ return None
59
59
  return self._icon
60
60
 
61
61
  @property
62
62
  def header(self) -> Path:
63
63
  """Returns the path to the header image."""
64
- return Path(self._steam.library_cache).joinpath(f'{self.appid}_header.jpg')
64
+ return self._library_cache_path.joinpath(f'{self.appid}_header.jpg')
65
65
 
66
66
  @property
67
67
  def grid(self) -> Path:
68
68
  """Returns the path to the 600x900 grid image."""
69
- return Path(self._steam.library_cache).joinpath(f'{self.appid}_library_600x900.jpg')
69
+ return self._library_cache_path.joinpath(f'{self.appid}_library_600x900.jpg')
70
70
 
71
71
  @property
72
72
  def hero(self) -> Path:
73
73
  """Returns the path to the hero image."""
74
- return Path(self._steam.library_cache).joinpath(f'{self.appid}_library_hero.jpg')
74
+ return self._library_cache_path.joinpath(f'{self.appid}_library_hero.jpg')
75
75
 
76
76
  @property
77
77
  def hero_blur(self) -> Path:
78
78
  """Returns the path to the blurred hero image."""
79
- return Path(self._steam.library_cache).joinpath(f'{self.appid}_library_hero_blur.jpg')
79
+ return self._library_cache_path.joinpath(f'{self.appid}_library_hero_blur.jpg')
80
80
 
81
81
  @property
82
82
  def manifest_path(self) -> Path:
@@ -115,6 +115,10 @@ class SteamGame(App):
115
115
  """Opens the game's store page in the Steam client."""
116
116
  self._commands.store(self.appid)
117
117
 
118
+ def install(self):
119
+ """Installs the game."""
120
+ self._commands.install(self.appid)
121
+
118
122
  def uninstall(self):
119
123
  """Uninstalls the game."""
120
124
  self._commands.uninstall(self.appid)
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
  import hashlib
3
- from typing import TYPE_CHECKING, List, Optional, Union
3
+ from typing import TYPE_CHECKING, List, Optional, Union, Generator
4
4
 
5
5
  import vdf # type: ignore
6
6
 
@@ -8,8 +8,8 @@ from steam_client.shortcut import Shortcut
8
8
 
9
9
  if TYPE_CHECKING:
10
10
  from .steam import Steam
11
- from .library_directory import LibraryDirectory
12
- from .game import SteamGame
11
+ from .library_folder import LibraryFolder
12
+ from .game import Game
13
13
 
14
14
 
15
15
  class Library:
@@ -18,7 +18,7 @@ class Library:
18
18
  def __init__(self, steam: 'Steam'):
19
19
  self._steam = steam
20
20
  self._libraries_hash: Optional[str] = None
21
- self._libraries: List[LibraryDirectory] = []
21
+ self._libraries: List[LibraryFolder] = []
22
22
 
23
23
  def _hash_steam_libraries(self) -> str:
24
24
  """Returns the MD5 hash of the Steam library folders file."""
@@ -35,44 +35,46 @@ class Library:
35
35
  libraries = vdf.load(f)
36
36
  # The is not always formatted the same way, so we grab the first key
37
37
  folder_key = list(libraries.keys())[0]
38
- self._libraries = [LibraryDirectory(self._steam, libraries[folder_key][item]["path"],
39
- libraries[folder_key][item]["apps"]) for item in libraries[folder_key]]
38
+ self._libraries = [LibraryFolder(self._steam.library_cache, libraries[folder_key][item]["path"],
39
+ libraries[folder_key][item]["apps"]) for item in libraries[folder_key]]
40
40
 
41
- def libraries(self) -> List[LibraryDirectory]:
41
+ def libraries(self) -> Generator[LibraryFolder, None, None]:
42
42
  """Returns the Steam library folders."""
43
43
  if self._is_updated():
44
44
  self._libraries_hash = self._hash_steam_libraries()
45
45
  self._update_libraries()
46
- return self._libraries
46
+ for library in self._libraries:
47
+ yield library
47
48
 
48
- def games(self) -> List[SteamGame]:
49
+ def games(self) -> Generator[Game, None, None]:
49
50
  """Returns the games from the Steam library."""
50
- games = []
51
51
  for library in self.libraries():
52
- games.extend(library.get_games())
53
- return games
52
+ for game in library.get_games():
53
+ yield game
54
54
 
55
- def game_by_id(self, appid: str) -> Optional[SteamGame]:
55
+ def game_by_id(self, appid: str) -> Optional[Game]:
56
56
  """Returns the game with the specified ID."""
57
57
  for game in self.games():
58
58
  if game.appid == appid:
59
59
  return game
60
60
  return None
61
61
 
62
- def game_by_name(self, name: str) -> Optional[SteamGame]:
62
+ def game_by_name(self, name: str) -> Optional[Game]:
63
63
  """Returns the game with the specified name."""
64
64
  for game in self.games():
65
65
  if game.name.casefold() == name.casefold():
66
66
  return game
67
67
  return None
68
68
 
69
- def shortcuts(self) -> List[Shortcut]:
69
+ def shortcuts(self) -> Generator[Shortcut, None, None]:
70
70
  """Returns the Non-Steam shortcuts from the Steam library."""
71
- shortcuts = []
72
71
  for user in self._steam.users:
73
- shortcuts.extend(user.shortcuts())
74
- return shortcuts
72
+ for shortcut in user.shortcuts():
73
+ yield shortcut
75
74
 
76
- def all(self) -> List[Union[SteamGame, Shortcut]]:
75
+ def all(self) -> Generator[Union[Game, Shortcut], None, None]:
77
76
  """Returns all the games and shortcuts from the Steam library."""
78
- return self.games() + self.shortcuts()
77
+ for game in self.games():
78
+ yield game
79
+ for shortcut in self.shortcuts():
80
+ yield shortcut
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass
3
+ from pathlib import Path
4
+ from typing import List
5
+
6
+ from .game import Game
7
+
8
+
9
+ @dataclass
10
+ class LibraryFolder:
11
+ """Represents a Steam library folder."""
12
+ library_cache_path: Path
13
+ path: str
14
+ apps: List[str]
15
+
16
+ def get_games(self) -> List[Game]:
17
+ return [Game(self.library_cache_path, self.path, appid) for appid in self.apps]