diff --git a/channelInfo.py b/channelInfo.py index 39730cc..07eed27 100644 --- a/channelInfo.py +++ b/channelInfo.py @@ -1,238 +1,134 @@ +from dataclasses import dataclass + + +@dataclass +class ChannelData: + shortname: str + stationname: str + has_data: bool + primary_color: str + secondary_color: str + + channels = { - "oe1": { - "shortname": "oe1", - "streamurl": "//oe1shoutcast.sf.apa.at/;", - "strmtype": "audio/mpeg", - "tracklist": "//hop.orf.at/img-trackservice/oe1.js", - "curProgram": "https://tube.orf.at/broadcastSchedule/currentBroadcast.jsonp", - "leftbuttonstring": "Hitlist", - "midbuttonstring": "Podcasts", - "infodata": "./infos/oe1infos.html", - "aticon": "./images/oe1-aticon.png", - "statncss": "./css/oe1.css", - "stationname": "Radio Österreich 1", - "cHasData": False, - "cPrimaryColor": "#b11a1a", - "cSecondaryColor": "#ffffff", - "cStationName": "Radio Ö1" + "oe1": ChannelData( + shortname="oe1", + stationname="Radio Ö1", + has_data=True, + primary_color="#b11a1a", + secondary_color="#ffffff" + ), + "oe3": ChannelData( + shortname="oe3", + has_data=True, + primary_color="#002350", + secondary_color="#E10032", + stationname="Hitradio Ö3" - }, - "oe3": { - "shortname": "oe3", - "streamurl": "//oe3shoutcast.sf.apa.at/;", - "strmtype": "audio/mpeg", - "tracklist": "http://ms01.oe3.fm/oe3metafiles/RMX/RMWEB.PHP?Res=200&Format=json&callback=onair&Type=long", - "curProgram": "http://ms01.oe3.fm/oe3metafiles/ModAK/ShowInfo.php?ImgRes=HD&InfoType=Full&Format=json&callback=sendung", - "leftbuttonstring": "Hitlist", - "midbuttonstring": "Podcasts", - "infodata": "./infos/oe3infos.html", - "aticon": "./images/oe3-aticon.png", - "statncss": "./css/oe3b.css", - "chcolor": "#f04040", - "stationname": "hitradio Ö3", - "cHasData": True, - "cPrimaryColor": "#002350", - "cSecondaryColor": "#E10032", - "cStationName": "Hitradio Ö3" - - }, - "fm4": { - "shortname": "fm4", - "streamurl": "//fm4shoutcast.sf.apa.at/;", - "strmtype": "audio/mpeg", - "tracklist": "//hop.orf.at/img-trackservice/fm4.js", - "curProgram": "https://tube.orf.at/broadcastSchedule/currentBroadcast.jsonp?scheme=Wochen-Plan-Fm4.xml", - "leftbuttonstring": "Hitlist", - "midbuttonstring": "Podcasts", - "infodata": "./infos/fm4infos.html", - "aticon": "./images/fm4-aticon.png", - "statncss": "./css/fm4b.css", - "stationname": "Radio FM4", - "cHasData": True, - "cPrimaryColor": "#FFE500", - "cSecondaryColor": "#000000", - }, - "bgl": { - "shortname": "bgl", - "streamurl": "//oe2bshoutcast.sf.apa.at/;", - "strmtype": "audio/mpeg", - "tracklist": "//hop.orf.at/img-trackservice/bgl.js", - "curProgram": "https://tube.orf.at/broadcastSchedule/currentBroadcast.jsonp?scheme=sendungsplan-bgl.xml", - "leftbuttonstring": "Hitlist", - "midbuttonstring": "Podcasts", - "infodata": "./infos/bglinfos.html", - "aticon": "./images/bgl-aticon.png", - "anicon": "./images/bgl-aticon-128.png", - "statncss": "./css/bgl.css", - "stationname": "Radio Burgenland", - "cHasData": True, - "cPrimaryColor": "#ffa60f", - "cSecondaryColor": "#d32824" - }, - "ktn": { - "shortname": "ktn", - "streamurl": "//oe2kshoutcast.sf.apa.at/;", - "strmtype": "audio/mpeg", - "tracklist": "//hop.orf.at/img-trackservice/ktn.js", - "curProgram": "https://tube.orf.at/broadcastSchedule/currentBroadcast.jsonp?scheme=sendungsplan-ktn.xml", - "leftbuttonstring": "Tracklist", - "midbuttonstring": "", - "infodata": "./infos/ktninfos.html", - "aticon": "./images/ktn-aticon.png", - "statncss": "./css/ktn.css", - "stationname": "Radio Kärnten", - "cHasData": False, - "cPrimaryColor": "#bc1716", - "cSecondaryColor": "#ffcd00" - }, - "noe": { - "shortname": "noe", - "streamurl": "//oe2nshoutcast.sf.apa.at/;", - "strmtype": "audio/mpeg", - "tracklist": "//hop.orf.at/img-trackservice/noe.js", - "curProgram": "https://tube.orf.at/broadcastSchedule/currentBroadcast.jsonp?scheme=sendungsplan-noe.xml", - "leftbuttonstring": "Hitlist", - "midbuttonstring": "Podcasts", - "infodata": "./infos/noeinfos.html", - "aticon": "./images/noe-aticon.png", - "statncss": "./css/noe.css", - "stationname": "Radio Niederösterreich", - "cHasData": True, - "cPrimaryColor": "#002777", - "cSecondaryColor": "#ffcd00" - }, - "ooe": { - "shortname": "ooe", - "streamurl": "//oe2oshoutcast.sf.apa.at/;", - "strmtype": "audio/mpeg", - "tracklist": "//hop.orf.at/img-trackservice/ooe.js", - "curProgram": "https://tube.orf.at/broadcastSchedule/currentBroadcast.jsonp?scheme=sendungsplan-ooe.xml", - "leftbuttonstring": "Hitlist", - "midbuttonstring": "", - "infodata": "./infos/ooeinfos.html", - "aticon": "./images/ooe-aticon.png", - "statncss": "./css/ooe.css", - "stationname": "Radio Oberösterreich", - "deskstream": "http://orfradio.liwest.at/liveHQ.m3u", - "cHasData": True, - "cPrimaryColor": "#bc1716", - "cSecondaryColor": "#ffffff" - }, - "sbg": { - "shortname": "sbg", - "streamurl": "//oe2sshoutcast.sf.apa.at/;", - "strmtype": "audio/mpeg", - "tracklist": "//hop.orf.at/img-trackservice/sbg.js", - "curProgram": "https://tube.orf.at/broadcastSchedule/currentBroadcast.jsonp?scheme=sendungsplan-sbg.xml", - "leftbuttonstring": "Hitlist", - "midbuttonstring": "", - "infodata": "./infos/sbginfos.html", - "aticon": "./images/sbg-aticon.png", - "splash": "./images/sbg-splash.png", - "statncss": "./css/sbg.css", - "stationname": "Radio Salzburg", - "cHasData": True, - "cPrimaryColor": "#bc1716", - "cSecondaryColor": "#ffffff" - }, - "stm": { - "shortname": "stm", - "streamurl": "//oe2stshoutcast.sf.apa.at/;", - "strmtype": "audio/mpeg", - "tracklist": "//hop.orf.at/img-trackservice/stmk.js", - "curProgram": "https://tube.orf.at/broadcastSchedule/currentBroadcast.jsonp?scheme=sendungsplan-stm.xml", - "leftbuttonstring": "Hitlist", - "midbuttonstring": "Podcasts", - "infodata": "./infos/stminfos.html", - "aticon": "./images/stm-aticon.png", - "statncss": "./css/stm.css", - "stationname": "Radio Steiermark", - "cHasData": True, - "cPrimaryColor": "#006843", - "cSecondaryColor": "#ffffff" - }, - "tir": { - "shortname": "tir", - "streamurl": "//oe2tshoutcast.sf.apa.at/;", - "strmtype": "audio/mpeg", - "tracklist": "//hop.orf.at/img-trackservice/tir.js", - "curProgram": "https://tube.orf.at/broadcastSchedule/currentBroadcast.jsonp?scheme=sendungsplan-tir.xml", - "leftbuttonstring": "Hitlist", - "midbuttonstring": "Podcasts", - "infodata": "./infos/tirinfos.html", - "aticon": "./images/tir-aticon.png", - "statncss": "./css/tir.css", - "stationname": "Radio Tirol", - "cHasData": True, - "cPrimaryColor": "#bc1716", - "cSecondaryColor": "#ffffff" - }, - "vbg": { - "shortname": "vbg", - "streamurl": "//oe2vshoutcast.sf.apa.at/;", - "strmtype": "audio/mpeg", - "tracklist": "//hop.orf.at/img-trackservice/vbg.js", - "curProgram": "https://tube.orf.at/broadcastSchedule/currentBroadcast.jsonp?scheme=sendungsplan-vbg.xml", - "leftbuttonstring": "Hitlist", - "midbuttonstring": "Podcasts", - "infodata": "./infos/vbginfos.html", - "aticon": "./images/vbg-aticon.png", - "statncss": "./css/vbg.css", - "stationname": "Radio Vorarlberg", - "cHasData": False, - "cPrimaryColor": "#bc1716", - "cSecondaryColor": "#ffffff" - }, - "wie": { - "shortname": "wie", - "streamurl": "//oe2w2shoutcast.sf.apa.at/;", - "strmtype": "audio/mpeg", - "tracklist": "//hop.orf.at/img-trackservice/wien.js", - "curProgram": "https://tube.orf.at/broadcastSchedule/currentBroadcast.jsonp?scheme=sendungsplan-wie.xml", - "leftbuttonstring": "Hitlist", - "midbuttonstring": "Podcasts", - "infodata": "./infos/wieinfos.html", - "aticon": "./images/wie-aticon.png", - "splash": "./images/wie-splash.png", - "statncss": "./css/wie.css", - "stationname": "Radio Wien", - "cHasData": True, - "cPrimaryColor": "#ee7e01", - "cSecondaryColor": "#552382" - }, - "kht": { - "shortname": "kht", - "stationname": "Kronehit", - "cHasData": True, - "cPrimaryColor": "#000000", - "cSecondaryColor": "#b89c4f" - }, - "886": { - "shortname": "886", - "stationname": "Radio 88.6", - "cHasData": True, - "cPrimaryColor": "#123e6b", - "cSecondaryColor": "#ffe116" - }, - "ara": { - "shortname": "ara", - "stationname": "Radio Arabella", - "cHasData": True, - "cPrimaryColor": "#003e88", - "cSecondaryColor": "#e6007e" - }, - "eng": { - "shortname": "eng", - "stationname": "Engergy Wien/Nö/Bgld", - "cHasData": True, - "cPrimaryColor": "#000000", - "cSecondaryColor": "#E2001A" - }, - "all": { - "shortname": "all", - "stationname": "Alle", - "cHasData": True, - "cPrimaryColor": "black", - "cSecondaryColor": "white" - } + ), + "fm4": ChannelData( + shortname="fm4", + stationname="Radio FM4", + has_data=True, + primary_color="#FFE500", + secondary_color="#000000", + ), + "bgl": ChannelData( + shortname="bgl", + stationname="Radio Burgenland", + has_data=True, + primary_color="#ffa60f", + secondary_color="#d32824" + ), + "ktn": ChannelData( + shortname="ktn", + stationname="Radio Kärnten", + has_data=True, + primary_color="#bc1716", + secondary_color="#ffcd00" + ), + "noe": ChannelData( + shortname="noe", + stationname="Radio Niederösterreich", + has_data=True, + primary_color="#002777", + secondary_color="#ffcd00" + ), + "ooe": ChannelData( + shortname="ooe", + stationname="Radio Oberösterreich", + has_data=True, + primary_color="#bc1716", + secondary_color="#ffffff" + ), + "sbg": ChannelData( + shortname="sbg", + stationname="Radio Salzburg", + has_data=True, + primary_color="#bc1716", + secondary_color="#ffffff" + ), + "stm": ChannelData( + shortname="stm", + stationname="Radio Steiermark", + has_data=True, + primary_color="#006843", + secondary_color="#ffffff" + ), + "tir": ChannelData( + shortname="tir", + stationname="Radio Tirol", + has_data=True, + primary_color="#bc1716", + secondary_color="#ffffff" + ), + "vbg": ChannelData( + shortname="vbg", + stationname="Radio Vorarlberg", + has_data=True, + primary_color="#bc1716", + secondary_color="#ffffff" + ), + "wie": ChannelData( + shortname="wie", + stationname="Radio Wien", + has_data=True, + primary_color="#ee7e01", + secondary_color="#552382" + ), + "kht": ChannelData( + shortname="kht", + stationname="Kronehit", + has_data=True, + primary_color="#000000", + secondary_color="#b89c4f" + ), + "886": ChannelData( + shortname="886", + stationname="Radio 88.6", + has_data=True, + primary_color="#123e6b", + secondary_color="#ffe116" + ), + "ara": ChannelData( + shortname="ara", + stationname="Radio Arabella", + has_data=True, + primary_color="#003e88", + secondary_color="#e6007e" + ), + "eng": ChannelData( + shortname="eng", + stationname="Engergy Wien/Nö/Bgld", + has_data=True, + primary_color="#000000", + secondary_color="#E2001A" + ), + "all": ChannelData( + shortname="all", + stationname="Alle", + has_data=True, + primary_color="black", + secondary_color="white" + ), } diff --git a/create.py b/create.py index 73cf2dd..833ded8 100644 --- a/create.py +++ b/create.py @@ -7,12 +7,6 @@ for i in [Channel, Song, Play]: i.create_table() for id, channel in channelInfo.channels.items(): - if "streamurl" in channel: - streamurl = "https:" + channel["streamurl"].replace(";", "") - else: - streamurl = None - if "cStationName" in channel: - channel["stationname"] = channel["cStationName"] - Channel.create(shortname=channel["shortname"], streamurl=streamurl, - stationname=channel["stationname"], has_data=channel["cHasData"], - primary_color=channel["cPrimaryColor"], secondary_color=channel["cSecondaryColor"]) + print("create", channel.stationname) + Channel.create(shortname=channel.shortname, stationname=channel.stationname, has_data=channel.has_data, + primary_color=channel.primary_color, secondary_color=channel.secondary_color) diff --git a/fetch.py b/fetch.py index 989d157..03f078a 100644 --- a/fetch.py +++ b/fetch.py @@ -1,17 +1,15 @@ from datetime import timedelta import sentry_sdk +from peewee import DoesNotExist, IntegrityError + import config from models import * -from parser import kronehit, aas, orf, ara +from parser import KroneHitFetcher, AchtundachzigsechsFetcher, ArabellaFetcher, OrfFetcher if config.sentryDSN: client = sentry_sdk.init(dsn=config.sentryDSN) -headers = { - 'User-Agent': 'Mozilla/5.0 (compatible; RadioStats/1.0;)', -} - def detect_show(artist, title): return "Ö3" in artist or "LiveStream" in title or "Radio Tirol" in title \ @@ -49,17 +47,17 @@ def add_entry(time, artist, title): for channel in Channel.select(): if channel.has_data: if channel.shortname == "kht": - pars = kronehit + pars = KroneHitFetcher() elif channel.shortname == "886": - pars = aas + pars = AchtundachzigsechsFetcher() elif channel.shortname == "ara": - pars = ara + pars = ArabellaFetcher() elif channel.shortname == "eng": continue elif channel.shortname == "all": continue else: - pars = orf + pars = OrfFetcher() for time, artist, title in pars.get(channel): add_entry(time, artist, title) diff --git a/models.py b/models.py index 4f97427..2b08c0d 100644 --- a/models.py +++ b/models.py @@ -1,11 +1,10 @@ -from peewee import * +from peewee import CharField, BooleanField, DateTimeField, ForeignKeyField from basemodel import BaseModel class Channel(BaseModel): shortname = CharField(unique=True, max_length=5) - streamurl = CharField(null=True) stationname = CharField() has_data = BooleanField() primary_color = CharField(max_length=7) diff --git a/parser/__init__.py b/parser/__init__.py index 3cd4350..f976bec 100644 --- a/parser/__init__.py +++ b/parser/__init__.py @@ -1,4 +1,6 @@ -from . import aas -from . import ara -from . import kronehit -from . import orf +from .base import BaseFetcher +from .aas import AchtundachzigsechsFetcher +from .ara import ArabellaFetcher +from .eng import EnergyFetcher +from .kronehit import KroneHitFetcher +from .orf import OrfFetcher diff --git a/parser/aas.py b/parser/aas.py index 530fe05..47840c8 100644 --- a/parser/aas.py +++ b/parser/aas.py @@ -1,18 +1,22 @@ -from utils import * from sentry_sdk import capture_exception + +from parser import BaseFetcher +from utils import * + URL = "https://meta.radio886.at/886/0" -def get(channel): - data = fetch(URL, True) - if "data" not in data: - capture_exception(Exception("886 didn't return any data.")) - return [] - for track in fetch(URL, True)["data"]: - artist = track["name"] - title = track["title"] - try: - time = time_to_date(string_to_time(track["scheduled_time"])) - yield time, artist, title - except ValueError as e: # in case time is 24:02:31 or similar - print(e) +class AchtundachzigsechsFetcher(BaseFetcher): + def get(self, channel): + data = fetch(URL, True) + if "data" not in data: + capture_exception(Exception("886 didn't return any data.")) + return [] + for track in fetch(URL, True)["data"]: + artist = track["name"] + title = track["title"] + try: + time = time_to_date(string_to_time(track["scheduled_time"])) + yield time, artist, title + except ValueError as e: # in case time is 24:02:31 or similar + print(e) diff --git a/parser/ara.py b/parser/ara.py index d30f915..e7bc80f 100644 --- a/parser/ara.py +++ b/parser/ara.py @@ -1,15 +1,17 @@ +from parser import BaseFetcher from utils import * URL = "http://www.arabella.at/live-feed/ajax.php?station=zenon-rp-wien" -def get(channel): - response=fetch(URL, True) - if response: - for track in response["songs"]: - artist = track["artist"] - title = track["title"] - dt = track["start_date_time"] - time = datetime(year=int(dt["year"]), month=int(dt["month"]), day=int(dt["day"]), - hour=int(dt["hours"]), minute=int(dt["minutes"]), second=int(dt["seconds"])) - yield time, artist, title +class ArabellaFetcher(BaseFetcher): + def get(self, channel): + response = fetch(URL, True) + if response: + for track in response["songs"]: + artist = track["artist"] + title = track["title"] + dt = track["start_date_time"] + time = datetime(year=int(dt["year"]), month=int(dt["month"]), day=int(dt["day"]), + hour=int(dt["hours"]), minute=int(dt["minutes"]), second=int(dt["seconds"])) + yield time, artist, title diff --git a/parser/base.py b/parser/base.py new file mode 100644 index 0000000..1453462 --- /dev/null +++ b/parser/base.py @@ -0,0 +1,11 @@ +from abc import ABC, abstractmethod +from datetime import datetime +from typing import Tuple, Iterable + +from models import Channel + + +class BaseFetcher(ABC): + @abstractmethod + def get(self, channel: Channel) -> Iterable[Tuple[datetime, str, str]]: + pass diff --git a/parser/eng.py b/parser/eng.py index 3175a59..8d33afd 100644 --- a/parser/eng.py +++ b/parser/eng.py @@ -1,19 +1,22 @@ from bs4 import BeautifulSoup +from parser import BaseFetcher from utils import * -def get(channel): - url = "http://www.energy.at/extern/tifo/?station=vie&hour={hour}&min={min}&date={date}&submit=1" - now = datetime.now() - timedelta(minutes=30) - url = url.format(hour=now.hour, min=now.minute, date=now.strftime("%d.%m.%Y")) - soup = BeautifulSoup(fetch(url, False), 'html.parser') - print(url) - for item in soup.findAll("div", "item"): - artist = item.find("p", "interpret").get_text() - title = item.find("p", "title").get_text() - timestring = item.find("span", "time").get_text() - datestring = item.find("span", "date").get_text() - time = local_to_utc(datetime.strptime(datestring + " " + timestring, '%d.%m.%Y %H:%M')) - yield time, artist, title - exit() +class EnergyFetcher(BaseFetcher): + disabled = True + + def get(self, channel): + url = "http://www.energy.at/extern/tifo/?station=vie&hour={hour}&min={min}&date={date}&submit=1" + now = datetime.now() - timedelta(minutes=30) + url = url.format(hour=now.hour, min=now.minute, date=now.strftime("%d.%m.%Y")) + soup = BeautifulSoup(fetch(url, False), 'html.parser') + print(url) + for item in soup.findAll("div", "item"): + artist = item.find("p", "interpret").get_text() + title = item.find("p", "title").get_text() + timestring = item.find("span", "time").get_text() + datestring = item.find("span", "date").get_text() + time = local_to_utc(datetime.strptime(datestring + " " + timestring, '%d.%m.%Y %H:%M')) + yield time, artist, title diff --git a/parser/kronehit.py b/parser/kronehit.py index 78b192e..57b1635 100644 --- a/parser/kronehit.py +++ b/parser/kronehit.py @@ -1,11 +1,13 @@ +from parser import BaseFetcher from utils import * URL = "https://www.kronehit.at/alles-ueber-kronehit/hitsuche/?format=json&channel=1" -def get(channel): - for track in fetch(URL, True)["items"]: - artist = track["ArtistName"] - title = track["TrackName"] - time = time_to_date(string_to_time(track["PlayTime"],seconds=False)) - yield time, artist, title +class KroneHitFetcher(BaseFetcher): + def get(self, channel): + for track in fetch(URL, True)["items"]: + artist = track["ArtistName"] + title = track["TrackName"] + time = time_to_date(string_to_time(track["PlayTime"], seconds=False)) + yield time, artist, title diff --git a/parser/orf.py b/parser/orf.py index a420fa3..84eae4a 100644 --- a/parser/orf.py +++ b/parser/orf.py @@ -1,22 +1,17 @@ +from parser import BaseFetcher from utils import * -def get(channel): - r = careful_fetch(channel.streamurl + "played.html?type=json") - print(r.text) - for song in r.json(): - time = datetime.fromtimestamp(song["playedat"]) - - if " - " in song["title"]: - # for whatever crazy reason only half of the channels are the other way round - if channel.shortname in ["oe3", "fm4", "noe", "wie", "stm"]: - artist, title = song["title"].split(" - ")[:2] - else: - title, artist = song["title"].split(" - ")[:2] - else: - artist = "" - title = song["title"] - if channel.shortname == "fm4" and "|" in title: - title = title.split("|")[0] - - yield (time, artist, title) +class OrfFetcher(BaseFetcher): + def get(self, channel): + r = careful_fetch(f"https://audioapi.orf.at/{channel.shortname}/json/4.0/live") + r.raise_for_status() + for song in r.json()[0]["items"]: + time = datetime.fromtimestamp(song["start"] / 1000) + try: + artist = song["interpreter"] + title = song["title"] + except KeyError: + print("not a song") + continue + yield (time, artist, title) diff --git a/poetry.lock b/poetry.lock index 63b9feb..82804f6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,63 +1,63 @@ [[package]] -category = "main" -description = "Screen-scraping library" name = "beautifulsoup4" +version = "4.9.2" +description = "Screen-scraping library" +category = "main" optional = false python-versions = "*" -version = "4.9.0" [package.dependencies] -soupsieve = [">1.2", "<2.0"] +soupsieve = {version = ">1.2", markers = "python_version >= \"3.0\""} [package.extras] html5lib = ["html5lib"] lxml = ["lxml"] [[package]] -category = "main" -description = "Fast, simple object-to-object and broadcast signaling" name = "blinker" -optional = false -python-versions = "*" version = "1.4" +description = "Fast, simple object-to-object and broadcast signaling" +category = "main" +optional = false +python-versions = "*" [[package]] -category = "main" -description = "Python package for providing Mozilla's CA Bundle." name = "certifi" +version = "2020.6.20" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" optional = false python-versions = "*" -version = "2020.4.5.1" [[package]] -category = "main" -description = "Universal encoding detector for Python 2 and 3" name = "chardet" +version = "3.0.4" +description = "Universal encoding detector for Python 2 and 3" +category = "main" optional = false python-versions = "*" -version = "3.0.4" [[package]] -category = "main" -description = "Composable command line interface toolkit" name = "click" +version = "7.1.2" +description = "Composable command line interface toolkit" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "7.1.1" [[package]] -category = "main" -description = "A simple framework for building complex web applications." name = "flask" +version = "1.1.2" +description = "A simple framework for building complex web applications." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "1.1.2" [package.dependencies] -Jinja2 = ">=2.10.1" -Werkzeug = ">=0.15" click = ">=5.1" itsdangerous = ">=0.24" +Jinja2 = ">=2.10.1" +Werkzeug = ">=0.15" [package.extras] dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"] @@ -65,26 +65,23 @@ docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx- dotenv = ["python-dotenv"] [[package]] -category = "main" -description = "Adds caching support to your Flask application" name = "flask-caching" +version = "1.9.0" +description = "Adds caching support to your Flask application" +category = "main" optional = false python-versions = "*" -version = "1.8.0" [package.dependencies] Flask = "*" [[package]] -category = "main" -description = "WSGI HTTP Server for UNIX" name = "gunicorn" +version = "20.0.4" +description = "WSGI HTTP Server for UNIX" +category = "main" optional = false python-versions = ">=3.4" -version = "20.0.4" - -[package.dependencies] -setuptools = ">=3.0" [package.extras] eventlet = ["eventlet (>=0.9.7)"] @@ -93,28 +90,28 @@ setproctitle = ["setproctitle"] tornado = ["tornado (>=0.2)"] [[package]] -category = "main" -description = "Internationalized Domain Names in Applications (IDNA)" name = "idna" +version = "2.10" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.9" [[package]] -category = "main" -description = "Various helpers to pass data to untrusted environments and back." name = "itsdangerous" +version = "1.1.0" +description = "Various helpers to pass data to untrusted environments and back." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.1.0" [[package]] -category = "main" -description = "A very fast and expressive template engine." name = "jinja2" +version = "2.11.2" +description = "A very fast and expressive template engine." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.11.2" [package.dependencies] MarkupSafe = ">=0.23" @@ -123,58 +120,59 @@ MarkupSafe = ">=0.23" i18n = ["Babel (>=0.8)"] [[package]] -category = "main" -description = "Safely add untrusted strings to HTML/XML markup." name = "markupsafe" +version = "1.1.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.1.1" [[package]] -category = "main" -description = "a little orm" name = "peewee" +version = "3.13.3" +description = "a little orm" +category = "main" optional = false python-versions = "*" -version = "3.13.3" [[package]] -category = "main" -description = "Pure Python MySQL Driver" name = "pymysql" +version = "0.10.1" +description = "Pure Python MySQL Driver" +category = "main" optional = false python-versions = "*" -version = "0.9.3" [package.extras] +ed25519 = ["PyNaCl (>=1.4.0)"] rsa = ["cryptography"] [[package]] -category = "main" -description = "World timezone definitions, modern and historical" name = "pytz" +version = "2020.1" +description = "World timezone definitions, modern and historical" +category = "main" optional = false python-versions = "*" -version = "2019.3" [[package]] -category = "main" -description = "Python client for Redis key-value store" name = "redis" +version = "3.5.3" +description = "Python client for Redis key-value store" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "3.4.1" [package.extras] hiredis = ["hiredis (>=0.1.3)"] [[package]] -category = "main" -description = "Python HTTP for Humans." name = "requests" +version = "2.24.0" +description = "Python HTTP for Humans." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.23.0" [package.dependencies] certifi = ">=2017.4.17" @@ -187,62 +185,58 @@ security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] [[package]] -category = "main" -description = "Python client for Sentry (https://getsentry.com)" name = "sentry-sdk" +version = "0.17.8" +description = "Python client for Sentry (https://sentry.io)" +category = "main" optional = false python-versions = "*" -version = "0.14.3" [package.dependencies] +blinker = {version = ">=1.1", optional = true, markers = "extra == \"flask\""} certifi = "*" +flask = {version = ">=0.11", optional = true, markers = "extra == \"flask\""} urllib3 = ">=1.10.0" -[package.dependencies.blinker] -optional = true -version = ">=1.1" - -[package.dependencies.flask] -optional = true -version = ">=0.11" - [package.extras] aiohttp = ["aiohttp (>=3.5)"] -beam = ["beam (>=2.12)"] +beam = ["apache-beam (>=2.12)"] bottle = ["bottle (>=0.12.13)"] celery = ["celery (>=3)"] +chalice = ["chalice (>=1.16.0)"] django = ["django (>=1.8)"] falcon = ["falcon (>=1.4)"] flask = ["flask (>=0.11)", "blinker (>=1.1)"] +pure_eval = ["pure-eval", "executing", "asttokens"] pyspark = ["pyspark (>=2.4.4)"] -rq = ["0.6"] +rq = ["rq (>=0.6)"] sanic = ["sanic (>=0.8)"] sqlalchemy = ["sqlalchemy (>=1.2)"] tornado = ["tornado (>=5)"] [[package]] -category = "main" -description = "Python 2 and 3 compatibility utilities" name = "six" +version = "1.15.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -version = "1.14.0" [[package]] -category = "main" -description = "A modern CSS selector implementation for Beautiful Soup." name = "soupsieve" +version = "2.0.1" +description = "A modern CSS selector implementation for Beautiful Soup." +category = "main" optional = false -python-versions = "*" -version = "1.9.5" +python-versions = ">=3.5" [[package]] -category = "main" -description = "A light weight Python library for the Spotify Web API" name = "spotipy" +version = "2.16.0" +description = "A light weight Python library for the Spotify Web API" +category = "main" optional = false python-versions = "*" -version = "2.11.2" [package.dependencies] requests = ">=2.20.0" @@ -253,69 +247,70 @@ doc = ["Sphinx (>=1.5.2)"] test = ["mock (2.0.0)"] [[package]] -category = "main" -description = "HTTP library with thread-safe connection pooling, file post, and more." name = "urllib3" +version = "1.22" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" optional = false python-versions = "*" -version = "1.22" [package.extras] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] [[package]] -category = "main" -description = "The comprehensive WSGI web application library." name = "werkzeug" +version = "1.0.1" +description = "The comprehensive WSGI web application library." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "1.0.1" [package.extras] dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"] watchdog = ["watchdog"] [metadata] -content-hash = "a8ff226072ae85c4c5c564886f4e0a019157c31acd922ccc0c1c0bf8fc03a9ed" +lock-version = "1.1" python-versions = ">=3.7" +content-hash = "d32e930d2994b6dcc97a0679843cbed9b5345b63a953e4ce98c935d281679b50" [metadata.files] beautifulsoup4 = [ - {file = "beautifulsoup4-4.9.0-py2-none-any.whl", hash = "sha256:a4bbe77fd30670455c5296242967a123ec28c37e9702a8a81bd2f20a4baf0368"}, - {file = "beautifulsoup4-4.9.0-py3-none-any.whl", hash = "sha256:d4e96ac9b0c3a6d3f0caae2e4124e6055c5dcafde8e2f831ff194c104f0775a0"}, - {file = "beautifulsoup4-4.9.0.tar.gz", hash = "sha256:594ca51a10d2b3443cbac41214e12dbb2a1cd57e1a7344659849e2e20ba6a8d8"}, + {file = "beautifulsoup4-4.9.2-py2-none-any.whl", hash = "sha256:645d833a828722357038299b7f6879940c11dddd95b900fe5387c258b72bb883"}, + {file = "beautifulsoup4-4.9.2-py3-none-any.whl", hash = "sha256:5dfe44f8fddc89ac5453f02659d3ab1668f2c0d9684839f0785037e8c6d9ac8d"}, + {file = "beautifulsoup4-4.9.2.tar.gz", hash = "sha256:1edf5e39f3a5bc6e38b235b369128416c7239b34f692acccececb040233032a1"}, ] blinker = [ {file = "blinker-1.4.tar.gz", hash = "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6"}, ] certifi = [ - {file = "certifi-2020.4.5.1-py2.py3-none-any.whl", hash = "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304"}, - {file = "certifi-2020.4.5.1.tar.gz", hash = "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"}, + {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"}, + {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"}, ] chardet = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, ] click = [ - {file = "click-7.1.1-py2.py3-none-any.whl", hash = "sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a"}, - {file = "click-7.1.1.tar.gz", hash = "sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc"}, + {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, + {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, ] flask = [ {file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"}, {file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"}, ] flask-caching = [ - {file = "Flask-Caching-1.8.0.tar.gz", hash = "sha256:3d0bd13c448c1640334131ed4163a12aff7df2155e73860f07fc9e5e75de7126"}, - {file = "Flask_Caching-1.8.0-py2.py3-none-any.whl", hash = "sha256:54b6140bb7b9f3e63d009ff08b03bacd84eefb1af1d30af06b4a6bc3c16fa3b2"}, + {file = "Flask-Caching-1.9.0.tar.gz", hash = "sha256:a0356ad868b1d8ec2d0e675a6fe891c41303128f8904d5d79e180d8b3f952aff"}, + {file = "Flask_Caching-1.9.0-py2.py3-none-any.whl", hash = "sha256:e6ef2e2af84e13c4fd32c1839c1943a42f11b6b0fbcfdd6bf46547ea5482dbfe"}, ] gunicorn = [ {file = "gunicorn-20.0.4-py2.py3-none-any.whl", hash = "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c"}, {file = "gunicorn-20.0.4.tar.gz", hash = "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626"}, ] idna = [ - {file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"}, - {file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"}, + {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, + {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] itsdangerous = [ {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"}, @@ -364,37 +359,37 @@ peewee = [ {file = "peewee-3.13.3.tar.gz", hash = "sha256:1269a9736865512bd4056298003aab190957afe07d2616cf22eaf56cb6398369"}, ] pymysql = [ - {file = "PyMySQL-0.9.3-py2.py3-none-any.whl", hash = "sha256:3943fbbbc1e902f41daf7f9165519f140c4451c179380677e6a848587042561a"}, - {file = "PyMySQL-0.9.3.tar.gz", hash = "sha256:d8c059dcd81dedb85a9f034d5e22dcb4442c0b201908bede99e306d65ea7c8e7"}, + {file = "PyMySQL-0.10.1-py2.py3-none-any.whl", hash = "sha256:44f47128dda8676e021c8d2dbb49a82be9e4ab158b9f03e897152a3a287c69ea"}, + {file = "PyMySQL-0.10.1.tar.gz", hash = "sha256:263040d2779a3b84930f7ac9da5132be0fefcd6f453a885756656103f8ee1fdd"}, ] pytz = [ - {file = "pytz-2019.3-py2.py3-none-any.whl", hash = "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d"}, - {file = "pytz-2019.3.tar.gz", hash = "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"}, + {file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"}, + {file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"}, ] redis = [ - {file = "redis-3.4.1-py2.py3-none-any.whl", hash = "sha256:b205cffd05ebfd0a468db74f0eedbff8df1a7bfc47521516ade4692991bb0833"}, - {file = "redis-3.4.1.tar.gz", hash = "sha256:0dcfb335921b88a850d461dc255ff4708294943322bd55de6cfd68972490ca1f"}, + {file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"}, + {file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"}, ] requests = [ - {file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"}, - {file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"}, + {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, + {file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"}, ] sentry-sdk = [ - {file = "sentry-sdk-0.14.3.tar.gz", hash = "sha256:bb90a4e19c7233a580715fc986cc44be2c48fc10b31e71580a2037e1c94b6950"}, - {file = "sentry_sdk-0.14.3-py2.py3-none-any.whl", hash = "sha256:23808d571d2461a4ce3784ec12bbee5bdb8c026c143fe79d36cef8a6d653e71f"}, + {file = "sentry-sdk-0.17.8.tar.gz", hash = "sha256:e159f7c919d19ae86e5a4ff370fccc45149fab461fbeb93fb5a735a0b33a9cb1"}, + {file = "sentry_sdk-0.17.8-py2.py3-none-any.whl", hash = "sha256:c9c0fa1412bad87104c4eee8dd36c7bbf60b0d92ae917ab519094779b22e6d9a"}, ] six = [ - {file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"}, - {file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"}, + {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, + {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, ] soupsieve = [ - {file = "soupsieve-1.9.5-py2.py3-none-any.whl", hash = "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5"}, - {file = "soupsieve-1.9.5.tar.gz", hash = "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda"}, + {file = "soupsieve-2.0.1-py3-none-any.whl", hash = "sha256:1634eea42ab371d3d346309b93df7870a88610f0725d47528be902a0d95ecc55"}, + {file = "soupsieve-2.0.1.tar.gz", hash = "sha256:a59dc181727e95d25f781f0eb4fd1825ff45590ec8ff49eadfd7f1a537cc0232"}, ] spotipy = [ - {file = "spotipy-2.11.2-py2-none-any.whl", hash = "sha256:a90dbadeb899763a6789dabbf9a57ec8874f1e72c38161669661c0714654acaf"}, - {file = "spotipy-2.11.2-py3-none-any.whl", hash = "sha256:293a070de156345359620e17945a379762488b0e00f01a25530ab7af1abea4ab"}, - {file = "spotipy-2.11.2.tar.gz", hash = "sha256:9d5ca9f600bbceb6c86d66e819e2a1446db819cfca349a2f55c3fdda11b606af"}, + {file = "spotipy-2.16.0-py2-none-any.whl", hash = "sha256:800330badc1b953417dace1532a586220d35b2240eb2e538e883e19e6bf1b53d"}, + {file = "spotipy-2.16.0-py3-none-any.whl", hash = "sha256:9d07b8948c30d8a338805440797263749ccad07c22009f9b3112aa2bcb2ebcea"}, + {file = "spotipy-2.16.0.tar.gz", hash = "sha256:315eadd1248053ed336b4d3adbf2e3c32895fdbb0cfcd170542c848c8fd45649"}, ] urllib3 = [ {file = "urllib3-1.22-py2.py3-none-any.whl", hash = "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b"}, diff --git a/pyproject.toml b/pyproject.toml index 8d13ebc..b1276ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,12 +9,12 @@ python = ">=3.7" requests = "^2.22.0" Flask = "^1.1.1" Flask-Caching = "^1.8.0" -sentry-sdk = {extras = ["flask"], version = "^0.14.1"} +sentry-sdk = {extras = ["flask"], version = "^0.17.1"} spotipy = "^2.4.4" peewee = "^3.13.1" beautifulsoup4 = "^4.8.2" -PyMySQL = "^0.9.3" -pytz = "^2019.3" +PyMySQL = "^0.10.0" +pytz = "^2020.1" gunicorn = "^20.0.4" redis = "^3.3.11" diff --git a/server.py b/server.py index 954633e..96ad35f 100644 --- a/server.py +++ b/server.py @@ -2,7 +2,7 @@ import calendar from datetime import datetime, timedelta from flask import jsonify, request -from playhouse.shortcuts import model_to_dict +from playhouse.shortcuts import model_to_dict, fn, SQL from app import app, cache from models import * diff --git a/update_channels.py b/update_channels.py new file mode 100644 index 0000000..acb9742 --- /dev/null +++ b/update_channels.py @@ -0,0 +1,12 @@ +import channelInfo +from models import Channel + +for id, channel in channelInfo.channels.items(): + print("update", channel.stationname) + + db_chan = Channel.get(shortname=channel.shortname) + db_chan.stationname = channel.stationname + db_chan.has_data = channel.has_data + db_chan.primary_color = channel.primary_color + db_chan.secondary_color = channel.secondary_color + db_chan.save() diff --git a/utils.py b/utils.py index c6b47f5..3a5e281 100644 --- a/utils.py +++ b/utils.py @@ -1,16 +1,18 @@ import sys -from datetime import datetime, timedelta +from datetime import datetime, timedelta, time from time import sleep import pytz import requests +from requests import Response -headers = { +s = requests.Session() +s.headers.update({ 'User-Agent': 'Mozilla/5.0 (compatible; RadioStats/1.0;)', -} +}) -def careful_fetch(url): +def careful_fetch(url) -> Response: """ :rtype: requests.models.Response """ @@ -19,7 +21,7 @@ def careful_fetch(url): tries = 0 while result is None: try: - req = requests.get(url, headers=headers) + req = s.get(url) if "Invalid resource" in req.text: raise requests.exceptions.ConnectionError return req @@ -33,11 +35,7 @@ def careful_fetch(url): pass -def string_to_time(timestring, seconds=True): - """ - - :rtype: datetime.time - """ +def string_to_time(timestring, seconds=True) -> time: if seconds: format = "%H:%M:%S" else: @@ -45,12 +43,7 @@ def string_to_time(timestring, seconds=True): return datetime.strptime(timestring, format).time() -def time_to_date(time): - """ - - :rtype: datetime.datetime - :type time: datetime.time - """ +def time_to_date(time: time) -> datetime: time_hour = time.hour day = datetime.now() current_hour = day.hour @@ -69,7 +62,7 @@ def local_to_utc(date): def fetch(url, json=False): - req = requests.get(url, headers=headers) + req = s.get(url) if req.status_code != 200: print("URL failed to fetch: {status} {url}".format(status=req.status_code, url=url), file=sys.stderr) return False diff --git a/web/yarn.lock b/web/yarn.lock index 1cae5dd..a45b214 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -2927,7 +2927,7 @@ debug@=3.1.0: dependencies: ms "2.0.0" -debug@^3.0.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: +debug@^3.0.0, debug@^3.1.1, debug@^3.2.5: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -3016,11 +3016,6 @@ deep-equal@^1.0.1: object-keys "^1.1.1" regexp.prototype.flags "^1.2.0" -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -3109,11 +3104,6 @@ detect-file@^1.0.0: resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - detect-node@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" @@ -4122,13 +4112,6 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-minipass@^1.2.5: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - fs-minipass@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" @@ -4737,7 +4720,7 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -4761,13 +4744,6 @@ iferr@^0.1.5: resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= -ignore-walk@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" - integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== - dependencies: - minimatch "^3.0.4" - ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -4960,7 +4936,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: +ini@^1.3.4, ini@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== @@ -6013,14 +5989,6 @@ minipass-pipeline@^1.2.2: dependencies: minipass "^3.0.0" -minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - minipass@^3.0.0, minipass@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.1.tgz#7607ce778472a185ad6d89082aa2070f79cedcd5" @@ -6028,13 +5996,6 @@ minipass@^3.0.0, minipass@^3.1.1: dependencies: yallist "^4.0.0" -minizlib@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" - mississippi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" @@ -6159,15 +6120,6 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -needle@^2.2.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.1.tgz#14af48732463d7475696f937626b1b993247a56a" - integrity sha512-x/gi6ijr4B7fwl6WYL9FwlCvRQKGlUNvnceho8wxkwXqN8jvVmmmATTmZPRRG7b/yC1eode26C2HO9jl78Du9g== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" @@ -6247,22 +6199,6 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-pre-gyp@*: - version "0.14.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" - integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4.4.2" - node-releases@^1.1.53: version "1.1.53" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.53.tgz#2d821bfa499ed7c5dffc5e2f28c88e78a08ee3f4" @@ -6311,14 +6247,6 @@ node-vibrant@^3.2.0-alpha: dependencies: abbrev "1" -nopt@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" - integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== - dependencies: - abbrev "1" - osenv "^0.1.4" - normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -6375,13 +6303,6 @@ normalize.css@~5.0.0: resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-5.0.0.tgz#7cec875ce8178a5333c4de80b68ea9c18b9d7c37" integrity sha1-fOyHXOgXilMzxN6Ato6pwYudfDc= -npm-bundled@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" - integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== - dependencies: - npm-normalize-package-bin "^1.0.1" - npm-conf@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" @@ -6390,20 +6311,6 @@ npm-conf@^1.1.0: config-chain "^1.1.11" pify "^3.0.0" -npm-normalize-package-bin@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" - integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== - -npm-packlist@^1.1.6: - version "1.4.8" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" - integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - npm-normalize-package-bin "^1.0.1" - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -6411,7 +6318,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -6631,7 +6538,7 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@0, osenv@^0.1.4: +osenv@0: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== @@ -7365,16 +7272,6 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -rc@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -7657,7 +7554,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3, rimraf@^2.7.1: +rimraf@2, rimraf@^2.5.4, rimraf@^2.6.3, rimraf@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -7748,7 +7645,7 @@ sass-loader@^8.0.2: schema-utils "^2.6.1" semver "^6.3.0" -sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4: +sax@>=0.6.0, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -8393,11 +8290,6 @@ strip-json-comments@^3.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180" integrity sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w== -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - strip-outer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" @@ -8487,19 +8379,6 @@ tar@^2.0.0: fstream "^1.0.12" inherits "2" -tar@^4.4.2: - version "4.4.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" - integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.8.6" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" - temp-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" @@ -9325,7 +9204,7 @@ yallist@^2.1.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: +yallist@^3.0.2: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==