Display list of recent books on profiles

main
Bob Mottram 2023-12-30 21:19:35 +00:00
parent 6c56b786eb
commit f1220b8497
3 changed files with 143 additions and 17 deletions

View File

@ -257,6 +257,36 @@ body, html {
image-rendering: var(--rendering);
}
book_list_section {
width: 100%;
}
book_list {
align-items: flex-start;
display: flex;
flex-wrap: nowrap;
list-style: none;
margin: 1rem 0;
overflow-x: scroll;
padding: 0 0 0 1rem;
}
book_event {
padding: 0 1rem 0 0;
}
book_span {
}
book_span_div {
border-radius: 9px;
height: 30vw;
width: 20vw;
}
book_image_div {
}
code {
color: var(--code-color);
white-space: pre;

View File

@ -9,6 +9,7 @@ __module_group__ = "Core"
import os
from collections import OrderedDict
from utils import get_content_from_post
from utils import has_object_dict
from utils import remove_id_ending
@ -196,19 +197,20 @@ def _add_book_to_reader(reader_books_json: {}, book_dict: {}) -> None:
}
return
reader_books_json[book_url][book_event_type] = book_dict
if book_dict.get('published'):
if 'timeline' not in reader_books_json:
reader_books_json['timeline'] = {}
published = book_dict['published']
if book_dict.get('updated'):
published = book_dict['updated']
post_time_object = \
date_from_string_format(published, ["%Y-%m-%dT%H:%M:%S%z"])
if post_time_object:
baseline_time = date_epoch()
days_diff = post_time_object - baseline_time
post_days_since_epoch = days_diff.days
reader_books_json['timeline'][post_days_since_epoch] = book_url
if not book_dict.get('published'):
return
if 'timeline' not in reader_books_json:
reader_books_json['timeline'] = {}
published = book_dict['published']
if book_dict.get('updated'):
published = book_dict['updated']
post_time_object = \
date_from_string_format(published, ["%Y-%m-%dT%H:%M:%S%z"])
if post_time_object:
baseline_time = date_epoch()
days_diff = post_time_object - baseline_time
post_days_since_epoch = days_diff.days
reader_books_json['timeline'][post_days_since_epoch] = book_url
def _add_reader_to_book(book_json: {}, book_dict: {}) -> None:
@ -357,3 +359,88 @@ def store_book_events(base_dir: str,
_deduplicate_recent_books_list(base_dir, max_recent_books)
return True
def html_profile_book_list(base_dir: str, actor: str, no_of_books: int,
translate: {}) -> str:
"""Returns html for displaying a list of books on a profile screen
"""
reading_path = base_dir + '/accounts/reading'
readers_path = reading_path + '/readers'
reader_books_filename = \
readers_path + '/' + actor.replace('/', '#') + '.json'
reader_books_json = {}
if not os.path.isfile(reader_books_filename):
return ''
reader_books_json = load_json(reader_books_filename)
if not reader_books_json.get('timeline'):
return ''
# sort the timeline in descending order
recent_books_json = \
OrderedDict(sorted(reader_books_json['timeline'].items(),
reverse=True))
html_str = '<div class="book_list_section">\n'
html_str += ' <ul class="book_list">\n'
ctr = 0
for _, book_url in recent_books_json.items():
if not reader_books_json.get(book_url):
continue
book_rating = None
book_wanted = False
book_finished = False
for event_type in ('want', 'finished', 'rated'):
if not reader_books_json[book_url].get(event_type):
continue
book_dict = reader_books_json[book_url][event_type]
if book_dict.get('name'):
book_title = book_dict['name']
if book_dict.get('image_url'):
book_image_url = book_dict['image_url']
if event_type == 'rated':
book_rating = book_dict['rating']
elif event_type == 'want':
book_wanted = True
elif event_type == 'finished':
book_finished = True
if book_title and book_image_url:
book_title = remove_html(book_title)
html_str += ' <li class="book_event">\n'
html_str += ' <span class="book_span">\n'
html_str += ' <div class="book_span_div">\n'
# book image
html_str += ' <a href="' + book_url + \
'" target="_blank" rel="nofollow noopener noreferrer">\n'
html_str += ' <div class="book_image_div">\n'
html_str += ' <img src="' + book_image_url + '" ' + \
'alt="' + book_title + '">\n'
html_str += ' </div>\n'
html_str += ' </a>\n'
# book details
html_str += ' <div class="book_details_div">\n'
html_str += ' <a href="' + book_url + \
'" target="_blank" rel="nofollow noopener noreferrer">\n'
html_str += ' <b>' + book_title.title() + '</b></a>\n'
if book_finished:
html_str += ' <br>' + \
translate['finished reading'].title() + '\n'
if book_wanted:
html_str += ' <br>' + \
translate['Wanted'] + '\n'
if book_rating is not None:
html_str += ' <br>'
for _ in range(int(book_rating)):
html_str += ''
html_str += ' (' + str(book_rating) + ')'
html_str += ' </div>\n'
html_str += ' </div>\n'
html_str += ' </span>\n'
html_str += ' </li>\n'
ctr += 1
if ctr >= no_of_books:
break
html_str += ' </ul>\n'
html_str += '</div>\n'
return html_str

View File

@ -103,6 +103,7 @@ from session import site_is_verified
from session import get_json
from shares import actor_attached_shares_as_html
from git import get_repo_url
from reading import html_profile_book_list
THEME_FORMATS = '.zip, .gz'
BLOCKFILE_FORMATS = '.csv'
@ -397,7 +398,8 @@ def html_profile_after_search(authorized: bool,
attached_shared_items,
website_url, repo_url,
send_blocks_str,
authorized)
authorized,
person_url)
domain_full = get_full_domain(domain, port)
@ -580,7 +582,8 @@ def _get_profile_header(base_dir: str, http_prefix: str, nickname: str,
access_keys: {},
joined_date: str,
occupation_name: str,
actor_proxied: str) -> str:
actor_proxied: str,
person_url: str) -> str:
"""The header of the profile screen, containing background
image and avatar
"""
@ -708,6 +711,9 @@ def _get_profile_header(base_dir: str, http_prefix: str, nickname: str,
html_str += \
' </figcaption>\n' + \
' </figure>\n\n'
# book events for this actor
html_str += html_profile_book_list(base_dir, person_url, 5, translate)
return html_str
@ -732,7 +738,8 @@ def _get_profile_header_after_search(base_dir: str,
website_url: str,
repo_url: str,
send_blocks_str: str,
authorized: bool) -> str:
authorized: bool,
person_url: str) -> str:
"""The header of a searched for handle, containing background
image and avatar
"""
@ -857,6 +864,8 @@ def _get_profile_header_after_search(base_dir: str,
html_str += \
_profile_shared_items_list(attached_shared_items,
translate)
# book events for this actor
html_str += html_profile_book_list(base_dir, person_url, 5, translate)
return html_str
@ -1248,7 +1257,7 @@ def html_profile(signing_priv_key_pem: str,
attached_shared_items,
access_keys, joined_date,
occupation_name,
actor_proxied)
actor_proxied, actor)
# keyboard navigation
user_path_str = '/users/' + nickname