Beispiel #1
0
    def test_simple(self):
        pairs = [
            ('a', 'test'),
            ('a2', b'\xd0\xb0\xd0\xb1\xd0\xb2\xd0\xb3'.decode('utf-8')),
            ('bb', 1),
            ('bb2', -500),
            ('ccc', 1.0),
            ('dddd', vdf.POINTER(1234)),
            ('fffff', vdf.COLOR(1234)),
            ('gggggg', vdf.UINT_64(1234)),
            ('hhhhhhh', vdf.INT_64(-1234)),
        ]

        data = OrderedDict(pairs)
        data['level1-1'] = OrderedDict(pairs)
        data['level1-1']['level2-1'] = OrderedDict(pairs)
        data['level1-1']['level2-2'] = OrderedDict(pairs)
        data['level1-2'] = OrderedDict(pairs)

        result = vdf.binary_loads(vdf.binary_dumps(data), mapper=OrderedDict)

        self.assertEqual(data, result)

        result = vdf.binary_loads(vdf.binary_dumps(data, alt_format=True), mapper=OrderedDict, alt_format=True)

        self.assertEqual(data, result)

        result = vdf.vbkv_loads(vdf.vbkv_dumps(data), mapper=OrderedDict)

        self.assertEqual(data, result)
Beispiel #2
0
    def test_simple(self):
        pairs = [
            ('a', 'test'),
            ('a2', b'\xff\xfe0\x041\x042\x043\x04'.decode('utf-16')),
            ('bb', 1),
            ('bb2', -500),
            ('ccc', 1.0),
            ('dddd', vdf.POINTER(1234)),
            ('fffff', vdf.COLOR(1234)),
            ('gggggg', vdf.UINT_64(1234)),
            ('hhhhhhh', vdf.INT_64(-1234)),
        ]

        data = OrderedDict(pairs)
        data['level1-1'] = OrderedDict(pairs)
        data['level1-1']['level2-1'] = OrderedDict(pairs)
        data['level1-1']['level2-2'] = OrderedDict(pairs)
        data['level1-2'] = OrderedDict(pairs)

        result = vdf.binary_loads(vdf.binary_dumps(data), mapper=OrderedDict)

        self.assertEqual(data, result)

        result = vdf.binary_loads(vdf.binary_dumps(data, alt_format=True),
                                  mapper=OrderedDict,
                                  alt_format=True)

        self.assertEqual(data, result)

        result = vdf.vbkv_loads(vdf.vbkv_dumps(data), mapper=OrderedDict)

        self.assertEqual(data, result)
Beispiel #3
0
    def test_dumps_empty(self):
        self.assertEqual(vdf.binary_dumps({}), b'')

        buf = BytesIO()
        vdf.binary_dump({}, buf)

        self.assertEqual(buf.getvalue(), b'')
Beispiel #4
0
 def save(self) -> None:
     """Save current file with current shortcuts data"""
     out = {}
     out['shortcuts'] = self.new_data
     utils.ensure_directory_for_file(self.path)
     with open(self.path, 'wb') as ss_file:
         ss_file.write(vdf.binary_dumps(out))
Beispiel #5
0
    def func(install_dir, name, steamid64=None, appid_in_vdf=False):
        if not steamid64:
            steamid64 = steam_user

        # Update shortcuts.vdf first
        steamid3 = int(steamid64) & 0xffffffff
        shortcuts_by_user[steamid3].append({
            "install_dir": install_dir, "name": name
        })

        shortcut_path = (
            steam_dir / "userdata" / str(steamid3) / "config"
            / "shortcuts.vdf"
        )
        shortcut_path.parent.mkdir(parents=True, exist_ok=True)
        data = {"shortcuts": {}}
        for shortcut_data in shortcuts_by_user[steamid3]:
            install_dir_ = shortcut_data["install_dir"]
            name_ = shortcut_data["name"]

            entry = {
                "AppName": name_,
                "StartDir": install_dir_,
                "exe": str(Path(install_dir_) / name_)
            }
            # Derive the shortcut ID
            crc_data = b"".join([
                entry["exe"].encode("utf-8"),
                entry["AppName"].encode("utf-8")
            ])
            result = zlib.crc32(crc_data) & 0xffffffff
            result = result | 0x80000000
            shortcut_id = (result << 32) | 0x02000000

            if appid_in_vdf:
                # Store the app ID in `shortcuts.vdf`. This is similar
                # in behavior to newer Steam releases.
                entry["appid"] = ~(result ^ 0xffffffff)

            data["shortcuts"][str(shortcut_id)] = entry

        shortcut_path.write_bytes(vdf.binary_dumps(data))

        appid = get_appid_from_shortcut(
            target=str(Path(install_dir) / name), name=name
        )

        # Create the fake prefix
        (steam_dir / "steamapps" / "compatdata" / str(appid) / "pfx").mkdir(
            parents=True)
        (steam_dir / "steamapps" / "compatdata" / str(appid) / "pfx.lock").touch()

        return shortcut_id
