--- slashdot-20181015.py 2019-10-12 02:28:46.020075954 +0200 +++ slashdot-ddeb027b3f1c.py 2021-02-11 20:18:38.341490217 +0100 @@ -1,7 +1,7 @@ #!/usr/bin/env python3 -# (c) 2018 Jesús Cea Avión - jcea@jcea.es - https://www.jcea.es/ +# (c) 2018-2020 Jesús Cea Avión - jcea@jcea.es - https://www.jcea.es/ # This code is licensed under AGPLv3. @@ -28,6 +28,7 @@ self._procesados = data['procesados'] self._buckets = data['buckets'] + self._solapamiento = data.get('solapamiento', True) self._procesados_nuevos = set() self.etag = data['etag'] self.modified = data['modified'] @@ -41,10 +42,14 @@ v['modified'] = self.modified return v + def notificado(self): + self._solapamiento = True + self.cambiado = True + def solapamiento(self): if self.saved: return self._solapamiento - return not self._procesados.isdisjoint(self._procesados_nuevos) + return self._solapamiento and not self._procesados.isdisjoint(self._procesados_nuevos) def update(self, guid, ts, title, link, summary): self._procesados_nuevos.add(guid) @@ -65,6 +70,10 @@ return self.update(guid, ts, title, link, summary) + def feed304(self): + self._procesados_nuevos.update(self._procesados) + return self.etag, self.modified + def itera_antiguos(self, horas=16): ts_antiguo = datetime.datetime.now() ts_antiguo -= datetime.timedelta(seconds=horas * 60 * 60) @@ -99,6 +108,8 @@ if not self.cambiado: return + self._solapamiento = self.solapamiento() + procesados = self._procesados_nuevos if not purga: procesados.update(self._procesados) @@ -106,6 +117,7 @@ with open(path + '.NEW', 'wb') as f: data = {'procesados': procesados, 'buckets': self._buckets, + 'solapamiento': self._solapamiento, 'etag': etag, 'modified': modified, } pickle.dump(data, f, pickle.HIGHEST_PROTOCOL) @@ -115,7 +127,6 @@ self.cambiado = False # Tras el save no deberíamos usar más este objeto - self._solapamiento = self.solapamiento() self.saved = True del self._procesados del self._procesados_nuevos @@ -136,20 +147,21 @@ finally: socket.setdefaulttimeout(timeout) - if feed.status == 304: - # print("Sin cambios") - return - - for entry in feed.entries: - summary = BeautifulSoup(entry["summary"], 'html.parser') - summary = list(summary.children)[0] - entradas.new(entry['id'], entry.updated_parsed, - entry['title'], entry['link'], summary) - - no_solapamiento = '' - if not entradas.solapamiento(): - no_solapamiento = 'HEMOS PERDIDO ENTRADAS' - no_solapamiento += '

\n' + if feed.status == 200: + etag, modified = feed.get('etag'), feed.get('modified') + for entry in feed.entries: + summary = BeautifulSoup(entry["summary"], 'html.parser') + summary = list(summary.children)[0] + entradas.new(entry['id'], entry.updated_parsed, + entry['title'], entry['link'], summary) + elif feed.status == 304: + # En el 304 no se manda ETAG ni Modified, así que coge los que comprobamos + # en la petición condicional. + etag, modified = entradas.feed304() + else: + raise RuntimeError(f'Estado: {feed.status}') + + # Si es 304, procesamos lo viejo por si tiene que salir el email. html_desc = html_links = '' entradas_a_borrar = [] @@ -164,9 +176,14 @@ # lo cierto es que queremos actualizar el etag y el modified AUNQUE # no haya habido cambios en el feed. Esto es algo a mejorar en el futuro. - entradas.save(feed.get('etag'), feed.get('modified')) + entradas.save(etag, modified) if html_desc: + no_solapamiento = '' + if not entradas.solapamiento(): + no_solapamiento = 'HEMOS PERDIDO ENTRADAS' + no_solapamiento += '

\n' + html_links = f'\n' html = f''' @@ -196,14 +213,17 @@ stdout=subprocess.PIPE, stderr=subprocess.PIPE) + entradas.notificado() + # XXX: Lo suyo sería grabar solo si hay cambios de verdad, pero # lo cierto es que queremos actualizar el etag y el modified AUNQUE # no haya habido cambios en el feed. Esto es algo a mejorar en el futuro. entradas = items() + etag, modified = entradas.feed304() # XXX: Para evitar "no solapamiento" for guid, ts in entradas_a_borrar: entradas.borrar(guid, ts) - entradas.save(feed.get('etag'), feed.get('modified'), purga=False) + entradas.save(etag, modified, purga=False) if __name__ == '__main__':