File: /volume1/@appstore/SynologyPhotos/usr/plugin/reverse_geocoding.py
#!/usr/bin/env python3
# Copyright (c) 2000-2020 Synology Inc. All rights reserved.
import argparse
import json
import os
import ssl
import sys
import urllib.request, urllib.error, urllib.parse
MAINLAND_CHINA_MAPPING = {
"NONE": "中国大陆",
"zh-CN": "中国大陆",
"zh-TW": "中國大陸",
}
class BadParameterException(Exception):
pass
class ReverseGeocodingRequest:
"""
A class to send reverse geocoding request and read the response in
structural format
"""
GET_REQUEST_FORMAT = "{0:s}?{1:s}"
ENVIRON_KEY_GEOCODING_SERVER_URL = "SYNO_PHOTOS_GEOCODING_SERVER_URL"
ENVIRON_KEY_API_KEY = "SYNO_PHOTOS_API_KEY"
ENVIRON_KEY_USER_AGENT = "SYNO_PHOTOS_USER_AGENT"
def __init__(self):
self.json_response = {}
def sendGetRequest(self, para):
self.getVariable()
para["syno_serial_number"] = "TEMP"
# remove after CST removes the check of serial number
request = urllib.request.Request(
ReverseGeocodingRequest.GET_REQUEST_FORMAT.format(
self.server_url, urllib.parse.urlencode(para)
)
)
request.add_header("User-Agent", self.user_agent)
request.add_header("Authorization", "Key " + self.api_key)
request.add_header("Accept", "application/json")
request.add_header("Accept-Charset", "UTF-8")
ctx = ssl.create_default_context(cafile="/etc/ssl/certs/ca-certificates.crt")
return urllib.request.urlopen(request, context=ctx)
def getVariable(self):
try:
self.server_url = os.environ.pop(
ReverseGeocodingRequest.ENVIRON_KEY_GEOCODING_SERVER_URL
)
self.api_key = os.environ.pop(ReverseGeocodingRequest.ENVIRON_KEY_API_KEY)
self.user_agent = os.environ.pop(
ReverseGeocodingRequest.ENVIRON_KEY_USER_AGENT
)
except KeyError:
raise BadParameterException("bad parameter")
if not self.server_url or not self.api_key or not self.user_agent:
raise BadParameterException("illegal parameter")
def send(self, lat, lon):
para = {"lat": lat, "lon": lon}
response = self.sendGetRequest(para)
self.json_response = json.load(response)
return 0
def json(self):
return self.json_response
def parseArgument():
parser = argparse.ArgumentParser(
description="A tool to reverse geocoding to human-readable address"
)
parser.add_argument(
"-lat",
"--latitude",
type=float,
dest="lat",
required=True,
help="the latitude of the coordinates",
)
parser.add_argument(
"-lon",
"--longitude",
type=float,
dest="lon",
required=True,
help="the longitude of the coordinates",
)
return parser.parse_args()
def get_local_country_and_state(response):
local_address = response.get("address", {}).get("NONE", {})
return [local_address.get("country", ""), local_address.get("state", "")]
def is_country_china(country):
return country == "中国"
def is_state_hk_or_mo(state):
return state == "香港 Hong Kong" or state == "澳門 Macau"
def is_country_denmark(country):
return country == "Danmark"
def update_state_to_country(response):
addr = response.get("address")
for key in addr:
item = addr[key]
if "country" in item:
if "state" in item:
item["country"] = item["state"]
del item["state"]
else:
del item["country"]
def update_to_mainland_china(response):
addr = response.get("address")
for key in addr:
item = addr[key]
if "country" in item:
country = item["country"]
if key in MAINLAND_CHINA_MAPPING:
item["country"] = MAINLAND_CHINA_MAPPING.get(key)
def remove_suburb(response):
addr = response.get("address")
for key in addr:
item = addr[key]
if "suburb" in item:
del item["suburb"]
def update_response(response):
country, state = get_local_country_and_state(response)
if is_country_china(country):
if is_state_hk_or_mo(state):
update_state_to_country(response)
else:
update_to_mainland_china(response)
if is_country_denmark(country):
remove_suburb(response)
def main():
args = parseArgument()
request = ReverseGeocodingRequest()
try:
request.send(args.lat, args.lon)
response = request.json()
if "error" in response:
sys.stderr.write("Failed to reverse geocoding\n")
sys.stderr.write("Response: {0}\n".format(response["error"]))
exit(4)
update_response(response)
except urllib.error.HTTPError as e:
sys.stderr.write("The server couldn't fulfill the request.\n")
sys.stderr.write("Error code: {0}\n".format(e.code))
sys.stderr.write("Full response: {0}\n".format(e.read()))
exit(1)
except urllib.error.URLError as e:
sys.stderr.write("We failed to reach a server.\n")
sys.stderr.write("Reason: {0}\n".format(e.reason))
exit(2)
except ValueError:
sys.stderr.write("Failed to decode response as JSON\n")
sys.stderr.write("Response: {0}\n".format(response))
exit(3)
except BadParameterException as e:
sys.stderr.write("Bad parameter\n")
sys.stderr.write("Message: {0}\n".format(e.message))
exit(5)
print(json.dumps(response, indent=4))
exit(0)
if __name__ == "__main__":
main()