jnfilter @ 2e9afc9e92c12b0fe026ec4aa286b812f3c2186c

Adiciona projeto inicial
  1diff --git a/.gitignore b/.gitignore
  2new file mode 100644
  3index 0000000000000000000000000000000000000000..b22ec9270590c359205e8c9e396771a2f3e6a2ed
  4--- /dev/null
  5+++ b/.gitignore
  6@@ -0,0 +1,3 @@
  7+.idea/
  8+__pycache__/
  9+
 10diff --git a/Procfile b/Procfile
 11new file mode 100644
 12index 0000000000000000000000000000000000000000..60ee5896c1c4de0851455a9fd9652569b36ee612
 13--- /dev/null
 14+++ b/Procfile
 15@@ -0,0 +1 @@
 16+web: uvicorn main:app --host=0.0.0.0 --port=${PORT}
 17diff --git a/main.py b/main.py
 18new file mode 100644
 19index 0000000000000000000000000000000000000000..f86611fa9ee1dfcfc15dd6b36bf3afd32fd076e5
 20--- /dev/null
 21+++ b/main.py
 22@@ -0,0 +1,87 @@
 23+import re
 24+from functools import reduce
 25+from typing import List, Iterator
 26+from xml.etree.ElementTree import ElementTree, fromstring, tostring, register_namespace
 27+
 28+import httpx
 29+from fastapi import FastAPI
 30+from starlette.responses import Response, PlainTextResponse
 31+
 32+app = FastAPI()
 33+
 34+URL = "https://jovemnerd.com.br/feed-nerdcast/"
 35+
 36+RegexCollection = {
 37+    "nerdcast": "NerdCast [0-9]+[a-c]* -",
 38+    "empreendedor": "Empreendedor [0-9]+ -",
 39+    "mamicas": "Caneca de Mamicas [0-9]+ -",
 40+    "english": "Speak English [0-9]+ -",
 41+    "nerdcash": "NerdCash [0-9]+ -",
 42+    "bunker": "Lá do Bunker  [0-9]+ -",
 43+}
 44+
 45+register_namespace("googleplay", "http://www.google.com/schemas/play-podcasts/1.0")
 46+register_namespace("itunes", "http://www.itunes.com/dtds/podcast-1.0.dtd")
 47+register_namespace("atom", "http://www.w3.org/2005/Atom")
 48+
 49+
 50+class XMLResponse(Response):
 51+    media_type = "application/xml"
 52+
 53+
 54+def match(title: str, series: List[str]) -> bool:
 55+    def _match(s):
 56+        return re.match(RegexCollection[s], title) is not None
 57+
 58+    return reduce(lambda x, y: x or _match(y), series, False)
 59+
 60+
 61+def filter_xml(xml_str: str, series: List[str]) -> str:
 62+    tree = ElementTree(fromstring(xml_str))
 63+    tree_root = tree.getroot()
 64+    for channel in tree_root.findall("./channel"):
 65+        for item in channel.findall("item"):
 66+            title = item.find("title").text
 67+            if not match(title, series):
 68+                channel.remove(item)
 69+
 70+    return tostring(tree_root, encoding='utf8', method='xml')
 71+
 72+
 73+def filter_titles_xml(xml_str) -> Iterator[str]:
 74+    tree = ElementTree(fromstring(xml_str))
 75+    tree_root = tree.getroot()
 76+    for item in tree_root.findall("./channel/item"):
 77+        yield item.find("title").text
 78+
 79+
 80+async def load_and_filter(series: str) -> str:
 81+    series = series or 'nerdcast'
 82+    series = series.split(',')
 83+    async with httpx.AsyncClient() as client:
 84+        response = await client.get(URL)
 85+        xml_str = response.content
 86+        return filter_xml(xml_str, series)
 87+
 88+
 89+async def load_titles() -> Iterator[str]:
 90+    async with httpx.AsyncClient() as client:
 91+        response = await client.get(URL)
 92+        xml_str = response.content
 93+        return filter_titles_xml(xml_str)
 94+
 95+
 96+@app.get("/", response_class=XMLResponse)
 97+async def root(q: str = ''):
 98+    return await load_and_filter(q)
 99+
100+
101+@app.get("/titles", response_class=PlainTextResponse)
102+async def titles():
103+    titles = await load_titles()
104+    return "\n".join(titles)
105+
106+
107+@app.get("/series")
108+async def titles():
109+    return [i[0] for i in RegexCollection.items()]
110diff --git a/requirements.txt b/requirements.txt
111new file mode 100644
112index 0000000000000000000000000000000000000000..092f079d3dd2bf9c4e743c7681767edc87b415b5
113--- /dev/null
114+++ b/requirements.txt
115@@ -0,0 +1,3 @@
116+httpx==0.21.1
117+fastapi==0.70.0
118+uvicorn==0.15.0