mirror of
				https://github.com/bspeice/elektricity
				synced 2025-10-31 17:20:23 -04:00 
			
		
		
		
	Initial repod server commit with basic Bassdrive support
This commit is contained in:
		
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| *.pyc | ||||
| bin/ | ||||
| lib/ | ||||
| share/ | ||||
| include/ | ||||
| .idea/workspace.xml | ||||
							
								
								
									
										1
									
								
								.idea/.name
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.idea/.name
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| repod | ||||
							
								
								
									
										22
									
								
								.idea/compiler.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								.idea/compiler.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="CompilerConfiguration"> | ||||
|     <resourceExtensions /> | ||||
|     <wildcardResourcePatterns> | ||||
|       <entry name="!?*.java" /> | ||||
|       <entry name="!?*.form" /> | ||||
|       <entry name="!?*.class" /> | ||||
|       <entry name="!?*.groovy" /> | ||||
|       <entry name="!?*.scala" /> | ||||
|       <entry name="!?*.flex" /> | ||||
|       <entry name="!?*.kt" /> | ||||
|       <entry name="!?*.clj" /> | ||||
|       <entry name="!?*.aj" /> | ||||
|     </wildcardResourcePatterns> | ||||
|     <annotationProcessing> | ||||
|       <profile default="true" name="Default" enabled="false"> | ||||
|         <processorPath useClasspath="true" /> | ||||
|       </profile> | ||||
|     </annotationProcessing> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										3
									
								
								.idea/copyright/profiles_settings.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.idea/copyright/profiles_settings.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| <component name="CopyrightManager"> | ||||
|   <settings default="" /> | ||||
| </component> | ||||
							
								
								
									
										6
									
								
								.idea/encodings.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.idea/encodings.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="Encoding"> | ||||
|     <file url="PROJECT" charset="UTF-8" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										35
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="FrameworkDetectionExcludesConfiguration"> | ||||
|     <type id="django" /> | ||||
|   </component> | ||||
|   <component name="ProjectLevelVcsManager" settingsEditedManually="false"> | ||||
|     <OptionsSetting value="true" id="Add" /> | ||||
|     <OptionsSetting value="true" id="Remove" /> | ||||
|     <OptionsSetting value="true" id="Checkout" /> | ||||
|     <OptionsSetting value="true" id="Update" /> | ||||
|     <OptionsSetting value="true" id="Status" /> | ||||
|     <OptionsSetting value="true" id="Edit" /> | ||||
|     <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"> | ||||
|     <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> | ||||
							
								
								
									
										8
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="ProjectModuleManager"> | ||||
|     <modules> | ||||
|       <module fileurl="file://$PROJECT_DIR$/repod.iml" filepath="$PROJECT_DIR$/repod.iml" /> | ||||
|     </modules> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										4
									
								
								Requirements
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								Requirements
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| pyramid>=1.6.1 | ||||
| feedgen>=0.3.2 | ||||
| PyYAML>=3.11 | ||||
| requests>=2.9.1 | ||||
							
								
								
									
										11
									
								
								example_conf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								example_conf.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| # Format: (all args are passed to __init__ as kwargs | ||||
| # | ||||
| # <mountpoint>: | ||||
| #   class: <feed_class> | ||||
| #   args: | ||||
| #     key: value | ||||
| subfactory-show: | ||||
|   package: bassdrive | ||||
|   class: BassdriveFeed | ||||
|   args: | ||||
|     url: http://archives.bassdrivearchive.com/1%20-%20Monday/Subfactory%20Show%20-%20DJ%20Spim/ | ||||
							
								
								
									
										9
									
								
								repod.iml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								repod.iml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <module type="PYTHON_MODULE" version="4"> | ||||
