From 0b8fc12b5f35e5770f1207ec6567696a0bee8771 Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 18:05:21 -0500 Subject: [PATCH 01/20] beginning to implement work around to get wait times, should import now #7 --- MouseTools/MouseTools.db | 0 MouseTools/__init__.py | 3 +- MouseTools/auth.py | 5 - MouseTools/database.py | 576 --------------------------------------- 4 files changed, 1 insertion(+), 583 deletions(-) delete mode 100644 MouseTools/MouseTools.db delete mode 100644 MouseTools/database.py diff --git a/MouseTools/MouseTools.db b/MouseTools/MouseTools.db deleted file mode 100644 index e69de29..0000000 diff --git a/MouseTools/__init__.py b/MouseTools/__init__.py index 370a352..194f277 100644 --- a/MouseTools/__init__.py +++ b/MouseTools/__init__.py @@ -6,12 +6,11 @@ from MouseTools.facilities import Facility from MouseTools.pointsofinterest import PointOfInterest from MouseTools.destinations import Destination -from MouseTools.database import DisneyDatabase import MouseTools.ids name = "MouseTools" -__version__ = "2.0.2" +__version__ = "2.1.0" __all__ = ["Destination", "Park", "EntertainmentVenue", "Attraction", "Entertainment", "Facility", "Character", "PointOfInterest", "DisneyDatabase"] diff --git a/MouseTools/auth.py b/MouseTools/auth.py index f7ce88b..39b0363 100644 --- a/MouseTools/auth.py +++ b/MouseTools/auth.py @@ -28,8 +28,3 @@ def getHeaders(): headers = {"Authorization":"BEARER {}".format(access_token), "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36", "Content-Type":"application/json;charset=UTF-8","Accept":"*/*"} return headers - -def couchbaseHeaders(): - - header = {"Authorization":"Basic RFBFQ1AtTU9CSUxFLldEVy5BTkRST0lELVBST0Q6RGhyeHMyZHVReGdiVjZ5Mg==","User-Agent":"CouchbaseLite/1.3 (1.4.1/8a21c5927a273a038fb3b66ec29c86425e871b11)","Content-Type":"application/json","Accept":"multipart/related"} - return header diff --git a/MouseTools/database.py b/MouseTools/database.py deleted file mode 100644 index 2639696..0000000 --- a/MouseTools/database.py +++ /dev/null @@ -1,576 +0,0 @@ -from .auth import couchbaseHeaders -from pathlib import Path -import datetime -import pkg_resources -import sqlite3 -import requests -import json -import re -import os - -# The facilities channel either doesn't have everything or parsing the links from global-facility-service has things that don't exist -class DisneyDatabase: - - def __init__(self, sync_on_init=True): - self.db_path = os.path.join(Path(os.path.abspath(__file__)).parent, "MouseTools.db") - self.conn = sqlite3.connect(self.db_path) - self.c = self.conn.cursor() - - self.create_last_sequence_table() - self.create_sync_table() - self.create_facilities_table() - self.create_calendar_table() - - last_sequence = self.c.execute("""SELECT COUNT(value) FROM lastSequence""").fetchone()[0] - if last_sequence != 0: - if sync_on_init: - self.sync_database() - else: - self.create_facilities_channel('wdw.facilities.1_0.en_us') - self.create_facilities_channel('dlr.facilities.1_0.en_us') - - - def sync_database(self): - - self.sync_facilities_channel() - self.sync_facilitystatus_channel() - self.sync_today_channel() - self.sync_calendar_channel() - - - def create_last_sequence_table(self): - - - self.c.execute("""CREATE TABLE IF NOT EXISTS lastSequence (channel TEXT PRIMARY KEY, value TEXT, channel_type TEXT)""") - - self.conn.commit() - - - - def create_facilities_table(self): - - # subType - self.c.execute("""CREATE TABLE IF NOT EXISTS facilities (id TEXT PRIMARY KEY, name TEXT, entityType TEXT, subType TEXT, doc_id TEXT, destination_code TEXT, park_id TEXT, resort_id TEXT, land_id TEXT, resort_area_id TEXT, entertainment_venue_id TEXT)""") - - self.conn.commit() - - def create_calendar_table(self): - - # subType - self.c.execute("""CREATE TABLE IF NOT EXISTS calendar (id TEXT PRIMARY KEY, date TEXT, destination_code TEXT, body TEXT)""") - - self.conn.commit() - - def create_sync_table(self): - - self.c.execute("""CREATE TABLE IF NOT EXISTS sync (id TEXT PRIMARY KEY, rev TEXT, body TEXT, channel TEXT)""") - - self.conn.commit() - - def channel_exists(self, channel): - - facility_channel_exists = self.c.execute("""SELECT COUNT(value) FROM lastSequence WHERE channel = '{}'""".format(channel)).fetchone()[0] - self.conn.commit() - - - return facility_channel_exists != 0 - - - - def create_facilities_channel(self, channel): - - payload = { - "channels": channel, - "style": 'all_docs', - "filter": 'sync_gateway/bychannel', - "feed": 'normal', - "heartbeat": 30000 - } - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_changes?feed=normal&heartbeat=30000&style=all_docs&filter=sync_gateway%2Fbychannel", data=json.dumps(payload), headers=couchbaseHeaders()) - s = json.loads(r.text) - - self.c.execute("INSERT INTO lastSequence (channel, value, channel_type) VALUES (?, ?, 'facilities')", (channel, s['last_seq'],)) - - # search for deleted: i['deleted'] or i['removed'] - docs = [] - for i in s['results']: - try: - i['deleted'] - continue - except: - this = {} - this['id'] = i['id'] - - docs.append(this) - - split_id = i['id'].split(":") - if len(split_id) > 1: - this = {} - this['id'] = split_id[0] - docs.append(this) - - # print('getting {} docs'.format(len(docs))) - - payload = {"docs": docs, "json":True} - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_bulk_get?revs=true&attachments=true", data=json.dumps(payload), headers=couchbaseHeaders()) - s = r.text - - cont_reg = re.compile("\w+-\w+:\s\w+\/\w+") - s = re.sub(cont_reg, "", s) - s = s.splitlines() - for x in s: - if x != '' and x[0] != '-': - try: - x = json.loads(x) - self.c.execute("INSERT INTO sync (id, rev, body, channel) VALUES (?, ?, ?, ?)", (x['_id'], x['_rev'], json.dumps(x), channel,)) - - split_id = x['_id'].split(':') - this['id'] = split_id[-1].split(';')[0].split('.')[-1] - - - this['name'] = x['name'] - this['entityType'] = x['type'] - - try: - this['sub'] = x['subType'] - except: - this['sub'] = None - - this['cb_id'] = x['_id'] - this['dest_code'] = x['_id'].split('.')[0] - - try: - this['park_id'] = x['ancestorThemeParkId'].split(';')[0] - except: - try: - this['park_id'] = x['ancestorWaterParkId'].split(';')[0] - except: - this['park_id'] = None - - try: - this['land_id'] = x['ancestorLandId'].split(';')[0] - except: - this['land_id'] = None - - try: - this['resort_id'] = x['ancestorResortId'].split(';')[0] - except: - this['resort_id'] = None - - try: - this['ra_id'] = x['ancestorResortAreaId'].split(';')[0] - except: - this['ra_id'] = None - - try: - this['ev_id'] = x['ancestorEntertainmentVenueId'].split(';')[0] - except: - this['ev_id'] = None - - self.c.execute("INSERT INTO facilities (id, name, entityType, subType, doc_id, destination_code, park_id, land_id, resort_id, resort_area_id, entertainment_venue_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", (this['id'], this['name'], this['entityType'], this['sub'], this['cb_id'], this['dest_code'], this['park_id'], this['land_id'], this['resort_id'], this['ra_id'], this['ev_id'],)) - except Exception as e: - # print(x) - # print(e) - continue - - self.conn.commit() - - def sync_facilities_channel(self): - - docs = [] - for row in self.c.execute("""SELECT * FROM lastSequence WHERE channel_type = 'facilities'""").fetchall(): - payload = { - "channels": row[0], - "style": 'all_docs', - "filter": 'sync_gateway/bychannel', - "feed": 'normal', - "heartbeat": 30000 - } - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_changes?feed=normal&heartbeat=30000&style=all_docs&since={}&filter=sync_gateway%2Fbychannel".format(row[1]), data=json.dumps(payload), headers=couchbaseHeaders()) - s = json.loads(r.text) - - self.c.execute("REPLACE INTO lastSequence (channel, value, channel_type) VALUES (?, ?, 'facilities')", (row[0], s['last_seq'],)) - - # search for deleted: i['deleted'] or i['removed'] - - for i in s['results']: - try: - test = i['deleted'] - self.c.execute("DELETE FROM facilities WHERE doc_id = ?", (i['id'],)) - self.c.execute("DELETE FROM sync WHERE id = ?", (i['id'],)) - num_id = i['id'].split(".")[-1].split(";")[0] - self.c.execute("DELETE FROM sync WHERE id LIKE '%facilitystatus.1_0.{}%'".format(num_id)) - except: - this = {} - this['id'] = i['id'] - - docs.append(this) - - split_id = i['id'].split(":") - if len(split_id) > 1: - this = {} - this['id'] = split_id[0] - docs.append(this) - - # print('updating {} docs'.format(len(docs))) - - payload = {"docs": docs, "json":True} - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_bulk_get?revs=true&attachments=true", data=json.dumps(payload), headers=couchbaseHeaders()) - s = r.text - - cont_reg = re.compile("\w+-\w+:\s\w+\/\w+") - s = re.sub(cont_reg, "", s) - s = s.splitlines() - for x in s: - if x != '': - try: - x = json.loads(x) - self.c.execute("INSERT OR REPLACE INTO sync (id, rev, body, channel) VALUES (?, ?, ?, ?)", (x['_id'], x['_rev'], json.dumps(x), row[0],)) - - split_id = x['_id'].split(':') - this['id'] = split_id[-1].split(';')[0].split('.')[-1] - - - this['name'] = x['name'] - this['entityType'] = x['type'] - - try: - this['sub'] = x['subType'] - except: - this['sub'] = None - - this['cb_id'] = x['_id'] - this['dest_code'] = x['_id'].split('.')[0] - - try: - this['park_id'] = x['ancestorThemeParkId'].split(';')[0] - except: - this['park_id'] = None - - try: - this['land_id'] = x['ancestorLandId'].split(';')[0] - except: - this['land_id'] = None - - try: - this['resort_id'] = x['ancestorResortId'].split(';')[0] - except: - this['resort_id'] = None - - try: - this['ra_id'] = x['ancestorResortAreaId'].split(';')[0] - except: - this['ra_id'] = None - - try: - this['ev_id'] = x['ancestorEntertainmentVenueId'].split(';')[0] - except: - this['ev_id'] = None - - self.c.execute("INSERT OR REPLACE INTO facilities (id, name, entityType, subType, doc_id, destination_code, park_id, land_id, resort_id, resort_area_id, entertainment_venue_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", (this['id'], this['name'], this['entityType'], this['sub'], this['cb_id'], this['dest_code'], this['park_id'], this['land_id'], this['resort_id'], this['ra_id'], this['ev_id'],)) - except Exception as e: - # print(e) - continue - - - self.conn.commit() - - - - - def create_facilitystatus_channel(self, channel): - - payload = { - "channels": channel, - "style": 'all_docs', - "filter": 'sync_gateway/bychannel', - "feed": 'normal', - "heartbeat": 30000 - } - - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_changes?feed=normal&heartbeat=30000&style=all_docs&filter=sync_gateway%2Fbychannel", data=json.dumps(payload), headers=couchbaseHeaders()) - s = json.loads(r.text) - - self.c.execute("INSERT OR REPLACE INTO lastSequence (channel, value, channel_type) VALUES (?, ?, 'facilitystatus')", (channel, s['last_seq'],)) - - # search for deleted: i['deleted'] or i['removed'] - docs = [] - for i in s['results']: - try: - i['deleted'] - continue - except: - this = {} - this['id'] = i['id'] - - docs.append(this) - - split_id = i['id'].split(":") - if len(split_id) > 1: - this = {} - this['id'] = split_id[0] - docs.append(this) - - # print('getting {} docs'.format(len(docs))) - - payload = {"docs": docs, "json":True} - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_bulk_get?revs=true&attachments=true", data=json.dumps(payload), headers=couchbaseHeaders()) - s = r.text - - cont_reg = re.compile("\w+-\w+:\s\w+\/\w+") - s = re.sub(cont_reg, "", s) - s = s.splitlines() - for x in s: - if x != '' and x[0] != '-': - try: - x = json.loads(x) - self.c.execute("INSERT INTO sync (id, rev, body, channel) VALUES (?, ?, ?, ?)", (x['_id'], x['_rev'], json.dumps(x), channel,)) - except Exception as e: - # print(e) - # print(x) - continue - - self.conn.commit() - - - def sync_facilitystatus_channel(self): - - docs = [] - for row in self.c.execute("""SELECT * FROM lastSequence WHERE channel_type = 'facilitystatus'""").fetchall(): - payload = { - "channels": row[0], - "style": 'all_docs', - "filter": 'sync_gateway/bychannel', - "feed": 'normal', - "heartbeat": 30000 - } - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_changes?feed=normal&heartbeat=30000&style=all_docs&since={}&filter=sync_gateway%2Fbychannel".format(row[1]), data=json.dumps(payload), headers=couchbaseHeaders()) - s = json.loads(r.text) - - - - self.c.execute("REPLACE INTO lastSequence (channel, value, channel_type) VALUES (?, ?, 'facilitystatus')", (row[0], s['last_seq'],)) - - # search for deleted: i['deleted'] or i['removed'] - - for i in s['results']: - try: - i['deleted'] - continue - except: - this = {} - this['id'] = i['id'] - - docs.append(this) - - split_id = i['id'].split(":") - if len(split_id) > 1: - this = {} - this['id'] = split_id[0] - docs.append(this) - - # print('getting {} docs'.format(len(docs))) - - payload = {"docs": docs, "json":True} - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_bulk_get?revs=true&attachments=true", data=json.dumps(payload), headers=couchbaseHeaders()) - s = r.text - - cont_reg = re.compile("\w+-\w+:\s\w+\/\w+") - s = re.sub(cont_reg, "", s) - s = s.splitlines() - for x in s: - if x != '' and x[0] != '-': - try: - x = json.loads(x) - self.c.execute("INSERT OR REPLACE INTO sync (id, rev, body, channel) VALUES (?, ?, ?, ?)", (x['_id'], x['_rev'], json.dumps(x), row[0],)) - except: - continue - - self.conn.commit() - - - - - def create_today_channel(self, channel): - - payload = { - "channels": channel, - "style": 'all_docs', - "filter": 'sync_gateway/bychannel', - "feed": 'normal', - "heartbeat": 30000 - } - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_changes?feed=normal&heartbeat=30000&style=all_docs&filter=sync_gateway%2Fbychannel", data=json.dumps(payload), headers=couchbaseHeaders()) - s = json.loads(r.text) - - self.c.execute("INSERT OR REPLACE INTO lastSequence (channel, value, channel_type) VALUES (?, ?, 'today')", (channel, s['last_seq'],)) - - docs = [] - for i in s['results']: - try: - i['deleted'] - continue - except: - this = {} - this['id'] = i['id'] - - docs.append(this) - - split_id = i['id'].split(":") - if len(split_id) > 1: - this = {} - this['id'] = split_id[0] - docs.append(this) - - payload = {"docs": docs, "json":True} - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_bulk_get?revs=true&attachments=true", data=json.dumps(payload), headers=couchbaseHeaders()) - s = r.text - - cont_reg = re.compile("\w+-\w+:\s\w+\/\w+") - s = re.sub(cont_reg, "", s) - s = s.splitlines() - for x in s: - if x != '' and x[0] != '-': - try: - x = json.loads(x) - self.c.execute("INSERT INTO sync (id, rev, body, channel) VALUES (?, ?, ?, ?)", (x['_id'], x['_rev'], json.dumps(x), channel,)) - except: - continue - - self.conn.commit() - - - def sync_today_channel(self): - - docs = [] - for row in self.c.execute("""SELECT * FROM lastSequence WHERE channel_type = 'today'""").fetchall(): - payload = { - "channels": row[0], - "style": 'all_docs', - "filter": 'sync_gateway/bychannel', - "feed": 'normal', - "heartbeat": 30000 - } - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_changes?feed=normal&heartbeat=30000&style=all_docs&since={}&filter=sync_gateway%2Fbychannel".format(row[1]), data=json.dumps(payload), headers=couchbaseHeaders()) - s = json.loads(r.text) - - - - self.c.execute("REPLACE INTO lastSequence (channel, value, channel_type) VALUES (?, ?, 'today')", (row[0], s['last_seq'],)) - - # search for deleted: i['deleted'] or i['removed'] - - for i in s['results']: - try: - i['deleted'] - continue - except: - this = {} - this['id'] = i['id'] - - docs.append(this) - - split_id = i['id'].split(":") - if len(split_id) > 1: - this = {} - this['id'] = split_id[0] - docs.append(this) - - # print('getting {} docs'.format(len(docs))) - - payload = {"docs": docs, "json":True} - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_bulk_get?revs=true&attachments=true", data=json.dumps(payload), headers=couchbaseHeaders()) - s = r.text - - cont_reg = re.compile("\w+-\w+:\s\w+\/\w+") - s = re.sub(cont_reg, "", s) - s = s.splitlines() - for x in s: - if x != '' and x[0] != '-': - try: - x = json.loads(x) - self.c.execute("INSERT OR REPLACE INTO sync (id, rev, body, channel) VALUES (?, ?, ?, ?)", (x['_id'], x['_rev'], json.dumps(x), row[0],)) - except: - continue - - self.conn.commit() - - - - def create_calendar_channel(self, channel): - - today = datetime.datetime.today() - - dest_code = channel.split('.')[0] - - self.c.execute("DELETE FROM calendar WHERE destination_code = ?", (dest_code,)) - - payload = { - "channels": channel, - "style": 'all_docs', - "filter": 'sync_gateway/bychannel', - "feed": 'normal', - "heartbeat": 30000 - } - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_changes?feed=normal&heartbeat=30000&style=all_docs&filter=sync_gateway%2Fbychannel", data=json.dumps(payload), headers=couchbaseHeaders()) - s = json.loads(r.text) - - self.c.execute("INSERT OR REPLACE INTO lastSequence (channel, value, channel_type) VALUES (?, ?, 'calendar')", (channel, s['last_seq'],)) - - docs = [] - for i in s['results']: - try: - i['deleted'] - continue - except: - this = {} - this['id'] = i['id'] - - docs.append(this) - - split_id = i['id'].split(":") - if len(split_id) > 1: - this = {} - this['id'] = split_id[0] - docs.append(this) - - payload = {"docs": docs, "json":True} - r = requests.post("https://realtime-sync-gw.wdprapps.disney.com/park-platform-pub/_bulk_get?revs=true&attachments=true", data=json.dumps(payload), headers=couchbaseHeaders()) - s = r.text - - cont_reg = re.compile("\w+-\w+:\s\w+\/\w+") - s = re.sub(cont_reg, "", s) - s = s.splitlines() - for x in s: - if x != '' and x[0] != '-': - try: - x = json.loads(x) - - split_id = x['id'].split('-') - day = split_id[0] - month = split_id[1] - if today.month > int(month): - year = today.year + 1 - elif today.month == int(month) and today.day > int(day): - year = today.year + 1 - else: - year = today.year - - date = "{}-{}-{}".format(year, month, day) - - dest_code = x['_id'].split('.')[0] - - self.c.execute("INSERT INTO calendar (id, date, destination_code, body) VALUES (?, ?, ?, ?)", (x['_id'], date, dest_code, json.dumps(x),)) - - except Exception as e: - # print(e) - continue - - self.conn.commit() - - - def sync_calendar_channel(self): - - - for row in self.c.execute("""SELECT * FROM lastSequence WHERE channel_type = 'calendar'""").fetchall(): - self.create_calendar_channel(row[0]) From 33b32df869f7bb893390564374a40ff25b12f08a Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 19:20:52 -0500 Subject: [PATCH 02/20] removing database dependencies --- MouseTools/characters.py | 2 +- MouseTools/destinations.py | 2 +- MouseTools/entertainments.py | 2 +- MouseTools/entertainmentvenues.py | 4 ++-- MouseTools/facilities.py | 2 +- MouseTools/parks.py | 4 ++-- MouseTools/pointsofinterest.py | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/MouseTools/characters.py b/MouseTools/characters.py index 6b53220..63fdf2b 100644 --- a/MouseTools/characters.py +++ b/MouseTools/characters.py @@ -7,7 +7,7 @@ from .attractions import Attraction from .entertainments import Entertainment from .facilities import Facility -from .database import DisneyDatabase + class Character(object): diff --git a/MouseTools/destinations.py b/MouseTools/destinations.py index af2cf45..efb9716 100644 --- a/MouseTools/destinations.py +++ b/MouseTools/destinations.py @@ -7,7 +7,7 @@ from .parks import Park from .entertainments import Entertainment from .attractions import Attraction -from .database import DisneyDatabase + WDW_CODE = 'wdw' DLR_CODE = 'dlr' diff --git a/MouseTools/entertainments.py b/MouseTools/entertainments.py index a3123ff..dede569 100644 --- a/MouseTools/entertainments.py +++ b/MouseTools/entertainments.py @@ -6,7 +6,7 @@ from .auth import getHeaders from .parks import Park from .pointsofinterest import PointOfInterest -from .database import DisneyDatabase + class Entertainment(object): diff --git a/MouseTools/entertainmentvenues.py b/MouseTools/entertainmentvenues.py index 545da2d..2cf77d7 100644 --- a/MouseTools/entertainmentvenues.py +++ b/MouseTools/entertainmentvenues.py @@ -3,8 +3,8 @@ import sys import sqlite3 from datetime import datetime, timedelta -from .auth import getHeaders, couchbaseHeaders -from .database import DisneyDatabase +from .auth import getHeaders + class EntertainmentVenue(object): diff --git a/MouseTools/facilities.py b/MouseTools/facilities.py index f511594..6e8a9fc 100644 --- a/MouseTools/facilities.py +++ b/MouseTools/facilities.py @@ -4,7 +4,7 @@ import sqlite3 from datetime import datetime, timedelta from .auth import getHeaders -from .database import DisneyDatabase + class Facility(object): diff --git a/MouseTools/parks.py b/MouseTools/parks.py index 26f7cc7..0b4247f 100644 --- a/MouseTools/parks.py +++ b/MouseTools/parks.py @@ -3,8 +3,8 @@ import sys import sqlite3 from datetime import datetime, timedelta -from .auth import getHeaders, couchbaseHeaders -from .database import DisneyDatabase +from .auth import getHeaders + class Park(object): diff --git a/MouseTools/pointsofinterest.py b/MouseTools/pointsofinterest.py index e4ed517..de418cc 100644 --- a/MouseTools/pointsofinterest.py +++ b/MouseTools/pointsofinterest.py @@ -4,7 +4,7 @@ import sqlite3 from datetime import datetime, timedelta from .auth import getHeaders -from .database import DisneyDatabase + class PointOfInterest(object): From bc4807d398b50e722655ffecacf6479bf8886982 Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 19:21:23 -0500 Subject: [PATCH 03/20] dictionary of park_id:themeparkapi_id --- MouseTools/ids.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MouseTools/ids.py b/MouseTools/ids.py index 1ae561d..2cd2ce6 100644 --- a/MouseTools/ids.py +++ b/MouseTools/ids.py @@ -17,6 +17,9 @@ WDW_PARK_IDS = [MK_ID, EPCOT_ID, HS_ID, AK_ID, TL_ID, BB_ID] DLR_PARK_IDS = [DLP_ID, CA_ID] +themeparkapi_ids = {MK_ID: "WaltDisneyWorldMagicKingdom", EPCOT_ID: "WaltDisneyWorldEpcot", HS_ID: "WaltDisneyWorldHollywoodStudios", + AK_ID: "WaltDisneyWorldAnimalKingdom", DLP_ID: "DisneylandResortMagicKingdom", CA_ID: "DisneylandResortCaliforniaAdventure"} + def ids(dest, type): dest_data = requests.get("https://api.wdpro.disney.go.com/facility-service/destinations/{}".format(dest), headers=getHeaders()).json() From ff23f8e7f0f34797ab05435f32c321b2e20e09ff Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 19:21:53 -0500 Subject: [PATCH 04/20] removing database dependency and moving to themepark api --- MouseTools/attractions.py | 162 +++++++++++++++----------------------- 1 file changed, 64 insertions(+), 98 deletions(-) diff --git a/MouseTools/attractions.py b/MouseTools/attractions.py index 9e0b48e..bce6cc8 100644 --- a/MouseTools/attractions.py +++ b/MouseTools/attractions.py @@ -3,9 +3,10 @@ import sys import sqlite3 from datetime import datetime, timedelta -from .auth import getHeaders, couchbaseHeaders +from .auth import getHeaders from .parks import Park -from .database import DisneyDatabase +from .ids import themeparkapi_ids + class Attraction(object): @@ -27,10 +28,6 @@ def __init__(self, id = None, sync_on_init=True): if error: raise ValueError('That attraction is not available. id: ' + str(id)) - self.__db = DisneyDatabase(sync_on_init) - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - self.__id = id self.__name = self.__data['name'] self.__entityType = self.__data['type'] @@ -38,15 +35,11 @@ def __init__(self, id = None, sync_on_init=True): self.__subType = self.__data['subType'] except: self.__subType = None - doc_id_query = c.execute("SELECT doc_id from facilities where doc_id LIKE ?", ("%{};entityType={}".format(self.__id, self.__entityType),)).fetchone() - self.__doc_id = doc_id_query[0] if doc_id_query is not None else None - self.__facilities_data = self.get_raw_facilities_data() + try: self.__anc_dest_id = self.__data['ancestorDestination']['id'].split(';')[0] - self.__dest_code = c.execute("SELECT destination_code FROM facilities WHERE id = ?", (self.__anc_dest_id,)).fetchone()[0] except: self.__anc_dest_id = None - self.__dest_code = None try: self.__anc_park_id = self.__data['links']['ancestorThemePark']['href'].split('/')[-1].split('?')[0] @@ -94,8 +87,6 @@ def __init__(self, id = None, sync_on_init=True): except: self.__anc_ev_id = None - conn.commit() - conn.close() def get_possible_ids(self): """Returns a list of possible ids of this entityType""" @@ -127,14 +118,6 @@ def get_subType(self): """Return object subType""" return self.__subType - def get_doc_id(self): - """Return object doc id""" - return self.__doc_id - - def get_destination_code(self): - """Return object destination code""" - return self.__dest_code - def get_ancestor_destination_id(self): """Return object ancestor destination id""" return self.__anc_dest_id @@ -167,115 +150,98 @@ def get_raw_data(self): """Returns the raw data from global-facility-service""" return self.__data - def get_raw_facilities_data(self): - """Returns the raw facilities data currently stored in the database""" - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - data = c.execute("SELECT body FROM sync WHERE id = ?", (self.__doc_id,)).fetchone() - conn.commit() - conn.close() + def get_themeparkapi_data(self): + """Returns the dictionary from the themepark api""" + park = themeparkapi_ids[self.__anc_park_id] + themepark_id = f"{park}_{self.__id}" + all_data = requests.get(f"https://api.themeparks.wiki/preview/parks/{park}/waittime").json() + for i in all_data: + if i["id"] == themepark_id: + return i - if data is None: - return None - else: - return json.loads(data[0]) - - def get_raw_facilitystatus_data(self): - """Returns the raw facilitystatus data from the database after syncing with Disney (returns most recent data)""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType=Attraction".format(self.__dest_code, self.__id),)).fetchone() - if data is None: - return None - else: - return json.loads(data[0]) + return None def get_wait_time(self): """Return current wait time of the object. Returns None if object doesn't have a wait time or no wait currently exists (eg. closed)""" - data = self.get_raw_facilitystatus_data() + data = self.get_themeparkapi_data() if data is None: return None else: - return data['waitMinutes'] + return data['waitTime'] def get_status(self): """Return current status of the object.""" - data = self.get_raw_facilitystatus_data() + data = self.get_themeparkapi_data() if data is None: return None else: return data['status'] - # TODO might have to change this from facilitystatus data to scheduleType from today, or test if none from status then get from today instead def fastpass_available(self): """Returns a boolean of whether this object has FastPass""" - data = self.get_raw_facilitystatus_data() + data = self.get_themeparkapi_data() if data is None: return False else: - return data['fastPassAvailable'] == 'true' - - def fastpass_times(self): - """Returns the current start and end time of the FastPass""" - start_time = None - end_time = None - - if self.fastpass_available(): - data = self.get_raw_facilitystatus_data() - - start_time = datetime.strptime(data['fastPassStartTime'], "%Y-%m-%dT%H:%M:%SZ") - end_time = datetime.strptime(data['fastPassEndTime'], "%Y-%m-%dT%H:%M:%SZ") - - return start_time, end_time + return data['fastPass'] + + # Deprecated + # def fastpass_times(self): + # """Returns the current start and end time of the FastPass""" + # start_time = None + # end_time = None + # + # if self.fastpass_available(): + # data = self.get_raw_facilitystatus_data() + # + # start_time = datetime.strptime(data['fastPassStartTime'], "%Y-%m-%dT%H:%M:%SZ") + # end_time = datetime.strptime(data['fastPassEndTime'], "%Y-%m-%dT%H:%M:%SZ") + # + # return start_time, end_time def get_last_update(self): """Returns facilities last update time as a datetime object""" - facility_data = self.get_raw_facilities_data() + facility_data = self.get_themeparkapi_data() if facility_data is None: return None else: - return datetime.strptime(facility_data['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") + return datetime.strptime(facility_data['lastUpdate'], "%Y-%m-%dT%H:%M:%S.%fZ") def get_coordinates(self): """Returns the object's latitude and longitude""" - facility_data = self.get_raw_facilities_data() - if facility_data is None: - return None - else: - return facility_data['latitude'], facility_data['longitude'] - - def get_description(self): - """Returns the object's descriptions""" - facility_data = self.get_raw_facilities_data() - if facility_data is None: - return None - else: - return facility_data['description'] - - def get_list_image(self): - """Returns the url to the object's list image""" - facility_data = self.get_raw_facilities_data() - if facility_data is None: - return None - else: - return facility_data['listImageUrl'] - - def get_facets(self): - """Returns a list of dictionaries of the object's facets""" - facility_data = self.get_raw_facilities_data() + facility_data = self.get_themeparkapi_data() if facility_data is None: return None else: - try: - return facility_data['facets'] - except: - return None + return facility_data['meta']['latitude'], facility_data['meta']['longitude'] + + # Check self.__data + # def get_description(self): + # """Returns the object's descriptions""" + # facility_data = self.get_raw_facilities_data() + # if facility_data is None: + # return None + # else: + # return facility_data['description'] + # + # def get_list_image(self): + # """Returns the url to the object's list image""" + # facility_data = self.get_raw_facilities_data() + # if facility_data is None: + # return None + # else: + # return facility_data['listImageUrl'] + # + # def get_facets(self): + # """Returns a list of dictionaries of the object's facets""" + # facility_data = self.get_raw_facilities_data() + # if facility_data is None: + # return None + # else: + # try: + # return facility_data['facets'] + # except: + # return None def admission_required(self): """Returns boolean of admission required""" From 27c0909253f6f38431b3ce57209b58ce53116f63 Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 20:02:54 -0500 Subject: [PATCH 05/20] removed possible ids given the ids module, changed functions --- MouseTools/attractions.py | 107 +++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 58 deletions(-) diff --git a/MouseTools/attractions.py b/MouseTools/attractions.py index bce6cc8..24e07bf 100644 --- a/MouseTools/attractions.py +++ b/MouseTools/attractions.py @@ -88,20 +88,6 @@ def __init__(self, id = None, sync_on_init=True): self.__anc_ev_id = None - def get_possible_ids(self): - """Returns a list of possible ids of this entityType""" - attractions = [] - - dest_data = requests.get("https://api.wdpro.disney.go.com/facility-service/destinations/{}".format(self.__anc_dest_id), headers=getHeaders()).json() - data = requests.get(dest_data['links']['attractions']['href'], headers=getHeaders()).json() - - for attract in data['entries']: - try: - attractions.append(attract['links']['self']['href'].split('/')[-1].split('?')[0]) - except: - pass - return attractions - def get_id(self): """Return object id""" return self.__id @@ -151,14 +137,13 @@ def get_raw_data(self): return self.__data def get_themeparkapi_data(self): - """Returns the dictionary from the themepark api""" + """Returns the dictionary from the themepark api for the given id""" park = themeparkapi_ids[self.__anc_park_id] themepark_id = f"{park}_{self.__id}" all_data = requests.get(f"https://api.themeparks.wiki/preview/parks/{park}/waittime").json() for i in all_data: if i["id"] == themepark_id: return i - return None def get_wait_time(self): @@ -185,20 +170,6 @@ def fastpass_available(self): else: return data['fastPass'] - # Deprecated - # def fastpass_times(self): - # """Returns the current start and end time of the FastPass""" - # start_time = None - # end_time = None - # - # if self.fastpass_available(): - # data = self.get_raw_facilitystatus_data() - # - # start_time = datetime.strptime(data['fastPassStartTime'], "%Y-%m-%dT%H:%M:%SZ") - # end_time = datetime.strptime(data['fastPassEndTime'], "%Y-%m-%dT%H:%M:%SZ") - # - # return start_time, end_time - def get_last_update(self): """Returns facilities last update time as a datetime object""" facility_data = self.get_themeparkapi_data() @@ -215,33 +186,53 @@ def get_coordinates(self): else: return facility_data['meta']['latitude'], facility_data['meta']['longitude'] - # Check self.__data - # def get_description(self): - # """Returns the object's descriptions""" - # facility_data = self.get_raw_facilities_data() - # if facility_data is None: - # return None - # else: - # return facility_data['description'] - # - # def get_list_image(self): - # """Returns the url to the object's list image""" - # facility_data = self.get_raw_facilities_data() - # if facility_data is None: - # return None - # else: - # return facility_data['listImageUrl'] - # - # def get_facets(self): - # """Returns a list of dictionaries of the object's facets""" - # facility_data = self.get_raw_facilities_data() - # if facility_data is None: - # return None - # else: - # try: - # return facility_data['facets'] - # except: - # return None + + def get_description(self): + """Returns the object's description""" + facility_data = self.__data + if facility_data is None: + return None + else: + try: + return facility_data['descriptions']['shortDescription']['sections']['body'] + except: + return None + + def get_media(self): + """Returns a dictionary of dictionaries of media relating to the entity""" + facility_data = self.__data + if facility_data is None: + return None + else: + return facility_data['media'] + + def get_facets(self): + """Returns a list of dictionaries of the object's facets""" + facility_data = self.get_themeparkapi_data() + if facility_data is None: + return None + else: + try: + return facility_data['facets'] + except: + return None + + def get_classifications(self): + """Returns a dictionary of lists of classifications related to the entity""" + + classifications = {} + + try: + for i in self.__data['classifications']: + id = i['id'].split("/")[-1] + if id not in classifications: + classifications[id] = [i['text']] + else: + classifications[id].append(i['text']) + except: + pass + + return classifications def admission_required(self): """Returns boolean of admission required""" @@ -253,7 +244,7 @@ def get_hours(self, date = ""): Returns the object's hours in the following order: operating open, operating close, Extra Magic open, Extra Magic close. Extra Magic hours will return None if there are none for today. If all hours are None then Disney has no hours for that day. - date = "YEAR-MONTH-DATE" + date = "yyyy-mm-dd" If you don't pass a date, it will get today's hours """ From d5b53c10b0ef9d8d4b41c65a3222776a6bc4fba9 Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 20:13:44 -0500 Subject: [PATCH 06/20] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d5eb72..e19aa28 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ I created this project to help with another project found [here](https://github. If you notice any issues please open a new issue with a "bug" label. Furthermore, if you have any feature requests, open a new issue with a "feature request" label. -This update would not have been possible without the work being done on the [themeparks package](https://github.com/cubehouse/themeparks). Parts of this update were inspired by them. +This package uses the [ThemeParks.wiki API](https://api.themeparks.wiki/). ### License This project is distributed under the MIT license. For more information see [LICENSE](https://github.com/scaratozzolo/MouseTools/blob/master/LICENSE) From bd1e2caf150d96f93a292c265685cfd9abc56d70 Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 20:18:47 -0500 Subject: [PATCH 07/20] removing database dependency from characters --- MouseTools/attractions.py | 2 +- MouseTools/characters.py | 52 ++++----------------------------------- 2 files changed, 6 insertions(+), 48 deletions(-) diff --git a/MouseTools/attractions.py b/MouseTools/attractions.py index 24e07bf..9750b31 100644 --- a/MouseTools/attractions.py +++ b/MouseTools/attractions.py @@ -11,7 +11,7 @@ class Attraction(object): - def __init__(self, id = None, sync_on_init=True): + def __init__(self, id = None): """ Constructor Function Gets all attraction data available and stores various elements into variables. diff --git a/MouseTools/characters.py b/MouseTools/characters.py index 63fdf2b..33614b1 100644 --- a/MouseTools/characters.py +++ b/MouseTools/characters.py @@ -12,7 +12,7 @@ class Character(object): - def __init__(self, id = None, sync_on_init=True): + def __init__(self, id = None): """ Constructor Function Gets all character data available and stores various elements into variables. @@ -29,10 +29,6 @@ def __init__(self, id = None, sync_on_init=True): if error: raise ValueError('That character is not available. id: ' + str(id)) - self.__db = DisneyDatabase(sync_on_init) - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - self.__id = id self.__name = self.__data['name'] self.__entityType = self.__data['type'] @@ -40,15 +36,10 @@ def __init__(self, id = None, sync_on_init=True): self.__subType = self.__data['subType'] except: self.__subType = None - doc_id_query = c.execute("SELECT doc_id from facilities where doc_id LIKE ?", ("%{};entityType={}".format(self.__id, self.__entityType),)).fetchone() - self.__doc_id = doc_id_query[0] if doc_id_query is not None else None - self.__facilities_data = self.get_raw_facilities_data() try: self.__anc_dest_id = self.__data['ancestorDestination']['id'].split(';')[0] - self.__dest_code = c.execute("SELECT destination_code FROM facilities WHERE id = ?", (self.__anc_dest_id,)).fetchone()[0] except: self.__anc_dest_id = None - self.__dest_code = None try: self.__anc_park_id = self.__data['links']['ancestorThemePark']['href'].split('/')[-1].split('?')[0] @@ -96,24 +87,7 @@ def __init__(self, id = None, sync_on_init=True): except: self.__anc_ev_id = None - conn.commit() - conn.close() - - - def get_possible_ids(self): - """Returns a list of possible ids of this entityType""" - ids = [] - - data = requests.get("https://api.wdpro.disney.go.com/facility-service/characters", headers=getHeaders()).json() - - for entry in data['entries']: - try: - ids.append(entry['links']['self']['href'].split('/')[-1].split('?')[0]) - except: - pass - - return ids def get_id(self): """Return object id""" @@ -131,14 +105,6 @@ def get_subType(self): """Return object subType""" return self.__subType - def get_doc_id(self): - """Return object doc id""" - return self.__doc_id - - def get_destination_code(self): - """Return object destination code""" - return self.__dest_code - def get_ancestor_destination_id(self): """Return object ancestor destination id""" return self.__anc_dest_id @@ -163,22 +129,14 @@ def get_ancestor_entertainment_venue_id(self): """Return object entertainment venue id""" return self.__anc_ev_id + def get_raw_data(self): + """Returns the raw data from global-facility-service""" + return self.__data + def get_links(self): """Returns a dictionary of related links""" return self.__data['links'] - def get_raw_facilities_data(self): - """Returns the raw facilities data currently stored in the database""" - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - data = c.execute("SELECT body FROM sync WHERE id = ?", (self.__doc_id,)).fetchone() - conn.commit() - conn.close() - - if data is None: - return None - else: - return json.loads(data[0]) def check_related_locations(self): """ From 3ecc2bbd0299ec84763cb4708f342923dbf24064 Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 21:03:14 -0500 Subject: [PATCH 08/20] removing dependency on database and adjusting other class methods --- MouseTools/destinations.py | 410 ++++++++++++++++--------------------- 1 file changed, 174 insertions(+), 236 deletions(-) diff --git a/MouseTools/destinations.py b/MouseTools/destinations.py index efb9716..d5e59ef 100644 --- a/MouseTools/destinations.py +++ b/MouseTools/destinations.py @@ -7,12 +7,9 @@ from .parks import Park from .entertainments import Entertainment from .attractions import Attraction +from .ids import WDW_PARK_IDS, DLR_PARK_IDS, WDW_ID, DLR_ID, DESTINATION_IDS, themeparkapi_ids -WDW_CODE = 'wdw' -DLR_CODE = 'dlr' -DEST_CODES = [WDW_CODE, DLR_CODE] - class Destination(object): def __init__(self, id = None, sync_on_init=True): @@ -29,36 +26,18 @@ def __init__(self, id = None, sync_on_init=True): pass if error: - raise ValueError('That destination is not available. id: ' + str(id) + '. Available destinations: {}'.format(", ".join(DEST_IDS))) + raise ValueError('That destination is not available. id: ' + str(id) + '. Available destinations: {}'.format(", ".join(DESTINATION_IDS))) self.__id = id + self.__name = self.__data['name'] + self.__entityType = self.__data['type'] - self.__db = DisneyDatabase(sync_on_init) - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - dest_data = c.execute("SELECT id, name, doc_id, destination_code, entityType FROM facilities WHERE entityType = 'destination' and id = ?", (self.__id,)).fetchone() - self.__id = dest_data[0] - self.__name = dest_data[1] - self.__doc_id = dest_data[2] - self.__dest_code = dest_data[3] - self.__entityType = dest_data[4] - self.__facilities_data = json.loads(c.execute("SELECT body FROM sync WHERE id = ?", (self.__doc_id,)).fetchone()[0]) - conn.commit() - conn.close() def get_possible_ids(self): """Returns a list of possible ids of this entityType""" - conn = sqlite3.connect(DisneyDatabase().db_path) - c = conn.cursor() - pos_ids = [row[0] for row in c.execute("SELECT id FROM facilities WHERE entityType = 'destination'")] - return pos_ids - - def get_destination_code(self): - """Returns the destination code""" - return self.__dest_code + return DESTINATION_IDS def get_id(self): """Returns the id of the destination""" @@ -68,10 +47,6 @@ def get_name(self): """Returns the name of the destination""" return self.__name - def get_doc_id(self): - """Returns the doc id""" - return self.__doc_id - def get_entityType(self): """Returns the entityType""" return self.__entityType @@ -84,18 +59,6 @@ def get_raw_data(self): """Returns the raw data from global-facility-service""" return self.__data - def get_raw_facilities_data(self): - """Returns the raw facilities data currently stored in the database""" - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - data = c.execute("SELECT body FROM sync WHERE id = ?", (self.__doc_id,)).fetchone() - conn.commit() - conn.close() - - if data is None: - return None - else: - return json.loads(data[0]) def get_attraction_ids(self): """ @@ -187,240 +150,215 @@ def get_character_ids(self): return ids - def get_wait_times(self): - """Returns a list of dictionaries in the form of {rideid:time} for attractions and entertainments for this destination""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) + def get_themeparkapi_data(self): + """Returns the list of dictionaries for all parks from the themeparks api""" - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() + all_data = [] - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE destination_code = ? and (entityType = 'Attraction' or entityType = 'Entertainment')", (self.__dest_code,))] + if self.__id == WDW_ID: + parks = WDW_PARK_IDS + else: + parks = DLR_PARK_IDS - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() + for id in parks: try: - if status_data is not None: - body = json.loads(status_data[0]) - data[row[0]] = body['waitMinutes'] + park = themeparkapi_ids[id] + all_data.extend(requests.get(f"https://api.themeparks.wiki/preview/parks/{park}/waittime").json()) except: continue - return data + return all_data + + + def get_wait_times(self): + """Returns a list of dictionaries in the form of {rideid:time} for attractions and entertainments for this destination""" + data = self.get_themeparkapi_data() + + times = {} + + for i in data: + id = i['id'].split("_")[-1] + try: + if i['meta']['type'] != "RESTAURANT": + times[id] = i['waitTime'] + except: + times[id] = i['waitTime'] + + return times def get_wait_times_detailed(self): """Returns a list of dictionaries in the form of {rideid:{name, status, wait_time}} for attractions and entertainments for this destination""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) + data = self.get_themeparkapi_data() - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() + times = {} - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE destination_code = ? and (entityType = 'Attraction' or entityType = 'Entertainment')", (self.__dest_code,))] - - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() + for i in data: + id = i['id'].split("_")[-1] + this = {} try: - if status_data is not None: - body = json.loads(status_data[0]) - this = {} - this['name'] = c.execute("SELECT name FROM facilities WHERE id = ?", (row[0],)).fetchone()[0] - this['status'] = body['status'] - this['wait_time'] = body['waitMinutes'] - this['last_updated'] = datetime.strptime(body['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") - this['entityType'] = row[1] - data[row[0]] = this - except Exception as e: - # print(e) - continue + if i['meta']['type'] != "RESTAURANT": + this['name'] = i['name'] + this['status'] = i['status'] + this['wait_time'] = i['waitTime'] + this['last_updated'] = datetime.strptime(i['lastUpdate'], "%Y-%m-%dT%H:%M:%S.%fZ") + this['entityType'] = i['meta']['type'].capitalize() + times[id] = this + except: + this['name'] = i['name'] + this['status'] = i['status'] + this['wait_time'] = i['waitTime'] + this['last_updated'] = datetime.strptime(i['lastUpdate'], "%Y-%m-%dT%H:%M:%S.%fZ") + this['entityType'] = "Entertainment" + times[id] = this - return data + return times def get_attraction_wait_times(self): """Returns a list of dictionaries in the form of {rideid:time} for attractions for this destination""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) + data = self.get_themeparkapi_data() - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() + times = {} - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE destination_code = ? and entityType = 'Attraction'", (self.__dest_code,))] - - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() + for i in data: + id = i['id'].split("_")[-1] try: - if status_data is not None: - body = json.loads(status_data[0]) - data[row[0]] = body['waitMinutes'] + if i['meta']['type'] == "ATTRACTION": + times[id] = i['waitTime'] except: continue - return data + return times def get_attraction_wait_times_detailed(self): """Returns a list of dictionaries in the form of {rideid:{name, status, wait_time}} for attractions for this destination""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) + data = self.get_themeparkapi_data() - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() + times = {} - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE destination_code = ? and entityType = 'Attraction'", (self.__dest_code,))] - - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() + for i in data: + id = i['id'].split("_")[-1] + this = {} try: - if status_data is not None: - body = json.loads(status_data[0]) - this = {} - this['name'] = c.execute("SELECT name FROM facilities WHERE id = ?", (row[0],)).fetchone()[0] - this['status'] = body['status'] - this['wait_time'] = body['waitMinutes'] - this['last_updated'] = datetime.strptime(body['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") - data[row[0]] = this - except Exception as e: - # print(e) + if i['meta']['type'] == "ATTRACTION": + this['name'] = i['name'] + this['status'] = i['status'] + this['wait_time'] = i['waitTime'] + this['last_updated'] = datetime.strptime(i['lastUpdate'], "%Y-%m-%dT%H:%M:%S.%fZ") + this['entityType'] = i['meta']['type'].capitalize() + times[id] = this + except: continue - return data + return times def get_entertainment_wait_times(self): """Returns a list of dictionaries in the form of {rideid:time} for entertainments for this destination""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() + data = self.get_themeparkapi_data() - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE destination_code = ? and entityType = 'Entertainment'", (self.__dest_code,))] + times = {} - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() - try: - if status_data is not None: - body = json.loads(status_data[0]) - data[row[0]] = body['waitMinutes'] - except: - continue + for i in data: + id = i['id'].split("_")[-1] + if 'type' not in i['meta'].keys(): + times[id] = i['waitTime'] - return data + return times def get_entertainment_wait_times_detailed(self): """Returns a list of dictionaries in the form of {rideid:{name, status, wait_time}} for entertainments for this destination""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE destination_code = ? and entityType = 'Entertainment'", (self.__dest_code,))] - - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() - try: - if status_data is not None: - body = json.loads(status_data[0]) - this = {} - this['name'] = c.execute("SELECT name FROM facilities WHERE id = ?", (row[0],)).fetchone()[0] - this['status'] = body['status'] - this['wait_time'] = body['waitMinutes'] - this['last_updated'] = datetime.strptime(body['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") - data[row[0]] = this - except Exception as e: - # print(e) - continue - - return data - - def get_raw_calendar_data(self, date=""): - """ - Returns raw calendar data on a date - """ - if self.__db.channel_exists('{}.calendar.1_0'.format(self.__dest_code)): - self.__db.sync_calendar_channel() - else: - self.__db.create_calendar_channel('{}.calendar.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - data = c.execute("SELECT body FROM calendar WHERE date = ?", (date,)).fetchone() - conn.commit() - conn.close() - - if data is None: - return None - else: - return json.loads(data[0]) - - def get_refurbishments(self, date=""): - """ - Returns a list of tuples in the form of (id, entityType) that are under refurbishment on a specified date - date = "YYY-MM-DD" - """ - if date == "": - DATE = datetime.today() - else: - year, month, day = date.split('-') - DATE = datetime(int(year), int(month), int(day)) - - STRDATE = "{}-{}-{}".format(DATE.year, self.__formatDate(str(DATE.month)), self.__formatDate(str(DATE.day))) - date = self.get_raw_calendar_data(STRDATE) - - ids = [] - try: - for i in date['refurbishments']: - split = i['facilityId'].split(";") - id = split[0] - entityType = split[1].split("=")[-1] - ids.append((id, entityType)) - except Exception as e: - print(e) - - return ids - - def get_closed(self, date=""): - """ - Returns a list of tuples in the form of (id, entityType) that are under closed on a specified date - date = "YYY-MM-DD" - """ - if date == "": - DATE = datetime.today() - else: - year, month, day = date.split('-') - DATE = datetime(int(year), int(month), int(day)) - - STRDATE = "{}-{}-{}".format(DATE.year, self.__formatDate(str(DATE.month)), self.__formatDate(str(DATE.day))) - date = self.get_raw_calendar_data(STRDATE) - - ids = [] - try: - for i in date['closed']: - split = i['facilityId'].split(";") - id = split[0] - entityType = split[1].split("=")[-1] - ids.append((id, entityType)) - except Exception as e: - print(e) - - return ids + data = self.get_themeparkapi_data() + + times = {} + + for i in data: + id = i['id'].split("_")[-1] + this = {} + if 'type' not in i['meta'].keys(): + this['name'] = i['name'] + this['status'] = i['status'] + this['wait_time'] = i['waitTime'] + this['last_updated'] = datetime.strptime(i['lastUpdate'], "%Y-%m-%dT%H:%M:%S.%fZ") + this['entityType'] = "Entertainment" + times[id] = this + + return times + + + # Deprecated, remove or replace? + # Replace with all park hours + # def get_raw_calendar_data(self, date=""): + # """ + # Returns raw calendar data on a date. Date should be in the form yyyy-mm-dd + # """ + # if self.__db.channel_exists('{}.calendar.1_0'.format(self.__dest_code)): + # self.__db.sync_calendar_channel() + # else: + # self.__db.create_calendar_channel('{}.calendar.1_0'.format(self.__dest_code)) + + # conn = sqlite3.connect(self.__db.db_path) + # c = conn.cursor() + # data = c.execute("SELECT body FROM calendar WHERE date = ?", (date,)).fetchone() + # conn.commit() + # conn.close() + + # if data is None: + # return None + # else: + # return json.loads(data[0]) + + # Can only get today's refurbishments now, will probably have to change this + # def get_refurbishments(self, date=""): + # """ + # Returns a list of tuples in the form of (id, entityType) that are under refurbishment on a specified date + # date = "YYY-MM-DD" + # """ + # if date == "": + # DATE = datetime.today() + # else: + # year, month, day = date.split('-') + # DATE = datetime(int(year), int(month), int(day)) + + # STRDATE = "{}-{}-{}".format(DATE.year, self.__formatDate(str(DATE.month)), self.__formatDate(str(DATE.day))) + # date = self.get_raw_calendar_data(STRDATE) + + # ids = [] + # try: + # for i in date['refurbishments']: + # split = i['facilityId'].split(";") + # id = split[0] + # entityType = split[1].split("=")[-1] + # ids.append((id, entityType)) + # except Exception as e: + # print(e) + + # return ids + + # Similar to refurbishments, can only get today's + # def get_closed(self, date=""): + # """ + # Returns a list of tuples in the form of (id, entityType) that are under closed on a specified date + # date = "YYY-MM-DD" + # """ + # if date == "": + # DATE = datetime.today() + # else: + # year, month, day = date.split('-') + # DATE = datetime(int(year), int(month), int(day)) + + # STRDATE = "{}-{}-{}".format(DATE.year, self.__formatDate(str(DATE.month)), self.__formatDate(str(DATE.day))) + # date = self.get_raw_calendar_data(STRDATE) + + # ids = [] + # try: + # for i in date['closed']: + # split = i['facilityId'].split(";") + # id = split[0] + # entityType = split[1].split("=")[-1] + # ids.append((id, entityType)) + # except Exception as e: + # print(e) + + # return ids def __formatDate(self, num): """ From 1273d78a50e1d88350dbe0cb8a61ac986c41dfea Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 21:14:33 -0500 Subject: [PATCH 09/20] removing database dependency and fixing/removing other functions --- MouseTools/entertainments.py | 135 +++++++++++++---------------------- 1 file changed, 51 insertions(+), 84 deletions(-) diff --git a/MouseTools/entertainments.py b/MouseTools/entertainments.py index dede569..b5417cb 100644 --- a/MouseTools/entertainments.py +++ b/MouseTools/entertainments.py @@ -6,12 +6,13 @@ from .auth import getHeaders from .parks import Park from .pointsofinterest import PointOfInterest +from .ids import themeparkapi_ids class Entertainment(object): - def __init__(self, id = None, sync_on_init=True): + def __init__(self, id = None): """ Constructor Function Gets all entertainment data available and stores various elements into variables. @@ -28,11 +29,6 @@ def __init__(self, id = None, sync_on_init=True): if error: raise ValueError('That entertainment is not available. id: ' + str(id)) - self.__db = DisneyDatabase(sync_on_init) - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - self.__id = id self.__name = self.__data['name'] self.__entityType = self.__data['type'] @@ -40,16 +36,11 @@ def __init__(self, id = None, sync_on_init=True): self.__subType = self.__data['subType'] except: self.__subType = None - doc_id_query = c.execute("SELECT doc_id from facilities where doc_id LIKE ?", ("%{};entityType={}".format(self.__id, self.__entityType),)).fetchone() - self.__doc_id = doc_id_query[0] if doc_id_query is not None else None - self.__facilities_data = self.get_raw_facilities_data() - # ID: 266858 doesn't have any of this information which causes a problem. try: self.__anc_dest_id = self.__data['ancestorDestination']['id'].split(';')[0] - self.__dest_code = c.execute("SELECT destination_code FROM facilities WHERE id = ?", (self.__anc_dest_id,)).fetchone()[0] except: self.__anc_dest_id = None - self.__dest_code = None + try: self.__anc_park_id = self.__data['links']['ancestorThemePark']['href'].split('/')[-1].split('?')[0] @@ -99,9 +90,6 @@ def __init__(self, id = None, sync_on_init=True): - conn.commit() - conn.close() - def get_possible_ids(self): """Returns a list of possible ids of this entityType""" entertainments = [] @@ -133,14 +121,6 @@ def get_subType(self): """Return object subType""" return self.__subType - def get_doc_id(self): - """Return object doc id""" - return self.__doc_id - - def get_destination_code(self): - """Return object destination code""" - return self.__dest_code - def get_ancestor_destination_id(self): """Return object ancestor theme or water park id""" return self.__anc_dest_id @@ -173,108 +153,78 @@ def get_raw_data(self): """Returns the raw data from global-facility-service""" return self.__data - def get_raw_facilities_data(self): - """Returns the raw facilities data currently stored in the database""" - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - data = c.execute("SELECT body FROM sync WHERE id = ?", (self.__doc_id,)).fetchone() - conn.commit() - conn.close() - - if data is None: - return None - else: - return json.loads(data[0]) - - def get_raw_facilitystatus_data(self): - """Returns the raw facilitystatus data from the database after syncing with Disney (returns most recent data)""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType=Entertainment".format(self.__dest_code, self.__id),)).fetchone() - if data is None: - return None - else: - return json.loads(data[0]) + def get_themeparkapi_data(self): + """Returns the dictionary from the themepark api for the given id""" + park = themeparkapi_ids[self.__anc_park_id] + themepark_id = f"{park}_{self.__id}" + all_data = requests.get(f"https://api.themeparks.wiki/preview/parks/{park}/waittime").json() + for i in all_data: + if i["id"] == themepark_id: + return i + return None def get_wait_time(self): """Return current wait time of the object. Returns None if object doesn't have a wait time or no wait currently exists (eg. closed)""" - data = self.get_raw_facilitystatus_data() + data = self.get_themeparkapi_data() if data is None: return None else: - return data['waitMinutes'] + return data['waitTime'] def get_status(self): """Return current status of the object.""" - data = self.get_raw_facilitystatus_data() + data = self.get_themeparkapi_data() if data is None: return None else: return data['status'] - # TODO might have to change this from facilitystatus data to scheduleType from today, or test if none from status then get from today instead def fastpass_available(self): """Returns a boolean of whether this object has FastPass""" - data = self.get_raw_facilitystatus_data() + data = self.get_themeparkapi_data() if data is None: return False else: - return data['fastPassAvailable'] == 'true' - - def fastpass_times(self): - """Returns the current start and end time of the FastPass""" - start_time = None - end_time = None - - if self.fastpass_available(): - data = self.get_raw_facilitystatus_data() - - start_time = datetime.strptime(data['fastPassStartTime'], "%Y-%m-%dT%H:%M:%SZ") - end_time = datetime.strptime(data['fastPassEndTime'], "%Y-%m-%dT%H:%M:%SZ") - - return start_time, end_time + return data['fastPass'] def get_last_update(self): """Returns facilities last update time as a datetime object""" - facility_data = self.get_raw_facilities_data() + facility_data = self.get_themeparkapi_data() if facility_data is None: return None else: - return datetime.strptime(facility_data['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") + return datetime.strptime(facility_data['lastUpdate'], "%Y-%m-%dT%H:%M:%S.%fZ") def get_coordinates(self): """Returns the object's latitude and longitude""" - facility_data = self.get_raw_facilities_data() + facility_data = self.get_themeparkapi_data() if facility_data is None: return None else: - return {"latitude": facility_data['latitude'], "longitude": facility_data['longitude']} + return {"latitude": facility_data['meta']['latitude'], "longitude": facility_data['meta']['longitude']} def get_description(self): - """Returns the object's descriptions""" - facility_data = self.get_raw_facilities_data() + """Returns the object's description""" + facility_data = self.__data if facility_data is None: return None else: - return facility_data['description'] + try: + return facility_data['descriptions']['shortDescription']['sections']['body'] + except: + return None - def get_list_image(self): - """Returns the url to the object's list image""" - facility_data = self.get_raw_facilities_data() + def get_media(self): + """Returns a dictionary of dictionaries of media relating to the entity""" + facility_data = self.__data if facility_data is None: return None else: - return facility_data['listImageUrl'] + return facility_data['media'] def get_facets(self): """Returns a list of dictionaries of the object's facets""" - facility_data = self.get_raw_facilities_data() + facility_data = self.get_themeparkapi_data() if facility_data is None: return None else: @@ -283,6 +233,23 @@ def get_facets(self): except: return None + def get_classifications(self): + """Returns a dictionary of lists of classifications related to the entity""" + + classifications = {} + + try: + for i in self.__data['classifications']: + id = i['id'].split("/")[-1] + if id not in classifications: + classifications[id] = [i['text']] + else: + classifications[id].append(i['text']) + except: + pass + + return classifications + def admission_required(self): """Returns boolean of admission required""" return self.__data['admissionRequired'] @@ -323,13 +290,13 @@ def get_associated_characters(self): chars.append(Character(data['entries'][i]['links']['self']['href'].split('/')[-1])) except: pass + return chars - def get_associated_characters(self): + def get_associated_character_ids(self): """ Returns a list of associated characters IDs """ - from .characters import Character chars = [] s = requests.get("https://api.wdpro.disney.go.com/global-pool-override-B/facility-service/associated-characters/{};entityType={}".format(self.__id, self.__entityType), headers=getHeaders()) From 0572ca94b3917347a0e5c80695dd4ea6d832bb93 Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 21:14:56 -0500 Subject: [PATCH 10/20] changes and fixes --- MouseTools/attractions.py | 3 +-- MouseTools/destinations.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/MouseTools/attractions.py b/MouseTools/attractions.py index 9750b31..14eb5d9 100644 --- a/MouseTools/attractions.py +++ b/MouseTools/attractions.py @@ -184,8 +184,7 @@ def get_coordinates(self): if facility_data is None: return None else: - return facility_data['meta']['latitude'], facility_data['meta']['longitude'] - + return {"latitude": facility_data['meta']['latitude'], "longitude": facility_data['meta']['longitude']} def get_description(self): """Returns the object's description""" diff --git a/MouseTools/destinations.py b/MouseTools/destinations.py index d5e59ef..71fb783 100644 --- a/MouseTools/destinations.py +++ b/MouseTools/destinations.py @@ -12,7 +12,7 @@ class Destination(object): - def __init__(self, id = None, sync_on_init=True): + def __init__(self, id = None): """ Constructor Function Allows access to various destination related data. From d723e7c1c8a7508c816ac262968e5138928414da Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 21:23:29 -0500 Subject: [PATCH 11/20] removing database dependency --- MouseTools/entertainmentvenues.py | 240 +----------------------------- 1 file changed, 4 insertions(+), 236 deletions(-) diff --git a/MouseTools/entertainmentvenues.py b/MouseTools/entertainmentvenues.py index 2cf77d7..282f77e 100644 --- a/MouseTools/entertainmentvenues.py +++ b/MouseTools/entertainmentvenues.py @@ -25,10 +25,6 @@ def __init__(self, id = None, sync_on_init=True): if error: raise ValueError('That entertainment venue is not available. id: ' + str(id)) - self.__db = DisneyDatabase(sync_on_init) - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - self.__id = id self.__name = self.__data['name'] @@ -37,15 +33,10 @@ def __init__(self, id = None, sync_on_init=True): self.__subType = self.__data['subType'] except: self.__subType = None - doc_id_query = c.execute("SELECT doc_id from facilities where doc_id LIKE ?", ("%{};entityType={}".format(self.__id, self.__entityType),)).fetchone() - self.__doc_id = doc_id_query[0] if doc_id_query is not None else None - self.__facilities_data = self.get_raw_facilities_data() try: self.__anc_dest_id = self.__data['ancestorDestination']['id'].split(';')[0] - self.__dest_code = c.execute("SELECT destination_code FROM facilities WHERE id = ?", (self.__anc_dest_id,)).fetchone()[0] except: self.__anc_dest_id = None - self.__dest_code = None try: self.__anc_park_id = self.__data['links']['ancestorThemePark']['href'].split('/')[-1].split('?')[0] @@ -93,8 +84,6 @@ def __init__(self, id = None, sync_on_init=True): except: self.__anc_ev_id = None - conn.commit() - conn.close() def get_possible_ids(self): """Returns a list of possible ids of this entityType""" @@ -127,14 +116,6 @@ def get_subType(self): """Return object subType""" return self.__subType - def get_doc_id(self): - """Return object doc id""" - return self.__doc_id - - def get_destination_code(self): - """Return object destination code""" - return self.__dest_code - def get_ancestor_destination_id(self): """Return object ancestor destination id""" return self.__anc_dest_id @@ -167,211 +148,6 @@ def get_raw_data(self): """Returns the raw data from global-facility-service""" return self.__data - def get_raw_facilities_data(self): - """Returns the raw facilities data currently stored in the database""" - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - data = c.execute("SELECT body FROM sync WHERE id = ?", (self.__doc_id,)).fetchone()[0] - conn.commit() - conn.close() - - if data is None: - return None - else: - return json.loads(data) - - def get_wait_times(self): - """Returns a list of dictionaries in the form of {rideid:time} for attractions and entertainments for this venue""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE entertainment_venue_id = ? and (entityType = 'Attraction' or entityType = 'Entertainment')", (self.__id,))] - - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() - try: - if status_data is not None: - body = json.loads(status_data[0]) - data[row[0]] = body['waitMinutes'] - except: - continue - - return data - - def get_wait_times_detailed(self): - """Returns a list of dictionaries in the form of {rideid:{name, status, wait_time}} for attractions and entertainments for this venue""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE entertainment_venue_id = ? and (entityType = 'Attraction' or entityType = 'Entertainment')", (self.__id,))] - - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() - try: - if status_data is not None: - body = json.loads(status_data[0]) - this = {} - this['name'] = c.execute("SELECT name FROM facilities WHERE id = ?", (row[0],)).fetchone()[0] - this['status'] = body['status'] - this['wait_time'] = body['waitMinutes'] - this['last_updated'] = datetime.strptime(body['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") - data[row[0]] = this - except Exception as e: - # print(e) - continue - - return data - - def get_attraction_wait_times(self): - """Returns a list of dictionaries in the form of {rideid:time} for attractions for this venue""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE entertainment_venue_id = ? and entityType = 'Attraction'", (self.__id,))] - - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() - try: - if status_data is not None: - body = json.loads(status_data[0]) - data[row[0]] = body['waitMinutes'] - except: - continue - - return data - - def get_attraction_wait_times_detailed(self): - """Returns a list of dictionaries in the form of {rideid:{name, status, wait_time}} for attractions for this venue""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE entertainment_venue_id = ? and entityType = 'Attraction'", (self.__id,))] - - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() - try: - if status_data is not None: - body = json.loads(status_data[0]) - this = {} - this['name'] = c.execute("SELECT name FROM facilities WHERE id = ?", (row[0],)).fetchone()[0] - this['status'] = body['status'] - this['wait_time'] = body['waitMinutes'] - this['last_updated'] = datetime.strptime(body['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") - data[row[0]] = this - except Exception as e: - # print(e) - continue - - return data - - def get_entertainment_wait_times(self): - """Returns a list of dictionaries in the form of {rideid:time} for entertainments for this venue""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE entertainment_venue_id = ? and entityType = 'Entertainment'", (self.__id,))] - - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() - try: - if status_data is not None: - body = json.loads(status_data[0]) - data[row[0]] = body['waitMinutes'] - except: - continue - - return data - - def get_entertainment_wait_times_detailed(self): - """Returns a list of dictionaries in the form of {rideid:{name, status, wait_time}} for entertainments for this venue""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE entertainment_venue_id = ? and entityType = 'Entertainment'", (self.__id,))] - - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() - try: - if status_data is not None: - body = json.loads(status_data[0]) - this = {} - this['name'] = c.execute("SELECT name FROM facilities WHERE id = ?", (row[0],)).fetchone()[0] - this['status'] = body['status'] - this['wait_time'] = body['waitMinutes'] - this['last_updated'] = datetime.strptime(body['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") - data[row[0]] = this - except Exception as e: - # print(e) - continue - - return data - - def get_status(self): - """Return current status of the object.""" - if self.__db.channel_exists('{}.today.1_0'.format(self.__dest_code)): - self.__db.sync_today_channel() - # maybe just sync this channel? and do same for previous methods - else: - self.__db.create_today_channel('{}.today.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - today_data = c.execute("""SELECT body FROM sync WHERE id = '{}.today.1_0.{}'""".format(self.__dest_code, self.__entityType)).fetchone() - - if today_data is None: - return None - else: - body = json.loads(today_data[0]) - try: - return body['facilities'][str(self.__id) + ';entityType=' + self.__entityType][0]['scheduleType'] - except: - return None - - def get_last_update(self): - """Returns facilities last update time as a datetime object""" - facility_data = self.get_raw_facilities_data() - if facility_data is None: - return None - else: - return datetime.strptime(facility_data['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") - def get_coordinates(self): """Returns the object's latitude and longitude""" try: @@ -387,21 +163,13 @@ def get_description(self): except: return None - def get_list_image(self): - """Returns the url to the object's list image""" - facility_data = self.get_raw_facilities_data() - if facility_data is None: - return None - else: - return facility_data['listImageUrl'] - - def get_detail_image(self): - """Returns the url to the object's detail image""" - facility_data = self.get_raw_facilities_data() + def get_media(self): + """Returns a dictionary of dictionaries of media relating to the entity""" + facility_data = self.__data if facility_data is None: return None else: - return facility_data['detailImageUrl'] + return facility_data['media'] def get_hours(self, date = ""): """ From 5af00074f12bef9137a29084e4faf5de79d362df Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 21:40:17 -0500 Subject: [PATCH 12/20] removing database dependency and fixing methods --- MouseTools/attractions.py | 9 +- MouseTools/entertainments.py | 7 +- MouseTools/entertainmentvenues.py | 2 +- MouseTools/facilities.py | 179 +++++++++++++----------------- 4 files changed, 85 insertions(+), 112 deletions(-) diff --git a/MouseTools/attractions.py b/MouseTools/attractions.py index 14eb5d9..74c8b16 100644 --- a/MouseTools/attractions.py +++ b/MouseTools/attractions.py @@ -180,11 +180,10 @@ def get_last_update(self): def get_coordinates(self): """Returns the object's latitude and longitude""" - facility_data = self.get_themeparkapi_data() - if facility_data is None: + try: + return self.__data['coordinates']['Guest Entrance']['gps'] + except: return None - else: - return {"latitude": facility_data['meta']['latitude'], "longitude": facility_data['meta']['longitude']} def get_description(self): """Returns the object's description""" @@ -207,7 +206,7 @@ def get_media(self): def get_facets(self): """Returns a list of dictionaries of the object's facets""" - facility_data = self.get_themeparkapi_data() + facility_data = self.__data if facility_data is None: return None else: diff --git a/MouseTools/entertainments.py b/MouseTools/entertainments.py index b5417cb..e1d4a79 100644 --- a/MouseTools/entertainments.py +++ b/MouseTools/entertainments.py @@ -197,11 +197,10 @@ def get_last_update(self): def get_coordinates(self): """Returns the object's latitude and longitude""" - facility_data = self.get_themeparkapi_data() - if facility_data is None: + try: + return self.__data['coordinates']['Guest Entrance']['gps'] + except: return None - else: - return {"latitude": facility_data['meta']['latitude'], "longitude": facility_data['meta']['longitude']} def get_description(self): """Returns the object's description""" diff --git a/MouseTools/entertainmentvenues.py b/MouseTools/entertainmentvenues.py index 282f77e..000911a 100644 --- a/MouseTools/entertainmentvenues.py +++ b/MouseTools/entertainmentvenues.py @@ -8,7 +8,7 @@ class EntertainmentVenue(object): - def __init__(self, id = None, sync_on_init=True): + def __init__(self, id = None): """ Constructor Function Gets all venue data available and stores various elements into variables. diff --git a/MouseTools/facilities.py b/MouseTools/facilities.py index 6e8a9fc..5a72261 100644 --- a/MouseTools/facilities.py +++ b/MouseTools/facilities.py @@ -9,7 +9,7 @@ class Facility(object): - def __init__(self, id = None, sync_on_init=True): + def __init__(self, id = None): """ Constructor Function Gets all facility data available and stores various elements into variables. @@ -26,10 +26,6 @@ def __init__(self, id = None, sync_on_init=True): if error: raise ValueError('That facility is not available. id: ' + str(id)) - self.__db = DisneyDatabase(sync_on_init) - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - self.__id = id self.__name = self.__data['name'] self.__entityType = self.__data['type'] @@ -37,15 +33,11 @@ def __init__(self, id = None, sync_on_init=True): self.__subType = self.__data['subType'] except: self.__subType = None - doc_id_query = c.execute("SELECT doc_id from facilities where doc_id LIKE ?", ("%{};entityType={}".format(self.__id, self.__entityType),)).fetchone() - self.__doc_id = doc_id_query[0] if doc_id_query is not None else None - self.__facilities_data = self.get_raw_facilities_data() + try: self.__anc_dest_id = self.__data['ancestorDestination']['id'].split(';')[0] - self.__dest_code = c.execute("SELECT destination_code FROM facilities WHERE id = ?", (self.__anc_dest_id,)).fetchone()[0] except: self.__anc_dest_id = None - self.__dest_code = None try: self.__anc_park_id = self.__data['links']['ancestorThemePark']['href'].split('/')[-1].split('?')[0] @@ -93,15 +85,21 @@ def __init__(self, id = None, sync_on_init=True): except: self.__anc_ev_id = None - conn.commit() - conn.close() + # There are just too many variations, could explore more + # def get_possible_ids(self): + # """Returns a list of possible ids of this entityType""" + # ids = [] + + # dest_data = requests.get("https://api.wdpro.disney.go.com/facility-service/destinations/{}".format(self.__anc_dest_id), headers=getHeaders()).json() + # data = requests.get(dest_data['links']['facilities']['href'], headers=getHeaders()).json() - def get_possible_ids(self): - """Returns a list of possible ids of this entityType""" - conn = sqlite3.connect(DisneyDatabase().db_path) - c = conn.cursor() - pos_ids = [row[0] for row in c.execute("SELECT id FROM facilities WHERE entityType ?", (self.__entityType,))] - return pos_ids + # for entry in data['entries']: + # try: + # ids.append(entry['links']['self']['href'].split('/')[-1].split('?')[0]) + # except: + # pass + + # return ids def get_id(self): """Return object id""" @@ -119,13 +117,9 @@ def get_subType(self): """Return object subType""" return self.__subType - def get_doc_id(self): - """Return object doc id""" - return self.__doc_id - - def get_destination_code(self): - """Return object destination code""" - return self.__dest_code + def get_ancestor_destination_id(self): + """Return object ancestor destination id""" + return self.__anc_dest_id def get_ancestor_park_id(self): """Return object ancestor theme or water park id""" @@ -151,107 +145,88 @@ def get_links(self): """Returns a dictionary of related links""" return self.__data['links'] - def get_raw_facilities_data(self): - """Returns the raw facilities data currently stored in the database""" - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - data = c.execute("SELECT body FROM sync WHERE id = ?", (self.__doc_id,)).fetchone() - conn.commit() - conn.close() - - if data is None: - return None - else: - return json.loads(data[0]) - - def get_status(self): - """Return current status of the object.""" - if self.__db.channel_exists('{}.today.1_0'.format(self.__dest_code)): - self.__db.sync_today_channel() - # maybe just sync this channel? and do same for previous methods - else: - self.__db.create_today_channel('{}.today.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - today_data = c.execute("SELECT body FROM sync WHERE id = ?", ('{}.today.1_0.{}'.format(self.__dest_code, self.__entityType),)).fetchone() - - if today_data is None: - return None - else: - body = json.loads(today_data[0]) - - return body['facilities'][self.__id + ';entityType=' + self.__entityType][0]['scheduleType'] - - def get_last_update(self): - """Returns facilities last update time as a datetime object""" - facility_data = self.get_raw_facilities_data() - if facility_data is None: - return None - else: - return datetime.strptime(facility_data['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") - def get_coordinates(self): """Returns the object's latitude and longitude""" - facility_data = self.get_raw_facilities_data() - if facility_data is None: + try: + return self.__data['coordinates']['Guest Entrance']['gps'] + except: return None - else: - return facility_data['latitude'], facility_data['longitude'] def get_description(self): - """Returns the object's descriptions""" - facility_data = self.get_raw_facilities_data() + """Returns the object's description""" + facility_data = self.__data if facility_data is None: return None else: - return facility_data['description'] + try: + return facility_data['descriptions']['shortDescription']['sections']['body'] + except: + return None - def get_list_image(self): - """Returns the url to the object's list image""" - facility_data = self.get_raw_facilities_data() + def get_media(self): + """Returns a dictionary of dictionaries of media relating to the entity""" + facility_data = self.__data if facility_data is None: return None else: - return facility_data['listImageUrl'] + return facility_data['media'] def get_facets(self): """Returns a list of dictionaries of the object's facets""" - facility_data = self.get_raw_facilities_data() + facility_data = self.__data if facility_data is None: return None else: - return facility_data['facets'] - - def get_todays_hours(self): - """Returns the start and end times for the object. Will return None, None if closed""" - start_time = None - end_time = None - - if self.__db.channel_exists('{}.today.1_0'.format(self.__dest_code)): - self.__db.sync_today_channel() - # maybe just sync this channel? and do same for previous methods - else: - self.__db.create_today_channel('{}.today.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() + try: + return facility_data['facets'] + except: + return None - today_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.today.1_0.{}".format(self.__dest_code, self.__entityType),)).fetchone() + def get_todays_hours(self, date=""): + """ + Gets the object's hours on a specific day and returns them as a datetime object. + Returns the object's hours in the following order: operating open, operating close, Extra Magic open, Extra Magic close. + Extra Magic hours will return None if there are none for today. + If all hours are None then Disney has no hours for that day. + date = "yyyy-mm-dd" + If you don't pass a date, it will get today's hours + """ - if today_data is None: - return start_time, end_time + if date == "": + DATE = datetime.today() else: - body = json.loads(today_data[0]) + year, month, day = date.split('-') + DATE = datetime(int(year), int(month), int(day)) - if body['facilities'][self.__id + ';entityType=' + self.__entityType][0]['scheduleType'] == 'Closed' or body['facilities'][self.__id + ';entityType=Attraction'][0]['scheduleType'] == 'Refurbishment': - return start_time, end_time + s = requests.get("https://api.wdpro.disney.go.com/facility-service/schedules/{}?date={}-{}-{}".format(self.__id, DATE.year, self.__formatDate(str(DATE.month)), self.__formatDate(str(DATE.day))), headers=getHeaders()) + data = json.loads(s.content) - start_time = datetime.strptime(body['facilities'][self.__id + ';entityType=' + self.__entityType][0]['startTime'], "%Y-%m-%dT%H:%M:%SZ") - end_time = datetime.strptime(body['facilities'][self.__id + ';entityType=' + self.__entityType][0]['endTime'], "%Y-%m-%dT%H:%M:%SZ") + operating_hours_start = None + operating_hours_end = None + extra_hours_start = None + extra_hours_end = None - return start_time, end_time + try: + for i in range(len(data['schedules'])): + if data['schedules'][i]['type'] == 'Operating': + operating_hours_start = datetime(DATE.year, DATE.month, DATE.day, int(data['schedules'][i]['startTime'][0:2]), int(data['schedules'][i]['startTime'][3:5])) + if int(data['schedules'][i]['endTime'][0:2]) >= 0 and int(data['schedules'][i]['endTime'][0:2]) <= 7: + DATETEMP = DATE + timedelta(days=1) + operating_hours_end = datetime(DATETEMP.year, DATETEMP.month, DATETEMP.day, int(data['schedules'][i]['endTime'][0:2]), int(data['schedules'][i]['endTime'][3:5])) + else: + operating_hours_end = datetime(DATE.year, DATE.month, DATE.day, int(data['schedules'][i]['endTime'][0:2]), int(data['schedules'][i]['endTime'][3:5])) + + if data['schedules'][i]['type'] == "Special Ticketed Event": + extra_hours_start = datetime(DATE.year, DATE.month, DATE.day, int(data['schedules'][i]['startTime'][0:2]), int(data['schedules'][i]['startTime'][3:5])) + if int(data['schedules'][i]['endTime'][0:2]) >= 0 and int(data['schedules'][i]['endTime'][0:2]) <= 7: + DATETEMP = DATE + timedelta(days=1) + extra_hours_end = datetime(DATETEMP.year, DATETEMP.month, DATETEMP.day, int(data['schedules'][i]['endTime'][0:2]), int(data['schedules'][i]['endTime'][3:5])) + else: + operating_hours_end = datetime(DATE.year, DATE.month, DATE.day, int(data['schedules'][i]['endTime'][0:2]), int(data['schedules'][i]['endTime'][3:5])) + + except KeyError: + pass + return operating_hours_start, operating_hours_end, extra_hours_start, extra_hours_end def __eq__(self, other): """ From 73702eaed46bc0ffbe1b5d807445a83097d1356c Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 21:53:37 -0500 Subject: [PATCH 13/20] removing database dependency and fixing methods --- MouseTools/parks.py | 277 ++++++++++++++------------------------------ 1 file changed, 87 insertions(+), 190 deletions(-) diff --git a/MouseTools/parks.py b/MouseTools/parks.py index 0b4247f..2203b82 100644 --- a/MouseTools/parks.py +++ b/MouseTools/parks.py @@ -4,6 +4,7 @@ import sqlite3 from datetime import datetime, timedelta from .auth import getHeaders +from .ids import themeparkapi_ids class Park(object): @@ -30,9 +31,6 @@ def __init__(self, id = None, sync_on_init=True): if error: raise ValueError('That park is not available. id: ' + str(id)) - self.__db = DisneyDatabase(sync_on_init) - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() self.__id = id @@ -42,15 +40,11 @@ def __init__(self, id = None, sync_on_init=True): self.__subType = self.__data['subType'] except: self.__subType = None - doc_id_query = c.execute("SELECT doc_id from facilities where doc_id LIKE ?", ("%{};entityType={}".format(self.__id, self.__entityType),)).fetchone() - self.__doc_id = doc_id_query[0] if doc_id_query is not None else None - self.__facilities_data = self.get_raw_facilities_data() + try: self.__anc_dest_id = self.__data['ancestorDestination']['id'].split(';')[0] - self.__dest_code = c.execute("SELECT destination_code FROM facilities WHERE id = ?", (self.__anc_dest_id,)).fetchone()[0] except: self.__anc_dest_id = None - self.__dest_code = None try: self.__anc_park_id = self.__data['links']['ancestorThemePark']['href'].split('/')[-1].split('?')[0] @@ -98,8 +92,6 @@ def __init__(self, id = None, sync_on_init=True): except: self.__anc_ev_id = None - conn.commit() - conn.close() def get_possible_ids(self): """Returns a list of possible ids of this entityType""" @@ -142,14 +134,6 @@ def get_subType(self): """Return object subType""" return self.__subType - def get_doc_id(self): - """Return object doc id""" - return self.__doc_id - - def get_destination_code(self): - """Return object destination code""" - return self.__dest_code - def get_ancestor_destination_id(self): """Return object ancestor destination id""" return self.__anc_dest_id @@ -182,209 +166,130 @@ def get_raw_data(self): """Returns the raw data from global-facility-service""" return self.__data - def get_raw_facilities_data(self): - """Returns the raw facilities data currently stored in the database""" - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - data = c.execute("SELECT body FROM sync WHERE id = ?", (self.__doc_id,)).fetchone()[0] - conn.commit() - conn.close() - - if data is None: - return None - else: - return json.loads(data) + def get_themeparkapi_data(self): + """Returns the list of dictionaries from the themepark api for the given id""" + park = themeparkapi_ids[self.__anc_park_id] + all_data = requests.get(f"https://api.themeparks.wiki/preview/parks/{park}/waittime").json() + return all_data def get_wait_times(self): """Returns a list of dictionaries in the form of {rideid:time} for attractions and entertainments for this park""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() + data = self.get_themeparkapi_data() - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE park_id = ? and (entityType = 'Attraction' or entityType = 'Entertainment')", (self.__id,))] + times = {} - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() + for i in data: + id = i['id'].split("_")[-1] try: - if status_data is not None: - body = json.loads(status_data[0]) - data[row[0]] = body['waitMinutes'] + if i['meta']['type'] != "RESTAURANT": + times[id] = i['waitTime'] except: - continue + times[id] = i['waitTime'] - return data + return times def get_wait_times_detailed(self): """Returns a list of dictionaries in the form of {rideid:{name, status, wait_time}} for attractions and entertainments for this park""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() + data = self.get_themeparkapi_data() - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE park_id = ? and (entityType = 'Attraction' or entityType = 'Entertainment')", (self.__id,))] + times = {} - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() + for i in data: + id = i['id'].split("_")[-1] + this = {} try: - if status_data is not None: - body = json.loads(status_data[0]) - this = {} - this['name'] = c.execute("SELECT name FROM facilities WHERE id = ?", (row[0],)).fetchone()[0] - this['status'] = body['status'] - this['wait_time'] = body['waitMinutes'] - this['last_updated'] = datetime.strptime(body['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") - this['entityType'] = row[1] - data[row[0]] = this - except Exception as e: - # print(e) - continue + if i['meta']['type'] != "RESTAURANT": + this['name'] = i['name'] + this['status'] = i['status'] + this['wait_time'] = i['waitTime'] + this['last_updated'] = datetime.strptime(i['lastUpdate'], "%Y-%m-%dT%H:%M:%S.%fZ") + this['entityType'] = i['meta']['type'].capitalize() + times[id] = this + except: + this['name'] = i['name'] + this['status'] = i['status'] + this['wait_time'] = i['waitTime'] + this['last_updated'] = datetime.strptime(i['lastUpdate'], "%Y-%m-%dT%H:%M:%S.%fZ") + this['entityType'] = "Entertainment" + times[id] = this - return data + return times def get_attraction_wait_times(self): """Returns a list of dictionaries in the form of {rideid:time} for attractions for this park""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) + data = self.get_themeparkapi_data() - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() + times = {} - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE park_id = ? and entityType = 'Attraction'", (self.__id,))] - - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() + for i in data: + id = i['id'].split("_")[-1] try: - if status_data is not None: - body = json.loads(status_data[0]) - data[row[0]] = body['waitMinutes'] + if i['meta']['type'] == "ATTRACTION": + times[id] = i['waitTime'] except: continue - return data + return times def get_attraction_wait_times_detailed(self): """Returns a list of dictionaries in the form of {rideid:{name, status, wait_time}} for attractions for this park""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() + data = self.get_themeparkapi_data() - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE park_id = ? and entityType = 'Attraction'", (self.__id,))] + times = {} - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() + for i in data: + id = i['id'].split("_")[-1] + this = {} try: - if status_data is not None: - body = json.loads(status_data[0]) - this = {} - this['name'] = c.execute("SELECT name FROM facilities WHERE id = ?", (row[0],)).fetchone()[0] - this['status'] = body['status'] - this['wait_time'] = body['waitMinutes'] - this['last_updated'] = datetime.strptime(body['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") - data[row[0]] = this - except Exception as e: - # print(e) + if i['meta']['type'] == "ATTRACTION": + this['name'] = i['name'] + this['status'] = i['status'] + this['wait_time'] = i['waitTime'] + this['last_updated'] = datetime.strptime(i['lastUpdate'], "%Y-%m-%dT%H:%M:%S.%fZ") + this['entityType'] = i['meta']['type'].capitalize() + times[id] = this + except: continue - return data + return times def get_entertainment_wait_times(self): """Returns a list of dictionaries in the form of {rideid:time} for entertainments for this park""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) + data = self.get_themeparkapi_data() - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() + times = {} - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE park_id = ? and entityType = 'Entertainment'", (self.__id,))] + for i in data: + id = i['id'].split("_")[-1] + if 'type' not in i['meta'].keys(): + times[id] = i['waitTime'] - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() - try: - if status_data is not None: - body = json.loads(status_data[0]) - data[row[0]] = body['waitMinutes'] - except: - continue - - return data + return times def get_entertainment_wait_times_detailed(self): """Returns a list of dictionaries in the form of {rideid:{name, status, wait_time}} for entertainments for this park""" - if self.__db.channel_exists('{}.facilitystatus.1_0'.format(self.__dest_code)): - self.__db.sync_facilitystatus_channel() - else: - self.__db.create_facilitystatus_channel('{}.facilitystatus.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - - ids = [row for row in c.execute("SELECT id, entityType FROM facilities WHERE park_id = ? and entityType = 'Entertainment'", (self.__id,))] - - data = {} - for row in ids: - status_data = c.execute("SELECT body FROM sync WHERE id = ?", ("{}.facilitystatus.1_0.{};entityType={}".format(self.__dest_code, row[0], row[1]),)).fetchone() - try: - if status_data is not None: - body = json.loads(status_data[0]) - this = {} - this['name'] = c.execute("SELECT name FROM facilities WHERE id = ?", (row[0],)).fetchone()[0] - this['status'] = body['status'] - this['wait_time'] = body['waitMinutes'] - this['last_updated'] = datetime.strptime(body['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") - data[row[0]] = this - except Exception as e: - # print(e) - continue - - return data - - def get_status(self): - """Return current status of the object.""" - if self.__db.channel_exists('{}.today.1_0'.format(self.__dest_code)): - self.__db.sync_today_channel() - # maybe just sync this channel? and do same for previous methods - else: - self.__db.create_today_channel('{}.today.1_0'.format(self.__dest_code)) - - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() + data = self.get_themeparkapi_data() - today_data = c.execute("""SELECT body FROM sync WHERE id = '{}.today.1_0.{}'""".format(self.__dest_code, self.__entityType)).fetchone() + times = {} - if today_data is None: - return None - else: - body = json.loads(today_data[0]) - - return body['facilities'][self.__id + ';entityType=' + self.__entityType][0]['scheduleType'] - - def get_last_update(self): - """Returns facilities last update time as a datetime object""" - facility_data = self.get_raw_facilities_data() - if facility_data is None: - return None - else: - return datetime.strptime(facility_data['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") + for i in data: + id = i['id'].split("_")[-1] + this = {} + if 'type' not in i['meta'].keys(): + this['name'] = i['name'] + this['status'] = i['status'] + this['wait_time'] = i['waitTime'] + this['last_updated'] = datetime.strptime(i['lastUpdate'], "%Y-%m-%dT%H:%M:%S.%fZ") + this['entityType'] = "Entertainment" + times[id] = this + + return times + + # Figure out how to get the current status + # def get_status(self): + # """Return current status of the object.""" + # park = themeparkapi_ids[self.__anc_park_id] + # all_data = requests.get(f"https://api.themeparks.wiki/preview/parks/{park}/calendar").json() def get_coordinates(self): """Returns the object's latitude and longitude""" @@ -401,21 +306,13 @@ def get_description(self): except: return None - def get_list_image(self): - """Returns the url to the object's list image""" - facility_data = self.get_raw_facilities_data() - if facility_data is None: - return None - else: - return facility_data['listImageUrl'] - - def get_detail_image(self): - """Returns the url to the object's detail image""" - facility_data = self.get_raw_facilities_data() + def get_media(self): + """Returns a dictionary of dictionaries of media relating to the entity""" + facility_data = self.__data if facility_data is None: return None else: - return facility_data['detailImageUrl'] + return facility_data['media'] def admission_required(self): """Returns boolean of admission required""" From de1dc5de7929fbd995e13361c8d8c0d385c00216 Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Thu, 7 Jan 2021 21:56:00 -0500 Subject: [PATCH 14/20] removing database dependency and fixing other methods --- MouseTools/parks.py | 2 +- MouseTools/pointsofinterest.py | 83 +++++++++------------------------- 2 files changed, 23 insertions(+), 62 deletions(-) diff --git a/MouseTools/parks.py b/MouseTools/parks.py index 2203b82..9cd1408 100644 --- a/MouseTools/parks.py +++ b/MouseTools/parks.py @@ -9,7 +9,7 @@ class Park(object): - def __init__(self, id = None, sync_on_init=True): + def __init__(self, id = None): """ Constructor Function Gets all park data available and stores various elements into variables. diff --git a/MouseTools/pointsofinterest.py b/MouseTools/pointsofinterest.py index de418cc..9bff06c 100644 --- a/MouseTools/pointsofinterest.py +++ b/MouseTools/pointsofinterest.py @@ -8,7 +8,7 @@ class PointOfInterest(object): - def __init__(self, id = None, sync_on_init=True): + def __init__(self, id = None): """ Constructor Function Gets all points of interest data available and stores various elements into variables. @@ -25,10 +25,6 @@ def __init__(self, id = None, sync_on_init=True): if error: raise ValueError('That point of interest is not available. id: ' + str(id)) - self.__db = DisneyDatabase(sync_on_init) - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - self.__id = id self.__name = self.__data['name'] self.__entityType = self.__data['type'] @@ -36,15 +32,11 @@ def __init__(self, id = None, sync_on_init=True): self.__subType = self.__data['subType'] except: self.__subType = None - doc_id_query = c.execute("SELECT doc_id from facilities where doc_id LIKE ?", ("%{};entityType={}".format(self.__id, self.__entityType),)).fetchone() - self.__doc_id = doc_id_query[0] if doc_id_query is not None else None - self.__facilities_data = self.get_raw_facilities_data() + try: self.__anc_dest_id = self.__data['ancestorDestination']['id'].split(';')[0] - self.__dest_code = c.execute("SELECT destination_code FROM facilities WHERE id = ?", (self.__anc_dest_id,)).fetchone()[0] except: self.__anc_dest_id = None - self.__dest_code = None try: self.__anc_park_id = self.__data['links']['ancestorThemePark']['href'].split('/')[-1].split('?')[0] @@ -92,15 +84,14 @@ def __init__(self, id = None, sync_on_init=True): except: self.__anc_ev_id = None - conn.commit() - conn.close() - def get_possible_ids(self): - """Returns a list of possible ids of this entityType""" - conn = sqlite3.connect(DisneyDatabase().db_path) - c = conn.cursor() - pos_ids = [row[0] for row in c.execute("SELECT id FROM facilities WHERE entityType = ?", (self.__entityType,))] - return pos_ids + + # def get_possible_ids(self): + # """Returns a list of possible ids of this entityType""" + # conn = sqlite3.connect(DisneyDatabase().db_path) + # c = conn.cursor() + # pos_ids = [row[0] for row in c.execute("SELECT id FROM facilities WHERE entityType = ?", (self.__entityType,))] + # return pos_ids def get_id(self): """Return object id""" @@ -118,14 +109,6 @@ def get_subType(self): """Return object subType""" return self.__subType - def get_doc_id(self): - """Return object doc id""" - return self.__doc_id - - def get_destination_code(self): - """Return object destination code""" - return self.__dest_code - def get_ancestor_destination_id(self): """Return object ancestor destination id""" return self.__anc_dest_id @@ -158,53 +141,31 @@ def get_raw_data(self): """Returns the raw data from global-facility-service""" return self.__data - def get_raw_facilities_data(self): - """Returns the raw facilities data currently stored in the database""" - conn = sqlite3.connect(self.__db.db_path) - c = conn.cursor() - data = c.execute("SELECT body FROM sync WHERE id = ?", (self.__doc_id,)).fetchone()[0] - conn.commit() - conn.close() - - if data is None: - return None - else: - return json.loads(data) - - def get_last_update(self): - """Returns facilities last update time as a datetime object""" - facility_data = self.get_raw_facilities_data() - if facility_data is None: - return None - else: - return datetime.strptime(facility_data['lastUpdate'], "%Y-%m-%dT%H:%M:%SZ") - def get_coordinates(self): """Returns the object's latitude and longitude""" - facility_data = self.get_raw_facilities_data() - if facility_data is None: + try: + return self.__data['coordinates']['Guest Entrance']['gps'] + except: return None - else: - return facility_data['latitude'], facility_data['longitude'] def get_description(self): - """Returns the object's descriptions""" - facility_data = self.get_raw_facilities_data() + """Returns the object's description""" + facility_data = self.__data if facility_data is None: return None else: - return facility_data['description'] + try: + return facility_data['descriptions']['shortDescription']['sections']['body'] + except: + return None - def get_list_image(self): - """Returns the url to the object's list image""" - facility_data = self.get_raw_facilities_data() + def get_media(self): + """Returns a dictionary of dictionaries of media relating to the entity""" + facility_data = self.__data if facility_data is None: return None else: - try: - return facility_data['listImageUrl'] - except: - return None + return facility_data['media'] def admission_required(self): """Returns boolean of admission required""" From 4f90819441f75f79e9569c51644b705c69fd6ac2 Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Mon, 11 Jan 2021 12:07:13 -0500 Subject: [PATCH 15/20] beta 1 --- MouseTools/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MouseTools/__init__.py b/MouseTools/__init__.py index 194f277..c94317c 100644 --- a/MouseTools/__init__.py +++ b/MouseTools/__init__.py @@ -11,6 +11,6 @@ name = "MouseTools" -__version__ = "2.1.0" +__version__ = "2.1.0b1" __all__ = ["Destination", "Park", "EntertainmentVenue", "Attraction", "Entertainment", "Facility", "Character", "PointOfInterest", "DisneyDatabase"] From 484080ece50a15ff7755414baeb547b368146db2 Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Mon, 11 Jan 2021 12:10:07 -0500 Subject: [PATCH 16/20] update readme --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index e19aa28..171f1b7 100644 --- a/README.md +++ b/README.md @@ -17,16 +17,13 @@ pip install git+https://github.com/scaratozzolo/MouseTools ### Example usage: -The first time you load MouseTools in any project, it will take a while to load as the initial database is set up and created. There is a lot of data to load and parse so just be patient. After this it shouldn't take as long as syncing takes less time. ```python import MouseTools wdw_dest = MouseTools.Destination(80007798) print(wdw_dest.get_park_ids()) -# sync_on_init means sync the database with Disney on object instantiation. Default is True. -# This parameter is helpful when creating many objects back to back as syncing only once is necessary. -dlr_dest = MouseTools.Destination(80008297, sync_on_init=True) +dlr_dest = MouseTools.Destination(80008297) print(dlr_dest.get_attraction_ids()) mk = MouseTools.Park(80007944) From 414c029f0bc0c425efbcc2f0ea10f77120b193f0 Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Mon, 11 Jan 2021 12:14:38 -0500 Subject: [PATCH 17/20] remove database --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index f92ae11..11c6d5b 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,5 @@ import setuptools from MouseTools.__init__ import __version__ -from MouseTools import DisneyDatabase From 73ad21d956eb9ab2476ceb8a168604a75ae8f714 Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Mon, 11 Jan 2021 12:15:12 -0500 Subject: [PATCH 18/20] remove database file requirement --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 11c6d5b..97b68f9 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,6 @@ long_description_content_type="text/markdown", url="https://github.com/scaratozzolo/MouseTools", packages=setuptools.find_packages(), - package_data = {'MouseTools': ['MouseTools.db']}, install_requires=["requests"], classifiers=( "Programming Language :: Python :: 3.7", From a9c150f648cdd08bda27673368d643288f033a2f Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Wed, 3 Mar 2021 14:34:59 -0500 Subject: [PATCH 19/20] 2.1.0 --- MouseTools/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MouseTools/__init__.py b/MouseTools/__init__.py index c94317c..194f277 100644 --- a/MouseTools/__init__.py +++ b/MouseTools/__init__.py @@ -11,6 +11,6 @@ name = "MouseTools" -__version__ = "2.1.0b1" +__version__ = "2.1.0" __all__ = ["Destination", "Park", "EntertainmentVenue", "Attraction", "Entertainment", "Facility", "Character", "PointOfInterest", "DisneyDatabase"] From 5db41d37fa3bdfee09b086d10d8a07d38e0d2856 Mon Sep 17 00:00:00 2001 From: Scott Caratozzolo Date: Wed, 3 Mar 2021 14:36:52 -0500 Subject: [PATCH 20/20] 2021 --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 19a3cdd..852f98f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Scott Caratozzolo +Copyright (c) 2021 Scott Caratozzolo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal