def main() -> None: """Main function""" print( "Specify a file to load the nation list from. (Based on this script's directory)" ) print( "Nation name and password should be seperated with a single comma, no space." ) inputPath = input("File: ") print( "\nShould the passwords be interpreted as autologins keys (encrypted versions)? (y/n)" ) autologinInput = input("Interpret as autologins? ").lower() if autologinInput in ("yes", "y"): isAutologin = True print("Okay, will interpret as autologin keys.") else: isAutologin = False print("Okay, will interpret as regular passwords.") print( "\nEnter a file to generate autologin keys in, or enter nothing to not generate a file." ) outputPath = input("Autologin Output File: ") requester = nsapi.NSRequester(config.userAgent) # Collect nationlist nations = {} with open(nsapi.absolute_path(inputPath), "r") as file: for line in file: # Ignore empty lines if not line == "\n": # Split exactly once to allow passwords that contain commas nation, password = line.strip().split(",", maxsplit=1) nations[nation] = password output = autologin(requester, nations, isAutologin) # Summarize results for nation, result in output.items(): if result: string = f"Successfully logged {nation} in. (Region: {result.region})" if result.wa: string += " (WA)" print(string) else: print(f"Failed to log in {nation}. Likely an incorrect password.") # Only generate output if desired if outputPath != "": with open(nsapi.absolute_path(outputPath), "w") as file: for nation, result in output.items(): print(f"{nation},{result.autologin if result else None}", file=file)
def main() -> None: """Main function for running this module""" # Setup API API = nsapi.NSRequester(config.userAgent) # Set endorser nation to check for nation = "kuriko" logging.info("Collecting data") logging.info("Current time is %s UTC", datetime.datetime.utcnow()) region, unendorsed = unendorsed_nations(API, nation) logging.info("Formatting results") # Create output display strings header = f"{nation} has not endorsed the following WA Members in {region}:" nationURLs = "\n".join( # Increment step so that the list is 1-indexed f"{step+1}. https://www.nationstates.net/nation={name}" for step, name in enumerate(unendorsed) ) # Output unendorsed nations logging.info("Writing results") with open(nsapi.absolute_path("endorsements.txt"), "w") as f: # Header print(header, file=f) # Formatted nation urls print(nationURLs, file=f) logging.info("Current time is %s UTC", datetime.datetime.utcnow())
def main() -> None: """Main function""" requester = nsapi.NSRequester(config.userAgent) with open(nsapi.absolute_path("delegacy.txt"), "w") as f: logging.info("Outputting to file.") print("Delegacy changes in the last twelve hours") print( "\n".join( re.sub( # In the text returned by NS api, nation names are enclosed by @@ # and region names by %%. @@(.*?)@@ is a regex pattern that matches # anything surrounded by the @@, as well as the @@ @@. we pull the nation name # by taking group 1 of the match (0 is the entire match). # the nation name is a group because of the () surround the .*? # .*? lazily matches any number of any characters "%%(.*?)%%", lambda match: f"https://www.nationstates.net/region={match.group(1)}", re.sub( "@@(.*?)@@", lambda match: f"https://www.nationstates.net/nation={match.group(1)}", happening.text, ), ) for happening in delegacy(requester) ), file=f, )
def main() -> None: """Main function""" requester = nsapi.NSRequester(config.userAgent) print("Specify the region you want to search for card farmers.") region = input("Region: ") print( "\nOptionally, provide a previous output file that indicates nations to not count." ) print( "(i.e. the script will only output nations not in the previous output, i.e. new farmers)." ) print("Or, press enter to not use a previous file.") previousPath = input("Previous Output File: ") print("\nEnter the name of the output file (defaults to `participants.txt`)") outputPath = nsapi.absolute_path(input("Output Path: ")) # Load previous file if provided if previousPath: with open(nsapi.absolute_path(previousPath), "r") as f: # Each nation name is surrounded by [nation]...[/nation] tags # we remove the leading ones, and then split on the trailing ones # this leaves an extra empty element due to the trailing end tag at the end, # so that is removed with the slice. This process is done for each line, # creating a 2D iterator, which is then flattened using `a for b in c for a in b` # (the double for acts like a nested for loop) previous = { nation for nationLine in ( line.replace("[nation]", "").split("[/nation]")[:-1] for line in f.readlines() ) for nation in nationLine } participants = check_region(requester, region, previous) with open(outputPath, "w") as file: for participant in participants: print(f"[nation]{participant}[/nation]", file=file, end="") # Print a trailing newline print("", file=file) print(f"\nCollection complete. ({len(participants)} nations selected.)")
def main() -> None: """Main function""" print( "Specify a json file to load the nation data from. (Based on this script's directory)" ) inputPath = input("File: ") print("Specify a json file to load old WA data from for comparison.") oldDataPath = input("Old Data File: ") print( "\nEnter a file to generate output in, or enter nothing to output to standard output." ) outputPath = input("Output File: ") requester = nsapi.NSRequester(config.userAgent) # Collect data with open(nsapi.absolute_path(inputPath), "r") as file: nations: t.Mapping[str, t.Collection[str]] = json.load(file) # collect current/old roster with open(nsapi.absolute_path(oldDataPath), "r") as file: current: t.Mapping[str, str] = json.load(file) output = check_roster(requester, nations) # compare changes = { nation: output[nation] if nation in output else Result(None) for nation, oldWA in current.items() if nation not in output or output[nation].wa != oldWA } # Summarize results if outputPath != "": with open(nsapi.absolute_path(outputPath), "w") as file: print_output(file, changes) else: print_output(sys.stdout, changes)
def main() -> None: """Main function""" # Create requester requester = nsapi.NSRequester(config.userAgent) print("Provide a data file to work through.") print( "Ideally, the file should be a csv-type text format, with each row in this format:" ) print("<card_link>,<sender>,<receiver>,<sender_password>") print( "e.g.: 'https://www.nationstates.net/page=deck/card=926511/season=1,hn67,hn67_ii,aPassword" ) print( "Technically, only the 'card=num/season=num' part of the link is required." ) print( "Also, the password is only required for the first occurence of a nation." ) print( "If your password contains a comma (','), it should be enclosed with double quotes (\")." ) print( "The path to the file is relative to this script. If the file is in the same directory," ) print("just enter the name (e.g. 'gifts.csv')") dataPath = input("Data file: ") print("\nInstead of saving your password in the file," " you can alternatively provide an API autologin,") print("which is a encrypted by NationStates version.") print("Enter 'yes'/'y' to interpret the passwords as autologins," " or 'no' (or anything else) to not.") autologinInput = input("Interpret password fields as autologin? ").lower() if autologinInput in ("yes", "y"): autologin = True print("Interpreting password field as autologins.") else: autologin = False # We save Nation objects so that they can all use the same Auth, i.e. pin nations: MutableMapping[str, nsapi.Nation] = {} with open(nsapi.absolute_path(dataPath), "r", newline="") as file: csvReader = csv.reader(file) for row in csvReader: try: # We need to prepare or find the nation object first (of the sender) nation = nsapi.clean_format(row[1]) if nation not in nations: nations[nation] = requester.nation(nation) # Update the nation auth using given password (or autologin) # Autologin is True if the passwords are actually autologins if autologin: nations[nation].login(row[3]) else: nations[nation].auth = nsapi.Auth(password=row[3]) # Now we can delegate to the function send_card(link=row[0], sender=nations[nation], receiver=row[2]) print(f"Sent {row[0]} from {nation} to {row[2]}") # Broad error cause we want to catch anything, so the whole # program doesnt crash. logs the message except Exception as exception: # pylint: disable=broad-except print("Failed to send a card. Error:", exception)
def main() -> None: """Main method""" # TODO add type checking into the arguments? # would possibly provide better error messages parser = argparse.ArgumentParser( description="Count the issues answered by a set of nations.") subparsers = parser.add_subparsers( help="The possible modes, rerun with [mode] -h for more info.", dest="sub", ) datesParser = subparsers.add_parser("dates") datesParser.add_argument("start", help="The start date, in YYYY-MM-DD format.") datesParser.add_argument("end", help="The end date, in YYYY-MM-DD format.") datesParser.add_argument( "-m", "--month", help="The month to use for a report. Defaults to month of end date.", default=None, ) monthParser = subparsers.add_parser("month") monthParser.add_argument( "month", help=("The month to count across, in YYYY-MM format. " "Compares issue counts from YYYY-MM-01 to (MM+1)-01."), ) # monthParser.add_argument( parser.add_argument( "-r", "--report", action="store_true", help=("Create output in report mode. Produces a formatted file in " "Issue Payout Reports folder for the given month. " "The report is labelled using the month of the starting date, " "unless specified by month parameter."), ) # XKI Puppet List default_source = ( "https://docs.google.com/spreadsheets/d/e/2PACX-1vSem15AVLXgdjxWBZOnWRFnF6NwkY0gVKPYI8" "aWuHJzlbyILBL3o1F5GK1hSK3iiBlXLIZBI5jdpkVr/pub?gid=1588413756&single=true&output=tsv" ) parser.add_argument( "-s", "--source", help=("""URL or file name to retrieve nation list from. Expects either one or two nations seperated by a tab per line, where the second is interpreted as the puppetmaster. Defaults to the XKI puppets URL.""" ), default=default_source, ) parser.add_argument( "-f", "--file", action="store_true", help="Makes the script source from a file instead of URL.", ) parser.add_argument( "-o", "--output", help= "File name to write (raw) output to. Outputs to stdout if not provided.", default=None, ) if len(sys.argv) > 1: args = parser.parse_args() else: inputString = input("Arguments (One line, -h for help): ") args = parser.parse_args(shlex.split(inputString)) requester = nsapi.NSRequester(config.userAgent) # Get input data if args.file: with open(nsapi.absolute_path(args.source)) as file: nations = [line.split("\t") for line in file.readlines()] else: text = requests.get(args.source).text nations = [line.split("\t") for line in text.split("\r\n")] # Convert to puppetmaster dicts # nation[1] is "" if no master, which is falsy # Clean the format of all the names puppets = { nsapi.clean_format(nation[0]): nsapi.clean_format(nation[1]) if nation[1] else nsapi.clean_format(nation[0]) for nation in nations } # Convert dates to start and end date objects if args.sub == "dates": start = datetime.date.fromisoformat(args.start) end = datetime.date.fromisoformat(args.end) # Usually makes sense to have the 'month' (for reports) be the ending date if not provided if args.month: month = datetime.date.fromisoformat(args.month + "-01") else: month = end.replace(day=1) elif args.sub == "month": month = datetime.date.fromisoformat(args.month + "-01") # Last day of previous month, i.e. 08 -> 07-31 start = month - datetime.timedelta(days=1) # Last day of this month, i.e. 08 -> 08-31 end = month.replace( day=calendar.monthrange(month.year, month.month)[1]) logging.info("month: %s start: %s end: %s", month, start, end) counts = count_change(requester, puppets.keys(), start, end) changes = counts[0] # Collect puppetmaster counts collected_count = {puppetmaster: 0 for puppetmaster in puppets.values()} for puppet, change in changes.items(): collected_count[puppets[puppet]] += change def write_output(file: t.TextIO) -> None: for puppetmaster, count in collected_count.items(): print(f"{puppetmaster},{count}", file=file) # Write output if args.output is not None: with open(args.output, "w") as file: write_output(file) else: write_output(sys.stdout) # Generate report if chosen. # Check the subcommand first, because if month # wasnt chosen, the .report attribute wont exist # this avoids any exception due to lazy eval # if args.sub == "month" and args.report: if args.report: report = generate_report(month, collected_count) # Check for output directory if not os.path.isdir(nsapi.absolute_path("IssuePayoutReports")): os.mkdir(nsapi.absolute_path("IssuePayoutReports")) # Write the report with open( nsapi.absolute_path( # Format the month to always be 2-digit f"IssuePayoutReports/issuePayoutReport_{month.year}-{month.month:0>2d}.txt" ), "w", ) as f: f.write(report)
- datetime.timedelta(days=1) ) # Replace the day with first day, and time with 0 .replace(day=1, hour=0, minute=0, second=0, microsecond=0).timestamp() ) bound = lastMonth output = input( "Enter the file name to generate output in (will override existing): ") # check trades of each card trades = [] for card in cards: for trade in requester.card(cardid=int(card["cardid"]), season=card["season"]).trades( safe=False, sincetime=str(bound)): if (nsapi.clean_format(trade.buyer) in members or nsapi.clean_format(trade.seller) in members): trades.append((card, trade)) # display filtered trades with open(nsapi.absolute_path(output), "w", encoding="utf-8") as file: for card, trade in trades: print( f"{card['name']} " "(https://www.nationstates.net/page=deck/card=926511/season=1/trades_history=1): " f"Sold from {trade.seller} to {trade.buyer}.", file=file, )
- datetime.timedelta(days=1) ) # Replace the day with first day, and time with 0 .replace(day=1, hour=0, minute=0, second=0, microsecond=0).timestamp() ) bound = lastMonth output = input( "Enter the file name to generate output in (will override existing): ") # check trades of each card trades = [] for card in cards: for trade in requester.card(cardid=int(card["cardid"]), season=card["season"]).trades( safe=False, sincetime=str(bound)): if (nsapi.clean_format(trade.buyer) in members or nsapi.clean_format(trade.seller) in members): trades.append((card, trade)) # display filtered trades with open(nsapi.absolute_path(output), "w") as file: for card, trade in trades: print( f"{card['name']} " "(https://www.nationstates.net/page=deck/card=926511/season=1/trades_history=1): " f"Sold from {trade.seller} to {trade.buyer}.", file=file, )
# Pull target endorsement list endorsers = set(requester.nation(target).shard("endorsements").split(",")) # Pull all nations in the region that are WA members logging.info("Collecting %s WA Members", region) # Pull all world wa nations worldWA = set(requester.wa().shard("members").split(",")) # Pull all region nations regionNations = set(requester.region(region).shard("nations").split(":")) # Intersect wa members and region members citizens = worldWA & regionNations logging.info("Comparing WA Member list with target endorsers") # Determine WA members who have not endorsed target nonendorsers = citizens - endorsers # Print output in formatted manner logging.info("Outputting results\n") with open(nsapi.absolute_path("endorsed.txt"), "w") as f: # Header print(f"The following WA Members of {region} have not endorsed {target}:", file=f) for step, nonendorser in enumerate(nonendorsers): # Increment step so that it is 1-based print(f"{step+1}. https://www.nationstates.net/nation={nonendorser}", file=f)
def resolve_path(rarity: str) -> str: """Generates an absolute path using the rarity name""" return nsapi.absolute_path(f"{rarity}Cards.json")