mirror of
https://github.com/derrod/legendary.git
synced 2024-12-22 17:55:27 +00:00
[cli] Add "info" command for app metadata
This commit is contained in:
parent
4706a42cee
commit
3a608610f3
151
legendary/cli.py
151
legendary/cli.py
|
@ -1208,6 +1208,146 @@ class LegendaryCLI:
|
||||||
# prevent update message on close
|
# prevent update message on close
|
||||||
self.core.update_available = False
|
self.core.update_available = False
|
||||||
|
|
||||||
|
def info(self, args):
|
||||||
|
name_or_path = args.app_name_or_manifest
|
||||||
|
app_name = manifest_uri = None
|
||||||
|
if os.path.exists(name_or_path) or name_or_path.startswith('http'):
|
||||||
|
manifest_uri = name_or_path
|
||||||
|
else:
|
||||||
|
app_name = name_or_path
|
||||||
|
|
||||||
|
if not args.offline and not manifest_uri:
|
||||||
|
try:
|
||||||
|
if not self.core.login():
|
||||||
|
logger.error('Log in failed!')
|
||||||
|
exit(1)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
game = self.core.get_game(app_name, update_meta=not args.offline)
|
||||||
|
manifest_data = None
|
||||||
|
entitlements = None
|
||||||
|
# load installed manifest or URI
|
||||||
|
if args.offline or manifest_uri:
|
||||||
|
if app_name and self.core.is_installed(app_name):
|
||||||
|
manifest_data, _ = self.core.get_installed_manifest(app_name)
|
||||||
|
elif manifest_uri and manifest_uri.startswith('http'):
|
||||||
|
r = self.core.egs.unauth_session.get(manifest_uri)
|
||||||
|
r.raise_for_status()
|
||||||
|
manifest_data = r.content
|
||||||
|
elif manifest_uri and os.path.exists(manifest_uri):
|
||||||
|
with open(manifest_uri, 'rb') as f:
|
||||||
|
manifest_data = f.read()
|
||||||
|
else:
|
||||||
|
logger.info('Game not installed and offline mode enabled, cannot load manifest.')
|
||||||
|
elif game:
|
||||||
|
# get latest metadata and manifest
|
||||||
|
egl_meta = self.core.egs.get_game_info(game.asset_info.namespace,
|
||||||
|
game.asset_info.catalog_item_id)
|
||||||
|
game.metadata = egl_meta
|
||||||
|
manifest_data, _ = self.core.get_cdn_manifest(game)
|
||||||
|
entitlements = self.core.egs.get_user_entitlements()
|
||||||
|
|
||||||
|
if game:
|
||||||
|
print('\nGame Information:')
|
||||||
|
print('- Title:', game.app_title)
|
||||||
|
print('- Latest version:', game.app_version)
|
||||||
|
print('- Cloud saves supported:', game.supports_cloud_saves)
|
||||||
|
if game.supports_cloud_saves:
|
||||||
|
print('- Cloud save folder:', game.metadata['customAttributes']['CloudSaveFolder']['value'])
|
||||||
|
print('- Is DLC:', game.is_dlc)
|
||||||
|
# Find custom launch options, if available
|
||||||
|
launch_options = []
|
||||||
|
i = 1
|
||||||
|
while f'extraLaunchOption_{i:03d}_Name' in game.metadata['customAttributes']:
|
||||||
|
launch_options.append((
|
||||||
|
game.metadata['customAttributes'][f'extraLaunchOption_{i:03d}_Name']['value'],
|
||||||
|
game.metadata['customAttributes'][f'extraLaunchOption_{i:03d}_Args']['value']
|
||||||
|
))
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
if launch_options:
|
||||||
|
print('- Extra launch options:')
|
||||||
|
for opt_name, opt_cmd in sorted(launch_options):
|
||||||
|
print(f' + Name: "{opt_name}", Parameters: {opt_cmd}')
|
||||||
|
|
||||||
|
# list all owned DLC based on entitlements
|
||||||
|
if entitlements and not game.is_dlc:
|
||||||
|
owned_entitlements = {i['entitlementName'] for i in entitlements}
|
||||||
|
owned_app_names = {g.app_name for g in self.core.get_assets()}
|
||||||
|
owned_dlc = []
|
||||||
|
for dlc in game.metadata['dlcItemList']:
|
||||||
|
installable = dlc.get('releaseInfo', None)
|
||||||
|
if dlc['entitlementName'] in owned_entitlements:
|
||||||
|
owned_dlc.append((installable, None, dlc['title']))
|
||||||
|
elif installable:
|
||||||
|
app_name = dlc['releaseInfo'][0]['appId']
|
||||||
|
if app_name in owned_app_names:
|
||||||
|
owned_dlc.append((installable, app_name, dlc['title']))
|
||||||
|
|
||||||
|
if owned_dlc:
|
||||||
|
print('- Owned DLC:')
|
||||||
|
for installable, app_name, title in owned_dlc:
|
||||||
|
if installable:
|
||||||
|
print(f' + App name: {app_name}, Title: "{title}"')
|
||||||
|
else:
|
||||||
|
print(f' + Title: "{title}" (no installation required)')
|
||||||
|
|
||||||
|
igame = self.core.get_installed_game(app_name)
|
||||||
|
if igame:
|
||||||
|
print('\nInstallation information:')
|
||||||
|
print(f'- Version:', igame.version)
|
||||||
|
print(f'- File size: {igame.install_size / 1024 / 1024 / 1024:.02f} GiB')
|
||||||
|
print('- Path:', igame.install_path)
|
||||||
|
print('- Save data path:', igame.save_path or '(None)')
|
||||||
|
print('- EGL sync GUID:', igame.egl_guid or '(None)')
|
||||||
|
if igame.install_tags:
|
||||||
|
print('- Tags:', ', '.join(igame.install_tags))
|
||||||
|
else:
|
||||||
|
print('- Tags: N/A')
|
||||||
|
print('- Requires ownership verification token (DRM):', igame.requires_ot)
|
||||||
|
|
||||||
|
installed_dlc = []
|
||||||
|
for dlc in game.metadata['dlcItemList']:
|
||||||
|
if not dlc.get('releaseInfo', None):
|
||||||
|
continue
|
||||||
|
app_name = dlc['releaseInfo'][0]['appId']
|
||||||
|
if igame := self.core.get_installed_game(app_name):
|
||||||
|
installed_dlc.append(igame)
|
||||||
|
|
||||||
|
if installed_dlc:
|
||||||
|
print('- Installed DLC')
|
||||||
|
for igame in installed_dlc:
|
||||||
|
print(' + App name: {}, Title: "{}", Size: {:.02f} GiB'.format(
|
||||||
|
igame.app_name, igame.title, igame.install_size / 1024 / 1024 / 1024
|
||||||
|
))
|
||||||
|
|
||||||
|
if manifest_data:
|
||||||
|
manifest = self.core.load_manifest(manifest_data)
|
||||||
|
print('\nManifest Information:')
|
||||||
|
print('- Manifest type:', 'JSON' if hasattr(manifest, 'json_data') else 'Binary')
|
||||||
|
print('- Manifest version:', manifest.version)
|
||||||
|
print('- Manifest feature level:', manifest.meta.feature_level)
|
||||||
|
print('- Manifest app name:', manifest.meta.app_name)
|
||||||
|
print('- Launch EXE:', manifest.meta.launch_exe or 'N/A')
|
||||||
|
print('- Launch Command:', manifest.meta.launch_command or '(None)')
|
||||||
|
print('- Build version:', manifest.meta.build_version)
|
||||||
|
print('- Build ID:', manifest.meta.build_id)
|
||||||
|
if manifest.meta.prereq_ids:
|
||||||
|
print('- Prerequisites:')
|
||||||
|
print(' + Prerequisite IDs:', ', '.join(manifest.meta.prereq_ids))
|
||||||
|
print(' + Prerequisite name:', manifest.meta.prereq_name)
|
||||||
|
print(' + Prerequisite path:', manifest.meta.prereq_path)
|
||||||
|
print(' + Prerequisite args:', manifest.meta.prereq_args or '(None)')
|
||||||
|
else:
|
||||||
|
print('- Prerequisites: (None)')
|
||||||
|
print('- Files:', manifest.file_manifest_list.count)
|
||||||
|
total_size = sum(fm.file_size for fm in manifest.file_manifest_list.elements)
|
||||||
|
print(' + Total: {:.02f} GiB (uncompressed)'.format(total_size / 1024 / 1024 / 1024))
|
||||||
|
print('- Chunks:', manifest.chunk_data_list.count)
|
||||||
|
total_size = sum(c.file_size for c in manifest.chunk_data_list.elements)
|
||||||
|
print(' + Total: {:.02f} GiB (compressed)'.format(total_size / 1024 / 1024 / 1024))
|
||||||
|
|
||||||
def cleanup(self, args):
|
def cleanup(self, args):
|
||||||
before = self.core.lgd.get_dir_size()
|
before = self.core.lgd.get_dir_size()
|
||||||
# delete metadata
|
# delete metadata
|
||||||
|
@ -1260,6 +1400,7 @@ def main():
|
||||||
egl_sync_parser = subparsers.add_parser('egl-sync', help='Setup or run Epic Games Launcher sync')
|
egl_sync_parser = subparsers.add_parser('egl-sync', help='Setup or run Epic Games Launcher sync')
|
||||||
status_parser = subparsers.add_parser('status', help='Show legendary status information')
|
status_parser = subparsers.add_parser('status', help='Show legendary status information')
|
||||||
clean_parser = subparsers.add_parser('cleanup', help='Remove old temporary, metadata, and manifest files')
|
clean_parser = subparsers.add_parser('cleanup', help='Remove old temporary, metadata, and manifest files')
|
||||||
|
info_parser = subparsers.add_parser('info', help='Prints info about specified app name or manifest')
|
||||||
|
|
||||||
install_parser.add_argument('app_name', help='Name of the app', metavar='<App Name>')
|
install_parser.add_argument('app_name', help='Name of the app', metavar='<App Name>')
|
||||||
uninstall_parser.add_argument('app_name', help='Name of the app', metavar='<App Name>')
|
uninstall_parser.add_argument('app_name', help='Name of the app', metavar='<App Name>')
|
||||||
|
@ -1276,6 +1417,8 @@ def main():
|
||||||
import_parser.add_argument('app_name', help='Name of the app', metavar='<App Name>')
|
import_parser.add_argument('app_name', help='Name of the app', metavar='<App Name>')
|
||||||
import_parser.add_argument('app_path', help='Path where the game is installed',
|
import_parser.add_argument('app_path', help='Path where the game is installed',
|
||||||
metavar='<Installation directory>')
|
metavar='<Installation directory>')
|
||||||
|
info_parser.add_argument('app_name_or_manifest', help='App name or manifest path/URI',
|
||||||
|
metavar='<App Name/Manifest URI>')
|
||||||
|
|
||||||
auth_parser.add_argument('--import', dest='import_egs_auth', action='store_true',
|
auth_parser.add_argument('--import', dest='import_egs_auth', action='store_true',
|
||||||
help='Import Epic Games Launcher authentication data (logs out of EGL)')
|
help='Import Epic Games Launcher authentication data (logs out of EGL)')
|
||||||
|
@ -1466,6 +1609,9 @@ def main():
|
||||||
clean_parser.add_argument('--keep-manifests', dest='keep_manifests', action='store_true',
|
clean_parser.add_argument('--keep-manifests', dest='keep_manifests', action='store_true',
|
||||||
help='Do not delete old manifests')
|
help='Do not delete old manifests')
|
||||||
|
|
||||||
|
info_parser.add_argument('--offline', dest='offline', action='store_true',
|
||||||
|
help='Only print info available offline')
|
||||||
|
|
||||||
args, extra = parser.parse_known_args()
|
args, extra = parser.parse_known_args()
|
||||||
|
|
||||||
if args.version:
|
if args.version:
|
||||||
|
@ -1475,7 +1621,8 @@ def main():
|
||||||
if args.subparser_name not in ('auth', 'list-games', 'list-installed', 'list-files',
|
if args.subparser_name not in ('auth', 'list-games', 'list-installed', 'list-files',
|
||||||
'launch', 'download', 'uninstall', 'install', 'update',
|
'launch', 'download', 'uninstall', 'install', 'update',
|
||||||
'repair', 'list-saves', 'download-saves', 'sync-saves',
|
'repair', 'list-saves', 'download-saves', 'sync-saves',
|
||||||
'verify-game', 'import-game', 'egl-sync', 'status', 'cleanup'):
|
'verify-game', 'import-game', 'egl-sync', 'status',
|
||||||
|
'info', 'cleanup'):
|
||||||
print(parser.format_help())
|
print(parser.format_help())
|
||||||
|
|
||||||
# Print the main help *and* the help for all of the subcommands. Thanks stackoverflow!
|
# Print the main help *and* the help for all of the subcommands. Thanks stackoverflow!
|
||||||
|
@ -1534,6 +1681,8 @@ def main():
|
||||||
cli.egs_sync(args)
|
cli.egs_sync(args)
|
||||||
elif args.subparser_name == 'status':
|
elif args.subparser_name == 'status':
|
||||||
cli.status(args)
|
cli.status(args)
|
||||||
|
elif args.subparser_name == 'info':
|
||||||
|
cli.info(args)
|
||||||
elif args.subparser_name == 'cleanup':
|
elif args.subparser_name == 'cleanup':
|
||||||
cli.cleanup(args)
|
cli.cleanup(args)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|
Loading…
Reference in a new issue