# Save Scummer
[![Build](https://github.com/JWCook/save-scummer/workflows/Build/badge.svg?branch=main)](https://github.com/JWCook/save-scummer/actions)
[![PyPI](https://img.shields.io/pypi/v/save-scummer?color=blue)](https://pypi.org/project/save-scummer)
[![PyPI - Python Versions](https://img.shields.io/pypi/pyversions/save-scummer)](https://pypi.org/project/save-scummer)
* [Features](#features)
* [Installation](#installation)
* [Autocompletion](#autocompletion--optional-)
* [Usage](#usage)
* [Add](#add)
* [Backup](#backup)
* [List](#list)
* [Restore](#restore)
* [Backup specifiers](#backup-specifiers)
* [Restore Examples](#restore-examples)
Save-Scummer is a simple CLI utility to backup and restore game saves.
This is intended for rogue-lite games like **Rogue Legacy**, **FTL** and **Don't Starve**,
but it could also be applied to other games or non-game applications.
I made this because I enjoy roguelike/rogue-lite games, but when one starts to get too difficult,
I may resort to [save-scumming](https://tvtropes.org/pmwiki/pmwiki.php/Main/SaveScumming) as an
option to make the game a bit easier. When doing that manually, I find myself wasting precious _seconds_
of time copying files back and forth, so naturally I decided to waste _hours_ making it (semi-)automated
instead.
A full backup utility (like [Duplicati](https://github.com/duplicati/duplicati)) or sync utility
(like [rsync](https://github.com/WayneD/rsync)) will obviously have _many_ more features, but for the
basic case of handling game saves, I wanted something simpler with concise command line usage.
# Features
* Just provide a save directory (or glob pattern) to configure a new game
* Easily make backups, and restore them by most recent (default), time expressions
(to indicate how far back in time you want to go), or choose from a list
* Tab autocompletion
# Installation
Install with [pipx](https://pipx.pypa.io/stable/) (recommended):
```sh
pipx install save-scummer
```
Or with pip:
```sh
pip install save-scummer
```
## Autocompletion (optional)
Tab autocompletion is available for most common shells: **bash, fish, zsh** and Windows **PowerShell**.
To install, run:
```sh
ssc --install [shell name]
``````
# Usage
Save-scummer provides the command `save-scummer` (also aliased as `ssc`) with the following subcommands:
```sh
sh: ssc COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
add Add a game and its save directory
backup Create a backup of one, multiple, or all games
ls List all currently configured games
restore Restore a backup of the specified game
```
## Add
Use `ssc add` to add (or update) a game and its save directory.
Relative paths, user paths, and [glob patterns](https://en.wikipedia.org/wiki/Glob_(programming))
are supported:
```sh
ssc add game1 ~/Games/game1 # Add a dir (including any subdirs)
ssc add game1 '~/Games/game1/**' # Equivalent glob pattern (quotes required)
ssc add game2 'C:\Games\game2\*.sav' # Add files ending in .sav
````
## Backup
Use `ssc backup` to create a new backup. Just specify the game title, and an optional description:
```sh
ssc backup game1 -d 'level 10 with full health'
```
Or just backup everything:
```sh
ssc backup --all
```
## List
Use `ssc ls` to show a summary of all configured games:
```sh
╒════════╤═════════════════╤═════════════════════════════════╕
│ Title │ Total backups │ Last saved │
╞════════╪═════════════════╪═════════════════════════════════╡
│ game1 │ 0 │ never │
├────────┼─────────────────┼─────────────────────────────────┤
│ game2 │ 7 (94.96 KB) │ 2021-01-19 15:20 (23 hours ago) │
╘════════╧═════════════════╧═════════════════════════════════╛
```
Or use `ssc ls [game title]` to show more details on a specific game and its backups:
```sh
Game: game2
Total backups: 7 (94.96 KB)
Last saved: 2021-01-19 15:20 (23 hours ago)
Last backed up: 2021-01-19 16:24 (22 hours ago)
Source directory: /home/user/game2/saves
Backup directory: /home/user/.local/share/save-scummer/backups/game2
Backup files:
0: game2-2021-01-26T19:23:26.zip
1: game2-2021-01-20T16:33:42-pre-restore.zip
2: game2-2021-01-19T19:26:10.zip
3: game2-2021-01-19T18:31:58.zip
4: game2-2021-01-18T12:17:52.zip
5: game2-2021-01-17T16:18:09.zip
6: game2-2021-01-17T15:01:58.zip
```
Note that "Last saved" is the time that the source files were created/modified.
## Restore
Use `ssc restore` to restore a backup. A specific backup can be indicated by backup
**index, age, date/time, or filename**. Otherwise, the most recent backup is restored.
```sh
Usage: ssc restore [OPTIONS] [TITLE]
Options:
-i, --index INTEGER Backup number (starting at 0, from newest to oldest)
-a, --age TEXT Minimum age (relative to current time)
-d, --date TEXT Maximum date/time (absolute)
-f TEXT Backup filename; either absolute or relative to backup dir
```
### Backup specifiers
**Index:**
The backup index, sorted from newest to oldest, e.g.
**"Restore the save from x backups ago."** 0 is the latest backup, 1 is the
backup made before that, etc.
Negative values can also be given; -1 would give you the oldest backup.
See `ls` command for full list of available backups.
**Age:**
Minimum age of the save to restore, e.g **"I want to go back in time by 1 hour."**
Amounts of time can be specified in 'HH:MM' format, or with a number followed by a unit.
Examples:
* '1:30' (an hour and a half ago)
* '30m' (or '30 minutes')
* '6h' (or '6 hours')
* '9 hours, 15 minutes' (or '9:15')
* '2d' (or '2 days')
* See [pytimeparse](https://github.com/wroberts/pytimeparse) for more formats
**Date/Time:**
Maximum date/time of the save to restore, e.g., **"I want to go back in
time to 1:30 yesterday."** Most date/time formats are supported.
Examples:
* '16:30' or '4:30 PM' (today)
* '2021-01-20'
* 'August 3 2020'
* Most date/time formats are supported; see
[dateutil](https://dateutil.readthedocs.io/en/stable/examples.html#parse-examples)
for more examples.
**Filename:**
Either a full path or just the filename (relative to the backup dir)
### Restore Examples
```sh
# Just restore the most recent backup
ssc restore game1
# Restore the backup made 2 backups ago (aka the 3rd most recent)
ssc restore game1 -i 2
# Restore a backup from (at least) an hour and a half ago
ssc restore game1 -a '1:30'
# Restore a backup from (at least) 2 days ago
ssc restore game1 -a 2d
# Restore a backup from 4:00 PM today or earlier
ssc restore game1 -d '4:00 PM'
# Restore a backup from March 22 or earlier
ssc restore game1 -d 'Mar 22 2021'
# Restore a backup by filename
ssc restore game1 -f game1-2021-01-20T00:09:10.zip
```
# Development setup
To set up for local development:
```sh
git clone https://github.com/JWCook/save-scummer && cd save-scummer
pip install -Ue '.[dev]'
```
To run linting, formatting, etc.:
```sh
pre-commit run -a
```
Raw data
{
"_id": null,
"home_page": "",
"name": "save-scummer",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": "",
"keywords": "backup,game,restore,roguelike,roguelite,save",
"author": "Jordan Cook",
"author_email": "",
"download_url": "https://files.pythonhosted.org/packages/44/44/8309867188ad837cf58df296c370e9be007380be2fe0e79f391fb192fb01/save_scummer-0.1.0.tar.gz",
"platform": null,
"description": "# Save Scummer\n\n[![Build](https://github.com/JWCook/save-scummer/workflows/Build/badge.svg?branch=main)](https://github.com/JWCook/save-scummer/actions)\n[![PyPI](https://img.shields.io/pypi/v/save-scummer?color=blue)](https://pypi.org/project/save-scummer)\n[![PyPI - Python Versions](https://img.shields.io/pypi/pyversions/save-scummer)](https://pypi.org/project/save-scummer)\n\n* [Features](#features)\n* [Installation](#installation)\n * [Autocompletion](#autocompletion--optional-)\n* [Usage](#usage)\n * [Add](#add)\n * [Backup](#backup)\n * [List](#list)\n * [Restore](#restore)\n * [Backup specifiers](#backup-specifiers)\n * [Restore Examples](#restore-examples)\n\n\nSave-Scummer is a simple CLI utility to backup and restore game saves.\nThis is intended for rogue-lite games like **Rogue Legacy**, **FTL** and **Don't Starve**,\nbut it could also be applied to other games or non-game applications.\n\nI made this because I enjoy roguelike/rogue-lite games, but when one starts to get too difficult,\nI may resort to [save-scumming](https://tvtropes.org/pmwiki/pmwiki.php/Main/SaveScumming) as an\noption to make the game a bit easier. When doing that manually, I find myself wasting precious _seconds_\nof time copying files back and forth, so naturally I decided to waste _hours_ making it (semi-)automated\ninstead.\n\nA full backup utility (like [Duplicati](https://github.com/duplicati/duplicati)) or sync utility\n(like [rsync](https://github.com/WayneD/rsync)) will obviously have _many_ more features, but for the\nbasic case of handling game saves, I wanted something simpler with concise command line usage.\n\n# Features\n* Just provide a save directory (or glob pattern) to configure a new game\n* Easily make backups, and restore them by most recent (default), time expressions\n (to indicate how far back in time you want to go), or choose from a list\n* Tab autocompletion\n\n# Installation\nInstall with [pipx](https://pipx.pypa.io/stable/) (recommended):\n```sh\npipx install save-scummer\n```\n\nOr with pip:\n```sh\npip install save-scummer\n```\n\n## Autocompletion (optional)\nTab autocompletion is available for most common shells: **bash, fish, zsh** and Windows **PowerShell**.\nTo install, run:\n```sh\nssc --install [shell name]\n``````\n\n# Usage\nSave-scummer provides the command `save-scummer` (also aliased as `ssc`) with the following subcommands:\n\n```sh\nsh: ssc COMMAND [ARGS]...\n\nOptions:\n --help Show this message and exit.\n\nCommands:\n add Add a game and its save directory\n backup Create a backup of one, multiple, or all games\n ls List all currently configured games\n restore Restore a backup of the specified game\n```\n\n## Add\nUse `ssc add` to add (or update) a game and its save directory.\n\nRelative paths, user paths, and [glob patterns](https://en.wikipedia.org/wiki/Glob_(programming))\nare supported:\n```sh\nssc add game1 ~/Games/game1 # Add a dir (including any subdirs)\nssc add game1 '~/Games/game1/**' # Equivalent glob pattern (quotes required)\nssc add game2 'C:\\Games\\game2\\*.sav' # Add files ending in .sav\n````\n\n## Backup\nUse `ssc backup` to create a new backup. Just specify the game title, and an optional description:\n```sh\nssc backup game1 -d 'level 10 with full health'\n```\nOr just backup everything:\n```sh\nssc backup --all\n```\n\n## List\nUse `ssc ls` to show a summary of all configured games:\n```sh\n\u2552\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2564\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2564\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2555\n\u2502 Title \u2502 Total backups \u2502 Last saved \u2502\n\u255e\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u256a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2561\n\u2502 game1 \u2502 0 \u2502 never \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 game2 \u2502 7 (94.96 KB) \u2502 2021-01-19 15:20 (23 hours ago) \u2502\n\u2558\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2567\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2567\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255b\n```\n\nOr use `ssc ls [game title]` to show more details on a specific game and its backups:\n```sh\nGame: game2\nTotal backups: 7 (94.96 KB)\nLast saved: 2021-01-19 15:20 (23 hours ago)\nLast backed up: 2021-01-19 16:24 (22 hours ago)\nSource directory: /home/user/game2/saves\nBackup directory: /home/user/.local/share/save-scummer/backups/game2\nBackup files:\n0: game2-2021-01-26T19:23:26.zip\n1: game2-2021-01-20T16:33:42-pre-restore.zip\n2: game2-2021-01-19T19:26:10.zip\n3: game2-2021-01-19T18:31:58.zip\n4: game2-2021-01-18T12:17:52.zip\n5: game2-2021-01-17T16:18:09.zip\n6: game2-2021-01-17T15:01:58.zip\n```\n\nNote that \"Last saved\" is the time that the source files were created/modified.\n\n## Restore\n\nUse `ssc restore` to restore a backup. A specific backup can be indicated by backup\n **index, age, date/time, or filename**. Otherwise, the most recent backup is restored.\n\n```sh\nUsage: ssc restore [OPTIONS] [TITLE]\n\nOptions:\n -i, --index INTEGER Backup number (starting at 0, from newest to oldest)\n -a, --age TEXT Minimum age (relative to current time)\n -d, --date TEXT Maximum date/time (absolute)\n -f TEXT Backup filename; either absolute or relative to backup dir\n```\n\n### Backup specifiers\n\n**Index:**\nThe backup index, sorted from newest to oldest, e.g.\n**\"Restore the save from x backups ago.\"** 0 is the latest backup, 1 is the\nbackup made before that, etc.\nNegative values can also be given; -1 would give you the oldest backup.\nSee `ls` command for full list of available backups.\n\n**Age:**\nMinimum age of the save to restore, e.g **\"I want to go back in time by 1 hour.\"**\nAmounts of time can be specified in 'HH:MM' format, or with a number followed by a unit.\nExamples:\n* '1:30' (an hour and a half ago)\n* '30m' (or '30 minutes')\n* '6h' (or '6 hours')\n* '9 hours, 15 minutes' (or '9:15')\n* '2d' (or '2 days')\n* See [pytimeparse](https://github.com/wroberts/pytimeparse) for more formats\n\n**Date/Time:**\nMaximum date/time of the save to restore, e.g., **\"I want to go back in\ntime to 1:30 yesterday.\"** Most date/time formats are supported.\nExamples:\n* '16:30' or '4:30 PM' (today)\n* '2021-01-20'\n* 'August 3 2020'\n* Most date/time formats are supported; see\n[dateutil](https://dateutil.readthedocs.io/en/stable/examples.html#parse-examples)\nfor more examples.\n\n**Filename:**\nEither a full path or just the filename (relative to the backup dir)\n\n### Restore Examples\n\n```sh\n# Just restore the most recent backup\nssc restore game1\n\n# Restore the backup made 2 backups ago (aka the 3rd most recent)\nssc restore game1 -i 2\n\n# Restore a backup from (at least) an hour and a half ago\nssc restore game1 -a '1:30'\n\n# Restore a backup from (at least) 2 days ago\nssc restore game1 -a 2d\n\n# Restore a backup from 4:00 PM today or earlier\nssc restore game1 -d '4:00 PM'\n\n# Restore a backup from March 22 or earlier\nssc restore game1 -d 'Mar 22 2021'\n\n# Restore a backup by filename\nssc restore game1 -f game1-2021-01-20T00:09:10.zip\n```\n\n# Development setup\nTo set up for local development:\n```sh\ngit clone https://github.com/JWCook/save-scummer && cd save-scummer\npip install -Ue '.[dev]'\n```\n\nTo run linting, formatting, etc.:\n```sh\npre-commit run -a\n```\n",
"bugtrack_url": null,
"license": "",
"summary": "A simple CLI utility to backup and restore game saves",
"version": "0.1.0",
"project_urls": {
"Source code": "https://github.com/JWCook/save-scummer"
},
"split_keywords": [
"backup",
"game",
"restore",
"roguelike",
"roguelite",
"save"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "1b5933d529a63ae8034938aca2389b309f4cb9ba1172eb13736f370416c1d850",
"md5": "99cbca9f9f2038d08b27cfc821eda0f1",
"sha256": "b87dced3acfcb49e942b6a68af5d331f8a09b9f5fcbe7c169325a231e1401beb"
},
"downloads": -1,
"filename": "save_scummer-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "99cbca9f9f2038d08b27cfc821eda0f1",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 13332,
"upload_time": "2023-12-29T17:38:41",
"upload_time_iso_8601": "2023-12-29T17:38:41.340246Z",
"url": "https://files.pythonhosted.org/packages/1b/59/33d529a63ae8034938aca2389b309f4cb9ba1172eb13736f370416c1d850/save_scummer-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "44448309867188ad837cf58df296c370e9be007380be2fe0e79f391fb192fb01",
"md5": "49e766a0e50bd55cdd86583e69dd2051",
"sha256": "1023617e6beb97f875770610501215fcd4bf31f026e7c9d97a9800633bb8c9b7"
},
"downloads": -1,
"filename": "save_scummer-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "49e766a0e50bd55cdd86583e69dd2051",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 10903,
"upload_time": "2023-12-29T17:38:42",
"upload_time_iso_8601": "2023-12-29T17:38:42.802241Z",
"url": "https://files.pythonhosted.org/packages/44/44/8309867188ad837cf58df296c370e9be007380be2fe0e79f391fb192fb01/save_scummer-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-12-29 17:38:42",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "JWCook",
"github_project": "save-scummer",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "save-scummer"
}