Skip to content

Commit e7ead98

Browse files
committed
update cards with lazy sync -sc new flag
1 parent 19adb81 commit e7ead98

File tree

4 files changed

+126
-96
lines changed

4 files changed

+126
-96
lines changed

README.md

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -100,32 +100,11 @@ sudo zypper install python3-pycurl python3-tqdm python3-cryptography python3-bea
100100
```shell
101101
sudo apk add py3-pycurl py3-tqdm py3-cryptography py3-beautifulsoup4 py3-pillow
102102
```
103-
104-
Some levels wont be added because they use external or different download URL's
105-
You can add levels to the database if you cd into where you installed you're database.
106-
From you're browser copy the number from level page <https://www.trle.net/sc/levelfeatures.php?lid=3684>
107-
108-
If you did just follow the command above you can use:
103+
Use the -sc flag to sync to trle
109104

110105
```shell
111106
python tombll_manage_data.py -h
112-
python3 tombll_manage_data.py -a 3684
113-
114-
```
115-
116-
Now that you have an data.json file you get a chance to edit it.
117-
Sometimes you need or want to edit those but right now I allow only trle.net
118-
You can add you're own local file with its md5sum and it should not try to download it.
119-
But it has to be a zip file at this point.
120-
121-
```text
122-
"zipFileName": "",
123-
"zipFileMd5": "",
124-
"download_url": ""
125-
```
126-
127-
```shell
128-
python3 tombll_manage_data.py -af data.json
107+
python3 tombll_manage_data.py -sc
129108

130109
```
131110

database/scrape_trle.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ def trle_page_table(table):
132132
field_name, extractor = field_mapping[idx]
133133
level[field_name] = extractor(cell)
134134

135+
level['trle_id'] = int(level['trle_id'])
135136
levels.append(level)
136137

137138
return levels

database/tombll_manage_data.py

Lines changed: 122 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def print_info():
3333
-ac [lid] Add a level card record without info and walkthrough
3434
-acr [lid lid] Add a range of level card records
3535
-rm [lid] Remove one level record
36+
-sc Sync cards
3637
-u [lid] Update a level record
3738
3839
-ld [lid] List download files records
@@ -196,93 +197,141 @@ def list_downloads(lid):
196197
print(row)
197198

198199

199-
def sync_cards():
200-
"""Lazy tail sync of cards."""
201-
index = match_tails()
202-
print(f"{index}")
200+
class TailSync:
201+
"""Match sync 5 records tails and add new records."""
203202

203+
def __init__(self):
204+
"""Set default member variables."""
205+
self.local = []
206+
self.trle = []
204207

205-
def match_tails(match_size=5, max_pages=100):
206-
"""Find a tail match between local and trle databases based ids."""
207-
local = []
208-
trle = []
208+
self.local_offset = 0
209+
self.trle_offset = 0
209210

210-
local_offset = 0
211-
trle_offset = 0
211+
def match_record(self, a, b):
212+
"""trle.net record data matching."""
213+
keys = ['trle_id', 'author', 'title', 'difficulty', 'duration', 'class', 'type', 'release']
214+
return all(a.get(k) == b.get(k) for k in keys)
212215

213-
def get_local_page_and_extend(offset):
214-
con = database_make_connection()
215-
page = get_local_page(offset, con)['levels']
216-
con.close()
217-
local.extend(page)
218-
return len(page)
219-
220-
def get_trle_page_and_extend(offset):
221-
page = get_trle_page(offset)['levels']
222-
trle.extend(page)
223-
return len(page)
224-
225-
def ensure_data(index_local, index_trle):
226-
"""Ensure enough items are available from each database."""
227-
nonlocal local_offset, trle_offset
228-
229-
# Load local pages if needed
230-
while index_local + match_size > len(local):
231-
local_offset += 1
232-
print(f"Loading local page at offset {local_offset}")
233-
if local_offset >= max_pages or get_local_page_and_extend(local_offset) == 0:
234-
return False
216+
def match_tails(self, match_size=5, max_pages=100):
217+
"""Find a tail match between local and trle databases based ids."""
235218

236-
# Load trle pages if needed
237-
while index_trle + match_size > len(trle):
238-
trle_offset += 1
239-
print(f"Loading trle page at offset {trle_offset}")
240-
if trle_offset >= max_pages or get_trle_page_and_extend(trle_offset) == 0:
241-
return False
219+
def get_local_page_and_extend(offset):
220+
con = database_make_connection()
221+
page = get_local_page(offset, con)['levels']
222+
con.close()
223+
self.local.extend(page)
224+
return len(page)
225+
226+
def get_trle_page_and_extend(offset):
227+
page = get_trle_page(offset)['levels']
228+
self.trle.extend(page)
229+
return len(page)
230+
231+
def ensure_data(index_local, index_trle):
232+
"""Ensure enough items are available from each database."""
233+
# Load local pages if needed
234+
while index_local + match_size > len(self.local):
235+
self.local_offset += 1
236+
print(f"Loading local page at offset {self.local_offset}")
237+
if self.local_offset >= max_pages or \
238+
get_local_page_and_extend(self.local_offset) == 0:
239+
return False
242240

