1
0
Fork 0
mirror of https://github.com/Findus23/RadioStats.git synced 2024-09-18 14:53:47 +02:00

major overhaul

- use new ORF API
- better structured fetchers
- easier channel metadata
This commit is contained in:
Lukas Winkler 2020-09-28 18:31:57 +02:00
parent 654962735d
commit d286059289
Signed by: lukas
GPG key ID: 54DE4D798D244853
17 changed files with 373 additions and 588 deletions

View file

@ -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"
),
}

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

11
parser/base.py Normal file
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

227
poetry.lock generated
View file

@ -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"},

View file

@ -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"

View file

@ -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 *

12
update_channels.py Normal file
View file

@ -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()

View file

@ -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

View file

@ -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==