Ivan000 commited on
Commit
41829e6
·
verified ·
1 Parent(s): 9626e82

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +50 -8
main.py CHANGED
@@ -6,6 +6,7 @@ import requests
6
  from bs4 import BeautifulSoup
7
  from urllib.parse import quote
8
  import xml.etree.ElementTree as ET
 
9
 
10
  app = FastAPI()
11
 
@@ -51,18 +52,52 @@ def duckduckgo_search(query: str):
51
  break
52
  return results
53
 
54
- # ========== OPDS Feed Generator ==========
55
- def generate_opds(query: str, results):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  ns = "http://www.w3.org/2005/Atom"
57
  ET.register_namespace("", ns)
58
  feed = ET.Element("feed", xmlns=ns)
59
  ET.SubElement(feed, "title").text = f"Search results for '{query}'"
60
- ET.SubElement(feed, "updated").text = "2025-07-31T12:00:00Z"
 
61
  for title, url in results:
62
  entry = ET.SubElement(feed, "entry")
63
  ET.SubElement(entry, "title").text = title
64
  ET.SubElement(entry, "id").text = url
65
- ET.SubElement(entry, "updated").text = "2025-07-31T12:00:00Z"
66
  ET.SubElement(entry, "link", {
67
  "rel": "http://opds-spec.org/acquisition",
68
  "href": f"/download?url={quote(url, safe='')}",
@@ -70,10 +105,17 @@ def generate_opds(query: str, results):
70
  })
71
  return ET.tostring(feed, encoding="utf-8", xml_declaration=True)
72
 
73
- @app.get("/opds")
74
- def opds_catalog(q: str = Query(..., description="Search query")) -> Response:
 
 
 
 
 
 
 
75
  results = duckduckgo_search(q)
76
- xml_data = generate_opds(q, results)
77
  return Response(content=xml_data, media_type="application/atom+xml")
78
 
79
  @app.get("/download")
@@ -89,4 +131,4 @@ def download_fb2(url: str) -> Response:
89
  content=fb2,
90
  media_type="application/fb2+xml",
91
  headers={"Content-Disposition": f"attachment; filename={filename}"}
92
- )
 
6
  from bs4 import BeautifulSoup
7
  from urllib.parse import quote
8
  import xml.etree.ElementTree as ET
9
+ from datetime import datetime
10
 
11
  app = FastAPI()
12
 
 
52
  break
53
  return results
54
 
55
+ # ========== OPDS Feed Generators ==========
56
+
57
+ def generate_root_feed():
58
+ ns = "http://www.w3.org/2005/Atom"
59
+ ET.register_namespace("", ns)
60
+ feed = ET.Element("feed", xmlns=ns)
61
+ ET.SubElement(feed, "title").text = "DuckDuckGo OPDS Catalog"
62
+ ET.SubElement(feed, "updated").text = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
63
+
64
+ # Link to search
65
+ entry = ET.SubElement(feed, "entry")
66
+ ET.SubElement(entry, "title").text = "Search"
67
+ ET.SubElement(entry, "id").text = "search"
68
+ ET.SubElement(entry, "link", {
69
+ "rel": "subsection",
70
+ "href": "/opds/search",
71
+ "type": "application/atom+xml;profile=opds-catalog;kind=acquisition"
72
+ })
73
+ ET.SubElement(entry, "updated").text = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
74
+
75
+ # Link to cached (not implemented yet)
76
+ entry2 = ET.SubElement(feed, "entry")
77
+ ET.SubElement(entry2, "title").text = "Cached"
78
+ ET.SubElement(entry2, "id").text = "cached"
79
+ ET.SubElement(entry2, "link", {
80
+ "rel": "subsection",
81
+ "href": "/opds/cached",
82
+ "type": "application/atom+xml;profile=opds-catalog;kind=navigation"
83
+ })
84
+ ET.SubElement(entry2, "updated").text = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
85
+
86
+ return ET.tostring(feed, encoding="utf-8", xml_declaration=True)
87
+
88
+
89
+ def generate_search_feed(query: str, results):
90
  ns = "http://www.w3.org/2005/Atom"
91
  ET.register_namespace("", ns)
92
  feed = ET.Element("feed", xmlns=ns)
93
  ET.SubElement(feed, "title").text = f"Search results for '{query}'"
94
+ ET.SubElement(feed, "updated").text = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
95
+
96
  for title, url in results:
97
  entry = ET.SubElement(feed, "entry")
98
  ET.SubElement(entry, "title").text = title
99
  ET.SubElement(entry, "id").text = url
100
+ ET.SubElement(entry, "updated").text = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
101
  ET.SubElement(entry, "link", {
102
  "rel": "http://opds-spec.org/acquisition",
103
  "href": f"/download?url={quote(url, safe='')}",
 
105
  })
106
  return ET.tostring(feed, encoding="utf-8", xml_declaration=True)
107
 
108
+ # ========== Routes ==========
109
+
110
+ @app.get("/opds", include_in_schema=False)
111
+ def opds_root() -> Response:
112
+ xml_data = generate_root_feed()
113
+ return Response(content=xml_data, media_type="application/atom+xml")
114
+
115
+ @app.get("/opds/search")
116
+ def opds_search(q: str = Query(..., description="Search query")) -> Response:
117
  results = duckduckgo_search(q)
118
+ xml_data = generate_search_feed(q, results)
119
  return Response(content=xml_data, media_type="application/atom+xml")
120
 
121
  @app.get("/download")
 
131
  content=fb2,
132
  media_type="application/fb2+xml",
133
  headers={"Content-Disposition": f"attachment; filename={filename}"}
134
+ )