Add support for bookmark thumbnails (#721)

* Preview Image

* fix tests

* add test

* download preview image

* relative path

* gst

* details view

* fix tests

* Improve preview image styles

* Remove preview image URL from model

* Revert form changes

* update tests

* make it work in uwsgi

---------

Co-authored-by: Sascha Ißbrücker <sascha.issbruecker@gmail.com>
This commit is contained in:
Viacheslav Slinko
2024-05-07 19:58:52 +03:00
committed by GitHub
parent e2415f652b
commit 87cd4061cb
26 changed files with 640 additions and 147 deletions

View File

@@ -10,138 +10,143 @@
data-bookmarks-total="{{ bookmark_list.bookmarks_total }}">
{% for bookmark_item in bookmark_list.items %}
<li ld-bookmark-item{% if bookmark_item.css_classes %} class="{{ bookmark_item.css_classes }}"{% endif %}>
<div class="title">
<label class="form-checkbox bulk-edit-checkbox">
<input type="checkbox" name="bookmark_id" value="{{ bookmark_item.id }}">
<i class="form-icon"></i>
</label>
{% if bookmark_item.favicon_file and bookmark_list.show_favicons %}
<img src="{% static bookmark_item.favicon_file %}" alt="">
{% endif %}
<a href="{{ bookmark_item.url }}" target="{{ bookmark_list.link_target }}" rel="noopener">
<span>{{ bookmark_item.title }}</span>
</a>
</div>
{% if bookmark_list.show_url %}
<div class="url-path truncate">
<a href="{{ bookmark_item.url }}" target="{{ bookmark_list.link_target }}" rel="noopener"
class="url-display">
{{ bookmark_item.url }}
<div class="content">
<div class="title">
<label class="form-checkbox bulk-edit-checkbox">
<input type="checkbox" name="bookmark_id" value="{{ bookmark_item.id }}">
<i class="form-icon"></i>
</label>
{% if bookmark_item.favicon_file and bookmark_list.show_favicons %}
<img class="favicon" src="{% static bookmark_item.favicon_file %}" alt="">
{% endif %}
<a href="{{ bookmark_item.url }}" target="{{ bookmark_list.link_target }}" rel="noopener">
<span>{{ bookmark_item.title }}</span>
</a>
</div>
{% endif %}
{% if bookmark_list.description_display == 'inline' %}
<div class="description inline truncate">
{% if bookmark_list.show_url %}
<div class="url-path truncate">
<a href="{{ bookmark_item.url }}" target="{{ bookmark_list.link_target }}" rel="noopener"
class="url-display">
{{ bookmark_item.url }}
</a>
</div>
{% endif %}
{% if bookmark_list.description_display == 'inline' %}
<div class="description inline truncate">
{% if bookmark_item.tag_names %}
<span class="tags">
{% for tag_name in bookmark_item.tag_names %}
<a href="?{% add_tag_to_query tag_name %}">{{ tag_name|hash_tag }}</a>
{% endfor %}
</span>
{% endif %}
{% if bookmark_item.tag_names and bookmark_item.description %} | {% endif %}
{% if bookmark_item.description %}
<span>{{ bookmark_item.description }}</span>
{% endif %}
</div>
{% else %}
{% if bookmark_item.description %}
<div class="description separate">{{ bookmark_item.description }}</div>
{% endif %}
{% if bookmark_item.tag_names %}
<span class="tags">
<div class="tags">
{% for tag_name in bookmark_item.tag_names %}
<a href="?{% add_tag_to_query tag_name %}">{{ tag_name|hash_tag }}</a>
{% endfor %}
</div>
{% endif %}
{% endif %}
{% if bookmark_item.notes %}
<div class="notes bg-gray text-gray-dark">
<div class="markdown">{% markdown bookmark_item.notes %}</div>
</div>
{% endif %}
<div class="actions text-gray">
{% if bookmark_item.display_date %}
{% if bookmark_item.web_archive_snapshot_url %}
<a href="{{ bookmark_item.web_archive_snapshot_url }}"
title="Show snapshot on the Internet Archive Wayback Machine"
target="{{ bookmark_list.link_target }}"
rel="noopener">
{{ bookmark_item.display_date }} ∞
</a>
{% else %}
<span>{{ bookmark_item.display_date }}</span>
{% endif %}
<span>|</span>
{% endif %}
{# View link is visible for both owned and shared bookmarks #}
{% if bookmark_list.show_view_action %}
<a ld-fetch="{% url 'bookmarks:details_modal' bookmark_item.id %}?return_url={{ bookmark_list.return_url|urlencode }}"
ld-on="click" ld-target="body|append"
href="{% url 'bookmarks:details' bookmark_item.id %}">View</a>
{% endif %}
{% if bookmark_item.is_editable %}
{# Bookmark owner actions #}
{% if bookmark_list.show_edit_action %}
<a href="{% url 'bookmarks:edit' bookmark_item.id %}?return_url={{ bookmark_list.return_url|urlencode }}">Edit</a>
{% endif %}
{% if bookmark_list.show_archive_action %}
{% if bookmark_item.is_archived %}
<button type="submit" name="unarchive" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm">Unarchive
</button>
{% else %}
<button type="submit" name="archive" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm">Archive
</button>
{% endif %}
{% endif %}
{% if bookmark_list.show_remove_action %}
<button ld-confirm-button type="submit" name="remove" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm">Remove
</button>
{% endif %}
{% else %}
{# Shared bookmark actions #}
<span>Shared by
<a href="?{% replace_query_param user=bookmark_item.owner.username %}">{{ bookmark_item.owner.username }}</a>
</span>
{% endif %}
{% if bookmark_item.tag_names and bookmark_item.description %} | {% endif %}
{% if bookmark_item.description %}
<span>{{ bookmark_item.description }}</span>
{% if bookmark_item.has_extra_actions %}
<div class="extra-actions">
<span class="hide-sm">|</span>
{% if bookmark_item.show_mark_as_read %}
<button type="submit" name="mark_as_read" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm btn-icon"
ld-confirm-button ld-confirm-icon="ld-icon-read" ld-confirm-question="Mark as read?">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<use xlink:href="#ld-icon-unread"></use>
</svg>
Unread
</button>
{% endif %}
{% if bookmark_item.show_unshare %}
<button type="submit" name="unshare" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm btn-icon"
ld-confirm-button ld-confirm-icon="ld-icon-unshare" ld-confirm-question="Unshare?">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<use xlink:href="#ld-icon-share"></use>
</svg>
Shared
</button>
{% endif %}
{% if bookmark_item.show_notes_button %}
<button type="button" class="btn btn-link btn-sm btn-icon toggle-notes">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<use xlink:href="#ld-icon-note"></use>
</svg>
Notes
</button>
{% endif %}
</div>
{% endif %}
</div>
{% else %}
{% if bookmark_item.description %}
<div class="description separate">{{ bookmark_item.description }}</div>
{% endif %}
{% if bookmark_item.tag_names %}
<div class="tags">
{% for tag_name in bookmark_item.tag_names %}
<a href="?{% add_tag_to_query tag_name %}">{{ tag_name|hash_tag }}</a>
{% endfor %}
</div>
{% endif %}
{% endif %}
{% if bookmark_item.notes %}
<div class="notes bg-gray text-gray-dark">
<div class="markdown">{% markdown bookmark_item.notes %}</div>
</div>
{% endif %}
<div class="actions text-gray">
{% if bookmark_item.display_date %}
{% if bookmark_item.web_archive_snapshot_url %}
<a href="{{ bookmark_item.web_archive_snapshot_url }}"
title="Show snapshot on the Internet Archive Wayback Machine"
target="{{ bookmark_list.link_target }}"
rel="noopener">
{{ bookmark_item.display_date }} ∞
</a>
{% else %}
<span>{{ bookmark_item.display_date }}</span>
{% endif %}
<span>|</span>
{% endif %}
{# View link is visible for both owned and shared bookmarks #}
{% if bookmark_list.show_view_action %}
<a ld-fetch="{% url 'bookmarks:details_modal' bookmark_item.id %}?return_url={{ bookmark_list.return_url|urlencode }}"
ld-on="click" ld-target="body|append"
href="{% url 'bookmarks:details' bookmark_item.id %}">View</a>
{% endif %}
{% if bookmark_item.is_editable %}
{# Bookmark owner actions #}
{% if bookmark_list.show_edit_action %}
<a href="{% url 'bookmarks:edit' bookmark_item.id %}?return_url={{ bookmark_list.return_url|urlencode }}">Edit</a>
{% endif %}
{% if bookmark_list.show_archive_action %}
{% if bookmark_item.is_archived %}
<button type="submit" name="unarchive" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm">Unarchive
</button>
{% else %}
<button type="submit" name="archive" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm">Archive
</button>
{% endif %}
{% endif %}
{% if bookmark_list.show_remove_action %}
<button ld-confirm-button type="submit" name="remove" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm">Remove
</button>
{% endif %}
{% else %}
{# Shared bookmark actions #}
<span>Shared by
<a href="?{% replace_query_param user=bookmark_item.owner.username %}">{{ bookmark_item.owner.username }}</a>
</span>
{% endif %}
{% if bookmark_item.has_extra_actions %}
<div class="extra-actions">
<span class="hide-sm">|</span>
{% if bookmark_item.show_mark_as_read %}
<button type="submit" name="mark_as_read" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm btn-icon"
ld-confirm-button ld-confirm-icon="ld-icon-read" ld-confirm-question="Mark as read?">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<use xlink:href="#ld-icon-unread"></use>
</svg>
Unread
</button>
{% endif %}
{% if bookmark_item.show_unshare %}
<button type="submit" name="unshare" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm btn-icon"
ld-confirm-button ld-confirm-icon="ld-icon-unshare" ld-confirm-question="Unshare?">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<use xlink:href="#ld-icon-share"></use>
</svg>
Shared
</button>
{% endif %}
{% if bookmark_item.show_notes_button %}
<button type="button" class="btn btn-link btn-sm btn-icon toggle-notes">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<use xlink:href="#ld-icon-note"></use>
</svg>
Notes
</button>
{% endif %}
</div>
{% endif %}
</div>
{% if bookmark_list.show_preview_images and bookmark_item.preview_image_file %}
<img class="preview-image" src="{% static bookmark_item.preview_image_file %}"/>
{% endif %}
</li>
{% endfor %}
</ul>

View File

@@ -37,6 +37,11 @@
</a>
{% endif %}
</div>
{% if details.preview_image_enabled and details.bookmark.preview_image_file %}
<div class="preview-image">
<img src="{% static details.bookmark.preview_image_file %}"/>
</div>
{% endif %}
<dl class="grid columns-2 columns-sm-1 gap-0">
{% if details.is_editable %}
<div class="status col-2">

View File

@@ -127,6 +127,15 @@
<button class="btn mt-2" name="refresh_favicons">Refresh Favicons</button>
{% endif %}
</div>
<div class="form-group">
<label for="{{ form.enable_preview_images.id_for_label }}" class="form-checkbox">
{{ form.enable_preview_images }}
<i class="form-icon"></i> Enable Preview Images
</label>
<div class="form-input-hint">
Automatically loads preview images for bookmarked websites and displays them next to each bookmark.
</div>
</div>
<div class="form-group">
<label for="{{ form.web_archive_integration.id_for_label }}" class="form-label">Internet Archive
integration</label>