slashdot-20181015-ddeb027b3f1c.diff (Código fuente)

--- 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 = '<font size=+2><b>HEMOS PERDIDO ENTRADAS</b></font>'
-        no_solapamiento += '<br/><br/>\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 = '<font size=+2><b>HEMOS PERDIDO ENTRADAS</b></font>'
+            no_solapamiento += '<br/><br/>\n'
+
         html_links = f'<ul>\n{html_links}\n</ul>\n'
         html = f'''<html>
 <head>
@@ -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__':