Refactoring work to make this a real program

master
bspeice 2016-05-17 10:40:23 -04:00
parent 5853c86a2d
commit fcc280b96c
13 changed files with 215 additions and 174 deletions

View File

@ -13,23 +13,7 @@
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="Python 3.5.1 (C:\Users\Bradlee Speice\Anaconda3\python.exe)" project-jdk-type="Python SDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="Python 3.5.1 (C:\Users\Bradlee Speice\Anaconda3\python.exe)" project-jdk-type="Python SDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
<component name="masterDetails">
<states>
<state key="ProjectJDKs.UI">
<settings>
<last-edited>Python 3.5.1 (C:\Users\Bradlee Speice\Anaconda3\python.exe)</last-edited>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project>

View File

@ -1,12 +1,15 @@
# Format: (all args are passed to __init__ as kwargs
# Format (all args are passed to __init__ as kwargs:
#
# <mountpoint>:
# class: <feed_class>
# args:
# key: value
subfactory-show:
package: bassdrive
class: BassdriveFeed
server:
port: 10000
podcasts:
subfactory-show:
class: podcasters.BassdriveFeed
args:
url: http://archives.bassdrivearchive.com/1%20-%20Monday/Subfactory%20Show%20-%20DJ%20Spim/
logo: http://www.bassdrive.com/img/radio_schedule_entries/image/original/subfactory-web-add-56.jpg

View File

@ -2,7 +2,9 @@
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>

View File

@ -1,30 +0,0 @@
"""
Given a configuration file, set up everything needed to kick
off the server.
"""
from importlib import import_module
import yaml
from pyramid.config import Configurator
from os.path import expanduser, join
# Needed for import_module call
# noinspection PyUnresolvedReferences
import modules
def build_configuration(conf=None) -> Configurator:
if conf is None:
conf = join(expanduser('~'), '.repodrc')
with open(conf) as conf_file:
conf_dict = yaml.load(conf_file)
server_conf = Configurator()
for mountpoint, feed in conf_dict.items():
feed_package = import_module('modules.' + feed['package'])
feed_class = getattr(feed_package, feed['class'])
feed_instance = feed_class(**feed['args'])
server_conf.add_route(mountpoint, '/' + mountpoint + '/')
server_conf.add_view(feed_instance.view, route_name=mountpoint)
return server_conf

View File

@ -1,10 +0,0 @@
from wsgiref.simple_server import make_server
from conf_parser import build_configuration
def start_server():
app = build_configuration().make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
if __name__ == '__main__':
start_server()

38
src/conf_parser.py Normal file
View File

@ -0,0 +1,38 @@
"""
Given a configuration file, set up everything needed to kick
off the server.
"""
from importlib import import_module
import yaml
from pyramid.config import Configurator
def build_configurator(podcasts: dict) -> Configurator:
server_conf = Configurator()
for mountpoint, feed in podcasts:
package, class_name = feed['class'].rsplit('.', 1)
feed_package = import_module(package)
feed_class = getattr(feed_package, class_name)
feed_instance = feed_class(**feed['args'])
server_conf.add_route(mountpoint, '/' + mountpoint + '/')
server_conf.add_view(feed_instance.view, route_name=mountpoint)
def build_configuration_text(file_str: str) -> (dict, Configurator):
conf_dict = yaml.load(file_str)
server_opts = conf_dict.get('server', None)
podcasts = build_configurator(conf_dict['podcasts'])
return server_opts, podcasts
def build_configuration(file_name) -> (dict, Configurator):
try:
with open(file_name) as conf_file:
return build_configuration_text(conf_file.read())
except FileNotFoundError:
print("Could not locate configuration file " +
"(does {} exist?)".format(file_name))
raise

View File

@ -11,6 +11,7 @@ class BasePodcast():
"Return a list of all episodes, in descending date order"
pass
# noinspection PyUnusedLocal
def view(self, request):
fg = self.build_feed()
response = Response(fg.rss_str(pretty=True))

View File

@ -1,22 +1,26 @@
"""
Podcast provider for the Bassdrive Archives
"""
from datetime import datetime
from html.parser import HTMLParser
from urllib.parse import unquote
import requests
from feedgen.feed import FeedGenerator
from podcast import BasePodcast
from datetime import datetime
from pytz import UTC
from podcasters.base import BasePodcast
class BassdriveParser(HTMLParser):
def error(self, message):
return super().error(message)
record_link_text = False
link_url = ''
def __init__(self, *args, **kwargs):
# noinspection PyArgumentList
super().__init__(*args, **kwargs)
self.links = []
@ -62,7 +66,6 @@ class BassdriveFeed(BasePodcast):
# And turn them into something usable
fg = FeedGenerator()
#fg.load_extension('podcast')
fg.id(self.url)
fg.title(self.title)
fg.description(self.title)
@ -79,8 +82,8 @@ class BassdriveFeed(BasePodcast):
fe.enclosure(self.url + link[1], 0, 'audio/mpeg')
# Bassdrive always uses date strings of
# [yyyy.mm.dd] with 0 padding, so that
# makes our lives easy
# [yyyy.mm.dd] with 0 padding on days and months,
# so that makes our lives easy
date_start = link[0].find('[')
date_str = link[0][date_start:date_start+12]
published = datetime.strptime(date_str, '[%Y.%m.%d]')

38
src/server.py Normal file
View File

@ -0,0 +1,38 @@
import argparse
from wsgiref.simple_server import make_server
from conf_parser import build_configuration
from os.path import expanduser, join
# noinspection PyUnresolvedReferences
def start_server(cmd_args: dict):
try:
server_conf, configurator = build_configuration(cmd_args.configuration)
app = configurator.make_wsgi_app()
server = make_server(cmd_args.host, cmd_args.port, app)
server.serve_forever()
except FileNotFoundError:
print("Unable to find configuration file. Does {} exist?"
.format(cmd_args.configuration))
except AttributeError:
print("Unable to parse configuration file. Is {} a valid YML file?"
.format(cmd_args.configuration))
except KeyError:
print('Unable to parse configuration file. Is there a `podcasts`'
'section?')
if __name__ == '__main__':
default_rc = join(expanduser('~'), '.repodrc')
parser = argparse.ArgumentParser()
parser.add_argument('--verbose', help='Run server in verbose mode')
parser.add_argument('--port', type=int, default=10000,
help='Port to use when starting the server')
parser.add_argument('--host', type=str, default='0.0.0.0',
help='Host address to start the server')
parser.add_argument('--configuration', type=str, default=default_rc,
help='Configuration file to start the server')
args = parser.parse_args()
start_server(args)

0
src/tests/__init__.py Normal file
View File

View File

@ -0,0 +1,12 @@
from unittest import TestCase
import conf_parser
class TestBuild_configurator(TestCase):
def test_build_configurator(self):
try:
# noinspection PyTypeChecker
conf_parser.build_configurator(None)
self.fail("Must have dictionary to set up configurator")
except TypeError:
pass