mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-01 17:03:38 +00:00
683 lines
13 KiB
Python
683 lines
13 KiB
Python
# Support for the GeoRSS format
|
|
# Copyright 2010-2023 Kurt McKee <contactme@kurtmckee.org>
|
|
# Copyright 2002-2008 Mark Pilgrim
|
|
# All rights reserved.
|
|
#
|
|
# This file is a part of feedparser.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are met:
|
|
#
|
|
# * Redistributions of source code must retain the above copyright notice,
|
|
# this list of conditions and the following disclaimer.
|
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
# this list of conditions and the following disclaimer in the documentation
|
|
# and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
from ..util import FeedParserDict
|
|
|
|
|
|
class Namespace:
|
|
supported_namespaces = {
|
|
"http://www.w3.org/2003/01/geo/wgs84_pos#": "geo",
|
|
"http://www.georss.org/georss": "georss",
|
|
"http://www.opengis.net/gml": "gml",
|
|
}
|
|
|
|
def __init__(self):
|
|
self.ingeometry = 0
|
|
super().__init__()
|
|
|
|
def _start_georssgeom(self, attrs_d):
|
|
self.push("geometry", 0)
|
|
context = self._get_context()
|
|
context["where"] = FeedParserDict()
|
|
|
|
_start_georss_point = _start_georssgeom
|
|
_start_georss_line = _start_georssgeom
|
|
_start_georss_polygon = _start_georssgeom
|
|
_start_georss_box = _start_georssgeom
|
|
|
|
def _save_where(self, geometry):
|
|
context = self._get_context()
|
|
context["where"].update(geometry)
|
|
|
|
def _end_georss_point(self):
|
|
geometry = _parse_georss_point(self.pop("geometry"))
|
|
if geometry:
|
|
self._save_where(geometry)
|
|
|
|
def _end_georss_line(self):
|
|
geometry = _parse_georss_line(self.pop("geometry"))
|
|
if geometry:
|
|
self._save_where(geometry)
|
|
|
|
def _end_georss_polygon(self):
|
|
this = self.pop("geometry")
|
|
geometry = _parse_georss_polygon(this)
|
|
if geometry:
|
|
self._save_where(geometry)
|
|
|
|
def _end_georss_box(self):
|
|
geometry = _parse_georss_box(self.pop("geometry"))
|
|
if geometry:
|
|
self._save_where(geometry)
|
|
|
|
def _start_where(self, attrs_d):
|
|
self.push("where", 0)
|
|
context = self._get_context()
|
|
context["where"] = FeedParserDict()
|
|
|
|
_start_georss_where = _start_where
|
|
|
|
def _parse_srs_attrs(self, attrs_d):
|
|
srs_name = attrs_d.get("srsname")
|
|
try:
|
|
srs_dimension = int(attrs_d.get("srsdimension", "2"))
|
|
except ValueError:
|
|
srs_dimension = 2
|
|
context = self._get_context()
|
|
if "where" not in context:
|
|
context["where"] = {}
|
|
context["where"]["srsName"] = srs_name
|
|
context["where"]["srsDimension"] = srs_dimension
|
|
|
|
def _start_gml_point(self, attrs_d):
|
|
self._parse_srs_attrs(attrs_d)
|
|
self.ingeometry = 1
|
|
self.push("geometry", 0)
|
|
|
|
def _start_gml_linestring(self, attrs_d):
|
|
self._parse_srs_attrs(attrs_d)
|
|
self.ingeometry = "linestring"
|
|
self.push("geometry", 0)
|
|
|
|
def _start_gml_polygon(self, attrs_d):
|
|
self._parse_srs_attrs(attrs_d)
|
|
self.push("geometry", 0)
|
|
|
|
def _start_gml_exterior(self, attrs_d):
|
|
self.push("geometry", 0)
|
|
|
|
def _start_gml_linearring(self, attrs_d):
|
|
self.ingeometry = "polygon"
|
|
self.push("geometry", 0)
|
|
|
|
def _start_gml_pos(self, attrs_d):
|
|
self.push("pos", 0)
|
|
|
|
def _end_gml_pos(self):
|
|
this = self.pop("pos")
|
|
context = self._get_context()
|
|
srs_name = context["where"].get("srsName")
|
|
srs_dimension = context["where"].get("srsDimension", 2)
|
|
swap = True
|
|
if srs_name and "EPSG" in srs_name:
|
|
epsg = int(srs_name.split(":")[-1])
|
|
swap = bool(epsg in _geogCS)
|
|
geometry = _parse_georss_point(this, swap=swap, dims=srs_dimension)
|
|
if geometry:
|
|
self._save_where(geometry)
|
|
|
|
def _start_gml_poslist(self, attrs_d):
|
|
self.push("pos", 0)
|
|
|
|
def _end_gml_poslist(self):
|
|
this = self.pop("pos")
|
|
context = self._get_context()
|
|
srs_name = context["where"].get("srsName")
|
|
srs_dimension = context["where"].get("srsDimension", 2)
|
|
swap = True
|
|
if srs_name and "EPSG" in srs_name:
|
|
epsg = int(srs_name.split(":")[-1])
|
|
swap = bool(epsg in _geogCS)
|
|
geometry = _parse_poslist(this, self.ingeometry, swap=swap, dims=srs_dimension)
|
|
if geometry:
|
|
self._save_where(geometry)
|
|
|
|
def _end_geom(self):
|
|
self.ingeometry = 0
|
|
self.pop("geometry")
|
|
|
|
_end_gml_point = _end_geom
|
|
_end_gml_linestring = _end_geom
|
|
_end_gml_linearring = _end_geom
|
|
_end_gml_exterior = _end_geom
|
|
_end_gml_polygon = _end_geom
|
|
|
|
def _end_where(self):
|
|
self.pop("where")
|
|
|
|
_end_georss_where = _end_where
|
|
|
|
|
|
# GeoRSS geometry parsers. Each return a dict with 'type' and 'coordinates'
|
|
# items, or None in the case of a parsing error.
|
|
|
|
|
|
def _parse_poslist(value, geom_type, swap=True, dims=2):
|
|
if geom_type == "linestring":
|
|
return _parse_georss_line(value, swap, dims)
|
|
elif geom_type == "polygon":
|
|
ring = _parse_georss_line(value, swap, dims)
|
|
return {"type": "Polygon", "coordinates": (ring["coordinates"],)}
|
|
else:
|
|
return None
|
|
|
|
|
|
def _gen_georss_coords(value, swap=True, dims=2):
|
|
# A generator of (lon, lat) pairs from a string of encoded GeoRSS
|
|
# coordinates. Converts to floats and swaps order.
|
|
latlons = (float(ll) for ll in value.replace(",", " ").split())
|
|
while True:
|
|
try:
|
|
t = [next(latlons), next(latlons)][:: swap and -1 or 1]
|
|
if dims == 3:
|
|
t.append(next(latlons))
|
|
yield tuple(t)
|
|
except StopIteration:
|
|
return
|
|
|
|
|
|
def _parse_georss_point(value, swap=True, dims=2):
|
|
# A point contains a single latitude-longitude pair, separated by
|
|
# whitespace. We'll also handle comma separators.
|
|
try:
|
|
coords = list(_gen_georss_coords(value, swap, dims))
|
|
return {"type": "Point", "coordinates": coords[0]}
|
|
except (IndexError, ValueError):
|
|
return None
|
|
|
|
|
|
def _parse_georss_line(value, swap=True, dims=2):
|
|
# A line contains a space separated list of latitude-longitude pairs in
|
|
# WGS84 coordinate reference system, with each pair separated by
|
|
# whitespace. There must be at least two pairs.
|
|
try:
|
|
coords = list(_gen_georss_coords(value, swap, dims))
|
|
return {"type": "LineString", "coordinates": coords}
|
|
except (IndexError, ValueError):
|
|
return None
|
|
|
|
|
|
def _parse_georss_polygon(value, swap=True, dims=2):
|
|
# A polygon contains a space separated list of latitude-longitude pairs,
|
|
# with each pair separated by whitespace. There must be at least four
|
|
# pairs, with the last being identical to the first (so a polygon has a
|
|
# minimum of three actual points).
|
|
try:
|
|
ring = list(_gen_georss_coords(value, swap, dims))
|
|
except (IndexError, ValueError):
|
|
return None
|
|
if len(ring) < 4:
|
|
return None
|
|
return {"type": "Polygon", "coordinates": (ring,)}
|
|
|
|
|
|
def _parse_georss_box(value, swap=True, dims=2):
|
|
# A bounding box is a rectangular region, often used to define the extents
|
|
# of a map or a rough area of interest. A box contains two space separate
|
|
# latitude-longitude pairs, with each pair separated by whitespace. The
|
|
# first pair is the lower corner, the second is the upper corner.
|
|
try:
|
|
coords = list(_gen_georss_coords(value, swap, dims))
|
|
return {"type": "Box", "coordinates": tuple(coords)}
|
|
except (IndexError, ValueError):
|
|
return None
|
|
|
|
|
|
# The list of EPSG codes for geographic (latitude/longitude) coordinate
|
|
# systems to support decoding of GeoRSS GML profiles.
|
|
_geogCS = [
|
|
3819,
|
|
3821,
|
|
3824,
|
|
3889,
|
|
3906,
|
|
4001,
|
|
4002,
|
|
4003,
|
|
4004,
|
|
4005,
|
|
4006,
|
|
4007,
|
|
4008,
|
|
4009,
|
|
4010,
|
|
4011,
|
|
4012,
|
|
4013,
|
|
4014,
|
|
4015,
|
|
4016,
|
|
4018,
|
|
4019,
|
|
4020,
|
|
4021,
|
|
4022,
|
|
4023,
|
|
4024,
|
|
4025,
|
|
4027,
|
|
4028,
|
|
4029,
|
|
4030,
|
|
4031,
|
|
4032,
|
|
4033,
|
|
4034,
|
|
4035,
|
|
4036,
|
|
4041,
|
|
4042,
|
|
4043,
|
|
4044,
|
|
4045,
|
|
4046,
|
|
4047,
|
|
4052,
|
|
4053,
|
|
4054,
|
|
4055,
|
|
4075,
|
|
4081,
|
|
4120,
|
|
4121,
|
|
4122,
|
|
4123,
|
|
4124,
|
|
4125,
|
|
4126,
|
|
4127,
|
|
4128,
|
|
4129,
|
|
4130,
|
|
4131,
|
|
4132,
|
|
4133,
|
|
4134,
|
|
4135,
|
|
4136,
|
|
4137,
|
|
4138,
|
|
4139,
|
|
4140,
|
|
4141,
|
|
4142,
|
|
4143,
|
|
4144,
|
|
4145,
|
|
4146,
|
|
4147,
|
|
4148,
|
|
4149,
|
|
4150,
|
|
4151,
|
|
4152,
|
|
4153,
|
|
4154,
|
|
4155,
|
|
4156,
|
|
4157,
|
|
4158,
|
|
4159,
|
|
4160,
|
|
4161,
|
|
4162,
|
|
4163,
|
|
4164,
|
|
4165,
|
|
4166,
|
|
4167,
|
|
4168,
|
|
4169,
|
|
4170,
|
|
4171,
|
|
4172,
|
|
4173,
|
|
4174,
|
|
4175,
|
|
4176,
|
|
4178,
|
|
4179,
|
|
4180,
|
|
4181,
|
|
4182,
|
|
4183,
|
|
4184,
|
|
4185,
|
|
4188,
|
|
4189,
|
|
4190,
|
|
4191,
|
|
4192,
|
|
4193,
|
|
4194,
|
|
4195,
|
|
4196,
|
|
4197,
|
|
4198,
|
|
4199,
|
|
4200,
|
|
4201,
|
|
4202,
|
|
4203,
|
|
4204,
|
|
4205,
|
|
4206,
|
|
4207,
|
|
4208,
|
|
4209,
|
|
4210,
|
|
4211,
|
|
4212,
|
|
4213,
|
|
4214,
|
|
4215,
|
|
4216,
|
|
4218,
|
|
4219,
|
|
4220,
|
|
4221,
|
|
4222,
|
|
4223,
|
|
4224,
|
|
4225,
|
|
4226,
|
|
4227,
|
|
4228,
|
|
4229,
|
|
4230,
|
|
4231,
|
|
4232,
|
|
4233,
|
|
4234,
|
|
4235,
|
|
4236,
|
|
4237,
|
|
4238,
|
|
4239,
|
|
4240,
|
|
4241,
|
|
4242,
|
|
4243,
|
|
4244,
|
|
4245,
|
|
4246,
|
|
4247,
|
|
4248,
|
|
4249,
|
|
4250,
|
|
4251,
|
|
4252,
|
|
4253,
|
|
4254,
|
|
4255,
|
|
4256,
|
|
4257,
|
|
4258,
|
|
4259,
|
|
4260,
|
|
4261,
|
|
4262,
|
|
4263,
|
|
4264,
|
|
4265,
|
|
4266,
|
|
4267,
|
|
4268,
|
|
4269,
|
|
4270,
|
|
4271,
|
|
4272,
|
|
4273,
|
|
4274,
|
|
4275,
|
|
4276,
|
|
4277,
|
|
4278,
|
|
4279,
|
|
4280,
|
|
4281,
|
|
4282,
|
|
4283,
|
|
4284,
|
|
4285,
|
|
4286,
|
|
4287,
|
|
4288,
|
|
4289,
|
|
4291,
|
|
4292,
|
|
4293,
|
|
4294,
|
|
4295,
|
|
4296,
|
|
4297,
|
|
4298,
|
|
4299,
|
|
4300,
|
|
4301,
|
|
4302,
|
|
4303,
|
|
4304,
|
|
4306,
|
|
4307,
|
|
4308,
|
|
4309,
|
|
4310,
|
|
4311,
|
|
4312,
|
|
4313,
|
|
4314,
|
|
4315,
|
|
4316,
|
|
4317,
|
|
4318,
|
|
4319,
|
|
4322,
|
|
4324,
|
|
4326,
|
|
4463,
|
|
4470,
|
|
4475,
|
|
4483,
|
|
4490,
|
|
4555,
|
|
4558,
|
|
4600,
|
|
4601,
|
|
4602,
|
|
4603,
|
|
4604,
|
|
4605,
|
|
4606,
|
|
4607,
|
|
4608,
|
|
4609,
|
|
4610,
|
|
4611,
|
|
4612,
|
|
4613,
|
|
4614,
|
|
4615,
|
|
4616,
|
|
4617,
|
|
4618,
|
|
4619,
|
|
4620,
|
|
4621,
|
|
4622,
|
|
4623,
|
|
4624,
|
|
4625,
|
|
4626,
|
|
4627,
|
|
4628,
|
|
4629,
|
|
4630,
|
|
4631,
|
|
4632,
|
|
4633,
|
|
4634,
|
|
4635,
|
|
4636,
|
|
4637,
|
|
4638,
|
|
4639,
|
|
4640,
|
|
4641,
|
|
4642,
|
|
4643,
|
|
4644,
|
|
4645,
|
|
4646,
|
|
4657,
|
|
4658,
|
|
4659,
|
|
4660,
|
|
4661,
|
|
4662,
|
|
4663,
|
|
4664,
|
|
4665,
|
|
4666,
|
|
4667,
|
|
4668,
|
|
4669,
|
|
4670,
|
|
4671,
|
|
4672,
|
|
4673,
|
|
4674,
|
|
4675,
|
|
4676,
|
|
4677,
|
|
4678,
|
|
4679,
|
|
4680,
|
|
4681,
|
|
4682,
|
|
4683,
|
|
4684,
|
|
4685,
|
|
4686,
|
|
4687,
|
|
4688,
|
|
4689,
|
|
4690,
|
|
4691,
|
|
4692,
|
|
4693,
|
|
4694,
|
|
4695,
|
|
4696,
|
|
4697,
|
|
4698,
|
|
4699,
|
|
4700,
|
|
4701,
|
|
4702,
|
|
4703,
|
|
4704,
|
|
4705,
|
|
4706,
|
|
4707,
|
|
4708,
|
|
4709,
|
|
4710,
|
|
4711,
|
|
4712,
|
|
4713,
|
|
4714,
|
|
4715,
|
|
4716,
|
|
4717,
|
|
4718,
|
|
4719,
|
|
4720,
|
|
4721,
|
|
4722,
|
|
4723,
|
|
4724,
|
|
4725,
|
|
4726,
|
|
4727,
|
|
4728,
|
|
4729,
|
|
4730,
|
|
4731,
|
|
4732,
|
|
4733,
|
|
4734,
|
|
4735,
|
|
4736,
|
|
4737,
|
|
4738,
|
|
4739,
|
|
4740,
|
|
4741,
|
|
4742,
|
|
4743,
|
|
4744,
|
|
4745,
|
|
4746,
|
|
4747,
|
|
4748,
|
|
4749,
|
|
4750,
|
|
4751,
|
|
4752,
|
|
4753,
|
|
4754,
|
|
4755,
|
|
4756,
|
|
4757,
|
|
4758,
|
|
4759,
|
|
4760,
|
|
4761,
|
|
4762,
|
|
4763,
|
|
4764,
|
|
4765,
|
|
4801,
|
|
4802,
|
|
4803,
|
|
4804,
|
|
4805,
|
|
4806,
|
|
4807,
|
|
4808,
|
|
4809,
|
|
4810,
|
|
4811,
|
|
4813,
|
|
4814,
|
|
4815,
|
|
4816,
|
|
4817,
|
|
4818,
|
|
4819,
|
|
4820,
|
|
4821,
|
|
4823,
|
|
4824,
|
|
4901,
|
|
4902,
|
|
4903,
|
|
4904,
|
|
4979,
|
|
]
|