diff --git a/dlibrary/dlibrary.py b/dlibrary/dlibrary.py index 82cf74f..97d657c 100755 --- a/dlibrary/dlibrary.py +++ b/dlibrary/dlibrary.py @@ -821,6 +821,47 @@ def copy_recursive(src, dest): else: shutil.copyfile(item, dest / item.name) + +memoized_similarities = {} + +def similarity(a, b): + if len(a) < len(b): + shorter = a + longer = b + else: + shorter = b + longer = a + if len(shorter) == 0: + return 0 + + if (shorter, longer) in memoized_similarities: + return memoized_similarities[(shorter, longer)] + + options = [similarity(shorter[1:], longer)] + for i in range(1, len(shorter)+1): + match_idx = longer.find(shorter[:i]) + if match_idx == -1: + break + options.append(i*i + similarity(shorter[i:], longer[match_idx+i:])) + result = max(options) + + memoized_similarities[(shorter, longer)] = result + return result + +def top(items, n, key): + if len(items) == 0: + return [] + winners = items[:1] + for item in items[1:]: + if len(winners) < n or key(item) > key(winners[-1]): + for i in range(len(winners)): + if key(item) > key(winners[i]): + winners.insert(i, item) + break + if len(winners) > n: + winners.pop() + return winners + def generate(args): jenv = Environment( loader=PackageLoader("dlibrary"), @@ -865,16 +906,28 @@ def generate(args): 'authors': authors, 'tags': tags, 'thumbnail_path': thumbnail_path, + 'images': images, } works.append(work) - work_dir = site_dir / 'works' / work_id + for (idx, work) in enumerate(works): + def suggestion_priority(other_work): + if other_work is work: + return -2 + if work['series'] and work['series'] == other_work['series']: + return -1 + return similarity(work['title'], other_work['title']) + suggested = top(works, 6, suggestion_priority) + + work_dir = site_dir / 'works' / work['id'] viewer_dir = work_dir / 'view' viewer_dir.mkdir(parents=True, exist_ok=True) with open(work_dir / 'index.html', 'w') as f: - f.write(work_template.render(depth=2, work=work, title=title, images=images)) + f.write(work_template.render(depth=2, work=work, title=work['title'], suggested=suggested)) with open(viewer_dir / 'index.html', 'w') as f: - f.write(viewer_template.render(depth=3, work=work, title=title, images=images)) + f.write(viewer_template.render(depth=3, work=work, title=work['title'])) + + print(f'\x1b[2K\r{idx+1}/{len(works)} works processed...', end='') def make_categorization(categorization, query, work_filter, work_style_cards=False): categorization_dir = site_dir / categorization diff --git a/dlibrary/static/dlibrary.css b/dlibrary/static/dlibrary.css index fc6aa0b..00c1846 100644 --- a/dlibrary/static/dlibrary.css +++ b/dlibrary/static/dlibrary.css @@ -78,7 +78,7 @@ body { margin-bottom: 25px; } -#card-listing { +.card-listing { display: flex; flex-wrap: wrap; justify-content: center; @@ -115,6 +115,7 @@ body { flex-wrap: wrap; justify-content: center; gap: 30px; + margin-bottom: 40px; } .work-preview { @@ -157,3 +158,7 @@ body { display: inline-block; margin-bottom: 5px; } + +#suggested-subheader { + text-align: center; +} diff --git a/dlibrary/static/index.js b/dlibrary/static/index.js index 2ea74f5..f818247 100644 --- a/dlibrary/static/index.js +++ b/dlibrary/static/index.js @@ -32,7 +32,7 @@ document.addEventListener('DOMContentLoaded', () => { const shuffleButton = document.getElementById('shuffle'); const sortButton = document.getElementById('sort'); const searchBox = document.getElementById('search'); - const listContainer = document.getElementById('card-listing'); + const listContainer = document.getElementById('main-listing'); let ordering = localStorage.getItem('indexOrdering') || 'dateDesc'; let shuffleSeed = parseInt(localStorage.getItem('shuffleSeed')) || newSeed(); diff --git a/dlibrary/templates/categorization.html b/dlibrary/templates/categorization.html index 40e6817..75a4c8b 100644 --- a/dlibrary/templates/categorization.html +++ b/dlibrary/templates/categorization.html @@ -4,7 +4,7 @@ {% from 'utils.html' import urlcat, index, root with context %}
{{ images | length }} |
{{ work['images'] | length }} |