243-
return True
241+
# Load trle pages if needed
242+
while index_trle + match_size > len(self.trle):
243+
self.trle_offset += 1
244+
print(f"Loading trle page at offset {self.trle_offset}")
245+
if self.trle_offset >= max_pages or get_trle_page_and_extend(self.trle_offset) == 0:
246+
return False
244247

245-
def ids_match(offset_local, offset_trle):
246-
"""Compare sequences of trle_ids from both lists."""
247-
if not ensure_data(offset_local, offset_trle):
248-
return False
248+
return True
249249

250-
for i in range(match_size):
251-
try:
252-
local_id = int(local[offset_local + i]['trle_id'])
253-
trle_id = int(trle[offset_trle + i]['trle_id'])
254-
if local_id != trle_id:
250+
def ids_match(offset_local, offset_trle):
251+
"""Compare sequences of trle_ids from both lists."""
252+
if not ensure_data(offset_local, offset_trle):
253+
return False
254+
255+
for i in range(match_size):
256+
try:
257+
local_id = int(self.local[offset_local + i]['trle_id'])
258+
trle_id = int(self.trle[offset_trle + i]['trle_id'])
259+
if local_id != trle_id:
260+
return False
261+
except IndexError:
255262
return False
263+
return True
264+
265+
# Load initial data
266+
get_local_page_and_extend(self.local_offset)
267+
get_trle_page_and_extend(self.trle_offset)
268+
269+
i = 0
270+
while True:
271+
if i + match_size > len(self.local):
272+
# Try to load more local data
273+
if not ensure_data(i, 0):
274+
break
275+
276+
for j in range(len(self.trle) - match_size + 1):
277+
if ids_match(i, j):
278+
print(f"Match found at local[{i}] and trle[{j}]")
279+
return (i, j)
280+
i += 1
281+
282+
# If we run out of trle data, load more
283+
if len(self.trle) - match_size < 1:
284+
added = get_trle_page_and_extend(self.trle_offset + 1)
285+
self.trle_offset += 1
286+
if added == 0 or self.trle_offset >= max_pages:
287+
break
288+
289+
print("❌ No match found after paging.")
290+
return None
291+
292+
def run(self):
293+
"""
294+
Tail-sync in 3 simple stages.
295+
296+
1. Update the last 5 matching records if their attributes differ.
297+
2. Add new records from remote page after the match.
298+
3. Update or delete unmatched local records after the match.
299+
"""
300+
local_start, remote_start = self.match_tails()
301+
tail_count = 5
302+
303+
# Stage 1: Check and update mismatched records
304+
for i in range(tail_count):
305+
try:
306+
local = self.local[local_start + i]
307+
remote = self.trle[remote_start + i]
256308
except IndexError:
257-
return False
258-
return True
309+
print(f"IndexError self.local[{local_start + i}] self.trle[{remote_start + i}]")
310+
sys.exit(1)
259311

260-
# Load initial data
261-
get_local_page_and_extend(local_offset)
262-
get_trle_page_and_extend(trle_offset)
312+
if not self.match_record(local, remote):
313+
update_level(local['trle_id'])
263314

264-
i = 0
265-
while True:
266-
if i + match_size > len(local):
267-
# Try to load more local data
268-
if not ensure_data(i, 0):
269-
break
315+
# Stage 2: Add new remote records
316+
existing_ids = {ids['trle_id'] for ids in self.local}
317+
for remote in self.trle[:remote_start]:
318+
if remote['trle_id'] not in existing_ids:
319+
add_level_card(remote['trle_id'])
270320

271-
for j in range(len(trle) - match_size + 1):
272-
if ids_match(i, j):
273-
print(f"Match found at local[{i}] and trle[{j}]")
274-
return (i, j)
275-
i += 1
276-
277-
# If we run out of trle data, load more
278-
if len(trle) - match_size < 1:
279-
added = get_trle_page_and_extend(trle_offset + 1)
280-
trle_offset += 1
281-
if added == 0 or trle_offset >= max_pages:
282-
break
321+
# Stage 3: Check unmatched local records
322+
for local in self.local[:local_start]:
323+
exists = any(r['trle_id'] == local['trle_id'] for r in self.trle)
324+
if exists:
325+
update_level(local['trle_id'])
326+
else:
327+
remove_level(local['trle_id'])
283328

284-
print("❌ No match found after paging.")
285-
return None
329+
330+
331+
def sync_cards():
332+
"""Lazy tail sync of cards."""
333+
tailsync = TailSync()
334+
tailsync.run()
286335

287336

288337
def get_local_page(offset, con):

src/TombRaiderLinuxLauncher.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ void TombRaiderLinuxLauncher::infoClicked() {
375375
InfoData info = controller.getInfo(id);
376376
if (info.m_body == "" && info.m_imageList.size() == 0) {
377377
controller.updateLevel(id);
378+
info = controller.getInfo(id);
378379
}
379380

380381
ui->infoWebEngineView->setHtml(info.m_body);

0 commit comments

Comments
 (0)