| 45 | |
| 46 | @dataclass |
| 47 | class SyncStats: |
| 48 | checked_urls: int = 0 |
| 49 | alive_urls: int = 0 |
| 50 | dead_urls: int = 0 |
| 51 | hard_fail_urls: int = 0 |
| 52 | transient_fail_urls: int = 0 |
| 53 | dead_removed_tiny: int = 0 |
| 54 | dead_removed_full: int = 0 |
| 55 | duplicates_removed_tiny: int = 0 |
| 56 | duplicates_removed_full: int = 0 |
| 57 | retained_failed_tiny: int = 0 |
| 58 | retained_failed_full: int = 0 |
| 59 | merged_added_full: int = 0 |
| 60 | tiny_links_before: int = 0 |
| 61 | tiny_links_after: int = 0 |
| 62 | full_links_before: int = 0 |
| 63 | full_links_after: int = 0 |
| 64 | tiny_changed: bool = False |
| 65 | full_changed: bool = False |
| 66 | state_changed: bool = False |
| 67 | |
| 68 | @property |
| 69 | def dead_removed_total(self) -> int: |
| 70 | return self.dead_removed_tiny + self.dead_removed_full |
| 71 | |
| 72 | @property |
| 73 | def duplicates_removed_total(self) -> int: |
| 74 | return self.duplicates_removed_tiny + self.duplicates_removed_full |
| 75 | |
| 76 | @property |
| 77 | def retained_failed_total(self) -> int: |
| 78 | return self.retained_failed_tiny + self.retained_failed_full |
| 79 | |
| 80 | def to_dict(self) -> Dict[str, object]: |
| 81 | data = asdict(self) |
| 82 | data["dead_removed_total"] = self.dead_removed_total |
| 83 | data["duplicates_removed_total"] = self.duplicates_removed_total |
| 84 | data["retained_failed_total"] = self.retained_failed_total |
| 85 | return data |
| 86 | |
| 87 | |
| 88 | class IncrementalContentDecoder: |