From f2d7da36d6523f0e7e873a3dfcd7493fa4aca1a7 Mon Sep 17 00:00:00 2001 From: Stefan Derkits Date: Sun, 13 Jan 2019 16:39:24 +0100 Subject: [PATCH 1/9] Port to Python3, cleanup code --- setup.py | 27 ++++---- streamscrobbler/streamscrobbler.py | 105 +++++++++++------------------ 2 files changed, 51 insertions(+), 81 deletions(-) diff --git a/setup.py b/setup.py index 4dfc508..4303165 100755 --- a/setup.py +++ b/setup.py @@ -1,21 +1,18 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from setuptools import setup, find_packages -import sys -import os - +from setuptools import setup setup( -name = "streamscrobbler", -packages = ["streamscrobbler"], -version = "0.0.1", -description = "A python class used on Dirble.com to get titles and bitrates on shoutcast and icecast streams", -author = "Håkan Nylén", -author_email = "confacted@gmail.com", -url = "https://github.com/Dirble/streamscrobbler-python", -keywords = ["shoutcast", "icecast", "stream", "ICY"], -install_requires = ["httplib2"], -classifiers = [], -include_package_data = True + name="streamscrobbler", + packages=["streamscrobbler"], + version="0.0.2", + description="A python class used on Dirble.com to get titles and bitrates on shoutcast and icecast streams", + author="Håkan Nylén", + author_email="confacted@gmail.com", + url="https://github.com/Dirble/streamscrobbler-python", + keywords=["shoutcast", "icecast", "stream", "ICY"], + install_requires=["httplib2"], + classifiers=[], + include_package_data=True ) diff --git a/streamscrobbler/streamscrobbler.py b/streamscrobbler/streamscrobbler.py index 5af7e5d..42128a0 100644 --- a/streamscrobbler/streamscrobbler.py +++ b/streamscrobbler/streamscrobbler.py @@ -1,34 +1,20 @@ #!/usr/bin/python # -*- coding: utf-8 -*- import httplib2 as http -import httplib +import http.client import re -from urlparse import urlparse +from urllib.parse import urlparse import pprint -import urllib2 - - -class streamscrobbler: - def parse_headers(self, response): - headers = {} - int = 0 - while True: - line = response.readline() - if line == '\r\n': - break # end of headers - if ':' in line: - key, value = line.split(':', 1) - headers[key] = value.rstrip() - if int == 12: - break; - int = int + 1 - return headers +import urllib.request +import urllib.error +import urllib.parse +class StreamScrobbler: + # this is the fucntion you should call with the url to get all data sorted as a object in the return def getServerInfo(self, url): - print - "shoutcast check v.2" + print("shoutcast check v.2") if url.endswith('.pls') or url.endswith('listen.pls?sid=1'): address = self.checkPLS(url) @@ -42,20 +28,19 @@ def getServerInfo(self, url): return meta_interval def getAllData(self, address): - shoutcast = False status = 0 - request = urllib2.Request(address) + request = urllib.request.Request(address) user_agent = 'iTunes/9.1.1' request.add_header('User-Agent', user_agent) request.add_header('icy-metadata', 1) try: - response = urllib2.urlopen(request, timeout=6) + response = urllib.request.urlopen(request, timeout=6) headers = self.getHeaders(response) pp = pprint.PrettyPrinter(indent=4) - print "parse headers: " + print("parse headers: ") pp.pprint(headers) - + if "server" in headers: shoutcast = headers['server'] elif "X-Powered-By" in headers: @@ -66,11 +51,11 @@ def getAllData(self, address): shoutcast = bool(1) if isinstance(shoutcast, bool): - if shoutcast is True: + if shoutcast: status = 1 else: status = 0 - metadata = False; + metadata = False elif "SHOUTcast" in shoutcast: status = 1 metadata = self.shoutcastCheck(response, headers, False) @@ -88,37 +73,36 @@ def getAllData(self, address): response.close() return {"status": status, "metadata": metadata} - except urllib2.HTTPError, e: - print ' Error, HTTPError = ' + str(e.code) + except urllib.error.HTTPError as e: + print((' Error, HTTPError = ' + str(e.code))) return {"status": status, "metadata": None} - except urllib2.URLError, e: - print " Error, URLError: " + str(e.reason) + except urllib.error.URLError as e: + print((" Error, URLError: " + str(e.reason))) return {"status": status, "metadata": None} - except Exception, err: - print " Error: " + str(err) + except Exception as err: + print((" Error: " + str(err))) return {"status": status, "metadata": None} - def checkPLS(self, address): try: - response = urllib2.urlopen(address, timeout=2) + stream = None + response = urllib.request.urlopen(address, timeout=2) for line in response: - if line.startswith("File1="): - stream = line; + if line.startswith(b"File1="): + stream = line.decode() response.close() - if 'stream' in locals(): - return stream[6:] + if stream: + return stream[6:].strip("\n") else: return bool(0) except Exception: return bool(0) - - def shoutcastCheck(self, response, headers, itsOld): - if itsOld is not True: + def shoutcastCheck(self, response, headers, is_old): + if not is_old: if 'icy-br' in headers: bitrate = headers['icy-br'] bitrate = bitrate.rstrip() @@ -150,9 +134,9 @@ def shoutcastCheck(self, response, headers, itsOld): elif headers.get('content-type') is not None: contenttype = headers.get('content-type') - if icy_metaint_header is not None: + if icy_metaint_header: metaint = int(icy_metaint_header) - print "icy metaint: " + str(metaint) + print(("icy metaint: " + str(metaint))) read_buffer = metaint + 255 content = response.read(read_buffer) @@ -160,36 +144,25 @@ def shoutcastCheck(self, response, headers, itsOld): end = "';" try: - title = re.search('%s(.*)%s' % (start, end), content[metaint:]).group(1) + title = re.search(bytes('%s(.*)%s' % (start, end)), content[metaint:]).group(1).decode() title = re.sub("StreamUrl='.*?';", "", title).replace("';", "").replace("StreamUrl='", "") title = re.sub("&artist=.*", "", title) title = re.sub("http://.*", "", title) title.rstrip() - except Exception, err: - print "songtitle error: " + str(err) - title = content[metaint:].split("'")[1] + except Exception as err: + print(("songtitle error: " + str(err))) + title = content[metaint:].split(b"'")[1] return {'song': title, 'bitrate': bitrate, 'contenttype': contenttype.rstrip()} else: - print - "No metaint" + print("No metaint") return False def getHeaders(self, response): - if self.is_empty(response.headers.dict) is False: - headers = response.headers.dict - elif hasattr(response.info(),"item") and self.is_empty(response.info().item()) is False: - headers = response.info().item() - else: - headers = self.parse_headers(response) - return headers - - def is_empty(self, any_structure): - if any_structure: - return False - else: - return True - + if response.get_headers(): + headers = dict(response.get_headers) + return headers + return dict() def stripTags(self, text): finished = 0 From a05ab0bf04b37dde012db27c2dbff04e1dfb88a6 Mon Sep 17 00:00:00 2001 From: Stefan Derkits Date: Sat, 2 Feb 2019 16:57:53 +0100 Subject: [PATCH 2/9] coding style changes, removed non-necessary class, make it work with python3 urllib --- README.md | 34 ++-- setup.py | 2 +- streamscrobbler/streamscrobbler.py | 288 +++++++++++++---------------- 3 files changed, 141 insertions(+), 183 deletions(-) diff --git a/README.md b/README.md index 986e1b6..059bf6d 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,12 @@ streamscrobbler-python ====================== -This python class gets the metadata and song played on a stream. The metadata is content-type (mpeg, ACC, ACC+), bitrate and played song. It has support to handling pls files directly for now. m3u support will come soon. +This python module gets the metadata and song played on a stream. The metadata is content-type (mpeg, ACC, ACC+), +bitrate and played song. It has support to handling pls files directly for now. -### dependencies -Streamscrobbler is importing these packages: - -* httplib2 as http -* httplib -* re -* urlparse -* pprint -* urllib2 - -prepare by installing them before testing this class. +### Dependencies +* Python 3.5 ### Streams supported Supports the following streamtypes: @@ -30,20 +22,16 @@ And also different stream services: * tunein ### How to use it -You use one function to get a object of status and metadata. -status is a integer of 0,1,2 - 0 is down, 1 is up, 2 is up with metadata -metadata is a object of bitrate, content-type and songtitle. +You use one function to get a dictionary of status and metadata. +metadata is a dictionary of bitrate, content-type and songtitle. See how to call it under here: ```Python from streamscrobbler import streamscrobbler -streamscrobbler = streamscrobbler() -##streamurl can be a url directly to the stream or to a pls file. Support for m3u is coming soon. -streamurl = "http://217.198.148.101:80/" -stationinfo = streamscrobbler.getServerInfo(streamurl) +##streamurl can be a url directly to the stream or to a pls file +streamurl = "http://somafm.com/seventies.pls" +stationinfo = streamscrobbler.get_server_info(streamurl) ##metadata is the bitrate and current song -metadata = stationinfo.get("metadata") -## status is the integer to tell if the server is up or down, 0 means down, 1 up, 2 means up but also got metadata. -status = stationinfo.get("status") -``` \ No newline at end of file +metadata = stationinfo["metadata"] +``` diff --git a/setup.py b/setup.py index 4303165..0182a7e 100755 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ author_email="confacted@gmail.com", url="https://github.com/Dirble/streamscrobbler-python", keywords=["shoutcast", "icecast", "stream", "ICY"], - install_requires=["httplib2"], + install_requires=[], classifiers=[], include_package_data=True ) diff --git a/streamscrobbler/streamscrobbler.py b/streamscrobbler/streamscrobbler.py index 42128a0..4607336 100644 --- a/streamscrobbler/streamscrobbler.py +++ b/streamscrobbler/streamscrobbler.py @@ -1,177 +1,147 @@ -#!/usr/bin/python # -*- coding: utf-8 -*- -import httplib2 as http -import http.client import re -from urllib.parse import urlparse -import pprint import urllib.request import urllib.error import urllib.parse -class StreamScrobbler: - - # this is the fucntion you should call with the url to get all data sorted as a object in the return - def getServerInfo(self, url): - print("shoutcast check v.2") - - if url.endswith('.pls') or url.endswith('listen.pls?sid=1'): - address = self.checkPLS(url) +# this is the function you should call with the url to get all data sorted as a object in the return +def get_server_info(url): + if url.endswith('.pls') or url.endswith('listen.pls?sid=1'): + address = check_pls(url) + else: + address = url + if isinstance(address, str): + meta_interval = get_all_data(address) + else: + meta_interval = {"status": 0, "metadata": None} + + return meta_interval + + +def get_all_data(address): + status = 0 + + request = urllib.request.Request(address) + user_agent = 'iTunes/9.1.1' + request.add_header('User-Agent', user_agent) + request.add_header('icy-metadata', 1) + try: + response = urllib.request.urlopen(request, timeout=6) + headers = dict(response.info()) + + if "server" in headers: + shoutcast = headers['server'] + elif "X-Powered-By" in headers: + shoutcast = headers['X-Powered-By'] + elif "icy-notice1" in headers: + shoutcast = headers['icy-notice2'] else: - address = url - if isinstance(address, str): - meta_interval = self.getAllData(address) - else: - meta_interval = {"status": 0, "metadata": None} - - return meta_interval + shoutcast = True - def getAllData(self, address): - status = 0 - - request = urllib.request.Request(address) - user_agent = 'iTunes/9.1.1' - request.add_header('User-Agent', user_agent) - request.add_header('icy-metadata', 1) - try: - response = urllib.request.urlopen(request, timeout=6) - headers = self.getHeaders(response) - pp = pprint.PrettyPrinter(indent=4) - print("parse headers: ") - pp.pprint(headers) - - if "server" in headers: - shoutcast = headers['server'] - elif "X-Powered-By" in headers: - shoutcast = headers['X-Powered-By'] - elif "icy-notice1" in headers: - shoutcast = headers['icy-notice2'] - else: - shoutcast = bool(1) - - if isinstance(shoutcast, bool): - if shoutcast: - status = 1 - else: - status = 0 - metadata = False - elif "SHOUTcast" in shoutcast: + if isinstance(shoutcast, bool): + if shoutcast: status = 1 - metadata = self.shoutcastCheck(response, headers, False) - elif "Icecast" or "137" in shoutcast: - status = 1 - metadata = self.shoutcastCheck(response, headers, True) - elif "StreamMachine" in shoutcast: - status = 1 - metadata = self.shoutcastCheck(response, headers, True) - elif shoutcast is not None: - status = 1 - metadata = self.shoutcastCheck(response, headers, True) else: - metadata = False - response.close() - return {"status": status, "metadata": metadata} + status = 0 + metadata = False + elif "SHOUTcast" in shoutcast: + status = 1 + metadata = shoutcast_check(response, headers, False) + elif "Icecast" or "137" or "StreamMachine" in shoutcast: + status = 1 + metadata = shoutcast_check(response, headers, True) + elif shoutcast: + status = 1 + metadata = shoutcast_check(response, headers, True) + else: + metadata = False + response.close() + return {"status": status, "metadata": metadata} + + except urllib.error.HTTPError as e: + print((' Error, HTTPError = ' + str(e.code))) + return {"status": status, "metadata": None} + + except urllib.error.URLError as e: + print((" Error, URLError: " + str(e.reason))) + return {"status": status, "metadata": None} + + except Exception as err: + print((" Error: " + str(err))) + return {"status": status, "metadata": None} + + +def check_pls(address): + try: + stream = None + response = urllib.request.urlopen(address, timeout=2) + for line in response: + if line.startswith(b"File1="): + stream = line.decode() + + response.close() + if stream: + return stream[6:].strip("\n") + else: + return False + except Exception: + return False - except urllib.error.HTTPError as e: - print((' Error, HTTPError = ' + str(e.code))) - return {"status": status, "metadata": None} - except urllib.error.URLError as e: - print((" Error, URLError: " + str(e.reason))) - return {"status": status, "metadata": None} +def shoutcast_check(response, headers, is_old): + bitrate = None + contenttype = None - except Exception as err: - print((" Error: " + str(err))) - return {"status": status, "metadata": None} + if 'icy-br' in headers: + if is_old: + bitrate = headers['icy-br'].split(",")[0] + else: + bitrate = headers['icy-br'] + bitrate = bitrate.rstrip() - def checkPLS(self, address): - try: - stream = None - response = urllib.request.urlopen(address, timeout=2) - for line in response: - if line.startswith(b"File1="): - stream = line.decode() - - response.close() - if stream: - return stream[6:].strip("\n") - else: - return bool(0) - except Exception: - return bool(0) - - def shoutcastCheck(self, response, headers, is_old): - if not is_old: - if 'icy-br' in headers: - bitrate = headers['icy-br'] - bitrate = bitrate.rstrip() - else: - bitrate = None + if 'icy-metaint' in headers: + icy_metaint_header = headers['icy-metaint'] + else: + icy_metaint_header = None - if 'icy-metaint' in headers: - icy_metaint_header = headers['icy-metaint'] - else: - icy_metaint_header = None + if "Content-Type" in headers: + contenttype = headers['Content-Type'].rstrip() + elif 'content-type' in headers: + contenttype = headers['content-type'].rstrip() - if "Content-Type" in headers: - contenttype = headers['Content-Type'] - elif 'content-type' in headers: - contenttype = headers['content-type'] - - else: - if 'icy-br' in headers: - bitrate = headers['icy-br'].split(",")[0] - else: - bitrate = None - if 'icy-metaint' in headers: - icy_metaint_header = headers['icy-metaint'] - else: - icy_metaint_header = None - - if headers.get('Content-Type') is not None: - contenttype = headers.get('Content-Type') - elif headers.get('content-type') is not None: - contenttype = headers.get('content-type') - - if icy_metaint_header: - metaint = int(icy_metaint_header) - print(("icy metaint: " + str(metaint))) - read_buffer = metaint + 255 - content = response.read(read_buffer) - - start = "StreamTitle='" - end = "';" - - try: - title = re.search(bytes('%s(.*)%s' % (start, end)), content[metaint:]).group(1).decode() - title = re.sub("StreamUrl='.*?';", "", title).replace("';", "").replace("StreamUrl='", "") - title = re.sub("&artist=.*", "", title) - title = re.sub("http://.*", "", title) - title.rstrip() - except Exception as err: - print(("songtitle error: " + str(err))) - title = content[metaint:].split(b"'")[1] - - return {'song': title, 'bitrate': bitrate, 'contenttype': contenttype.rstrip()} - else: - print("No metaint") - return False + if icy_metaint_header: + metaint = int(icy_metaint_header) + read_buffer = metaint + 255 + content = response.read(read_buffer) - def getHeaders(self, response): - if response.get_headers(): - headers = dict(response.get_headers) - return headers - return dict() - - def stripTags(self, text): - finished = 0 - while not finished: - finished = 1 - start = text.find("<") - if start >= 0: - stop = text[start:].find(">") - if stop >= 0: - text = text[:start] + text[start + stop + 1:] - finished = 0 - return text \ No newline at end of file + start = "StreamTitle='" + end = "';" + + try: + title = re.search(bytes('%s(.*)%s' % (start, end), "utf-8"), content[metaint:]).group(1).decode("utf-8") + title = re.sub("StreamUrl='.*?';", "", title).replace("';", "").replace("StreamUrl='", "") + title = re.sub("&artist=.*", "", title) + title = re.sub("http://.*", "", title) + title.rstrip() + except Exception as err: + print(("songtitle error: " + str(err))) + title = content[metaint:].split(b"'")[1] + + return {'song': title, 'bitrate': bitrate, 'contenttype': contenttype} + else: + print("No metaint") + return False + + +def strip_tags(text): + finished = 0 + while not finished: + finished = 1 + start = text.find("<") + if start >= 0: + stop = text[start:].find(">") + if stop >= 0: + text = text[:start] + text[start + stop + 1:] + finished = 0 + return text From 5021ffce1f77a057c3c86fa54e64677cd1c41423 Mon Sep 17 00:00:00 2001 From: Stefan Derkits Date: Tue, 26 Feb 2019 11:33:23 +0100 Subject: [PATCH 3/9] run black (code formatting) over the code --- streamscrobbler/streamscrobbler.py | 48 +++++++++++++++++------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/streamscrobbler/streamscrobbler.py b/streamscrobbler/streamscrobbler.py index 4607336..fe7996e 100644 --- a/streamscrobbler/streamscrobbler.py +++ b/streamscrobbler/streamscrobbler.py @@ -7,7 +7,7 @@ # this is the function you should call with the url to get all data sorted as a object in the return def get_server_info(url): - if url.endswith('.pls') or url.endswith('listen.pls?sid=1'): + if url.endswith(".pls") or url.endswith("listen.pls?sid=1"): address = check_pls(url) else: address = url @@ -23,19 +23,19 @@ def get_all_data(address): status = 0 request = urllib.request.Request(address) - user_agent = 'iTunes/9.1.1' - request.add_header('User-Agent', user_agent) - request.add_header('icy-metadata', 1) + user_agent = "iTunes/9.1.1" + request.add_header("User-Agent", user_agent) + request.add_header("icy-metadata", 1) try: response = urllib.request.urlopen(request, timeout=6) headers = dict(response.info()) if "server" in headers: - shoutcast = headers['server'] + shoutcast = headers["server"] elif "X-Powered-By" in headers: - shoutcast = headers['X-Powered-By'] + shoutcast = headers["X-Powered-By"] elif "icy-notice1" in headers: - shoutcast = headers['icy-notice2'] + shoutcast = headers["icy-notice2"] else: shoutcast = True @@ -60,7 +60,7 @@ def get_all_data(address): return {"status": status, "metadata": metadata} except urllib.error.HTTPError as e: - print((' Error, HTTPError = ' + str(e.code))) + print((" Error, HTTPError = " + str(e.code))) return {"status": status, "metadata": None} except urllib.error.URLError as e: @@ -93,22 +93,22 @@ def shoutcast_check(response, headers, is_old): bitrate = None contenttype = None - if 'icy-br' in headers: + if "icy-br" in headers: if is_old: - bitrate = headers['icy-br'].split(",")[0] + bitrate = headers["icy-br"].split(",")[0] else: - bitrate = headers['icy-br'] + bitrate = headers["icy-br"] bitrate = bitrate.rstrip() - if 'icy-metaint' in headers: - icy_metaint_header = headers['icy-metaint'] + if "icy-metaint" in headers: + icy_metaint_header = headers["icy-metaint"] else: icy_metaint_header = None if "Content-Type" in headers: - contenttype = headers['Content-Type'].rstrip() - elif 'content-type' in headers: - contenttype = headers['content-type'].rstrip() + contenttype = headers["Content-Type"].rstrip() + elif "content-type" in headers: + contenttype = headers["content-type"].rstrip() if icy_metaint_header: metaint = int(icy_metaint_header) @@ -119,8 +119,16 @@ def shoutcast_check(response, headers, is_old): end = "';" try: - title = re.search(bytes('%s(.*)%s' % (start, end), "utf-8"), content[metaint:]).group(1).decode("utf-8") - title = re.sub("StreamUrl='.*?';", "", title).replace("';", "").replace("StreamUrl='", "") + title = ( + re.search(bytes("%s(.*)%s" % (start, end), "utf-8"), content[metaint:]) + .group(1) + .decode("utf-8") + ) + title = ( + re.sub("StreamUrl='.*?';", "", title) + .replace("';", "") + .replace("StreamUrl='", "") + ) title = re.sub("&artist=.*", "", title) title = re.sub("http://.*", "", title) title.rstrip() @@ -128,7 +136,7 @@ def shoutcast_check(response, headers, is_old): print(("songtitle error: " + str(err))) title = content[metaint:].split(b"'")[1] - return {'song': title, 'bitrate': bitrate, 'contenttype': contenttype} + return {"song": title, "bitrate": bitrate, "contenttype": contenttype} else: print("No metaint") return False @@ -142,6 +150,6 @@ def strip_tags(text): if start >= 0: stop = text[start:].find(">") if stop >= 0: - text = text[:start] + text[start + stop + 1:] + text = text[:start] + text[start + stop + 1 :] finished = 0 return text From b5bd576e853af10de0da48b9e29a38f9d4363317 Mon Sep 17 00:00:00 2001 From: Stefan Derkits Date: Mon, 2 Sep 2019 15:09:35 +0200 Subject: [PATCH 4/9] Add pythonpackage.yml for GithubActions --- .github/workflows/pythonpackage.yml | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/pythonpackage.yml diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml new file mode 100644 index 0000000..bc2f641 --- /dev/null +++ b/.github/workflows/pythonpackage.yml @@ -0,0 +1,34 @@ +name: Python package + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + max-parallel: 4 + matrix: + python-version: [2.7, 3.5, 3.6, 3.7] + + steps: + - uses: actions/checkout@v1 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Lint with flake8 + run: | + pip install flake8 + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pip install pytest + pytest From 3ef2c4f0b8d1779cca89ac98a786443868a8b135 Mon Sep 17 00:00:00 2001 From: Stefan Derkits Date: Mon, 2 Sep 2019 16:35:39 +0200 Subject: [PATCH 5/9] Update pythonpackage.yml --- .github/workflows/pythonpackage.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index bc2f641..07991a5 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -9,7 +9,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: [2.7, 3.5, 3.6, 3.7] + python-version: [3.5, 3.6, 3.7, 3.8] steps: - uses: actions/checkout@v1 @@ -17,10 +17,6 @@ jobs: uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - name: Lint with flake8 run: | pip install flake8 @@ -32,3 +28,6 @@ jobs: run: | pip install pytest pytest + - name: Build source package + run: | + python setup.py sdist From 91040f727688465485c3602f26347b1efef9be6f Mon Sep 17 00:00:00 2001 From: Stefan Derkits Date: Mon, 2 Sep 2019 16:38:14 +0200 Subject: [PATCH 6/9] Update pythonpackage.yml --- .github/workflows/pythonpackage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 07991a5..6d7c574 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -9,7 +9,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: [3.5, 3.6, 3.7, 3.8] + python-version: [3.5, 3.6, 3.7] steps: - uses: actions/checkout@v1 From 16d5298e236d30f1853a885237c2918d136132d1 Mon Sep 17 00:00:00 2001 From: Stefan Derkits Date: Mon, 2 Sep 2019 16:58:24 +0200 Subject: [PATCH 7/9] Update pythonpackage.yml --- .github/workflows/pythonpackage.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 6d7c574..9975809 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -24,10 +24,6 @@ jobs: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Test with pytest - run: | - pip install pytest - pytest - name: Build source package run: | python setup.py sdist From 7ca76ec019b392871001d3638db91735f7c55968 Mon Sep 17 00:00:00 2001 From: Stefan Derkits Date: Sat, 15 May 2021 19:31:44 +0200 Subject: [PATCH 8/9] Always try to get Shoutcast Metadata Some streams have gateways (e.g. via nginx) and thus dont have shoutcast in server header or x-powered-by or icy-notice-1 Check them by assuming they are old servers to be most compatible --- streamscrobbler/streamscrobbler.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/streamscrobbler/streamscrobbler.py b/streamscrobbler/streamscrobbler.py index fe7996e..ec03949 100644 --- a/streamscrobbler/streamscrobbler.py +++ b/streamscrobbler/streamscrobbler.py @@ -39,21 +39,15 @@ def get_all_data(address): else: shoutcast = True - if isinstance(shoutcast, bool): - if shoutcast: - status = 1 - else: - status = 0 - metadata = False + if isinstance(shoutcast, bool) and shoutcast: + status = 1 + metadata = shoutcast_check(response, headers, True) elif "SHOUTcast" in shoutcast: status = 1 metadata = shoutcast_check(response, headers, False) elif "Icecast" or "137" or "StreamMachine" in shoutcast: status = 1 metadata = shoutcast_check(response, headers, True) - elif shoutcast: - status = 1 - metadata = shoutcast_check(response, headers, True) else: metadata = False response.close() @@ -98,7 +92,7 @@ def shoutcast_check(response, headers, is_old): bitrate = headers["icy-br"].split(",")[0] else: bitrate = headers["icy-br"] - bitrate = bitrate.rstrip() + bitrate = bitrate.rstrip() if "icy-metaint" in headers: icy_metaint_header = headers["icy-metaint"] From a41d2101d3c64a798b76d3811152d612efaa60f7 Mon Sep 17 00:00:00 2001 From: Stefan Derkits Date: Sat, 15 May 2021 19:37:11 +0200 Subject: [PATCH 9/9] bump version to 0.0.3 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0182a7e..841cb37 100755 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name="streamscrobbler", packages=["streamscrobbler"], - version="0.0.2", + version="0.0.3", description="A python class used on Dirble.com to get titles and bitrates on shoutcast and icecast streams", author="Håkan Nylén", author_email="confacted@gmail.com",