From 5e00f7eb42f2c533bd0b99acba5a2b8b0e9829fb Mon Sep 17 00:00:00 2001 From: Gabriel Arakaki Giovanini Date: Sun, 26 Jun 2022 15:50:22 +0200 Subject: feat: Adiocina processo na pipeline para gerar rpm Esse vai ser a forma padrao de dar deploy no `gabrielgio.me`. --- .build.yml | 24 ++++++++++++ .gitlab-ci.yml | 14 ------- Makefile | 15 ++++++++ jnfilter/main.py | 94 +++++++++++++++++++++++++++++++++++++++++++++++ main.py | 89 -------------------------------------------- requirements.txt | 3 -- setup.py | 23 ++++++++++++ test/dev-requirements.txt | 0 test/test_main.py | 0 9 files changed, 156 insertions(+), 106 deletions(-) create mode 100644 .build.yml delete mode 100644 .gitlab-ci.yml create mode 100644 Makefile create mode 100644 jnfilter/main.py delete mode 100644 main.py delete mode 100644 requirements.txt create mode 100644 setup.py create mode 100644 test/dev-requirements.txt create mode 100644 test/test_main.py diff --git a/.build.yml b/.build.yml new file mode 100644 index 0000000..79061c0 --- /dev/null +++ b/.build.yml @@ -0,0 +1,24 @@ +image: fedora/36 +packages: + - rsync + - make + +secrets: + - 008c4f67-b864-47f8-9790-cd32f2ae8516 + +environment: + deploy: builds@gabrielgio.me + +tasks: + - deps: | + cd jnfilter + make install_deps + - build: | + cd jnfilter + make + - deploy: | + cd jnfilter + sshopts="ssh -o StrictHostKeyChecking=no" + rsync --rsh="$sshopts" -rP dist/*.rpm $deploy:/var/www/artifacs.gabrielgio.me/jnfilter/ + + diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 23dbe2b..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,14 +0,0 @@ -pages: - image: - name: pandoc/alpine - entrypoint: - - "" - stage: build - script: - - mkdir public - - pandoc -s --include-in-header=docs/bamboo.min.css -s README.md -o public/index.html - artifacts: - paths: - - public - only: - - master diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ed3ae00 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ + +rpm: rpm_dist + rpmbuild -bb \ + ./build/bdist.linux-x86_64/rpm/SPECS/jnfilter.spec \ + --define "_topdir $(PWD)/build/bdist.linux-x86_64/rpm/" + +rpm_dist: + python setup.py bdist_rpm + +clean: + python setup.py clean --all + rm -rf dist jnfilter.egg-info + +install_deps: + dnf install -y rpmdevtools rpmlint python diff --git a/jnfilter/main.py b/jnfilter/main.py new file mode 100644 index 0000000..9795b8c --- /dev/null +++ b/jnfilter/main.py @@ -0,0 +1,94 @@ +import re +import httpx +import uvicorn + +from functools import reduce +from typing import List, Iterator +from xml.etree.ElementTree import ElementTree, fromstring, tostring, register_namespace +from fastapi import FastAPI +from starlette.responses import Response, PlainTextResponse + + +app = FastAPI() + +URL = "https://jovemnerd.com.br/feed-nerdcast/" + +RegexCollection = { + "nerdcast": "NerdCast [0-9]+[a-c]* -", + "empreendedor": "Empreendedor [0-9]+ -", + "mamicas": "Caneca de Mamicas [0-9]+ -", + "english": "Speak English [0-9]+ -", + "nerdcash": "NerdCash [0-9]+ -", + "bunker": "Lá do Bunker [0-9]+ -", + "tech": "NerdTech [0-9]+ -", + "genera": "Generacast [0-9]+ -", +} + +register_namespace("googleplay", "http://www.google.com/schemas/play-podcasts/1.0") +register_namespace("itunes", "http://www.itunes.com/dtds/podcast-1.0.dtd") +register_namespace("atom", "http://www.w3.org/2005/Atom") + + +class XMLResponse(Response): + media_type = "application/xml" + + +def match(title: str, series: List[str]) -> bool: + def _match(s): + return re.match(RegexCollection[s], title) is not None + + return reduce(lambda x, y: x or _match(y), series, False) + + +def filter_xml(xml_str: str, series: List[str]) -> str: + tree = ElementTree(fromstring(xml_str)) + tree_root = tree.getroot() + for channel in tree_root.findall("./channel"): + for item in channel.findall("item"): + title = item.find("title").text + if not match(title, series): + channel.remove(item) + + return tostring(tree_root, encoding='utf8', method='xml') + + +def filter_titles_xml(xml_str) -> Iterator[str]: + tree = ElementTree(fromstring(xml_str)) + tree_root = tree.getroot() + for item in tree_root.findall("./channel/item"): + yield item.find("title").text + + +async def load_and_filter(series: str) -> str: + series = series or 'nerdcast' + series = series.split(',') + async with httpx.AsyncClient() as client: + response = await client.get(URL) + xml_str = response.content + return filter_xml(xml_str, series) + + +async def load_titles() -> Iterator[str]: + async with httpx.AsyncClient() as client: + response = await client.get(URL) + xml_str = response.content + return filter_titles_xml(xml_str) + +@app.head("/") +@app.get("/", response_class=XMLResponse) +async def root(q: str = ''): + return await load_and_filter(q) + + +@app.get("/titles", response_class=PlainTextResponse) +async def titles(): + titles = await load_titles() + return "\n".join(titles) + + +@app.get("/series") +async def titles(): + return [i[0] for i in RegexCollection.items()] + +def run(): + uvicorn.run(app=app, host="0.0.0.0", port=32000) diff --git a/main.py b/main.py deleted file mode 100644 index 1f909b0..0000000 --- a/main.py +++ /dev/null @@ -1,89 +0,0 @@ -import re -from functools import reduce -from typing import List, Iterator -from xml.etree.ElementTree import ElementTree, fromstring, tostring, register_namespace - -import httpx -from fastapi import FastAPI -from starlette.responses import Response, PlainTextResponse - -app = FastAPI() - -URL = "https://jovemnerd.com.br/feed-nerdcast/" - -RegexCollection = { - "nerdcast": "NerdCast [0-9]+[a-c]* -", - "empreendedor": "Empreendedor [0-9]+ -", - "mamicas": "Caneca de Mamicas [0-9]+ -", - "english": "Speak English [0-9]+ -", - "nerdcash": "NerdCash [0-9]+ -", - "bunker": "Lá do Bunker [0-9]+ -", - "tech": "NerdTech [0-9]+ -", - "genera": "Generacast [0-9]+ -", -} - -register_namespace("googleplay", "http://www.google.com/schemas/play-podcasts/1.0") -register_namespace("itunes", "http://www.itunes.com/dtds/podcast-1.0.dtd") -register_namespace("atom", "http://www.w3.org/2005/Atom") - - -class XMLResponse(Response): - media_type = "application/xml" - - -def match(title: str, series: List[str]) -> bool: - def _match(s): - return re.match(RegexCollection[s], title) is not None - - return reduce(lambda x, y: x or _match(y), series, False) - - -def filter_xml(xml_str: str, series: List[str]) -> str: - tree = ElementTree(fromstring(xml_str)) - tree_root = tree.getroot() - for channel in tree_root.findall("./channel"): - for item in channel.findall("item"): - title = item.find("title").text - if not match(title, series): - channel.remove(item) - - return tostring(tree_root, encoding='utf8', method='xml') - - -def filter_titles_xml(xml_str) -> Iterator[str]: - tree = ElementTree(fromstring(xml_str)) - tree_root = tree.getroot() - for item in tree_root.findall("./channel/item"): - yield item.find("title").text - - -async def load_and_filter(series: str) -> str: - series = series or 'nerdcast' - series = series.split(',') - async with httpx.AsyncClient() as client: - response = await client.get(URL) - xml_str = response.content - return filter_xml(xml_str, series) - - -async def load_titles() -> Iterator[str]: - async with httpx.AsyncClient() as client: - response = await client.get(URL) - xml_str = response.content - return filter_titles_xml(xml_str) - -@app.head("/") -@app.get("/", response_class=XMLResponse) -async def root(q: str = ''): - return await load_and_filter(q) - - -@app.get("/titles", response_class=PlainTextResponse) -async def titles(): - titles = await load_titles() - return "\n".join(titles) - - -@app.get("/series") -async def titles(): - return [i[0] for i in RegexCollection.items()] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 092f079..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -httpx==0.21.1 -fastapi==0.70.0 -uvicorn==0.15.0 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..96868e5 --- /dev/null +++ b/setup.py @@ -0,0 +1,23 @@ +from setuptools import setup + +requirements = [ + 'httpx==0.21.1', + 'fastapi==0.70.0', + 'uvicorn==0.15.0' +] + + +setup(name='jnfilter', + version='0.2.0', + description='A FastAPI server to filter Nercast podcast feed', + url='https://git.sr.ht/~gabrielgio/jnfilter', + author='Gabriel Arakaki Giovanini', + author_email='mail@gabrielgio.me', + license='MIT', + packages=['jnfilter'], + entry_points=""" + [console_scripts] + jnfilterd=jnfilter.main:run + """, + install_requires=requirements, + zip_safe=False) diff --git a/test/dev-requirements.txt b/test/dev-requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/test_main.py b/test/test_main.py new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3