worked on detail page
This commit is contained in:
parent
e3392163ac
commit
03aff17cc7
|
|
@ -53,8 +53,8 @@
|
|||
hr {color:#fff;}
|
||||
.topbar a {color:#fff; text-decoration:none;}
|
||||
</style>
|
||||
<link rel="stylesheet" href="../../conf/main.css">
|
||||
<div class="logo"><a href="/"><img src="../../conf/logo.png" /></a></div>
|
||||
<link rel="stylesheet" href="{{stylesheet}}">
|
||||
<div class="logo"><a href="/"><img src="{{logo}}" /></a></div>
|
||||
<!-- End Styles+Logo -->
|
||||
<div class="header">
|
||||
<a href="/">Chrissys random stuff.</a>
|
||||
|
|
@ -66,6 +66,7 @@
|
|||
<li><a href="/" >Main</a></li>
|
||||
<li><a href="/projekte">Projects</a></li>
|
||||
<li><a href="/blog">Blog</a></li>
|
||||
<li><a href="/pics">Photography</a></li>
|
||||
<li><a href="/kontakt">Contact</a></li>
|
||||
<li><a href="/rss.xml">RSS-Feed</a></li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
#!/usr/bin/python3
|
||||
"""!@brief: helper routines for dealing with GPS Data from exif
|
||||
@author: Luzia Christiane Tesar
|
||||
@date Mi 12. Aug 13:12:33 CEST 2026
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import requests
|
||||
import json
|
||||
from datetime import datetime
|
||||
from PIL import Image
|
||||
from PIL.ExifTags import TAGS, GPSTAGS
|
||||
|
||||
REV_API_URL = "https://nominatim.openstreetmap.org/reverse"
|
||||
headers = {"User-Agent": "Purrrrrpic :3"}
|
||||
|
||||
|
||||
def get_exif_data(image):
|
||||
"""Returns a dictionary from the exif data of an PIL Image item. Also converts the GPS Tags"""
|
||||
exif_data = {}
|
||||
try:
|
||||
info = image._getexif()
|
||||
if info:
|
||||
for tag, value in info.items():
|
||||
decoded = TAGS.get(tag, tag)
|
||||
if decoded == "GPSInfo":
|
||||
gps_data = {}
|
||||
for t in value:
|
||||
sub_decoded = GPSTAGS.get(t, t)
|
||||
gps_data[sub_decoded] = value[t]
|
||||
|
||||
exif_data[decoded] = gps_data
|
||||
else:
|
||||
exif_data[decoded] = value
|
||||
|
||||
except:
|
||||
pass
|
||||
return exif_data
|
||||
|
||||
|
||||
def _get_if_exist(data, key):
|
||||
if key in data:
|
||||
return data[key]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _convert_to_degress(value):
|
||||
"""Helper function to convert the GPS coordinates stored in the EXIF to degress in float format"""
|
||||
d = float(value[0])
|
||||
|
||||
m = float(value[1])
|
||||
|
||||
s = float(value[2])
|
||||
|
||||
return d + (m / 60.0) + (s / 3600.0)
|
||||
|
||||
|
||||
def get_lat_lon(exif_data):
|
||||
"""Returns the latitude and longitude, if available, from the provided exif_data (obtained through get_exif_data above)"""
|
||||
lat = None
|
||||
lon = None
|
||||
|
||||
if "GPSInfo" in exif_data:
|
||||
gps_info = exif_data["GPSInfo"]
|
||||
gps_latitude = _get_if_exist(gps_info, "GPSLatitude")
|
||||
gps_latitude_ref = _get_if_exist(gps_info, "GPSLatitudeRef")
|
||||
gps_longitude = _get_if_exist(gps_info, "GPSLongitude")
|
||||
gps_longitude_ref = _get_if_exist(gps_info, "GPSLongitudeRef")
|
||||
|
||||
if gps_latitude and gps_latitude_ref and gps_longitude and gps_longitude_ref:
|
||||
lat = _convert_to_degress(gps_latitude)
|
||||
if gps_latitude_ref != "N":
|
||||
lat = 0 - lat
|
||||
|
||||
lon = _convert_to_degress(gps_longitude)
|
||||
if gps_longitude_ref != "E":
|
||||
lon = 0 - lon
|
||||
|
||||
return lat, lon
|
||||
|
||||
def getReverseAPI(lat, lon):
|
||||
try:
|
||||
payload = {"lat": lat, "lon": lon, "format": "json", "addressdetails": "1"}
|
||||
r = requests.get(REV_API_URL, headers=headers, params=payload)
|
||||
return r.json()
|
||||
except requests.exceptions.HTTPError as errh:
|
||||
print ("Http Error:",errh)
|
||||
except requests.exceptions.ConnectionError as errc:
|
||||
print ("Error Connecting:",errc)
|
||||
except requests.exceptions.Timeout as errt:
|
||||
print ("Timeout Error:",errt)
|
||||
except requests.exceptions.RequestException as err:
|
||||
print ("OOps: Something Else",err)
|
||||
|
||||
def getCity(geo):
|
||||
return geo["address"]["city"] or ""
|
||||
|
||||
|
||||
def getCountry(geo):
|
||||
return geo["address"]["country"] or ""
|
||||
|
||||
|
||||
def getRoad(geo):
|
||||
return geo["address"]["road"] or ""
|
||||
|
||||
|
||||
def getHouseNumber(geo):
|
||||
return geo["address"]["house_number"] or ""
|
||||
|
||||
|
||||
def getPostCode(geo):
|
||||
return geo["address"]["postcode"] or ""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
img = Image.open("eh23/IMG20260403174725.jpg")
|
||||
exifdata = get_exif_data(img)
|
||||
lat, lon = get_lat_lon(exifdata)
|
||||
geo = getReverseAPI(lat, lon)
|
||||
print(getCity(geo))
|
||||
print(getCountry(geo))
|
||||
print(getRoad(geo))
|
||||
307
purrpic.py
307
purrpic.py
|
|
@ -8,33 +8,61 @@ import os
|
|||
import sys
|
||||
import glob
|
||||
|
||||
# import exif
|
||||
from PIL import Image
|
||||
from PIL.ExifTags import TAGS, GPSTAGS
|
||||
import argparse
|
||||
import configparser
|
||||
from pathlib import Path
|
||||
import datetime
|
||||
from gps_location import get_lat_lon, getReverseAPI
|
||||
|
||||
BUILD_DIR = Path("./build").resolve()
|
||||
CONF_DIR = Path("./conf").resolve()
|
||||
THUMBSIZE = (300, 300)
|
||||
GLOBALNAME = "Chrissys random Imagelibrary"
|
||||
THUMBSIZE = (800, 800)
|
||||
GLOBALNAME = "Chrissys random Photogallery"
|
||||
LICENCE = "CC BY-NC-SA 4.0"
|
||||
AUTHOR = "Luzia Christiane Tesar"
|
||||
LANGUAGE = "en"
|
||||
DESCRIPTION = ""
|
||||
TODAY = datetime.datetime.today().strftime("%Y-%m-%d")
|
||||
CANONICALURL = "https://dm2lct.radio"
|
||||
STYLESHEET = "https://dm2lct.radio/config/main.css"
|
||||
LOGO = "https://dm2lct.radio/config/logo.png"
|
||||
COPYRIGHT = f"© {datetime.datetime.today().year} by {AUTHOR}. This work is licensed under {LICENCE}. To view a copy of this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/"
|
||||
|
||||
exclude = set([".thumbnails", ".git", "conf", "build"])
|
||||
|
||||
|
||||
class HTML:
|
||||
def __init__(self, **kwargs):
|
||||
def __init__(self):
|
||||
self.header = Path(CONF_DIR / "header.html").read_text()
|
||||
self.footer = Path(CONF_DIR / "footer.html").read_text()
|
||||
for key, value in kwargs.items():
|
||||
setattr(self, key, value)
|
||||
self.leaflet = Path(CONF_DIR / "leaflet.html").read_text()
|
||||
|
||||
self.lat = None
|
||||
self.lon = None
|
||||
self.geo = None
|
||||
self.datetime = None
|
||||
self.file_link = None
|
||||
self.make = None
|
||||
self.model = None
|
||||
self.focus = None
|
||||
self.caption = None
|
||||
|
||||
self.ev = None
|
||||
self.exposure = None
|
||||
self.exposure_mode = None
|
||||
self.exposure_program = None
|
||||
self.f_num = None
|
||||
self.flash = None
|
||||
self.focal_length = None
|
||||
self.focus_distance = None
|
||||
self.focus_mode = None
|
||||
self.iso = None
|
||||
self.lv = None
|
||||
self.software = None
|
||||
self.subject_distance = None
|
||||
self.lens_model = None
|
||||
|
||||
def title(self, title):
|
||||
return f"""<h1>{title}</h1>\n"""
|
||||
|
|
@ -77,12 +105,75 @@ class HTML:
|
|||
header = header.replace("{{published_date}}", TODAY)
|
||||
header = header.replace("{{modified_date}}", TODAY)
|
||||
header = header.replace("{{canonical_url}}", CANONICALURL)
|
||||
header = header.replace("{{stylesheet}}", STYLESHEET)
|
||||
header = header.replace("{{logo}}", LOGO)
|
||||
return header
|
||||
|
||||
def leaflet(self, lat, lon, zoom=10):
|
||||
lfhtml = self.leaflet.replace("{LAT}", lat)
|
||||
lfhtml = lfhtml.replace("{LON}", lon)
|
||||
lfhtml = lfhtml.replace("{ZOOM}", zoom)
|
||||
return lfhtml
|
||||
|
||||
def getImgInfo(self, img):
|
||||
exif = EXIF()
|
||||
exifdata = exif.getData(img)
|
||||
|
||||
if "Make" in exifdata:
|
||||
self.make = exifdata["Make"]
|
||||
|
||||
if "Model" in exifdata:
|
||||
self.model = exifdata["Model"]
|
||||
|
||||
if "DateTimeOriginal" in exifdata:
|
||||
self.datetime = datetime.datetime.strptime(
|
||||
exifdata["DateTimeOriginal"], "%Y:%m:%d %H:%M:%S"
|
||||
)
|
||||
|
||||
if "FocalLength" in exifdata:
|
||||
self.focal_length = exifdata["FocalLength"]
|
||||
|
||||
if "LensModel" in exifdata:
|
||||
self.lens_model = exifdata["LensModel"]
|
||||
|
||||
if "ExposureTime" in exifdata:
|
||||
self.exposure = exifdata["ExposureTime"]
|
||||
|
||||
if "FNumber" in exifdata:
|
||||
self.f_num = exifdata["FNumber"]
|
||||
|
||||
if "ISOSpeedRatings" in exifdata:
|
||||
self.iso = exifdata["ISOSpeedRatings"]
|
||||
|
||||
if "Software" in exifdata:
|
||||
self.software = exifdata["Software"]
|
||||
|
||||
if "GPSInfo" in exifdata:
|
||||
self.lat, self.lon = get_lat_lon(exifdata)
|
||||
self.geo = getReverseAPI(self.lat, self.lon)
|
||||
|
||||
def writeGrid(self, imglist, linklist):
|
||||
try:
|
||||
buf: ""
|
||||
buf += self.div("row")
|
||||
# imglist = glob.glob(str(odir) + "/.thumbnails/*")
|
||||
imglist = []
|
||||
for img in Path.iterdir(odir / ".thumbnails"):
|
||||
imglist.append(img)
|
||||
for n in range(0, 3):
|
||||
buf += self.div("column")
|
||||
for i in range(n, len(imglist), 3):
|
||||
buf += self.aimg(".thumbnails/" + imglist[i].name, imglist[i].name)
|
||||
buf += self.endDiv()
|
||||
buf += self.endDiv()
|
||||
except:
|
||||
pass
|
||||
return buf
|
||||
|
||||
def writeIndex(self, odir, meta) -> None:
|
||||
try:
|
||||
title=meta['title']
|
||||
desc=meta['description']
|
||||
title = meta["title"]
|
||||
desc = meta["description"]
|
||||
buf = self.headermeta(title)
|
||||
buf += self.title(title)
|
||||
if len(desc) > 0:
|
||||
|
|
@ -92,17 +183,15 @@ class HTML:
|
|||
buf += self.li(f"© {AUTHOR}, {LICENCE}")
|
||||
buf += self.endUl()
|
||||
buf += self.div("row")
|
||||
#imglist = glob.glob(str(odir) + "/.thumbnails/*")
|
||||
imglist =[]
|
||||
imglist = []
|
||||
for img in Path.iterdir(odir / ".thumbnails"):
|
||||
imglist.append(img)
|
||||
for n in range(0, 3):
|
||||
buf += self.div("column")
|
||||
breakpoint()
|
||||
for i in range(n, len(imglist), 3):
|
||||
buf += self.aimg(
|
||||
".thumbnails/" + imglist[i].name,
|
||||
imglist[i].name)
|
||||
".thumbnails/" + imglist[i].name, f"{imglist[i].stem}.html"
|
||||
)
|
||||
buf += self.endDiv()
|
||||
buf += self.endDiv()
|
||||
buf += self.footer
|
||||
|
|
@ -111,37 +200,109 @@ class HTML:
|
|||
except:
|
||||
pass
|
||||
|
||||
def writeDetail(self, img, previmg, nextimg):
|
||||
buf = self.headermeta(title)
|
||||
buf += self.title(title)
|
||||
buf += self.img(image)
|
||||
buf += self.footer
|
||||
with open(f"build/{self.outfolder}/index.html", "w", encoding="utf-8") as file:
|
||||
file.write(buf)
|
||||
def writeDetail(self, odir):
|
||||
try:
|
||||
breakpoint()
|
||||
imglist = []
|
||||
for file in Path.iterdir(odir):
|
||||
if file.suffix in [".jpg", ".png", "JPEG", "PNG"]:
|
||||
imglist.append(file)
|
||||
else:
|
||||
continue
|
||||
for img in imglist:
|
||||
with Image.open(img) as i:
|
||||
self.getImgInfo(i)
|
||||
buf = self.headermeta(GLOBALNAME)
|
||||
buf += self.div("div")
|
||||
buf += self.div("divleft")
|
||||
buf += self.link("index.html", "Back")
|
||||
buf += self.endDiv()
|
||||
buf += self.endDiv()
|
||||
buf += self.img(img)
|
||||
buf += self.div("div")
|
||||
if imglist.index(img) != 0:
|
||||
buf += self.div("divleft")
|
||||
buf += self.link(
|
||||
f"{imglist[(imglist.index(img) - 1) % len(imglist)].stem}.html",
|
||||
"Perv",
|
||||
)
|
||||
buf += self.endDiv()
|
||||
|
||||
def writeMain(self, titles):
|
||||
with open(f"{str(BUILD_DIR)}/index.html", "w", encoding="utf-8") as file:
|
||||
title = "Chrissys random Imagelibrary"
|
||||
file.write(self.headermeta(title))
|
||||
file.write(self.title(title))
|
||||
if imglist.index(img) != len(imglist) - 1:
|
||||
buf += self.div("divright")
|
||||
buf += self.link(
|
||||
f"{imglist[(imglist.index(img) + 1) % len(imglist)].stem}.html",
|
||||
"Next",
|
||||
)
|
||||
buf += self.endDiv()
|
||||
buf += self.endDiv()
|
||||
|
||||
buf += self.div("div")
|
||||
buf += '<p style="margin-top:3cm;"><table>\n'
|
||||
|
||||
if self.datetime:
|
||||
buf += f"<tr><td><b>Time </td><td>{self.datetime.strftime('%Y-%m-%d %H:%M')}</td></tr>\n"
|
||||
|
||||
if self.geo:
|
||||
buf += f"<tr><td><b>Place </td><td><a href = https://www.openstreetmap.org/?mlat={self.lat}&mlon={self.lon}map=17/{self.lat}/{self.lon}>{self.geo['address']['road']}, {self.geo['address']['town']}</a></td></tr>\n"
|
||||
|
||||
if self.make:
|
||||
buf += f"<tr><td><b>Camera</td><td>{self.make} {self.model}</td></tr>\n"
|
||||
|
||||
if self.lens_model:
|
||||
buf += (
|
||||
f"<tr><td><b>Lens Model </td><td>{self.lens_model}</td></tr>\n"
|
||||
)
|
||||
|
||||
if self.focal_length:
|
||||
buf += f"<tr><td><b>Focal Length </td><td>{self.focal_length}</td></tr>\n"
|
||||
|
||||
if self.f_num:
|
||||
buf += (
|
||||
f"<tr><td><b>Aperture </td><td>{self.focal_length}</td></tr>\n"
|
||||
)
|
||||
|
||||
if self.exposure:
|
||||
buf += (
|
||||
f"<tr><td><b>Exposure Time </td><td>{self.exposure}</td></tr>\n"
|
||||
)
|
||||
|
||||
if self.iso:
|
||||
buf += f"<tr><td><b>ISO </td><td>{self.iso}</td></tr>\n"
|
||||
|
||||
if self.software:
|
||||
buf += f"<tr><td><b>Software </td><td>{self.software}</td></tr>\n"
|
||||
|
||||
buf += "</table></p>\n"
|
||||
buf += self.endDiv()
|
||||
|
||||
buf += self.footer
|
||||
with open(odir / f"{img.stem}.html", "w", encoding="utf-8") as file:
|
||||
file.write(buf)
|
||||
except:
|
||||
pass
|
||||
|
||||
def writeMain(self, metadata):
|
||||
with open(BUILD_DIR / "index.html", "w", encoding="utf-8") as file:
|
||||
breakpoint()
|
||||
file.write(self.headermeta(GLOBALNAME))
|
||||
file.write(self.title(GLOBALNAME))
|
||||
file.write(self.div("row"))
|
||||
dirs = list(
|
||||
filter(lambda x: x.is_dir() and x not in exclude, os.scandir(BUILD_DIR))
|
||||
)
|
||||
dirs = metadata.keys()
|
||||
dirlist = []
|
||||
for d in dirs:
|
||||
dirlist.append(d)
|
||||
for n in range(0, 3):
|
||||
file.write(self.div("column"))
|
||||
for i in range(n, len(dirs), 3):
|
||||
thumbs = os.listdir(
|
||||
str(BUILD_DIR) + "/" + dirs[i].name + "/.thumbnails"
|
||||
)
|
||||
for i in range(n, len(dirlist), 3):
|
||||
thumbs = os.listdir(BUILD_DIR / dirlist[i] / ".thumbnails")
|
||||
file.write(self.div("desc"))
|
||||
file.write(titles[dirs[i].name])
|
||||
file.write(metadata[dirlist[i]]["title"])
|
||||
file.write(self.endDiv())
|
||||
file.write(
|
||||
self.aimg(
|
||||
str(dirs[i].name) + "/.thumbnails/" + thumbs[0],
|
||||
str(dirs[i].name) + "/",
|
||||
),
|
||||
dirlist[i] + "/.thumbnails/" + thumbs[0], dirlist[i] + "/"
|
||||
)
|
||||
)
|
||||
file.write(self.endDiv())
|
||||
file.write(self.endDiv())
|
||||
|
|
@ -153,6 +314,31 @@ class EXIF:
|
|||
for key, value in kwargs.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
def getData(self, image):
|
||||
"""Returns a dictionary from the exif data of an PIL Image item. Also converts the GPS Tags"""
|
||||
exif_data = {}
|
||||
try:
|
||||
info = image._getexif()
|
||||
if info:
|
||||
for tag, value in info.items():
|
||||
decoded = TAGS.get(tag, tag)
|
||||
if decoded == "GPSInfo":
|
||||
gps_data = {}
|
||||
for t in value:
|
||||
sub_decoded = GPSTAGS.get(t, t)
|
||||
gps_data[sub_decoded] = value[t]
|
||||
|
||||
exif_data[decoded] = gps_data
|
||||
else:
|
||||
if type(value) == str:
|
||||
exif_data[decoded] = value.strip("\x00")
|
||||
else:
|
||||
exif_data[decoded] = value
|
||||
|
||||
except:
|
||||
pass
|
||||
return exif_data
|
||||
|
||||
|
||||
class IMG:
|
||||
def __init__(self, **kwargs):
|
||||
|
|
@ -161,16 +347,18 @@ class IMG:
|
|||
|
||||
|
||||
def createThumb(img, thumbdir):
|
||||
file = Path(img).stem
|
||||
with Image.open(img) as im:
|
||||
im.thumbnail(THUMBSIZE)
|
||||
im.convert("RGB").save(str(thumbdir) + "/" + file + ".jpg", "JPEG")
|
||||
im.convert("RGB").save(str(thumbdir) + "/" + img.stem + ".jpg", "JPEG")
|
||||
|
||||
|
||||
def processImage(img, odir):
|
||||
file = Path(img).stem
|
||||
breakpoint()
|
||||
with Image.open(img) as im:
|
||||
im.convert("RGB").save(str(odir) + "/" + file + ".jpg", "JPEG")
|
||||
exif = im.getexif()
|
||||
exif[315] = AUTHOR
|
||||
exif[33432] = COPYRIGHT
|
||||
im.save(str(odir) + "/" + img.stem + ".jpg", "JPEG", exif=exif)
|
||||
|
||||
|
||||
def generateDir(path):
|
||||
|
|
@ -180,6 +368,7 @@ def generateDir(path):
|
|||
Path.mkdir(thumbdir, parents=True, exist_ok=True)
|
||||
return odir, thumbdir
|
||||
|
||||
|
||||
def parseIni(file):
|
||||
meta = {"title": None, "category": None, "description": [], "files": []}
|
||||
try:
|
||||
|
|
@ -187,14 +376,14 @@ def parseIni(file):
|
|||
for line in f:
|
||||
if line.startswith("desc = "):
|
||||
meta["description"].append(line.removeprefix("desc = ").strip())
|
||||
elif line.endswith(".jpg\n" or ".png\n" or ".jpeg\n"):
|
||||
elif line.endswith((".jpg\n", ".png\n", ".jpeg\n")):
|
||||
meta["files"].append(line.strip())
|
||||
elif line.startswith("title = "):
|
||||
meta["title"] = line.removeprefix("title = ").strip()
|
||||
elif line.startswith("category = "):
|
||||
meta["category"] = line.removeprefix("category = ").strip()
|
||||
else:
|
||||
next
|
||||
continue
|
||||
except:
|
||||
pass
|
||||
return meta
|
||||
|
|
@ -202,8 +391,7 @@ def parseIni(file):
|
|||
|
||||
def processDir(path):
|
||||
try:
|
||||
if Path.is_file(path /".purrpic.ini"):
|
||||
breakpoint()
|
||||
if Path.is_file(path / ".purrpic.ini"):
|
||||
meta = parseIni(path / ".purrpic.ini")
|
||||
odir, thumbdir = generateDir(path)
|
||||
for img in meta["files"]:
|
||||
|
|
@ -213,9 +401,21 @@ def processDir(path):
|
|||
except:
|
||||
pass
|
||||
|
||||
|
||||
def writeIndex(odir, meta):
|
||||
html = HTML()
|
||||
html.writeIndex(odir, meta)
|
||||
html.writeIndex(odir, meta)
|
||||
|
||||
|
||||
def writeMain(metadata):
|
||||
html = HTML()
|
||||
html.writeMain(metadata)
|
||||
|
||||
|
||||
def writeDetail(odir):
|
||||
html = HTML()
|
||||
html.writeDetail(odir)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
|
|
@ -235,26 +435,19 @@ if __name__ == "__main__":
|
|||
type=lambda p: Path(p).resvolve(),
|
||||
help="",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--start",
|
||||
"-s",
|
||||
type=str,
|
||||
help="",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
breakpoint()
|
||||
if args.outpath:
|
||||
BUILD_DIR = args.outpath
|
||||
|
||||
metadata = {}
|
||||
for d in args.inpath.iterdir():
|
||||
if d.is_dir() and d.name not in exclude:
|
||||
# processDir(d.name)
|
||||
try:
|
||||
odir, thumbdir, meta = processDir(d)
|
||||
odir, _, meta = processDir(d)
|
||||
metadata[d.name] = meta
|
||||
writeIndex(odir, meta)
|
||||
writeDetail(odir)
|
||||
except:
|
||||
next
|
||||
# html = HTML()
|
||||
# html.writeMain(metadata)
|
||||
continue
|
||||
writeMain(metadata)
|
||||
|
|
|
|||
Loading…
Reference in New Issue