diff --git a/README.md b/README.md index dc3316c..f1df7d6 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Written by Renan Greca in 2017. This code is free to distribute and alter. ## Download -The latest stable release is 1.2.0. Download the Python file (Mac or Linux) or the Windows executable here: +The latest stable release is 2.0.0. Download the Python file (Mac or Linux) or the Windows executable here: https://github.com/RenanGreca/Switch-Screenshots/releases/tag/v1.2.0 @@ -16,12 +16,16 @@ https://github.com/RenanGreca/Switch-Screenshots/releases ## Usage Place the program and the `game_ids.json` file in the same directory as the -Switch's Album folder, either on -the microSD card or on your computer after transferring the Album. +Switch's Album folder, either on the microSD card or on your computer after +transferring the Album. After running, all screenshots will be placed within directories according to which game they are from. They can be found within the Output directory. +If the game is currently not in the IDs file, a folder will be created using +the game ID instead of title. You can rename it but please contribute the ID +to the repository by filing an issue or pull request. + ### Windows Double-click `organize_screenshots.exe`. @@ -37,10 +41,15 @@ On a terminal, run: python organize_screenshots.py ``` +#### Optional parameters: + +* `-i INPUT_DIR`: Specifies location of the Album directory. Default: `./Album/`. +* `-o OUTPUT_DIR`: Specifies desired output directory. Default: `./Output/`. + ## About the game IDs Switch screenshots are stored in the following format: `[timestamp]-[game id].jpg`. -Therefore, we can use the filenames to figure out which game it was from. +Therefore, we can use the filenames to figure out from which game it was taken. For example, the screenshot `2017030619573600-F1C11A22FAEE3B82F21B330E1B786A39.jpg` was taken on March 6, 2017 in the game The Legend of Zelda: Breath of the Wild. @@ -48,8 +57,11 @@ Some titles may have more than one ID, depending on the region or version. Demos also have their own IDs. The Switch UI contains multiple IDs, for different parts of the UI (home menu, - friends list, system settings, etc.). For simplicity, I've labeled all those - IDs as "Nintendo Switch". +friends list, system settings, etc.). For simplicity, I've labeled all those +IDs as "Nintendo Switch". + +Today, the Switch saves files as JPG (screenshots) or MP4 (recordings). The program +also supports PNG files in case Nintendo ever adds lossless screenshots. The `game_ids.json` file follows this format: ``` @@ -61,7 +73,7 @@ The `game_ids.json` file follows this format: ## Contributing -The initial version of `game_ids.json` contains only the titles I have played. +The initial version of `game_ids.json` contained only the titles I have played. If you have a screenshot for a game that is not on this list, the program will output a warning telling you which screenshot it was. @@ -73,5 +85,6 @@ The Windows `.exe` was generated using PyInstaller. ## Discussion -If you want to discuss the program or ask questions about it, please check out -the [Reddit thread at /r/NintendoSwitch](https://www.reddit.com/r/NintendoSwitch/comments/6rcttl/i_made_a_program_to_organize_switch_screenshots/) or tweet at me [@RenanGreca](https://twitter.com/RenanGreca). :) +If you want to discuss the program or ask questions about it, create an issue, check out the +[Reddit thread at /r/NintendoSwitch](https://www.reddit.com/r/NintendoSwitch/comments/6rcttl/i_made_a_program_to_organize_switch_screenshots/) +or send me a tweet [@RenanGreca](https://twitter.com/RenanGreca). :) diff --git a/game_ids.json b/game_ids.json index 6f08b24..eb5e358 100644 --- a/game_ids.json +++ b/game_ids.json @@ -18,6 +18,7 @@ "D6F3EB1178A90392C0B8A57476DADED0": "Axiom Verge", "C0A771DA35FEA8B9400647F18EA0169B": "Axiom Verge", + "EAD9CDD267F449963C89657382E411AE": "Baba is You", "56A9001957E1FA9E6227F5C3F7F107DC": "Banner Saga 2", "79EC1189088E767339D21942767BCF2E": "Battle Chef Brigade", "E27E5ADA5A86332E7C52B3562FCF5A27": "Bayonetta 2", @@ -33,6 +34,7 @@ "A6C056CABE0E1894654A3769FAF6D11E": "Captain Toad's Treasure Tracker", "93FA958835AC3573C5186D5F5B0DB6B2": "Cave Story+", "75A32021BE3512D7AA96B2D72F764411": "Celeste", + "BBBCE85F6EBFFC9C493F35F910EE935B": "ChromaGun - Demo", "03F6D2DE86ACBC923C87A67D746E299C": "Clustertruck", "EA5CEAD0C10C4580E4DCED858DDFCF69": "Dandara", @@ -168,6 +170,7 @@ "8AEDFF741E2D23FBED39474178692DAF": "Super Mario Odyssey", "099ECEEF904DB62AEE3A76A3137C241B": "Super Mario Party", "0E7DF678130F4F0FA2C88AE72B47AFDF": "Super Smash Bros. Ultimate", + "C6D726972790F87F6521C61FBA400A1DX": "Super Smash Bros. Ultimate", "691C9B2C6D1F1E032DDC01FD026159FD": "Tetris 99", "1B7686315C6209EBBD25E3E11E89316C": "The Binding of Isaac Afterbirth+", @@ -191,6 +194,7 @@ "404652E38014828AC0ED1A3EE2F1DEA3": "VOEZ", "993AC1F3383F4FF879FEA9A85677F9F9": "VVVVVV", + "B189E7FDF30356EC7B08C94ADE944BBB": "Wandersong", "E2DADADBE272660A316475FCCDECFECB": "Wonder Boy - The Dragon's Trap", "C4E9854DE59E1AAD6BFE8091E8A5B77D": "World of Goo", diff --git a/organize_screenshots.py b/organize_screenshots.py index 21604a1..a9e62f0 100644 --- a/organize_screenshots.py +++ b/organize_screenshots.py @@ -3,39 +3,74 @@ # Place this script in the same directory as the Switch's Album folder. # View README.md for more details. +# More information: https://github.com/RenanGreca/Switch-Screenshots import os import json from shutil import copy2 +import argparse +import sys -# Create a list of all the image files in the Album directory. +# Argument parser +parser = argparse.ArgumentParser(description='''Nintendo Switch screenshot organizer. + Identifies images and creates new directory structure based on game title. + More information: https://github.com/RenanGreca/Switch-Screenshots''') +parser.add_argument('-i', '--input_dir', type=str, required=False, default='./Album/', + help='(str) Path to the Album directory. Default: ./Album/') +parser.add_argument('-o', '--output_dir', type=str, required=False, default='./Output/', + help='(str) Desired output directory. Default: ./Output/') + +# Create a list of all the image/video files in the Album directory. # Thanks to L. Teder # https://stackoverflow.com/a/36898903 def list_images(dir): r = [] - for root, dirs, files in os.walk(dir): + for root, _, files in os.walk(dir): for name in files: if "jpg" in name or "mp4" in name or "png" in name: r.append(os.path.join(root, name)) return r -# Load game IDs file -with open('game_ids.json') as data_file: - game_ids = json.load(data_file) - -# Iterate over images -for image in list_images('Album'): - image_id = image.split('-')[1].split('.')[0] - - if not os.path.exists('Output'): - os.makedirs('Output') - - # If the ID was in the JSON file, create a directory and copy the file - if image_id in game_ids: - game_title = game_ids[image_id] - path = os.path.join('Output', game_title) - if not os.path.exists(path): - os.makedirs(path) - copy2(image, path) - else: - print "Game ID not found for image", image +def organize_screenshots(game_ids, input_dir, output_dir): + images = list_images(input_dir) + count = len(images) + + not_found = [] + # Iterate over images + for idx, image in enumerate(images): + # Split the filename to find the game ID + image_id = image.split('-')[1].split('.')[0] + + if image_id in game_ids: + # If the ID was in the JSON file, create a directory using the game's title and copy the file + game_title = game_ids[image_id] + path = os.path.join(output_dir, game_title) + if not os.path.exists(path): + os.makedirs(path) + copy2(image, path) + else: + # Otherwise, create a directory using the game's ID + not_found.append(image) + path = os.path.join(output_dir, image_id) + if not os.path.exists(path): + os.makedirs(path) + copy2(image, path) + + # Print progress indicator + sys.stdout.write("\r"+str(idx+1)+"/"+str(count)) + sys.stdout.flush() + + if len(not_found): + print("\nGame IDs not found for the following files:") + print("\n".join(not_found)) + +if __name__ == '__main__': + args = parser.parse_args() + input_dir = args.input_dir + output_dir = args.output_dir + + # Load game IDs file + with open('game_ids.json') as data_file: + game_ids = json.load(data_file) + + organize_screenshots(game_ids, input_dir, output_dir) \ No newline at end of file