Beispiel #6
0
    def func(proton_app, compat_tool_name):
        compat_tools.append({
            "appid": proton_app.appid,
            "compat_tool_name": compat_tool_name
        })

        # Add the header section
        content = struct.pack(
            APPINFO_STRUCT_HEADER,
            b"'DV\x07",  # Magic number
            1  # Universe, protontricks ignores this
        )

        # Serialize the Proton manifest VDF section, which contains
        # information about different Proton installations
        appid = 123500
        infostate = 2
        last_updated = 2
        access_token = 2
        change_number = 2
        sha_hash = b"0"*20

        compat_tool_entries = {}

        for compat_tool in compat_tools:
            compat_tool_entries[compat_tool["compat_tool_name"]] = {
                # The name implies it could be a list, but in practice
                # it has been a string. Do the same thing here.
                "aliases": compat_tool["compat_tool_name"],
                "appid": compat_tool["appid"]
            }

        binary_vdf = vdf.binary_dumps({
            "appinfo": {
                "extended": {
                    "compat_tools": compat_tool_entries
                }
            }
        })

        entry_size = len(binary_vdf) + 40

        # Add the only VDF binary section
        content += struct.pack(
            APPINFO_STRUCT_SECTION,
            appid, entry_size, infostate, last_updated, access_token,
            sha_hash, change_number
        )
        content += binary_vdf

        # Add the EOF section
        content += b"ffff"
        (steam_dir / "appcache" / "appinfo.vdf").write_bytes(content)
Beispiel #7
0
def create_backup_of_shortcuts(config, user, dry_run=False):
    def _create_directory_if_needed(directory):
        if os.path.exists(directory):
            return

        logger.debug("Creating directory: %s" % directory)
        os.makedirs(directory)

    backup_dir = backup_directory(config)
    if backup_dir is None:
        logger.info(
            "No backups directory specified, so not backing up shortcuts.vdf before overwriting. See config.txt for more info"
        )
        return

    _create_directory_if_needed(backup_dir)

    if not os.path.isdir(backup_dir):
        logger.warning(
            "Backup directory path is something other than a directory. Skipping backups"
        )
        return

    backup_path = shortcuts_backup_path(backup_dir, user)

    # Make sure the user-specific backups dir exists
    _create_directory_if_needed(os.path.dirname(backup_path))

    formatted_obj = {
        'shortcuts':
        {str(i): item
         for i, item in enumerate(shortcuts.get_shortcuts(user))}
    }
    byte_str = vdf.binary_dumps(formatted_obj)
    with open(backup_path, 'wb') as fp:
        fp.write(byte_str)
Beispiel #8
0
 def test_dumps_value_invalid_type(self):
     with self.assertRaises(TypeError):
         vdf.binary_dumps({'': None})
