jnfilter @ 2e9afc9e92c12b0fe026ec4aa286b812f3c2186c

 1import re
 2from functools import reduce
 3from typing import List, Iterator
 4from xml.etree.ElementTree import ElementTree, fromstring, tostring, register_namespace
 5
 6import httpx
 7from fastapi import FastAPI
 8from starlette.responses import Response, PlainTextResponse
 9
10app = FastAPI()
11
12URL = "https://jovemnerd.com.br/feed-nerdcast/"
13
14RegexCollection = {
15    "nerdcast": "NerdCast [0-9]+[a-c]* -",
16    "empreendedor": "Empreendedor [0-9]+ -",
17    "mamicas": "Caneca de Mamicas [0-9]+ -",
18    "english": "Speak English [0-9]+ -",
19    "nerdcash": "NerdCash [0-9]+ -",
20    "bunker": "Lá do Bunker  [0-9]+ -",
21}
22
23register_namespace("googleplay", "http://www.google.com/schemas/play-podcasts/1.0")
24register_namespace("itunes", "http://www.itunes.com/dtds/podcast-1.0.dtd")
25register_namespace("atom", "http://www.w3.org/2005/Atom")
26
27
28class XMLResponse(Response):
29    media_type = "application/xml"
30
31
32def match(title: str, series: List[str]) -> bool:
33    def _match(s):
34        return re.match(RegexCollection[s], title) is not None
35
36    return reduce(lambda x, y: x or _match(y), series, False)
37
38
39def filter_xml(xml_str: str, series: List[str]) -> str:
40    tree = ElementTree(fromstring(xml_str))
41    tree_root = tree.getroot()
42    for channel in tree_root.findall("./channel"):
43        for item in channel.findall("item"):
44            title = item.find("title").text
45            if not match(title, series):
46                channel.remove(item)
47
48    return tostring(tree_root, encoding='utf8', method='xml')
49
50
51def filter_titles_xml(xml_str) -> Iterator[str]:
52    tree = ElementTree(fromstring(xml_str))
53    tree_root = tree.getroot()
54    for item in tree_root.findall("./channel/item"):
55        yield item.find("title").text
56
57
58async def load_and_filter(series: str) -> str:
59    series = series or 'nerdcast'
60    series = series.split(',')
61    async with httpx.AsyncClient() as client:
62        response = await client.get(URL)
63        xml_str = response.content
64        return filter_xml(xml_str, series)
65
66
67async def load_titles() -> Iterator[str]:
68    async with httpx.AsyncClient() as client:
69        response = await client.get(URL)
70        xml_str = response.content
71        return filter_titles_xml(xml_str)
72
73
74@app.get("/", response_class=XMLResponse)
75async def root(q: str = ''):
76    return await load_and_filter(q)
77
78
79@app.get("/titles", response_class=PlainTextResponse)
80async def titles():
81    titles = await load_titles()
82    return "\n".join(titles)
83
84
85@app.get("/series")
86async def titles():
87    return [i[0] for i in RegexCollection.items()]