|   <component name="NewModuleRootManager" inherit-compiler-output="true"> | ||||
|     <exclude-output /> | ||||
|     <content url="file://$MODULE_DIR$" /> | ||||
|     <orderEntry type="inheritedJdk" /> | ||||
|     <orderEntry type="sourceFolder" forTests="false" /> | ||||
|   </component> | ||||
| </module> | ||||
							
								
								
									
										0
									
								
								repod/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								repod/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										29
									
								
								repod/conf_parser.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								repod/conf_parser.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| """ | ||||
| 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 | ||||
|  | ||||
| # Needed for import_module call | ||||
| # noinspection PyUnresolvedReferences | ||||
| import modules | ||||
|  | ||||
| # Hardcoded, need to look up from users $HOME later | ||||
| file_loc = 'example_conf.yaml' | ||||
|  | ||||
|  | ||||
| def build_configuration(conf=file_loc) -> Configurator: | ||||
|     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 | ||||
							
								
								
									
										11
									
								
								repod/example_conf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								repod/example_conf.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| # Format: (all args are passed to __init__ as kwargs | ||||
| # | ||||
| # <mountpoint>: | ||||
| #   class: <feed_class> | ||||
| #   args: | ||||
| #     key: value | ||||
| subfactory-show: | ||||
|   package: bassdrive | ||||
|   class: BassdriveFeed | ||||
|   args: | ||||
|     url: http://archives.bassdrivearchive.com/1%20-%20Monday/Subfactory%20Show%20-%20DJ%20Spim/ | ||||
							
								
								
									
										0
									
								
								repod/modules/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								repod/modules/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										74
									
								
								repod/modules/bassdrive.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								repod/modules/bassdrive.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,74 @@ | ||||
| """ | ||||
| Podcast provider for the Bassdrive Archives | ||||
| """ | ||||
| from html.parser import HTMLParser | ||||
| from urllib.parse import unquote | ||||
|  | ||||
| import requests | ||||
| from feedgen.feed import FeedGenerator | ||||
|  | ||||
| from podcast import BasePodcast | ||||
|  | ||||
|  | ||||
| class BassdriveParser(HTMLParser): | ||||
|     links = [] | ||||
|     record_link_text = False | ||||
|     link_url = '' | ||||
|  | ||||
|     def handle_starttag(self, tag, attrs): | ||||
|         href = '' | ||||
|         for attr, val in attrs: | ||||
|             if attr == 'href': | ||||
|                 href = val | ||||
|  | ||||
|         if tag == 'a' and href.find('mp3') != -1: | ||||
|             self.record_link_text = True | ||||
|             self.link_url = href | ||||
|  | ||||
|     def handle_data(self, data): | ||||
|         if self.record_link_text: | ||||
|             print(self.link_url) | ||||
|             self.links.append((data, self.link_url)) | ||||
|             self.record_link_text = False | ||||
|  | ||||
|     def get_links(self): | ||||
|         # Reverse to sort in descending date order | ||||
|         self.links.reverse() | ||||
|         return self.links | ||||
|  | ||||
|  | ||||
| class BassdriveFeed(BasePodcast): | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         print(kwargs) | ||||
|         self.url = kwargs['url'] | ||||
|         # Get the title and DJ while handling trailing slash | ||||
|         url_pretty = unquote(self.url) | ||||
|         elems = filter(lambda x: x, url_pretty.split('/')) | ||||
|         self.title, self.dj = list(elems)[-1].split(' - ') | ||||
|  | ||||
|     def build_feed(self): | ||||
|         "Build the feed given our existing URL" | ||||
|         # Get all the episodes | ||||
|         page_content = str(requests.get(self.url).content) | ||||
|         parser = BassdriveParser() | ||||
|         parser.feed(page_content) | ||||
|         links = parser.get_links() | ||||
|  | ||||
|         # And turn them into something usable | ||||
|         fg = FeedGenerator() | ||||
|         fg.load_extension('podcast') | ||||
|         fg.id(self.url) | ||||
|         fg.title(self.title) | ||||
|         fg.description(self.title) | ||||
|         fg.author({'name': self.dj}) | ||||
|         fg.language('en') | ||||
|         fg.link({'href': self.url, 'rel': 'alternate'}) | ||||
|  | ||||
|         for link in links: | ||||
|             fe = fg.add_entry() | ||||
|             fe.author({'name': self.dj}) | ||||
|             fe.title(link[0]) | ||||
|             fe.description(link[0]) | ||||
|             fe.enclosure(self.url + link[1], 0, 'audio/mpeg') | ||||
|  | ||||
|         return fg | ||||
							
								
								
									
										16
									
								
								repod/podcast.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								repod/podcast.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| """ | ||||
| Base skeleton for what needs to be implemented by a podcast provider | ||||
| """ | ||||
| from feedgen.feed import FeedGenerator | ||||
| from pyramid.response import Response | ||||
|  | ||||
| class BasePodcast(): | ||||
|     def build_feed(self) -> FeedGenerator: | ||||
|         "Return a list of all episodes, in descending date order" | ||||
|         pass | ||||
|  | ||||
|     def view(self, request): | ||||
|         fg = self.build_feed() | ||||
|         response = Response(fg.rss_str(pretty=True)) | ||||
|         response.content_type = 'application/rss+xml' | ||||
|         return response | ||||
							
								
								
									
										10
									
								
								repod/server.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								repod/server.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| 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() | ||||
		Reference in New Issue
	
	Block a user
	 Bradlee Speice
					Bradlee Speice