harii88 commited on
Commit
af2eed4
·
verified ·
1 Parent(s): 819476a

Update backend/adapters.py

Browse files
Files changed (1) hide show
  1. backend/adapters.py +91 -31
backend/adapters.py CHANGED
@@ -1,5 +1,9 @@
1
  import httpx
2
  from datetime import datetime, timezone
 
 
 
 
3
  class BaseAdapter:
4
  def __init__(self, url, api_key):
5
  self.base_url = url.rstrip("/")
@@ -15,61 +19,117 @@ class BaseAdapter:
15
  async def schedule_record(self, channel_id, start_ts, end_ts, name): raise NotImplementedError
16
  async def get_record_status(self, record_id): raise NotImplementedError
17
  async def get_video_url(self, record_id): raise NotImplementedError
 
18
  class EPGStationAdapter(BaseAdapter):
19
  async def get_epg(self, hours=24):
20
  now = int(datetime.now(timezone.utc).timestamp())
21
- async with httpx.AsyncClient(timeout=30.0) as c:
22
- res = await c.get(f"{self.base_url}/api/v3/programs", headers=self.headers, params={"startAt": now, "endAt": now + hours*3600, "type": 0}, verify=False)
23
- items = res.json().get("programs", []) if res.status_code == 200 else []
24
- return [{"id": str(p["id"]), "title": p.get("name","Unknown"), "start": p["startAt"], "end": p["endAt"], "channel_id": str(p["channelId"]), "channel_name": p.get("channelName","")} for p in items]
 
 
 
 
 
 
 
 
 
 
 
25
  async def schedule_record(self, channel_id, start_ts, end_ts, name):
26
- async with httpx.AsyncClient(timeout=30.0) as c:
27
- res = await c.post(f"{self.base_url}/api/v3/reserves", json={"channelId": channel_id, "startAt": int(start_ts), "endAt": int(end_ts), "name": name, "isSaveOriginal": True}, headers=self.headers, verify=False)
28
- return str(res.json().get("id","")) if res.status_code == 200 else ""
 
 
 
 
 
29
  async def get_record_status(self, record_id):
30
- async with httpx.AsyncClient(timeout=30.0) as c:
31
- res = await c.get(f"{self.base_url}/api/v3/recorded/{record_id}", headers=self.headers, verify=False)
32
- return res.json().get("state",{}) if res.status_code == 200 else {}
 
 
 
 
33
  async def get_video_url(self, record_id):
34
  return f"{self.base_url}/api/v3/videos/{record_id}/stream"
 
35
  class KonomiTVAdapter(BaseAdapter):
36
  async def get_epg(self, hours=24):
37
- async with httpx.AsyncClient(timeout=30.0, verify=False) as c:
38
- res = await c.get(f"{self.base_url}/api/v1/programs", headers=self.headers)
39
- items = res.json().get("programs", []) if res.status_code == 200 else []
40
- return [{"id": str(p["id"]), "title": p.get("title","Unknown"), "start": p.get("start_time",0), "end": p.get("end_time",0), "channel_id": str(p.get("channel_id","")), "channel_name": p.get("channel_name","")} for p in items]
 
 
 
 
 
 
 
41
  async def schedule_record(self, channel_id, start_ts, end_ts, name):
42
- async with httpx.AsyncClient(timeout=30.0, verify=False) as c:
43
- res = await c.post(f"{self.base_url}/api/v1/reserve", json={"channel_id": channel_id, "start_time": int(start_ts), "end_time": int(end_ts)}, headers=self.headers)
44
- return str(res.json().get("id","")) if res.status_code == 200 else ""
 
 
 
 
45
  async def get_record_status(self, record_id): return {"status": "completed"}
46
  async def get_video_url(self, record_id): return f"{self.base_url}/api/v1/stream/{record_id}"
 
47
  class MirakurunAdapter(BaseAdapter):
48
  async def get_epg(self, hours=24):
49
  now = int(datetime.now(timezone.utc).timestamp())
50
- async with httpx.AsyncClient(timeout=30.0) as c:
51
- res = await c.get(f"{self.base_url}/api/programs", headers=self.headers, params={"startAt": now, "endAt": now + hours*3600}, verify=False)
52
- items = res.json() if res.status_code == 200 else []
53
- return [{"id": str(p["id"]), "title": p.get("name","Unknown"), "start": p.get("startAt",0), "end": p.get("endAt",0), "channel_id": str(p.get("channelId","")), "channel_name": p.get("channelName","")} for p in items]
 
 
 
 
 
 
54
  async def schedule_record(self, channel_id, start_ts, end_ts, name):
55
- async with httpx.AsyncClient(timeout=30.0) as c:
56
- res = await c.post(f"{self.base_url}/api/reserves", json={"channelType": "GR", "channel": channel_id, "startAt": int(start_ts), "endAt": int(end_ts)}, headers=self.headers, verify=False)
57
- return str(res.json().get("id","")) if res.status_code == 200 else ""
 
 
 
 
58
  async def get_record_status(self, record_id): return {"status": "completed"}
59
  async def get_video_url(self, record_id): return f"{self.base_url}/api/recorded/{record_id}/stream.mp4"
 
60
  class EDCBAdapter(BaseAdapter):
61
  async def get_epg(self, hours=24):
62
  now = int(datetime.now(timezone.utc).timestamp())
63
- async with httpx.AsyncClient(timeout=30.0) as c:
64
- res = await c.get(f"{self.base_url}/api/programs", headers=self.headers, params={"startAt": now, "endAt": now + hours*3600}, verify=False)
65
- items = res.json() if res.status_code == 200 else []
66
- return [{"id": str(p["id"]), "title": p.get("title","Unknown"), "start": p.get("startTime",0), "end": p.get("endTime",0), "channel_id": str(p.get("channelID","")), "channel_name": p.get("channelName","")} for p in items]
 
 
 
 
 
 
67
  async def schedule_record(self, channel_id, start_ts, end_ts, name):
68
- async with httpx.AsyncClient(timeout=30.0) as c:
69
- res = await c.post(f"{self.base_url}/api/reserve", json={"channelID": channel_id, "startTime": int(start_ts), "endTime": int(end_ts), "recMode": 4}, headers=self.headers, verify=False)
70
- return str(res.json().get("id","")) if res.status_code == 200 else ""
 
 
 
 
71
  async def get_record_status(self, record_id): return {"status": "completed"}
72
  async def get_video_url(self, record_id): return f"{self.base_url}/api/recfile/{record_id}"
 
73
  def get_adapter(source_type, url, api_key):
74
  mapping = {"epgstation": EPGStationAdapter, "mirakurun": MirakurunAdapter, "konomitv": KonomiTVAdapter, "edcb": EDCBAdapter}
75
  cls = mapping.get(source_type.lower(), EPGStationAdapter)
 
1
  import httpx
2
  from datetime import datetime, timezone
3
+ import logging
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
  class BaseAdapter:
8
  def __init__(self, url, api_key):
9
  self.base_url = url.rstrip("/")
 
19
  async def schedule_record(self, channel_id, start_ts, end_ts, name): raise NotImplementedError
20
  async def get_record_status(self, record_id): raise NotImplementedError
21
  async def get_video_url(self, record_id): raise NotImplementedError
22
+
23
  class EPGStationAdapter(BaseAdapter):
24
  async def get_epg(self, hours=24):
25
  now = int(datetime.now(timezone.utc).timestamp())
26
+ try:
27
+ async with httpx.AsyncClient(timeout=30.0, verify=False) as c:
28
+ res = await c.get(f"{self.base_url}/api/v3/programs", headers=self.headers, params={"startAt": now, "endAt": now + hours*3600, "type": 0})
29
+ if res.status_code != 200:
30
+ logger.error(f"EPGStation API error: {res.status_code} - {res.text}")
31
+ return []
32
+ items = res.json().get("programs", [])
33
+ return [{"id": str(p["id"]), "title": p.get("name","Unknown"), "start": p["startAt"], "end": p["endAt"], "channel_id": str(p["channelId"]), "channel_name": p.get("channelName","")} for p in items]
34
+ except httpx.ConnectError as e:
35
+ logger.error(f"Connection failed: {str(e)}")
36
+ return []
37
+ except Exception as e:
38
+ logger.error(f"EPG fetch error: {str(e)}")
39
+ return []
40
+
41
  async def schedule_record(self, channel_id, start_ts, end_ts, name):
42
+ try:
43
+ async with httpx.AsyncClient(timeout=30.0, verify=False) as c:
44
+ res = await c.post(f"{self.base_url}/api/v3/reserves", json={"channelId": channel_id, "startAt": int(start_ts), "endAt": int(end_ts), "name": name, "isSaveOriginal": True}, headers=self.headers)
45
+ return str(res.json().get("id","")) if res.status_code == 200 else ""
46
+ except Exception as e:
47
+ logger.error(f"Schedule error: {str(e)}")
48
+ return ""
49
+
50
  async def get_record_status(self, record_id):
51
+ try:
52
+ async with httpx.AsyncClient(timeout=30.0, verify=False) as c:
53
+ res = await c.get(f"{self.base_url}/api/v3/recorded/{record_id}", headers=self.headers)
54
+ return res.json().get("state",{}) if res.status_code == 200 else {}
55
+ except:
56
+ return {}
57
+
58
  async def get_video_url(self, record_id):
59
  return f"{self.base_url}/api/v3/videos/{record_id}/stream"
