From 6c9d35c7910254d0c9d0536a8661d1d22ccdbb2c Mon Sep 17 00:00:00 2001 From: ComradeCrow Date: Sun, 21 Jan 2024 16:40:38 -0800 Subject: initial commit --- .gitignore | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ podweb.py | 102 ++++++++++++++++++++++++++++++++++++ readme.md | 2 + requirements.txt | 6 +++ 4 files changed, 266 insertions(+) create mode 100644 .gitignore create mode 100755 podweb.py create mode 100644 readme.md create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b92086e --- /dev/null +++ b/.gitignore @@ -0,0 +1,156 @@ +# ---> Python +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +debug_* +*.opml \ No newline at end of file diff --git a/podweb.py b/podweb.py new file mode 100755 index 0000000..4ac83ea --- /dev/null +++ b/podweb.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +import os +import copy +import click +import yaml +import xml + +import podcastparser +import urllib + +global options +options = {"DEBUG": False, "serverlist": os.path.normpath(os.path.join(os.path.expanduser("~/.config/podweb"), "serverlist")), "podcastpath": ""} + +class PodWeb(): + + def __init__(self, DEBUG : bool = False) -> None: + self.options = options + self.options.update({"DEBUG": DEBUG}) + self.servers = [] + self.DEFAULT_SERVERLIST_HEADING = '''## You can add podcast xml feeds here. +## You can also optionally add categories and names for the podcasts. +## The order of category, name, and url does not matter. +## Here are some example entries: +## - category: example category +## name: example podcast 1 +## url: https://example.com/feed.xml +## - name: example podcast 2 +## url: example.com/feed2.xml +''' + + if self.options["DEBUG"]: + self.config_path = "." + self.config_filepath = "debug_config.yaml" + self.options["serverlist"] = "debug_serverlist" + else: + self.config_path = os.path.normpath(os.path.expanduser("~/.config/podweb")) + self.config_filepath = os.path.join(self.config_path, "config.yaml") + + self._load_config() + self._load_serverlist() + + def _load_config(self) -> None: + + if not os.path.exists(self.config_path): os.makedirs(self.config_path) + + if not os.path.isfile(self.config_filepath): + with open(self.config_filepath, "w+") as f: + yaml.dump(self.options, f) + + else: + with open(self.config_filepath, "r+") as f: + self.options.update(yaml.full_load(f)) + + def _update_config(self, changed_option : dict) -> None: + '''Makes a change to the config file''' + with open(self.options["serverlist"], "w+") as f: + config_options = yaml.full_load(f) + config_options.update(changed_option) + f.write(config_options) + + def _load_serverlist(self) -> list: + '''Loads the contents of the serverlist''' + self._create_serverlist() + with open(self.options["serverlist"], "r+") as f: + content = yaml.full_load(f) + if content: + self.servers = content + + def _create_serverlist(self) -> None: + '''Checks if the serverlist does not exist and creates it if not''' + if not os.path.isfile(self.options["serverlist"]): + with open(self.options["serverlist"], "w+") as f: + f.write(self.DEFAULT_SERVERLIST_HEADING) + + def _update_serverlist(self) -> None: + '''This is destructive and overwrites the current serverlist with the stored serverlist''' + with open(self.options["serverlist"], "w+") as f: + f.write(self.DEFAULT_SERVERLIST_HEADING) + if len(self.servers): + with open(self.options["serverlist"], "a") as f: + yaml.dump(self.servers, f) + + def add_podcast(self, feedurl : str, name = None, category = None) -> None: + for i in self.servers: + iparse = urllib.parse.urlparse(i["url"]) + feedparse = urllib.parse.urlparse(feedurl) + if iparse.hostname == feedparse.hostname and iparse.path == feedparse.path: + return None + parsed = podcastparser.parse(feedurl, urllib.request.urlopen(feedurl)) + if name: + new_feed = {"url": feedurl, "name": name} + else: + new_feed = {"url": feedurl, "name": parsed["title"]} + if category: new_feed.update({"category": category}) + self.servers.append(new_feed) + self._update_serverlist() + + def import_opml(self, opml_path : str): + pass + + +testweb = PodWeb(DEBUG = True) \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..e423f9a --- /dev/null +++ b/readme.md @@ -0,0 +1,2 @@ +#PodWeb +A small in-progress cli podcast fetcher \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..d9967a0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +podcastparser +pyyaml +click +pytest >= 4.6 +pytest-cov +coverage -- cgit 1.4.1-2-gfad0