Skip to content

Instantly share code, notes, and snippets.

@noirscape
Last active June 9, 2020 15:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save noirscape/f9a6e3e0d297c914b5e466abf17b4e21 to your computer and use it in GitHub Desktop.
Save noirscape/f9a6e3e0d297c914b5e466abf17b4e21 to your computer and use it in GitHub Desktop.
Upload folder
import os
import shutil
import requests
import argparse
import base64
from typing import List
def parse_arguments(debug_args=None):
parser = argparse.ArgumentParser(description="Upload a folder of images and videos to a szurubooru instance.")
szuru_api_group = parser.add_argument_group('szuru api settings')
post_group = parser.add_argument_group('post settings')
szuru_api_group.add_argument("-l", metavar="URL", dest="url", help="Szurubooru API URL, no trailing slash", required=True)
szuru_api_group.add_argument("-u", metavar="USERNAME", dest="username", help="Username that can upload", required=True)
szuru_api_group.add_argument("-p", metavar="PASSWORD", dest="password", help="Password belonging to username", required=True)
post_group.add_argument("-f", metavar="FOLDER", dest="folder", help="The folder to upload", default=".")
post_group.add_argument("-r", metavar="RATING", dest="rating", help="Rating of uploaded images", required=True, choices=["safe", "sketchy", "unsafe"])
post_group.add_argument("-t", metavar="TAG", dest="tags", help="Tag(s) to add on the uploaded image", required=True, nargs="+")
post_group.add_argument("-s", dest="link_relationship", help="Link nearby posts with a relationship", action="store_true")
if debug_args is not None:
return parser.parse_args(debug_args)
else:
return parser.parse_args()
def store_file_temporary(filename: str) -> str:
"""Uploads a file to the temporary server storage to reduce repeated uploads.
Arguments:
filename (str): Full path of file to upload
Returns:
str: Token of uploaded file.
"""
headers = {
"Accept": "application/json"
}
r = requests.post(url=arguments.url + "/uploads", headers=headers, files={
"content": open(filename, 'rb')
}, auth=(arguments.username, arguments.password))
return r.json()["token"]
def reverse_image_search(token: str) -> dict:
"""Preforms a token-based image search on the server.
Arguments:
token: An image token produced by `store_file_temporary()`
Returns:
dict: Image search result. See [here](https://github.com/rr-/szurubooru/blob/master/API.md#image-search-result) for more.
"""
headers = {
"Accept": "application/json",
"Content-Type": "application/json"
}
json = {
"contentToken": token
}
r = requests.post(url=arguments.url + "/posts/reverse-search", json=json, auth=(arguments.username, arguments.password), headers=headers)
return r.json()
def create_post(token: str, relations: List[str]) -> dict:
"""Create a new post on the server.
Arguments:
token (str): An image token produced by `store_file_temporary()`
relations (List[str]): A list containing relationships to add to the post.
Returns:
dict: A post. See [here](https://github.com/rr-/szurubooru/blob/master/API.md#image-search-result) for details.
"""
headers = {
"Accept": "application/json",
"Content-Type": "application/json"
}
json = {
"contentToken": token,
"tags": arguments.tags,
"safety": arguments.rating
}
r = requests.post(url=arguments.url + "/posts/", json=json, auth=(arguments.username, arguments.password), headers=headers)
return r.json()
class IdenticalFileException(Exception):
pass
def make_new_post(filename: str):
"""Preforms a number of functions in sequence to make a new post.
Arguments:
filename (str): Full path of file to add.
Raises:
IdenticalFileException: Close match (if not overriden) or exact match found.
"""
token = store_file_temporary(filename)
reverse_result = reverse_image_search(token)
relations = []
for post in reverse_result["similarPosts"]:
relations.append(post["id"])
if reverse_result["exactPost"]:
raise IdenticalFileException("Exact match found at ID {}".format(str(reverse_result["exactPost"]["id"])))
elif len(reverse_result["similarPosts"]) != 0 and not arguments.link_relationship:
raise IdenticalFileException("Close match(es) found at ID(s) {}".format(relations))
else:
result = create_post(token, relations)
print(result)
arguments = parse_arguments()
for filename in os.listdir(arguments.folder):
_, extension = os.path.splitext(filename)
if extension in ['.png', '.jpg', '.gif', '.webm', '.mp4', '.swf']:
try:
make_new_post(os.path.join(arguments.folder, filename))
except IdenticalFileException as e:
print(f'{filename}: {e}')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment