Update trackbert version to 0.2.3, add tabulate to dependencies, and refactor main function arguments in __main__.py. Also, introduce HTTPRequest class for handling HTTP requests.
This commit is contained in:
parent
751a7ad9e5
commit
ad44b1e1cc
12 changed files with 197 additions and 52 deletions
10
README.md
10
README.md
|
@ -50,7 +50,15 @@ tracking providers.
|
||||||
|
|
||||||
To add a new shipment, run `trackbert --tracking-number <tracking-number> --carrier <carrier-id>`. Find the required carrier ID in the [KeyDelivery API management](https://app.kd100.com/api-management).
|
To add a new shipment, run `trackbert --tracking-number <tracking-number> --carrier <carrier-id>`. Find the required carrier ID in the [KeyDelivery API management](https://app.kd100.com/api-management).
|
||||||
|
|
||||||
To run the main loop, run `trackbert`. This will check the status of all shipments every 5 minutes, and print the status to the console. If the status of a shipment changes, you will get a desktop notification.
|
To run the main loop, run `trackbert`. This will check the status of all shipments every minute, and print the status to the console. If the status of a shipment changes, you will get a desktop notification.
|
||||||
|
|
||||||
|
## Caveats
|
||||||
|
|
||||||
|
### DHL
|
||||||
|
|
||||||
|
By default, the script queries for updates for each active shipment once per minute. However, if you have the DHL API enabled, you will quickly run into the rate limit. Therefore, the script will only query for updates once per hour (`if minute == 0`). For the default 250 requests per day limit, this means that you can only track up to 10 shipments simultaneously.
|
||||||
|
|
||||||
|
You may request a higher rate limit from DHL. See the [DHL Developer Portal](https://developer.dhl.com/) for details. If you do this, you can set `ratelimited = 0` (note that 0/1 is a boolean value in the config file) in your `config.ini` to disable the rate limit.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "trackbert"
|
name = "trackbert"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
authors = [
|
authors = [
|
||||||
{ name="Kumi Mitterer", email="trackbert@kumi.email" },
|
{ name="Kumi Mitterer", email="trackbert@kumi.email" },
|
||||||
]
|
]
|
||||||
|
@ -26,6 +26,7 @@ dependencies = [
|
||||||
"sqlalchemy",
|
"sqlalchemy",
|
||||||
"alembic",
|
"alembic",
|
||||||
"python-dateutil",
|
"python-dateutil",
|
||||||
|
"tabulate",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from pykeydelivery import KeyDelivery
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tabulate import tabulate
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
import subprocess
|
import subprocess
|
||||||
|
@ -18,9 +19,27 @@ def main():
|
||||||
|
|
||||||
# Arguments related to the tracker
|
# Arguments related to the tracker
|
||||||
|
|
||||||
parser.add_argument("--tracking-number", "-n", type=str, required=False)
|
parser.add_argument(
|
||||||
parser.add_argument("--carrier", "-c", type=str, required=False)
|
"--tracking-number",
|
||||||
parser.add_argument("--description", "-d", type=str, required=False)
|
"-n",
|
||||||
|
type=str,
|
||||||
|
required=False,
|
||||||
|
help="Tracking number of the shipment",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--carrier",
|
||||||
|
"-c",
|
||||||
|
type=str,
|
||||||
|
required=False,
|
||||||
|
help="Carrier code of the shipment – use --list-carriers to list all supported carriers",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--description",
|
||||||
|
"-d",
|
||||||
|
type=str,
|
||||||
|
required=False,
|
||||||
|
help="Optional description for the shipment",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--update",
|
"--update",
|
||||||
"-u",
|
"-u",
|
||||||
|
@ -36,10 +55,29 @@ def main():
|
||||||
help="Disable existing shipment",
|
help="Disable existing shipment",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--list-carriers",
|
||||||
|
"-l",
|
||||||
|
action="store_true",
|
||||||
|
required=False,
|
||||||
|
help="List supported carriers",
|
||||||
|
)
|
||||||
|
|
||||||
# Arguments related to the config file
|
# Arguments related to the config file
|
||||||
|
|
||||||
parser.add_argument("--generate-config", action="store_true", required=False)
|
parser.add_argument(
|
||||||
parser.add_argument("--config-file", "-C", type=str, required=False)
|
"--generate-config",
|
||||||
|
action="store_true",
|
||||||
|
required=False,
|
||||||
|
help="Generate new config file",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--config-file",
|
||||||
|
"-C",
|
||||||
|
type=str,
|
||||||
|
required=False,
|
||||||
|
help="Path to the config file to use or generate (default: config.ini)",
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
@ -60,26 +98,52 @@ def main():
|
||||||
|
|
||||||
# Load config file
|
# Load config file
|
||||||
|
|
||||||
if not config_file.exists():
|
if args.config_file and not config_file.exists():
|
||||||
print(f"Config file {config_file} does not exist. Use -g to generate it.")
|
print(f"Config file {config_file} does not exist. Use -g to generate it.")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
tracker = Tracker(config_file)
|
||||||
|
|
||||||
db = Database("sqlite:///trackbert.db")
|
# List carriers if requested
|
||||||
|
|
||||||
|
if args.list_carriers:
|
||||||
|
print("Supported carriers:\n")
|
||||||
|
|
||||||
|
carriers = set(
|
||||||
|
[
|
||||||
|
(api[0], (api[3] if len(api) > 3 else None))
|
||||||
|
for api in tracker.apis
|
||||||
|
if not any(
|
||||||
|
[
|
||||||
|
others[1] > api[1]
|
||||||
|
for others in filter(lambda x: x[0] == api[0], tracker.apis)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
print(tabulate(sorted(carriers, key=lambda x: x[0]), headers=["Code", "Name"]))
|
||||||
|
exit(0)
|
||||||
|
|
||||||
if args.tracking_number is not None and args.carrier is not None:
|
if args.tracking_number is not None and args.carrier is not None:
|
||||||
if shipment := db.get_shipment(args.tracking_number) and not args.update:
|
if (
|
||||||
|
shipment := tracker.db.get_shipment(args.tracking_number)
|
||||||
|
and not args.update
|
||||||
|
):
|
||||||
print(f"Shipment {args.tracking_number} already exists. Use -u to update.")
|
print(f"Shipment {args.tracking_number} already exists. Use -u to update.")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
if shipment:
|
if shipment:
|
||||||
db.update_shipment(args.tracking_number, args.carrier, args.description)
|
tracker.db.update_shipment(
|
||||||
|
args.tracking_number, args.carrier, args.description
|
||||||
|
)
|
||||||
print(
|
print(
|
||||||
f"Updated shipment for {args.tracking_number} with carrier {args.carrier}"
|
f"Updated shipment for {args.tracking_number} with carrier {args.carrier}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
db.create_shipment(args.tracking_number, args.carrier, args.description)
|
tracker.db.create_shipment(
|
||||||
|
args.tracking_number, args.carrier, args.description
|
||||||
|
)
|
||||||
print(
|
print(
|
||||||
f"Created shipment for {args.tracking_number} with carrier {args.carrier}"
|
f"Created shipment for {args.tracking_number} with carrier {args.carrier}"
|
||||||
)
|
)
|
||||||
|
@ -88,17 +152,16 @@ def main():
|
||||||
|
|
||||||
if args.tracking_number is not None:
|
if args.tracking_number is not None:
|
||||||
if args.disable:
|
if args.disable:
|
||||||
if not db.get_shipment(args.tracking_number):
|
if not tracker.db.get_shipment(args.tracking_number):
|
||||||
print(f"Shipment {args.tracking_number} does not exist.")
|
print(f"Shipment {args.tracking_number} does not exist.")
|
||||||
exit(1)
|
exit(1)
|
||||||
db.disable_shipment(args.tracking_number)
|
tracker.db.disable_shipment(args.tracking_number)
|
||||||
print(f"Disabled shipment for {args.tracking_number}")
|
print(f"Disabled shipment for {args.tracking_number}")
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
print("You must specify a carrier with -c")
|
print("You must specify a carrier with -c")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
tracker = Tracker()
|
|
||||||
asyncio.run(tracker.start_async())
|
asyncio.run(tracker.start_async())
|
||||||
|
|
||||||
|
|
||||||
|
|
21
src/trackbert/classes/http.py
Normal file
21
src/trackbert/classes/http.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
from urllib.request import Request, urlopen
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPRequest(Request):
|
||||||
|
USER_AGENT = "Mozilla/5.0 (compatible; Trackbert/dev; +https://kumig.it/kumitterer/trackbert)"
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.add_header("User-Agent", self.USER_AGENT)
|
||||||
|
|
||||||
|
def execute(self, load_json: bool = True, *args, **kwargs):
|
||||||
|
response = urlopen(self, *args, **kwargs).read()
|
||||||
|
if load_json:
|
||||||
|
response = json.loads(response)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def add_json_payload(self, payload: dict):
|
||||||
|
self.add_header("Content-Type", "application/json")
|
||||||
|
self.data = json.dumps(payload).encode("utf-8")
|
|
@ -17,13 +17,15 @@ class Tracker:
|
||||||
loop_interval = 60
|
loop_interval = 60
|
||||||
loop_timeout = 30
|
loop_timeout = 30
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, config: Optional[PathLike] = None):
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
format="%(asctime)s %(levelname)s: %(message)s",
|
format="%(asctime)s %(levelname)s: %(message)s",
|
||||||
level=logging.DEBUG,
|
level=logging.WARN,
|
||||||
datefmt="%Y-%m-%d %H:%M:%S",
|
datefmt="%Y-%m-%d %H:%M:%S",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self._pre_start(config)
|
||||||
|
|
||||||
self.find_apis()
|
self.find_apis()
|
||||||
|
|
||||||
def find_apis(self):
|
def find_apis(self):
|
||||||
|
@ -37,24 +39,32 @@ class Tracker:
|
||||||
|
|
||||||
logging.debug(f"Found API {api.stem}")
|
logging.debug(f"Found API {api.stem}")
|
||||||
|
|
||||||
module = importlib.import_module(f"trackbert.trackers.{api.stem}")
|
try:
|
||||||
|
module = importlib.import_module(f"trackbert.trackers.{api.stem}")
|
||||||
|
except:
|
||||||
|
logging.error(f"Error loading class {api.stem}")
|
||||||
|
|
||||||
if "tracker" in module.__dict__:
|
if "tracker" in module.__dict__:
|
||||||
tracker = module.tracker
|
tracker = module.tracker
|
||||||
logging.debug(f"Found tracker {api.stem}")
|
logging.debug(f"Found tracker {api.stem}")
|
||||||
try:
|
try:
|
||||||
api = tracker()
|
api = tracker(config=self.config_path)
|
||||||
carriers = api.supported_carriers()
|
carriers = api.supported_carriers()
|
||||||
|
|
||||||
for carrier, priority in carriers:
|
for carrier in carriers:
|
||||||
self.apis.append((carrier, priority, api))
|
self.apis.append((carrier[0], carrier[1], api, (carrier[2] if len(carrier) > 2 else None)))
|
||||||
except:
|
except Exception as e:
|
||||||
logging.exception(f"Error loading tracker {api.stem}")
|
logging.error(f"Error loading tracker {api.__class__.__name__}: {e}")
|
||||||
|
|
||||||
def query_api(self, tracking_number: str, carrier: str) -> list:
|
def query_api(self, tracking_number: str, carrier: str) -> list:
|
||||||
logging.debug(f"Querying API for {tracking_number} with carrier {carrier}")
|
logging.debug(f"Querying API for {tracking_number} with carrier {carrier}")
|
||||||
|
|
||||||
for api_carrier, _, api in sorted(self.apis, key=lambda x: x[1], reverse=True):
|
for api_entry in sorted(self.apis, key=lambda x: x[1], reverse=True):
|
||||||
|
api_carrier = api_entry[0]
|
||||||
|
priority = api_entry[1]
|
||||||
|
api = api_entry[2]
|
||||||
|
name = api_entry[3] if len(api_entry) > 3 else None
|
||||||
|
|
||||||
if api_carrier == "*" or api_carrier == carrier:
|
if api_carrier == "*" or api_carrier == carrier:
|
||||||
logging.debug(
|
logging.debug(
|
||||||
f"Using API {api.__class__.__name__} for {tracking_number} with carrier {carrier}"
|
f"Using API {api.__class__.__name__} for {tracking_number} with carrier {carrier}"
|
||||||
|
@ -177,19 +187,28 @@ class Tracker:
|
||||||
await asyncio.sleep(self.loop_interval)
|
await asyncio.sleep(self.loop_interval)
|
||||||
|
|
||||||
def _pre_start(self, config: Optional[PathLike] = None):
|
def _pre_start(self, config: Optional[PathLike] = None):
|
||||||
|
self.config_path = config
|
||||||
|
|
||||||
parser = ConfigParser()
|
parser = ConfigParser()
|
||||||
parser.read(config or [])
|
parser.read(config or [])
|
||||||
|
|
||||||
self.database_uri = parser.get("Trackbert", "database", fallback="sqlite:///trackbert.db")
|
self.debug = parser.getboolean("Trackbert", "debug", fallback=False)
|
||||||
|
|
||||||
|
if self.debug:
|
||||||
|
logger = logging.getLogger()
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
self.database_uri = parser.get(
|
||||||
|
"Trackbert", "database", fallback="sqlite:///trackbert.db"
|
||||||
|
)
|
||||||
self.db = Database(self.database_uri)
|
self.db = Database(self.database_uri)
|
||||||
|
|
||||||
self.loop_interval = parser.getint("Trackbert", "interval", fallback=60)
|
self.loop_interval = parser.getint("Trackbert", "interval", fallback=60)
|
||||||
self.notify("Trackbert", "Starting up")
|
|
||||||
|
|
||||||
def start(self, config: Optional[PathLike] = None):
|
def start(self, config: Optional[PathLike] = None):
|
||||||
self._pre_start(config)
|
self.notify("Trackbert", "Starting up")
|
||||||
self.start_loop()
|
self.start_loop()
|
||||||
|
|
||||||
async def start_async(self, config: Optional[PathLike] = None):
|
async def start_async(self, config: Optional[PathLike] = None):
|
||||||
self._pre_start(config)
|
self.notify("Trackbert", "Starting up")
|
||||||
await self.start_loop_async()
|
await self.start_loop_async()
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
[Trackbert]
|
||||||
|
debug = 0
|
||||||
|
|
||||||
[KeyDelivery]
|
[KeyDelivery]
|
||||||
key = api_key
|
key = api_key
|
||||||
secret = api_secret
|
secret = api_secret
|
||||||
|
@ -9,3 +12,4 @@ secret = api_secret
|
||||||
[DHL]
|
[DHL]
|
||||||
key = api_key
|
key = api_key
|
||||||
secret = api_secret
|
secret = api_secret
|
||||||
|
ratelimited = 1
|
|
@ -1,18 +1,22 @@
|
||||||
|
from typing import Optional, Tuple, List, Generator
|
||||||
|
|
||||||
|
from ..classes.database import Event
|
||||||
|
|
||||||
class BaseTracker:
|
class BaseTracker:
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_status(self, tracking_number, carrier):
|
def get_status(self, tracking_number: str, carrier: str) -> Generator[Event, None, None]:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def supported_carriers(self):
|
def supported_carriers(self) -> List[Tuple[str, int, Optional[str]]]:
|
||||||
"""Defines the carriers supported by this tracker.
|
"""Defines the carriers supported by this tracker.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list: List of supported carriers as tuples of (carrier_code, priority),
|
list: List of supported carriers as tuples of (carrier_code, priority,
|
||||||
where priority is an integer. The carrier with the highest priority
|
carrier_name (optional)), where priority is an integer. The carrier
|
||||||
will be used when tracking a shipment. "*" can be used as a wildcard
|
with the highest priority will be used when tracking a shipment.
|
||||||
to match all carriers.
|
"*" can be used as a wildcard to match all carriers.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
NotImplementedError: When this method is not implemented by the subclass.
|
NotImplementedError: When this method is not implemented by the subclass.
|
||||||
|
|
|
@ -7,13 +7,30 @@ from dateutil.parser import parse
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from configparser import ConfigParser
|
||||||
|
|
||||||
|
|
||||||
class DHL(BaseTracker):
|
class DHL(BaseTracker):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.api = DHLAPI.from_config("config.ini")
|
self.api = DHLAPI.from_config(str(kwargs.get("config")))
|
||||||
|
|
||||||
|
config = ConfigParser()
|
||||||
|
config.read(kwargs.get("config"))
|
||||||
|
|
||||||
|
self.ratelimited = config.getboolean("dhl", "ratelimited", fallback=True)
|
||||||
|
|
||||||
def get_status(self, tracking_number, carrier):
|
def get_status(self, tracking_number, carrier):
|
||||||
response = self.api.track(tracking_number)
|
if self.ratelimited:
|
||||||
|
if datetime.now().minute != 0:
|
||||||
|
logging.warn("Skipping DHL API call due to ratelimiting")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = self.api.track(tracking_number)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error getting events for {tracking_number}: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
all_events = response["shipments"][0]["events"]
|
all_events = response["shipments"][0]["events"]
|
||||||
|
@ -23,13 +40,11 @@ class DHL(BaseTracker):
|
||||||
logging.error(f"Error getting events for {tracking_number}: {all_events}")
|
logging.error(f"Error getting events for {tracking_number}: {all_events}")
|
||||||
return
|
return
|
||||||
|
|
||||||
events = sorted(
|
events = sorted(all_events, key=lambda x: x["timestamp"], reverse=True)
|
||||||
all_events, key=lambda x: x["timestamp"], reverse=True
|
|
||||||
)
|
|
||||||
|
|
||||||
for event in events:
|
for event in events:
|
||||||
event_time = parse(event["timestamp"]).strftime("%Y-%m-%d %H:%M:%S")
|
event_time = parse(event["timestamp"]).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
event_locality = f"[{event['location']['address']['addressLocality']}] "
|
event_locality = f"[{event['location']['address']['addressLocality']}] "
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -46,7 +61,7 @@ class DHL(BaseTracker):
|
||||||
|
|
||||||
def supported_carriers(self):
|
def supported_carriers(self):
|
||||||
return [
|
return [
|
||||||
("dhl", 100),
|
("dhl", 100, "DHL"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import logging
|
||||||
|
|
||||||
class FedEx(BaseTracker):
|
class FedEx(BaseTracker):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.api = FedExAPI.from_config("config.ini")
|
self.api = FedExAPI.from_config(str(kwargs.get("config")))
|
||||||
|
|
||||||
def get_status(self, tracking_number, carrier):
|
def get_status(self, tracking_number, carrier):
|
||||||
response = self.api.track_by_tracking_number(tracking_number)
|
response = self.api.track_by_tracking_number(tracking_number)
|
||||||
|
@ -47,7 +47,7 @@ class FedEx(BaseTracker):
|
||||||
|
|
||||||
def supported_carriers(self):
|
def supported_carriers(self):
|
||||||
return [
|
return [
|
||||||
("fedex", 100),
|
("fedex", 100, "FedEx"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ class GLS(BaseTracker):
|
||||||
|
|
||||||
def supported_carriers(self):
|
def supported_carriers(self):
|
||||||
return [
|
return [
|
||||||
("gls", 100),
|
("gls", 100, "GLS"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from .base import BaseTracker
|
from .base import BaseTracker
|
||||||
from ..classes.database import Event
|
from ..classes.database import Event
|
||||||
|
from ..classes.http import HTTPRequest
|
||||||
|
|
||||||
from pykeydelivery import KeyDelivery as KeyDeliveryAPI
|
from pykeydelivery import KeyDelivery as KeyDeliveryAPI
|
||||||
|
|
||||||
|
@ -9,7 +10,7 @@ import logging
|
||||||
|
|
||||||
class KeyDelivery(BaseTracker):
|
class KeyDelivery(BaseTracker):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.api = KeyDeliveryAPI.from_config("config.ini")
|
self.api = KeyDeliveryAPI.from_config(str(kwargs.get("config")))
|
||||||
|
|
||||||
def get_status(self, tracking_number, carrier):
|
def get_status(self, tracking_number, carrier):
|
||||||
all_events = self.api.realtime(carrier, tracking_number)
|
all_events = self.api.realtime(carrier, tracking_number)
|
||||||
|
@ -36,9 +37,18 @@ class KeyDelivery(BaseTracker):
|
||||||
)
|
)
|
||||||
|
|
||||||
def supported_carriers(self):
|
def supported_carriers(self):
|
||||||
return [
|
try:
|
||||||
("*", 1),
|
request = HTTPRequest("https://app.kd100.com/console/utils/kdbm")
|
||||||
]
|
response = request.execute()
|
||||||
|
carriers = [
|
||||||
|
(carrier["code"], 1, carrier["name"])
|
||||||
|
for carrier in response["data"]
|
||||||
|
]
|
||||||
|
return carriers
|
||||||
|
except:
|
||||||
|
return [
|
||||||
|
("*", 1),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
tracker = KeyDelivery
|
tracker = KeyDelivery
|
||||||
|
|
|
@ -30,7 +30,7 @@ class PostAT(BaseTracker):
|
||||||
|
|
||||||
def supported_carriers(self):
|
def supported_carriers(self):
|
||||||
return [
|
return [
|
||||||
("austrian_post", 100),
|
("austrian_post", 100, "Austrian Post"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue