source: feed2telegram/trunk/feed2telegram.py@ 9

Last change on this file since 9 was 9, checked in by cheese, 7 years ago

#1 give chat id manually

File size: 5.0 KB
Line 
1#-*- coding: utf-8 -*-
2import datetime
3import email
4import json
5import os
6import sys
7import threading
8import time
9import traceback
10import urlparse
11
12import feedparser
13import requests
14
15class Telegram:
16 class API:
17 URL = 'https://api.telegram.org/bot<token>/<method>'
18
19 def __init__(self, token, method, http_method='POST'):
20 self.token = token
21 self.method = method
22 self.http_method = http_method.upper()
23 self.param = {}
24
25 def setParam(self, **kwargs):
26 self.param.update(kwargs)
27 return self
28
29 @property
30 def url(self):
31 ret = Telegram.API.URL.replace('<token>', self.token).replace('<method>', self.method)
32 return ret
33
34 @property
35 def header(self):
36 header = {
37 'accept': 'application/x-www-form-urlencoded',
38 }
39 return header
40
41 def __init__(self, token, chat_id):
42 self.token = token
43 self.chatId = chat_id
44
45 def request(self, api):
46 if api.http_method == 'GET':
47 req = requests.get(api.url, headers=api.header, params=api.param)
48 else:# if api.http_method == 'POST':
49 req = requests.get(api.url, headers=api.header, data=api.param)
50
51 response = req.json()
52
53 if not response['ok']:
54 raise Exception(response['description'])
55
56 return response
57
58 def getUpdates(self, limit=None):
59 api = Telegram.API(token=self.token, method='getUpdates', http_method='GET')
60
61 if limit:
62 api.setParam(limit=limit)
63
64 return self.request(api)
65
66 def sendMessage(self, text):
67 api = Telegram.API(token=self.token, method='sendMessage').setParam(chat_id=self.chatId, text=text)
68 return self.request(api)
69
70class Feed:
71 def __init__(self, url):
72 self.url = url
73 self.etag = None
74 self.modified = None
75 self.feed = None
76
77 self.save_dir = '.changes'
78
79 if os.path.isfile(self.filepath):
80 self.load()
81
82 @property
83 def filepath(self):
84 domain = urlparse.urlparse(self.url).netloc
85 return os.path.join(self.save_dir, domain)
86
87 def save(self):
88 data = {
89 'url': self.url,
90 'etag': self.etag,
91 'modified': self.modified
92 }
93 jsonstr = json.dumps(data, indent=2)
94
95 if not os.path.isdir(self.save_dir):
96 os.makedirs(self.save_dir)
97
98 with open(self.filepath, 'w') as f:
99 f.write(jsonstr)
100
101 def load(self):
102 with open(self.filepath, 'r') as f:
103 jsonobj = json.load(f)
104
105 self.etag = jsonobj['etag']
106 self.modified = jsonobj['modified']
107
108 def get(self):
109 self.feed = feedparser.parse(self.url, etag=self.etag, modified=self.modified)
110
111 self.etag = self.feed.etag
112 self.modified = self.feed.modified
113
114 return self.feed
115
116class Datetime:
117 def __init__(self):
118 self.datetime = None
119
120 def setRfc2822(self, value):
121 parsed = email.utils.parsedate(value)
122 self.datetime = datetime.datetime(*parsed[:6])
123 return self
124
125 def toTimestamp(self):
126 timetuple = self.datetime.timetuple()
127 return time.mktime(timetuple)
128
129class Feed2Telegram:
130 def __init__(self,
131 feed_url, # required
132 telegram_token, # required
133 chat_id, # required
134 callback_get_message, # required
135 callback_get_entries=lambda entries: entries,
136 check_interval=60*60,
137 new_entries_only=False,
138 send_error=True,
139 continue_on_error=False,
140 threaded=False):
141 self.url = feed_url
142 self.feed = Feed(self.url)
143
144 self.token = telegram_token
145 self.chat_id = chat_id
146 self.telegram = Telegram(self.token, self.chat_id)
147
148 self.get_message = callback_get_message
149 self.get_entries = callback_get_entries
150
151 self.new_entries_only = new_entries_only
152 self.send_error = send_error
153 self.continue_on_error = continue_on_error
154
155 self.thread = None
156 if threaded:
157 self.thread = threading.Thread(target=self.run)
158
159 self.stop_event = threading.Event()
160 self.last_modified = None
161
162 def isSendingEntry(self, entry):
163 if self.new_entries_only:
164 if self.last_modified:
165 published = Datetime().setRfc2822(entry.published).toTimestamp()
166 last = Datetime().setRfc2822(self.last_modified).toTimestamp()
167
168 if published > last:
169 return True
170 else:
171 return True
172
173 return False
174
175 def run(self):
176 while not self.stop_event.is_set():
177 try:
178 self.last_modified = self.feed.modified
179 feed = self.feed.get()
180
181 for entry in self.get_entries(feed.entries):
182 if self.stop_event.is_set():
183 break
184
185 if not self.isSendingEntry(entry):
186 continue
187
188 message = self.get_message(entry)
189 self.telegram.sendMessage(message)
190
191 self.feed.save()
192
193 except:
194 if self.send_error:
195 e = traceback.format_exc()
196 sys.stderr.write(e)
197 self.telegram.sendMessage(e)
198
199 if not self.continue_on_error:
200 raise
201
202 finally:
203 if not self.stop_event.is_set() and self.continue_on_error:
204 self.stop_event.wait(60 * 60)
205
206 def start(self):
207 self.stop_event.clear()
208
209 if self.thread:
210 self.thread.run()
211 else:
212 self.run()
213
214 def join(self, timeout=None):
215 if self.thread:
216 self.thread.join(timeout)
217
218 def stop(self):
219 self.stop_event.set()
220
Note: See TracBrowser for help on using the repository browser.