Beispiel #9
0
def add_games_to_shortcut_file(steam_path, steamid, games, skip_backup,
                               use_executable_path):
    if use_executable_path:
        print()
        print("⚠ ⚠ WARNING: ⚠ ⚠")
        print(
            "Using the path to the executable instead of the Epic Games Launcher URI"
        )
        print("You may experience issues with online games (eg GTAV!)")
        print()

    shortcut_file_path = os.path.join(steam_path, "userdata", steamid,
                                      "config", "shortcuts.vdf")

    if not os.path.exists(shortcut_file_path):
        print(f"Could not find shortcuts file at `{shortcut_file_path}`")
        print(
            "Make a shortcut in Steam (Library ➡ ➕ Add Game ➡ Add a Non-Steam Game...) first. Aborting."
        )
        exit(-2)

    # read in the shortcuts file
    with open(shortcut_file_path, "rb") as sf:
        shortcuts = vdf.binary_load(sf)

    # Make a set that contains the path of every shortcut installed. If a path is already in the
    # shortuts file, we won't add another one (ie the path is what makes a shortcut unique)
    all_paths = set()

    for k, v in shortcuts["shortcuts"].items():
        all_paths.add(v["Exe"])

    # the shortcuts "list" is actually a dict of "index": value
    # find the last one so we can add on to the end
    added = 0
    last_index = int(max(shortcuts["shortcuts"].keys()))
    for game in games:
        shortcut = game.executable_path if use_executable_path else game.uri
        if shortcut in all_paths:
            print(
                f"Not creating shortcut for `{game.display_name}` since it already has one"
            )
            continue
        last_index += 1
        shortcuts["shortcuts"][str(last_index)] = to_shortcut(
            game, use_executable_path)
        added += 1

    print(f"Added {added} new games")
    if added == 0:
        print(f"No need to update `shortcuts.vdf`")
        return

    if skip_backup:
        print("Not backing up `shortcuts.vdf` since you enjoy danger")
        os.remove(shortcut_file_path)
    else:
        timestamp = time.strftime("%Y%m%d-%H%M%S")
        new_filename = shortcut_file_path + f"-{timestamp}.bak"

        print(f"Backing up `shortcuts.vdf` to `{new_filename}`")
        os.rename(shortcut_file_path, new_filename)

    new_bytes = vdf.binary_dumps(shortcuts)
    with open(shortcut_file_path, "wb") as shortcut_file:
        shortcut_file.write(new_bytes)

    print("Updated `shortcuts.vdf` successfully!")
    print()
    print("➡   Restart Steam!")
Beispiel #10
0
def set_shortcuts(user_context, shortcuts):
    # make the list of shortcuts under a nested "shortcuts" key with each index
    formatted_obj = {'shortcuts': {str(i): item for i, item in enumerate(shortcuts)}}
    byte_str = vdf.binary_dumps(formatted_obj)
    with open(paths.shortcuts_path(user_context), 'wb') as fp:
        fp.write(byte_str)
Beispiel #11
0
 def test_dumps_value_invalid_type(self):
     with self.assertRaises(TypeError):
         vdf.binary_dumps({'': None})
Beispiel #12
0
 def test_dumps_params_invalid(self):
     with self.assertRaises(TypeError):
         vdf.binary_dumps([])
     with self.assertRaises(TypeError):
         vdf.binary_dumps(b'aaaa')
Beispiel #13
0
 def test_dumps_unicode(self):
     self.assertEqual(vdf.binary_dumps({u('a'): u('b')}),
                      b'\x01a\x00b\x00\x08')
Beispiel #14
0
 def test_dumps_key_invalid_type(self):
     with self.assertRaises(TypeError):
         vdf.binary_dumps({1: 1})
     with self.assertRaises(TypeError):
         vdf.binary_dumps({None: 1})
Beispiel #15
0
 def test_dumps_unicode_alternative(self):
     self.assertEqual(vdf.binary_dumps({u('a'): u('b')}, alt_format=True),
                      b'\x01a\x00b\x00\x0b')
Beispiel #16
0
 def test_dumps_empty(self):
     self.assertEqual(vdf.binary_dumps({}), b'')
Beispiel #17
0
 def test_dumps_empty(self):
     self.assertEqual(vdf.binary_dumps({}), b'')