60
+
61
  class KonomiTVAdapter(BaseAdapter):
62
  async def get_epg(self, hours=24):
63
+ try:
64
+ async with httpx.AsyncClient(timeout=30.0, verify=False) as c:
65
+ res = await c.get(f"{self.base_url}/api/v1/programs", headers=self.headers)
66
+ if res.status_code != 200:
67
+ return []
68
+ items = res.json().get("programs", [])
69
+ return [{"id": str(p["id"]), "title": p.get("title","Unknown"), "start": p.get("start_time",0), "end": p.get("end_time",0), "channel_id": str(p.get("channel_id","")), "channel_name": p.get("channel_name","")} for p in items]
70
+ except Exception as e:
71
+ logger.error(f"KonomiTV error: {str(e)}")
72
+ return []
73
+
74
  async def schedule_record(self, channel_id, start_ts, end_ts, name):
75
+ try:
76
+ async with httpx.AsyncClient(timeout=30.0, verify=False) as c:
77
+ res = await c.post(f"{self.base_url}/api/v1/reserve", json={"channel_id": channel_id, "start_time": int(start_ts), "end_time": int(end_ts)}, headers=self.headers)
78
+ return str(res.json().get("id","")) if res.status_code == 200 else ""
79
+ except:
80
+ return ""
81
+
82
  async def get_record_status(self, record_id): return {"status": "completed"}
83
  async def get_video_url(self, record_id): return f"{self.base_url}/api/v1/stream/{record_id}"
84
+
85
  class MirakurunAdapter(BaseAdapter):
86
  async def get_epg(self, hours=24):
87
  now = int(datetime.now(timezone.utc).timestamp())
88
+ try:
89
+ async with httpx.AsyncClient(timeout=30.0, verify=False) as c:
90
+ res = await c.get(f"{self.base_url}/api/programs", headers=self.headers, params={"startAt": now, "endAt": now + hours*3600})
91
+ if res.status_code != 200:
92
+ return []
93
+ items = res.json()
94
+ return [{"id": str(p["id"]), "title": p.get("name","Unknown"), "start": p.get("startAt",0), "end": p.get("endAt",0), "channel_id": str(p.get("channelId","")), "channel_name": p.get("channelName","")} for p in items]
95
+ except:
96
+ return []
97
+
98
  async def schedule_record(self, channel_id, start_ts, end_ts, name):
99
+ try:
100
+ async with httpx.AsyncClient(timeout=30.0, verify=False) as c:
101
+ res = await c.post(f"{self.base_url}/api/reserves", json={"channelType": "GR", "channel": channel_id, "startAt": int(start_ts), "endAt": int(end_ts)}, headers=self.headers)
102
+ return str(res.json().get("id","")) if res.status_code == 200 else ""
103
+ except:
104
+ return ""
105
+
106
  async def get_record_status(self, record_id): return {"status": "completed"}
107
  async def get_video_url(self, record_id): return f"{self.base_url}/api/recorded/{record_id}/stream.mp4"
108
+
109
  class EDCBAdapter(BaseAdapter):
110
  async def get_epg(self, hours=24):
111
  now = int(datetime.now(timezone.utc).timestamp())
112
+ try:
113
+ async with httpx.AsyncClient(timeout=30.0, verify=False) as c:
114
+ res = await c.get(f"{self.base_url}/api/programs", headers=self.headers, params={"startAt": now, "endAt": now + hours*3600})
115
+ if res.status_code != 200:
116
+ return []
117
+ items = res.json()
118
+ return [{"id": str(p["id"]), "title": p.get("title","Unknown"), "start": p.get("startTime",0), "end": p.get("endTime",0), "channel_id": str(p.get("channelID","")), "channel_name": p.get("channelName","")} for p in items]
119
+ except:
120
+ return []
121
+
122
  async def schedule_record(self, channel_id, start_ts, end_ts, name):
123
+ try:
124
+ async with httpx.AsyncClient(timeout=30.0, verify=False) as c:
125
+ res = await c.post(f"{self.base_url}/api/reserve", json={"channelID": channel_id, "startTime": int(start_ts), "endTime": int(end_ts), "recMode": 4}, headers=self.headers)
126
+ return str(res.json().get("id","")) if res.status_code == 200 else ""
127
+ except:
128
+ return ""
129
+
130
  async def get_record_status(self, record_id): return {"status": "completed"}
131
  async def get_video_url(self, record_id): return f"{self.base_url}/api/recfile/{record_id}"
132
+
133
  def get_adapter(source_type, url, api_key):
134
  mapping = {"epgstation": EPGStationAdapter, "mirakurun": MirakurunAdapter, "konomitv": KonomiTVAdapter, "edcb": EDCBAdapter}
135
  cls = mapping.get(source_type.lower(), EPGStationAdapter)