-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreader.py
More file actions
82 lines (63 loc) · 2.52 KB
/
Copy pathreader.py
File metadata and controls
82 lines (63 loc) · 2.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
from __future__ import annotations
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime
from typing import List, Optional, Tuple
import chromium
import firefox
from browsers import CHROMIUM, FIREFOX
from history_record import HistoryRecord, ProfileReadError
from log_setup import get_logger
from profiles import BrowserProfile
from progress import ProgressBar
log = get_logger(__name__)
_READERS = {
CHROMIUM: chromium.read_profile_history,
FIREFOX: firefox.read_profile_history,
}
DEFAULT_MAX_WORKERS = 8
def _read_one(
profile: BrowserProfile,
start_date: Optional[datetime],
end_date: Optional[datetime],
) -> Tuple[BrowserProfile, Optional[List[HistoryRecord]], Optional[ProfileReadError]]:
read_fn = _READERS.get(profile.engine)
if read_fn is None:
return profile, None, ProfileReadError(profile.label, f"Unsupported engine: {profile.engine}")
try:
records = read_fn(profile, start_date, end_date)
return profile, records, None
except ProfileReadError as exc:
return profile, None, exc
def read_all_history(
profiles: List[BrowserProfile],
start_date: Optional[datetime] = None,
end_date: Optional[datetime] = None,
max_workers: int = DEFAULT_MAX_WORKERS,
show_progress: bool = True,
) -> Tuple[List[HistoryRecord], List[ProfileReadError]]:
all_records: List[HistoryRecord] = []
errors: List[ProfileReadError] = []
if not profiles:
return all_records, errors
bar = ProgressBar(total=len(profiles), label="Reading profiles") if show_progress else None
workers = max(1, min(max_workers, len(profiles)))
log.debug("Reading %d profile(s) with %d worker thread(s).", len(profiles), workers)
with ThreadPoolExecutor(max_workers=workers) as executor:
futures = {
executor.submit(_read_one, profile, start_date, end_date): profile
for profile in profiles
}
for future in as_completed(futures):
profile, records, error = future.result()
if error is not None:
log.warning("Skipped %s: %s", error.profile_label, error.reason)
errors.append(error)
else:
log.info("%s -> %d visit(s) found.", profile.label, len(records))
all_records.extend(records)
if bar is not None:
bar.update(1)
if bar is not None:
bar.finish()
all_records.sort(key=lambda r: r.visit_time or datetime.min)
return all_records, errors