Beispiel #18
0
def add_games_to_shortcut_file(steam_path, steamid, games, skip_backup,
                               use_uri):
    """Add the given games to the shortcut file

    Args:
        steam_path (string): location of the root of the steam installation
        steamid (string): numeric steamid to add shortcuts to
        games ([GameDefinition]): games to add
        skip_backup (bool): if we shouldn't back up the file
        use_uri ([type]): if we should use the EGS uri, or the path to the executable

    Returns:
        (([string], integer), string): First element of tuple is a tuple of an array of "results" to display and the number of games added, 
                                         The second is an error text if something went wrong
    """
    if use_uri:
        print()
        print("⚠ ⚠ NOTICE: ⚠ ⚠")
        print("Using a URI instead of executable path")
        print("You may experience issues with game streaming")
        print()
    else:
        print()
        print("⚠ ⚠ NOTICE: ⚠ ⚠")
        print(
            "Using the path to the executable instead of the Epic Games Launcher URI"
        )
        print("You may experience issues with online games (eg GTAV!)")
        print()

    shortcut_file_path = os.path.join(steam_path, "userdata", steamid,
                                      "config", "shortcuts.vdf")

    if not os.path.exists(shortcut_file_path):
        message = f"Could not find shortcuts file at `{shortcut_file_path}` \n Make a shortcut in Steam (Library ➡ ➕ Add Game ➡ Add a Non-Steam Game...) first. Aborting."
        print(message)
        return None, message

    # read in the shortcuts file
    with open(shortcut_file_path, "rb") as sf:
        shortcuts = vdf.binary_load(sf)

    # Make a set that contains the path of every shortcut installed. If a path is already in the
    # shortuts file, we won't add another one (ie the path is what makes a shortcut unique)
    all_paths = set()

    for k, v in shortcuts["shortcuts"].items():
        exe_key = "Exe"
        if exe_key not in v:
            exe_key = "exe"
        if exe_key not in v:
            print(
                "Warning: Entry in shortcuts.vdf has no `Exe` field! Is this a malformed entry?"
            )
            print(v)
            continue
        all_paths.add(v[exe_key])

    # the shortcuts "list" is actually a dict of "index": value
    # find the last one so we can add on to the end
    added = 0

    all_indexes = shortcuts["shortcuts"].keys()
    if len(all_indexes) == 0:
        last_index = 0
    else:
        last_index = max(int(idx) for idx in all_indexes)

    game_results = []
    for game in games:
        shortcut = game.uri if use_uri else game.executable_path
        if shortcut in all_paths:
            msg = f"{game.display_name}: Not creating shortcut since it already has one"
            print(msg)
            game_results.append(msg)
            continue
        last_index += 1
        shortcuts["shortcuts"][str(last_index)] = to_shortcut(game, use_uri)
        added += 1

    print(f"Added {added} new games")
    if added == 0:
        msg = f"No need to update `shortcuts.vdf` - nothing new to add"
        print(msg)
        return None, msg

    if skip_backup:
        print("Not backing up `shortcuts.vdf` since you enjoy danger")
        os.remove(shortcut_file_path)
    else:
        timestamp = time.strftime("%Y%m%d-%H%M%S")
        new_filename = shortcut_file_path + f"-{timestamp}.bak"

        print(f"Backing up `shortcuts.vdf` to `{new_filename}`")
        os.rename(shortcut_file_path, new_filename)

    new_bytes = vdf.binary_dumps(shortcuts)
    with open(shortcut_file_path, "wb") as shortcut_file:
        shortcut_file.write(new_bytes)

    print("Updated `shortcuts.vdf` successfully!")
    print()
    print("➡   Restart Steam!")
    return (game_results, added), None
Beispiel #19
0
 def test_dumps_key_invalid_type(self):
     with self.assertRaises(TypeError):
         vdf.binary_dumps({1:1})
     with self.assertRaises(TypeError):
         vdf.binary_dumps({None:1})
Beispiel #20
0
 def test_dumps_unicode_alternative(self):
     self.assertEqual(vdf.binary_dumps({u('a'): u('b')}, alt_format=True), b'\x01a\x00b\x00\x0b')
Beispiel #21
0
 def test_dumps_unicode(self):
     self.assertEqual(vdf.binary_dumps({u('a'): u('b')}), b'\x01a\x00b\x00\x08')