16
16
ascii image. In both instances, a ID may be used as primary argument instead.
17
17
"""
18
18
19
+ import argparse
19
20
import json
21
+ import os
22
+ from collections import Counter
20
23
from pathlib import Path
24
+ from pprint import pprint
21
25
from random import randint , random
22
26
from typing import List
23
27
from urllib .parse import urljoin
24
28
25
- import click
26
29
import colorama
27
30
import requests
28
- from click import style
29
31
from colorama import Fore , Style
32
+ from colorama .ansi import clear_screen
30
33
from PIL import Image , ImageOps
31
34
from rich .console import Console
32
35
from rich .progress import track
33
36
34
- #region Image Processing
37
+ __version__ = "0.0.1"
38
+ assets = Path ('assets/' )
39
+ assets .mkdir (parents = True , exist_ok = True )
40
+ ASSETS = assets
41
+ BASE_API = "https://pokeapi.co/api/v2/pokemon/"
42
+ SPRITE_API = "https://pokeres.bastionbot.org/images/pokemon/"
43
+ CONSOLE = Console ()
44
+
45
+ #region image processing
35
46
36
47
CHARS = [' ' , '.' , 'o' , 'v' , '@' , '#' , 'W' ]
37
48
@@ -76,34 +87,12 @@ def img2ascii(image, width=20, mirror_image=False) -> List[str]:
76
87
77
88
#endregion
78
89
79
- CONTEXT_SETTINGS = dict (max_content_width = 120 )
80
-
81
- @click .group (invoke_without_command = True , context_settings = CONTEXT_SETTINGS , help = style ("PKMN utility tool." , fg = 'bright_magenta' ))
82
- @click .option ('--verbose' , is_flag = True , default = False , help = style ("Enable verbose terminal output." , fg = 'bright_yellow' ))
83
- @click .version_option (version = '0.0.1' , prog_name = "get-data" , help = style ("Show the version and exit." , fg = 'bright_yellow' ))
84
- @click .pass_context
85
- def cli (ctx , verbose ):
86
- ctx .ensure_object (dict )
87
- assets = Path ('assets/' )
88
- assets .mkdir (parents = True , exist_ok = True )
89
- ctx .obj ['ASSETS' ] = assets
90
- ctx .obj ['BASE_API' ] = "https://pokeapi.co/api/v2/pokemon/"
91
- ctx .obj ['SPRITE_API' ] = "https://pokeres.bastionbot.org/images/pokemon/"
92
- ctx .obj ['CONSOLE' ] = Console ()
93
- ctx .obj ['VERBOSE' ] = verbose
94
-
95
- @cli .command (context_settings = CONTEXT_SETTINGS , help = style ("Create a new PKMN data file." , fg = 'bright_green' ))
96
- @click .option ('--name' , type = click .STRING , help = style ("Name of a pokemon (English)." , fg = 'bright_yellow' ))
97
- @click .option ('--id' , type = click .STRING , help = style ("A pokemon ID." , fg = 'bright_yellow' ))
98
- @click .pass_context
99
- def make (ctx , name , id ):
90
+ def req_pkmn_data (id_ : int , verbose : bool ) -> None :
100
91
result = None
101
- query = name or id
102
- console = ctx .obj ['CONSOLE' ]
103
92
104
- # make result is stored in assets/{id}.json
105
- with console .status ('Making initial request . . .' , spinner = 'dots3' ) as _ :
106
- response = requests .get (urljoin (ctx . obj [ ' BASE_API' ], query )).json ()
93
+ # result is stored in assets/{id}.json
94
+ with CONSOLE .status ('Making initial request . . .' , spinner = 'dots3' ) as _ :
95
+ response = requests .get (urljoin (BASE_API , str ( id_ ) )).json ()
107
96
level = randint (30 , 60 )
108
97
result = {
109
98
'id' : response ['id' ],
@@ -130,55 +119,83 @@ def make(ctx, name, id):
130
119
}
131
120
result ['moves' ] = moves
132
121
133
- with open (ctx . obj [ ' ASSETS' ] .joinpath (f"{ result ['id' ]} .json" ), mode = 'w' , encoding = 'utf-8' ) as file_handler :
122
+ with open (ASSETS .joinpath (f"{ result ['id' ]} .json" ), mode = 'w' , encoding = 'utf-8' ) as file_handler :
134
123
json .dump (result , file_handler )
135
124
136
- if ctx .obj ['VERBOSE' ]:
137
- console .print (result )
138
- click .echo ('\n ' )
125
+ if verbose :
126
+ pprint (result )
139
127
140
- click . secho (f"Done! A new JSON file was created in ' { ctx . obj [ ' ASSETS' ] } /'." , fg = 'bright_yellow' )
128
+ print (f"{ Fore . YELLOW } Done! A new JSON file was created in { str ( ASSETS )!r } . { Style . RESET_ALL } " )
141
129
142
- @cli .command (context_settings = CONTEXT_SETTINGS , help = style ("Create an ASCII image." , fg = 'bright_green' ))
143
- @click .option ('--name' , type = click .STRING , help = style ("Name of a pokemon (English)." , fg = 'bright_yellow' ))
144
- @click .option ('--id' , type = click .STRING , help = style ("A pokemon ID." , fg = 'bright_yellow' ))
145
- @click .option ('--mirror/--no-mirror' , is_flag = True , default = False , help = style ("Mirror image (Player)." , fg = 'bright_yellow' ))
146
- @click .pass_context
147
- def ascii (ctx , name , id , mirror ):
148
- query = name or id
149
-
130
+ def gen_sprite (id_ : int , mirror : bool , verbose : bool ) -> None :
150
131
colorama .init (autoreset = False )
151
132
152
- # the base api only contains very small sprites,
153
- # but there's another API which provides higher
154
- # quality sprites which are only searchable by id
155
- with ctx .obj ['CONSOLE' ].status ('Creating new ASCII image . . .' , spinner = 'dots3' ) as _ :
156
- if name :
157
- query = requests .get (urljoin (ctx .obj ['BASE_API' ], query )).json ()['id' ]
158
-
159
- # first find and download the pokemon sprite
160
- filename = f"{ query } .png"
161
- image_path = ctx .obj ['ASSETS' ].joinpath (filename )
162
- response = requests .get (urljoin (ctx .obj ['SPRITE_API' ], filename ), stream = True )
133
+ with CONSOLE .status ('Creating new ASCII image . . .' , spinner = 'dots3' ) as _ :
134
+ filename = f"{ id_ } .png"
135
+ image_path = ASSETS .joinpath (filename )
136
+ response = requests .get (urljoin (SPRITE_API , filename ), stream = True )
163
137
with open (image_path , mode = 'wb' ) as file_handler :
164
138
for chunk in response .iter_content (1024 ):
165
139
file_handler .write (chunk )
166
140
167
- # then generate the ascii image and store the result in assets/{id}.txt
168
141
ascii_art = img2ascii (Image .open (image_path ), width = 20 , mirror_image = mirror )
169
- with open (ctx . obj [ ' ASSETS' ] .joinpath (f"{ query } .txt" ), mode = 'w' , encoding = 'utf-8' ) as file_handler :
142
+ with open (ASSETS .joinpath (f"{ id_ } .txt" ), mode = 'w' , encoding = 'utf-8' ) as file_handler :
170
143
file_handler .writelines (ascii_art )
171
144
172
- # cleanup
173
145
image_path .unlink (missing_ok = True )
174
146
175
- if ctx .obj ['VERBOSE' ]:
176
- click .echo (f"\n { '' .join (ascii_art )} " )
147
+ if verbose :
148
+ print (f"\n { '' .join (ascii_art )} " )
149
+
150
+ print (f"{ Fore .YELLOW } Done! A new ASCII image was created in { str (ASSETS )!r} .{ Style .RESET_ALL } " )
151
+
152
+ def check_manifest (verbose : bool ) -> None :
153
+ extensions = ['.txt' , '.json' ]
154
+
155
+ files = list (filter (
156
+ lambda file : file .suffix in extensions and file .stem .isnumeric (),
157
+ [file for file in ASSETS .glob (r'**/*' )]
158
+ ))
159
+
160
+ ids = list (map (lambda file : int (file .stem ), files ))
161
+ duplicates = [id_ for id_ , count in Counter (ids ).items () if count > 1 ]
162
+
163
+ manifest = {
164
+ 'files' : list (map (str , files )),
165
+ 'duplicates' : duplicates ,
166
+ 'game_ready' : len (duplicates ) >= 2 ,
167
+ }
168
+
169
+ with open ("manifest.json" , mode = 'w' , encoding = 'utf-8' ) as file_handler :
170
+ json .dump (manifest , file_handler )
171
+
172
+ if verbose : pprint (manifest )
173
+
174
+ def main ():
175
+ parser = argparse .ArgumentParser ()
176
+
177
+ parser .add_argument ('--version' , action = 'version' , version = f"%(prog)s { __version__ } " )
178
+ parser .add_argument ('--verbose' , action = 'store_true' , help = "increase output verbosity" )
179
+
180
+ subparser = parser .add_subparsers (dest = 'command' )
181
+
182
+ make_parser = subparser .add_parser ('make' , help = "create new pkmn data" )
183
+ make_parser .add_argument ('--id' , type = int , nargs = '+' , required = True , help = "one or more pokemon id" )
184
+ make_parser .add_argument ('--mirror' , action = 'store_true' , help = "mirror sprite" )
185
+
186
+ manifest_parser = subparser .add_parser ('manifest' , help = "validate manifest" )
187
+
188
+ args = parser .parse_args ()
189
+
190
+ if args .command == 'make' :
191
+ for id_ in args .id :
192
+ req_pkmn_data (id_ , verbose = False )
193
+ gen_sprite (id_ , args .mirror , args .verbose )
194
+ elif args .command == 'manifest' :
195
+ check_manifest (args .verbose )
196
+ else :
197
+ raise NotImplementedError ()
177
198
178
- click .secho (f"Done! A new ASCII image was created in '{ ctx .obj ['ASSETS' ]} /'." , fg = 'bright_yellow' )
179
199
180
200
if __name__ == '__main__' :
181
- try :
182
- cli (obj = {})
183
- except KeyboardInterrupt :
184
- pass
201
+ main ()
0 commit comments