initial version

master
mtheiler 4 months ago
parent 4e0c4d7023
commit 90901c99f8
  1. 241
      commons-uploader2.py

@ -0,0 +1,241 @@
# commons-upload-tool based on github.com/fastily/pwiki
# purpose: batch upload your self-made photos and videos to Wikimedia Commons
# author: mtheiler
# date: 2022-04-20
# further down there you are able to insert your own defaults e.g. username, ...
import argparse
import getpass
import logging
import re
import os
from datetime import date, datetime
from pathlib import Path
from textwrap import dedent
from typing import Any
# PIL is the Python Imaging Library which provides the python interpreter with image editing capabilities
from PIL import Image
from PIL.Image import Exif
from PIL.ExifTags import TAGS
from PIL.ExifTags import GPSTAGS
from rich.logging import RichHandler
# see: https://github.com/fastily/pwiki
from pwiki import wgen
from pwiki.wiki import Wiki
log = logging.getLogger(__name__)
_MTC_FILE = Path.home() / ".scu.px.txt"
def _make_wiki(*args: Any) -> Wiki:
"""Convienence method, creates a new `Wiki` pointed at Commons with `args`
Returns:
Wiki: The Wiki resulting object
"""
return Wiki("commons.wikimedia.org", *args)
def getExifTags(rawEXIF):
"""Gets Exif Tags from the raw EXIF data of the image
and extracts DateTime and the GPS data """
exifTags = {} # place to store the EXIF data
gpsTags = {} # place to store the GPS data
#pulling out the EXIF tags.
for tag, value in rawEXIF.items():
decoded = TAGS.get(tag,tag)
exifTags[decoded] = value
dateTime = exifTags['DateTimeDigitized']
rawGPS = exifTags['GPSInfo']
# Pulling out the GPS specific tags.
# see: https://pillow.readthedocs.io/en/stable/reference/ExifTags.html
for gpstag , value in rawGPS.items():
decoded = TAGS.get(gpstag,gpstag)
gpsTags[decoded] = value
latitude_direction=gpsTags[1] # N or S
(lat_degrees, lat_minutes, lat_seconds) = gpsTags[2] # latitude
longitude_direction=gpsTags[3] # W or E
(long_degrees, long_minutes, long_seconds) = gpsTags[4] # longitude
# see: https://commons.wikimedia.org/wiki/Template:Location
commons_location= dedent(f"""\
{{{{Location|{lat_degrees}|{lat_minutes}|{lat_seconds}|{latitude_direction}|{long_degrees}|{long_minutes}|{long_seconds}|{longitude_direction}}}}}
""")
return (dateTime, commons_location)
def _main() -> None:
"""Main driver, to be run if this script is invoked directly."""
for lg in (logging.getLogger("pwiki"), log):
lg.addHandler(RichHandler(rich_tracebacks=True))
lg.setLevel(logging.INFO)
verbose = True
cli_parser = argparse.ArgumentParser(description="Simple Commons Uploader 2 (MTh)")
cli_parser.add_argument('--user', type=str, help="username to use")
cli_parser.add_argument('--pw', type=str, help="password to use")
cli_parser.add_argument('--cat', type=str, help="commons category to use")
cli_parser.add_argument('--fnx', type=str, help="part of the filename on commons")
cli_parser.add_argument("-i", action='store_true', help="force interactive login")
cli_parser.add_argument("--wgen", action='store_true', help="run wgen password manager")
cli_parser.add_argument('dirs', metavar='folders', type=Path, nargs='*', help='folders with files to upload')
# uncomment any of the following lines to set your own defaults
# local directory to find pictures to upload
# myTest1 = Path('./test')
# local list of directories.
# cli_parser.set_defaults(dirs=[myTest1])
# this string will become part of the constructed filename on Commons
# cli_parser.set_defaults(fnx='test')
# Commons Category
# cli_parser.set_defaults(cat='testCategory')
# Wikipedia Username
# cli_parser.set_defaults(user='my username')
# Wikipedia Password
# cli_parser.set_defaults(pw='my very secret password') # Password
args = cli_parser.parse_args()
if args.fnx:
fileNameExt=args.fnx
if args.wgen:
wgen.setup_px(_MTC_FILE, False)
return
if args.i:
wiki = _make_wiki(input("Please login to continue.\nUsername: "), getpass.getpass())
elif args.user:
if not args.pw:
log.critical("No password specified, please pass the --pw flag with a pasword.")
return
wiki = _make_wiki(args.user, args.pw)
elif _MTC_FILE.is_file():
wiki = _make_wiki(*wgen.load_px(_MTC_FILE).popitem())
else:
wiki = _make_wiki()
if args.cat:
commomsCategory=args.cat
result=wiki.exists(f"Category:{commomsCategory}")
if not result:
log.critical(f"Category:{commomsCategory} does not exists")
return
if not args.dirs:
log.critical("You didn't specify and directories to upload!")
return
ext_list = {"." + e for e in wiki.uploadable_filetypes()}
fails = []
uploadedFileNames: List[str]
uploadedFileNames = []
for base_dir in args.dirs:
if not base_dir.is_dir():
continue
i = 1
if verbose:
print('===Dir=',base_dir)
for f in base_dir.iterdir():
if not f.is_file() or (file_ext := f.suffix.lower()) not in ext_list:
continue
# construct an image description from filename without path and without suffix
imageDescription = (os.path.basename(f)).removesuffix(file_ext)
# date
timestamp = None
if file_ext in (".jpg", ".jpeg"):
try:
with Image.open(f) as img:
rawEXIF = img.getexif() #Get the EXIF data from the image.
exifDateTime, gpsLocation = getExifTags(rawEXIF)
d, time = exifDateTime.split()
myDate=d.replace(':', '-')
timestamp = f"{myDate} {time}"
except Exception as e:
log.warning("Could not parse EXIF for %s", f, exc_info=True)
desc = dedent(f"""\
=={{{{int:filedesc}}}}==
{{{{Information
|description={imageDescription}
|date={timestamp or datetime.fromtimestamp(f.stat().st_mtime).strftime('%Y-%m-%d %H:%M:%S')}
|source={{{{Own}}}}
|author=~~~
}}}}
{gpsLocation}
=={{{{int:license-header}}}}==
{{{{Self|Cc-by-sa-4.0}}}}
[[Category:{commomsCategory}]]""")
# [[Category:Files by {wiki.username}]]""")
if verbose:
print("This will be saved on Commons:")
print(desc)
filenameCommons=f"{imageDescription}_{myDate}_{fileNameExt}{file_ext}"
if verbose:
print("filenameCommons=",filenameCommons)
# todo Argument einführen, wenn gesetzt, dann kein Upload
# Upload to Commons using pwiki, beim Test auskommentiert
if not wiki.upload(f, filenameCommons, desc, summary="fileupload with python-script"):
fails.append(f)
i += 1
uploadedFileNames.append(filenameCommons)
if fails:
log.warning("Failed to upload %d files: %s", len(fails), fails)
else:
log.info("Finished with no failures")
# wiki.save_cookies() mth
# append filenames to gallery
text4Gallery = f"""\n\n== {commomsCategory} {myDate} ==\n"""
text4Gallery += "\n<gallery widths=200>"
for oneUploadedFilename in uploadedFileNames:
text4Gallery += f"""\n{oneUploadedFilename} | {oneUploadedFilename}"""
text4Gallery += "\n</gallery>"
myGallery=f"""User:{wiki.username}/gallery"""
if verbose:
print('Gallery=', myGallery)
print(text4Gallery)
wiki.edit(myGallery, append=text4Gallery, summary="edit gallery with python-script")
if __name__ == '__main__':
_main()
Loading…
Cancel
Save