diff --git a/catalog/book/models.py b/catalog/book/models.py index b4cef44c..7f118188 100644 --- a/catalog/book/models.py +++ b/catalog/book/models.py @@ -159,15 +159,16 @@ class Edition(Item): return [(i.value, i.label) for i in id_types] @classmethod - def lookup_id_cleanup(cls, lookup_id_type, lookup_id_value): + def lookup_id_cleanup(cls, lookup_id_type: str | IdType, lookup_id_value: str): if lookup_id_type in [IdType.ASIN.value, IdType.ISBN.value]: return detect_isbn_asin(lookup_id_value) return super().lookup_id_cleanup(lookup_id_type, lookup_id_value) - def merge_to(self, to_item): + def merge_to(self, to_item: "Edition | None"): super().merge_to(to_item) - for work in self.works.all(): - to_item.works.add(work) + if to_item: + for work in self.works.all(): + to_item.works.add(work) self.works.clear() def delete(self, using=None, soft=True, *args, **kwargs): @@ -278,17 +279,18 @@ class Work(Item): ] return [(i.value, i.label) for i in id_types] - def merge_to(self, to_item): + def merge_to(self, to_item: "Work | None"): super().merge_to(to_item) - for edition in self.editions.all(): - to_item.editions.add(edition) + if to_item: + for edition in self.editions.all(): + to_item.editions.add(edition) self.editions.clear() if ( to_item and self.title != to_item.title and self.title not in to_item.other_title ): - to_item.other_title += [self.title] + to_item.other_title += [self.title] # type: ignore to_item.save() def delete(self, using=None, soft=True, *args, **kwargs): diff --git a/catalog/book/utils.py b/catalog/book/utils.py index 5436e6f6..41c5eb3b 100644 --- a/catalog/book/utils.py +++ b/catalog/book/utils.py @@ -50,14 +50,15 @@ def is_asin(asin): return re.match(r"^B[A-Z0-9]{9}$", asin) is not None -def detect_isbn_asin(s): +def detect_isbn_asin(s: str) -> tuple[IdType, str] | tuple[None, None]: if not s: return None, None n = re.sub(r"[^0-9A-Z]", "", s.upper()) if is_isbn_13(n): return IdType.ISBN, n if is_isbn_10(n): - return IdType.ISBN, isbn_10_to_13(n) + v = isbn_10_to_13(n) + return (IdType.ISBN, v) if v else (None, None) if is_asin(n): return IdType.ASIN, n return None, None diff --git a/catalog/common/models.py b/catalog/common/models.py index 1bc55180..3c7ed647 100644 --- a/catalog/common/models.py +++ b/catalog/common/models.py @@ -1,7 +1,7 @@ import re import uuid from functools import cached_property -from typing import TYPE_CHECKING, cast +from typing import TYPE_CHECKING, Any, Iterable, Type, cast from auditlog.context import disable_auditlog from auditlog.models import AuditlogHistoryField, LogEntry @@ -9,6 +9,7 @@ from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.core.files.uploadedfile import SimpleUploadedFile from django.db import connection, models +from django.db.models import QuerySet from django.utils import timezone from django.utils.baseconv import base62 from django.utils.translation import gettext_lazy as _ @@ -145,26 +146,26 @@ class AvailableItemCategory(models.TextChoices): # class SubItemType(models.TextChoices): -# Season = "season", _("剧集分季") -# Episode = "episode", _("剧集分集") -# Version = "version", _("版本") +# Season = "season", _("season") +# Episode = "episode", _("episode") +# Version = "production", _("production") # class CreditType(models.TextChoices): -# Author = 'author', _('作者') -# Translater = 'translater', _('译者') -# Producer = 'producer', _('出品人') -# Director = 'director', _('电影') -# Actor = 'actor', _('演员') -# Playwright = 'playwright', _('播客') -# VoiceActor = 'voiceactor', _('配音') -# Host = 'host', _('主持人') -# Developer = 'developer', _('开发者') -# Publisher = 'publisher', _('出版方') +# Author = 'author', _('author') +# Translater = 'translater', _('translater') +# Producer = 'producer', _('producer') +# Director = 'director', _('director') +# Actor = 'actor', _('actor') +# Playwright = 'playwright', _('playwright') +# VoiceActor = 'voiceactor', _('voiceactor') +# Host = 'host', _('host') +# Developer = 'developer', _('developer') +# Publisher = 'publisher', _('publisher') class PrimaryLookupIdDescriptor(object): # TODO make it mixin of Field - def __init__(self, id_type): + def __init__(self, id_type: IdType): self.id_type = id_type def __get__(self, instance, cls=None): @@ -184,7 +185,7 @@ class PrimaryLookupIdDescriptor(object): # TODO make it mixin of Field class LookupIdDescriptor(object): # TODO make it mixin of Field - def __init__(self, id_type): + def __init__(self, id_type: IdType): self.id_type = id_type def __get__(self, instance, cls=None): @@ -198,14 +199,14 @@ class LookupIdDescriptor(object): # TODO make it mixin of Field # class ItemId(models.Model): # item = models.ForeignKey('Item', models.CASCADE) -# id_type = models.CharField(_("源网站"), blank=False, choices=IdType.choices, max_length=50) -# id_value = models.CharField(_("源网站ID"), blank=False, max_length=1000) +# id_type = models.CharField(_("Id Type"), blank=False, choices=IdType.choices, max_length=50) +# id_value = models.CharField(_("ID Value"), blank=False, max_length=1000) # class ItemCredit(models.Model): # item = models.ForeignKey('Item', models.CASCADE) -# credit_type = models.CharField(_("类型"), choices=CreditType.choices, blank=False, max_length=50) -# name = models.CharField(_("名字"), blank=False, max_length=1000) +# credit_type = models.CharField(_("Credit Type"), choices=CreditType.choices, blank=False, max_length=50) +# name = models.CharField(_("Name"), blank=False, max_length=1000) # def check_source_id(sid): @@ -241,11 +242,11 @@ class ItemInSchema(Schema): rating_count: int | None -class ItemSchema(ItemInSchema, BaseSchema): +class ItemSchema(BaseSchema, ItemInSchema): pass -class Item(SoftDeleteMixin, PolymorphicModel): +class Item(PolymorphicModel, SoftDeleteMixin): url_path = "item" # subclass must specify this type = None # subclass must specify this child_class = None # subclass may specify this to allow link to parent item @@ -315,13 +316,15 @@ class Item(SoftDeleteMixin, PolymorphicModel): return IdType.choices @classmethod - def lookup_id_cleanup(cls, lookup_id_type, lookup_id_value): + def lookup_id_cleanup( + cls, lookup_id_type: str | IdType, lookup_id_value: str + ) -> tuple[str | IdType, str] | tuple[None, None]: if not lookup_id_type or not lookup_id_value or not lookup_id_value.strip(): return None, None return lookup_id_type, lookup_id_value.strip() @classmethod - def get_best_lookup_id(cls, lookup_ids): + def get_best_lookup_id(cls, lookup_ids: dict[IdType, str]) -> tuple[IdType, str]: """get best available lookup id, ideally commonly used""" for t in IdealIdTypes: if lookup_ids.get(t): @@ -333,23 +336,23 @@ class Item(SoftDeleteMixin, PolymorphicModel): return None @property - def child_items(self): + def child_items(self) -> "QuerySet[Item]": return Item.objects.none() @property - def child_item_ids(self): + def child_item_ids(self) -> list[int]: return list(self.child_items.values_list("id", flat=True)) - def set_parent_item(self, value): + def set_parent_item(self, value: "Item | None"): # raise ValueError("cannot set parent item") pass @property - def parent_uuid(self): + def parent_uuid(self) -> str | None: return self.parent_item.uuid if self.parent_item else None @property - def sibling_items(self): + def sibling_items(self) -> "QuerySet[Item]": return Item.objects.none() @property @@ -357,19 +360,19 @@ class Item(SoftDeleteMixin, PolymorphicModel): return "" @property - def sibling_item_ids(self): + def sibling_item_ids(self) -> list[int]: return list(self.sibling_items.values_list("id", flat=True)) @classmethod - def get_ap_object_type(cls): + def get_ap_object_type(cls) -> str: return cls.__name__ @property - def ap_object_type(self): + def ap_object_type(self) -> str: return self.get_ap_object_type() @property - def ap_object_ref(self): + def ap_object_ref(self) -> dict[str, Any]: o = { "type": self.get_ap_object_type(), "href": self.absolute_url, @@ -379,12 +382,12 @@ class Item(SoftDeleteMixin, PolymorphicModel): o["image"] = self.cover_image_url return o - def log_action(self, changes): + def log_action(self, changes: dict[str, Any]): LogEntry.objects.log_create( # type: ignore self, action=LogEntry.Action.UPDATE, changes=changes ) - def merge_to(self, to_item): + def merge_to(self, to_item: "Item | None"): if to_item is None: if self.merged_to_item is not None: self.merged_to_item = None @@ -394,7 +397,7 @@ class Item(SoftDeleteMixin, PolymorphicModel): raise ValueError("cannot merge to self") if to_item.merged_to_item is not None: raise ValueError("cannot merge to item which is merged to another item") - if to_item.__class__ != self.__class__: + if not isinstance(to_item, self.__class__): raise ValueError("cannot merge to item in a different model") self.log_action({"!merged": [str(self.merged_to_item), str(to_item)]}) self.merged_to_item = to_item @@ -403,11 +406,11 @@ class Item(SoftDeleteMixin, PolymorphicModel): res.item = to_item res.save() - def recast_to(self, model): + def recast_to(self, model: "type[Item]") -> "Item": logger.warning(f"recast item {self} to {model}") - if self.__class__ == model: + if isinstance(self, model): return self - if model not in Item.__subclasses__(): + if not issubclass(model, Item): raise ValueError("invalid model to recast to") ct = ContentType.objects.get_for_model(model) old_ct = self.polymorphic_ctype @@ -442,15 +445,15 @@ class Item(SoftDeleteMixin, PolymorphicModel): return f"/api{self.url}" @property - def class_name(self): + def class_name(self) -> str: return self.__class__.__name__.lower() @property - def display_title(self): + def display_title(self) -> str: return self.title @classmethod - def get_by_url(cls, url_or_b62): + def get_by_url(cls, url_or_b62: str) -> "Item | None": b62 = url_or_b62.strip().split("/")[-1] if len(b62) not in [21, 22]: r = re.search(r"[A-Za-z0-9]{21,22}", url_or_b62) @@ -633,7 +636,7 @@ class ExternalResource(models.Model): return SiteName.Unknown @property - def site_label(self): + def site_label(self) -> str: if self.id_type == IdType.Fediverse: from takahe.utils import Takahe @@ -704,7 +707,7 @@ def item_content_types(): _CATEGORY_LIST = None -def item_categories(): +def item_categories() -> dict[ItemCategory, list[type[Item]]]: global _CATEGORY_LIST if _CATEGORY_LIST is None: _CATEGORY_LIST = {} diff --git a/catalog/podcast/models.py b/catalog/podcast/models.py index 8fbda661..d0f3b348 100644 --- a/catalog/podcast/models.py +++ b/catalog/podcast/models.py @@ -114,12 +114,14 @@ class PodcastEpisode(Item): self.program = value @property - def display_title(self): - return f"{self.program.title} - {self.title}" + def display_title(self) -> str: + return f"{self.program.title} - {self.title}" if self.program else self.title @property - def cover_image_url(self): - return self.cover_url or self.program.cover_image_url + def cover_image_url(self) -> str | None: + return self.cover_url or ( + self.program.cover_image_url if self.program else None + ) def get_url_with_position(self, position=None): return ( diff --git a/catalog/sites/bookstw.py b/catalog/sites/bookstw.py index 32be8229..54c7093c 100644 --- a/catalog/sites/bookstw.py +++ b/catalog/sites/bookstw.py @@ -135,7 +135,7 @@ class BooksTW(AbstractSite): } pd = ResourceContent(metadata=data) - t, n = detect_isbn_asin(isbn) + t, n = detect_isbn_asin(str(isbn)) if t: pd.lookup_ids[t] = n pd.cover_image, pd.cover_image_extention = BasicImageDownloader.download_image( diff --git a/journal/api.py b/journal/api.py index 8cef0a54..0529d7af 100644 --- a/journal/api.py +++ b/journal/api.py @@ -169,7 +169,7 @@ def list_reviews(request, category: AvailableItemCategory | None = None): """ queryset = Review.objects.filter(owner=request.user.identity) if category: - queryset = queryset.filter(q_item_in_category(category)) + queryset = queryset.filter(q_item_in_category(category)) # type: ignore[arg-type] return queryset.prefetch_related("item") diff --git a/journal/models/__init__.py b/journal/models/__init__.py index 4f409333..fa71eb3a 100644 --- a/journal/models/__init__.py +++ b/journal/models/__init__.py @@ -4,7 +4,6 @@ from .common import ( Piece, PieceInteraction, PiecePost, - UserOwnedObjectMixin, VisibilityType, max_visiblity_to_user, q_item_in_category, @@ -14,6 +13,7 @@ from .common import ( ) from .like import Like from .mark import Mark +from .mixins import UserOwnedObjectMixin from .rating import Rating from .renderers import render_md from .review import Review @@ -25,3 +25,37 @@ from .utils import ( reset_journal_visibility_for_user, update_journal_for_merged_item, ) + +__all__ = [ + "Collection", + "CollectionMember", + "FeaturedCollection", + "Comment", + "Piece", + "PieceInteraction", + "PiecePost", + "UserOwnedObjectMixin", + "VisibilityType", + "max_visiblity_to_user", + "q_item_in_category", + "q_owned_piece_visible_to_user", + "q_piece_in_home_feed_of_user", + "q_piece_visible_to_user", + "Like", + "Mark", + "Rating", + "render_md", + "Review", + "Shelf", + "ShelfLogEntry", + "ShelfManager", + "ShelfMember", + "ShelfType", + "Tag", + "TagManager", + "TagMember", + "journal_exists_for_item", + "remove_data_by_user", + "reset_journal_visibility_for_user", + "update_journal_for_merged_item", +] diff --git a/journal/models/common.py b/journal/models/common.py index 7307a9ec..77c6c80e 100644 --- a/journal/models/common.py +++ b/journal/models/common.py @@ -73,7 +73,7 @@ def q_piece_in_home_feed_of_user(viewing_user: User): return Q(owner_id__in=viewer.following, visibility__lt=2) | Q(owner_id=viewer.pk) -def q_item_in_category(item_category: ItemCategory | AvailableItemCategory): +def q_item_in_category(item_category: ItemCategory): classes = item_categories()[item_category] # q = Q(item__instance_of=classes[0]) # for cls in classes[1:]: diff --git a/journal/models/mixins.py b/journal/models/mixins.py index a534500f..8c7da950 100644 --- a/journal/models/mixins.py +++ b/journal/models/mixins.py @@ -1,10 +1,10 @@ from typing import TYPE_CHECKING -from users.models import APIdentity, User - if TYPE_CHECKING: from django.db.models import ForeignKey + from users.models import APIdentity, User + from .common import Piece @@ -21,7 +21,9 @@ class UserOwnedObjectMixin: owner: ForeignKey[APIdentity, Piece] visibility: int - def is_visible_to(self: "Piece", viewing_user: User) -> bool: # noqa # type: ignore + def is_visible_to( + self: "Piece", viewing_user: "User" # noqa # type: ignore + ) -> bool: owner = self.owner if not owner or not owner.is_active: return False @@ -41,7 +43,7 @@ class UserOwnedObjectMixin: else: return True - def is_editable_by(self: "Piece", viewing_user: User): # type: ignore + def is_editable_by(self: "Piece", viewing_user: "User"): # type: ignore return viewing_user.is_authenticated and ( viewing_user.is_staff or viewing_user.is_superuser diff --git a/journal/templates/_list_item.html b/journal/templates/_list_item.html index f46c1ffd..15b34337 100644 --- a/journal/templates/_list_item.html +++ b/journal/templates/_list_item.html @@ -71,7 +71,7 @@ {{ mark.review.created_time|date }}
- 评论: + {% trans "Review" %} {{ mark.review.title }} diff --git a/journal/templates/_sidebar_user_mark_list.html b/journal/templates/_sidebar_user_mark_list.html index 363aaf6b..1a03ec03 100644 --- a/journal/templates/_sidebar_user_mark_list.html +++ b/journal/templates/_sidebar_user_mark_list.html @@ -23,44 +23,44 @@ {% endif %} {% endfor %} + value="reviews">{% trans "review" %} @@ -70,18 +70,18 @@ padding: var(--pico-form-element-spacing-vertical) calc(var(--pico-form-element-spacing-horizontal)/4) !important } - ---> + + --> diff --git a/journal/templates/calendar_data.html b/journal/templates/calendar_data.html index 112d5bef..7d4eb7a5 100644 --- a/journal/templates/calendar_data.html +++ b/journal/templates/calendar_data.html @@ -5,7 +5,7 @@ data: $("#calendar_data").text(), start_monday: false, always_show_tooltip: false, - month_names: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], + month_names: ['{% trans "JAN" %}', '{% trans "FEB" %}', '{% trans "MAR" %}', '{% trans "APR" %}', '{% trans "MAY" %}', '{% trans "JUN" %}', '{% trans "JUL" %}', '{% trans "AUG" %}', '{% trans "SEP" %}', '{% trans "OCT" %}', '{% trans "NOV" %}', '{% trans "DEC" %}'], day_names: ['', '', ''], colors: { 'default': getComputedStyle(document.documentElement).getPropertyValue('--pico-form-element-background-color'), diff --git a/journal/templates/collection.html b/journal/templates/collection.html index 0e9b8709..ecd943d5 100644 --- a/journal/templates/collection.html +++ b/journal/templates/collection.html @@ -89,17 +89,17 @@
{% if stats.progress %} - {{ stats.progress }} 进行中
+ {{ stats.progress }} in progress
{% endif %} {% if stats.complete %} - {{ stats.complete }} 已完成 + {{ stats.complete }} completed {% elif not stats.progress %} - 尚未开始 + not started {% endif %}
- 开始于{{ featured_since|date }} - + Started {{ featured_since|date }} + diff --git a/journal/templates/comment.html b/journal/templates/comment.html index 1095ebaf..2a3c0698 100644 --- a/journal/templates/comment.html +++ b/journal/templates/comment.html @@ -66,7 +66,7 @@
- +
diff --git a/journal/templates/user_collection_list.html b/journal/templates/user_collection_list.html index 4744c884..35e3f146 100644 --- a/journal/templates/user_collection_list.html +++ b/journal/templates/user_collection_list.html @@ -11,8 +11,12 @@ {{ site_name }} - {{ identity.display_name }} - - {% if liked %}喜欢的{% endif %} - 收藏单 + {% if liked %} + {% trans "Liked Collections" %} + {% else %} + {% trans "Collections" %} + {% endif %} + {% include "common_libs.html" %} @@ -21,8 +25,11 @@
{{ identity.display_name }} - - {% if liked %}喜欢的{% endif %} - 收藏单 + {% if liked %} + {% trans "Liked Collections" %} + {% else %} + {% trans "Collections" %} + {% endif %}
{% for collection in collections %}

@@ -41,7 +48,7 @@ {% endif %}

{% empty %} -
暂无
+
{% trans "nothing so far." %}
{% endfor %}
{% include "_sidebar.html" with show_profile=1 %} diff --git a/journal/templates/user_tagmember_list.html b/journal/templates/user_tagmember_list.html index cc28f2b5..adec4e83 100644 --- a/journal/templates/user_tagmember_list.html +++ b/journal/templates/user_tagmember_list.html @@ -10,7 +10,6 @@ {% if tag.visibility > 0 %} {% endif %} - 个人标签 {{ identity.display_name }} - {% trans 'Tags' %} {% if identity.user == request.user %}
\n" "Language-Team: LANGUAGE \n" @@ -33,7 +33,7 @@ msgstr "副标题" msgid "original title" msgstr "原名" -#: catalog/book/models.py:99 catalog/book/models.py:249 +#: catalog/book/models.py:99 catalog/book/models.py:250 msgid "author" msgstr "作者" @@ -85,322 +85,329 @@ msgstr "价格" msgid "imprint" msgstr "出品方" -#: catalog/book/models.py:256 catalog/game/models.py:58 +#: catalog/book/models.py:257 catalog/game/models.py:58 #: catalog/movie/models.py:68 catalog/music/models.py:85 #: catalog/performance/models.py:111 catalog/performance/models.py:260 #: catalog/tv/models.py:131 catalog/tv/models.py:292 msgid "other title" msgstr "其它标题" -#: catalog/common/models.py:29 +#: catalog/common/models.py:30 msgid "Unknown" msgstr "未知" -#: catalog/common/models.py:30 +#: catalog/common/models.py:31 msgid "Douban" msgstr "豆瓣" -#: catalog/common/models.py:31 catalog/common/models.py:64 +#: catalog/common/models.py:32 catalog/common/models.py:65 msgid "Goodreads" msgstr "Goodreads" -#: catalog/common/models.py:32 catalog/common/models.py:66 +#: catalog/common/models.py:33 catalog/common/models.py:67 msgid "Google Books" msgstr "谷歌图书" -#: catalog/common/models.py:33 +#: catalog/common/models.py:34 msgid "BooksTW" msgstr "博客來" -#: catalog/common/models.py:34 catalog/common/models.py:59 +#: catalog/common/models.py:35 catalog/common/models.py:60 #: catalog/templates/movie.html:51 catalog/templates/tvseason.html:68 #: catalog/templates/tvshow.html:63 msgid "IMDb" msgstr "IMDb" -#: catalog/common/models.py:35 +#: catalog/common/models.py:36 msgid "TMDB" msgstr "TMDB" -#: catalog/common/models.py:36 catalog/common/models.py:75 +#: catalog/common/models.py:37 catalog/common/models.py:76 msgid "Bandcamp" msgstr "Bandcamp" -#: catalog/common/models.py:37 +#: catalog/common/models.py:38 msgid "Spotify" msgstr "Spotify" -#: catalog/common/models.py:38 +#: catalog/common/models.py:39 msgid "IGDB" msgstr "IGDB" -#: catalog/common/models.py:39 +#: catalog/common/models.py:40 msgid "Steam" msgstr "Steam" -#: catalog/common/models.py:40 catalog/common/models.py:89 +#: catalog/common/models.py:41 catalog/common/models.py:90 msgid "Bangumi" msgstr "Bangumi" -#: catalog/common/models.py:41 +#: catalog/common/models.py:42 msgid "BGG" msgstr "BGG" -#: catalog/common/models.py:43 +#: catalog/common/models.py:44 msgid "RSS" msgstr "RSS" -#: catalog/common/models.py:44 +#: catalog/common/models.py:45 msgid "Discogs" msgstr "Discogs" -#: catalog/common/models.py:45 catalog/common/models.py:91 +#: catalog/common/models.py:46 catalog/common/models.py:92 msgid "Apple Music" msgstr "苹果音乐" -#: catalog/common/models.py:46 catalog/common/models.py:92 +#: catalog/common/models.py:47 catalog/common/models.py:93 msgid "Fediverse" msgstr "联邦宇宙" -#: catalog/common/models.py:50 +#: catalog/common/models.py:51 msgid "WikiData" msgstr "维基数据" -#: catalog/common/models.py:51 +#: catalog/common/models.py:52 msgid "ISBN10" msgstr "ISBN10" -#: catalog/common/models.py:52 catalog/templates/edition.html:19 +#: catalog/common/models.py:53 catalog/templates/edition.html:19 msgid "ISBN" msgstr "ISBN" -#: catalog/common/models.py:53 +#: catalog/common/models.py:54 msgid "ASIN" msgstr "ASIN" -#: catalog/common/models.py:54 +#: catalog/common/models.py:55 msgid "ISSN" msgstr "ISSN" -#: catalog/common/models.py:55 +#: catalog/common/models.py:56 msgid "CUBN" msgstr "统一书号" -#: catalog/common/models.py:56 +#: catalog/common/models.py:57 msgid "ISRC" msgstr "ISRC" -#: catalog/common/models.py:57 +#: catalog/common/models.py:58 msgid "GTIN UPC EAN" msgstr "条形码" -#: catalog/common/models.py:58 +#: catalog/common/models.py:59 msgid "RSS Feed URL" msgstr "RSS网址" -#: catalog/common/models.py:60 +#: catalog/common/models.py:61 msgid "TMDB TV Serie" msgstr "TMDB电视剧集" -#: catalog/common/models.py:61 +#: catalog/common/models.py:62 msgid "TMDB TV Season" msgstr "TMDB电视分季" -#: catalog/common/models.py:62 +#: catalog/common/models.py:63 msgid "TMDB TV Episode" msgstr "TMDB电视单集" -#: catalog/common/models.py:63 +#: catalog/common/models.py:64 msgid "TMDB Movie" msgstr "TMDB电影" -#: catalog/common/models.py:65 +#: catalog/common/models.py:66 msgid "Goodreads Work" msgstr "Goodreads著作" -#: catalog/common/models.py:67 +#: catalog/common/models.py:68 msgid "Douban Book" msgstr "豆瓣图书" -#: catalog/common/models.py:68 +#: catalog/common/models.py:69 msgid "Douban Book Work" msgstr "豆瓣图书著作" -#: catalog/common/models.py:69 +#: catalog/common/models.py:70 msgid "Douban Movie" msgstr "豆瓣电影" -#: catalog/common/models.py:70 +#: catalog/common/models.py:71 msgid "Douban Music" msgstr "豆瓣音乐" -#: catalog/common/models.py:71 +#: catalog/common/models.py:72 msgid "Douban Game" msgstr "豆瓣游戏" -#: catalog/common/models.py:72 +#: catalog/common/models.py:73 msgid "Douban Drama" msgstr "豆瓣舞台剧" -#: catalog/common/models.py:73 +#: catalog/common/models.py:74 msgid "Douban Drama Version" msgstr "豆瓣舞台剧版本" -#: catalog/common/models.py:74 +#: catalog/common/models.py:75 msgid "BooksTW Book" msgstr "博客来图书" -#: catalog/common/models.py:76 +#: catalog/common/models.py:77 msgid "Spotify Album" msgstr "Spotify专辑" -#: catalog/common/models.py:77 +#: catalog/common/models.py:78 msgid "Spotify Podcast" msgstr "Spotify播客" -#: catalog/common/models.py:86 +#: catalog/common/models.py:87 msgid "IGDB Game" msgstr "IGDB游戏" -#: catalog/common/models.py:87 +#: catalog/common/models.py:88 msgid "BGG Boardgame" msgstr "BGG桌游" -#: catalog/common/models.py:88 +#: catalog/common/models.py:89 msgid "Steam Game" msgstr "Steam游戏" -#: catalog/common/models.py:90 +#: catalog/common/models.py:91 msgid "Apple Podcast" msgstr "苹果播客" -#: catalog/common/models.py:108 catalog/common/models.py:125 -#: catalog/common/models.py:138 catalog/jobs/discover.py:91 +#: catalog/common/models.py:109 catalog/common/models.py:126 +#: catalog/common/models.py:139 catalog/jobs/discover.py:91 #: common/templates/_header.html:25 +#: journal/templates/_sidebar_user_mark_list.html:31 msgid "Book" msgstr "书" -#: catalog/common/models.py:109 +#: catalog/common/models.py:110 msgid "TV Serie" msgstr "电视剧集" -#: catalog/common/models.py:110 catalog/templates/_sidebar_edit.html:140 +#: catalog/common/models.py:111 catalog/templates/_sidebar_edit.html:140 msgid "TV Season" msgstr "电视分季" -#: catalog/common/models.py:111 +#: catalog/common/models.py:112 msgid "TV Episode" msgstr "电视单集" -#: catalog/common/models.py:112 catalog/common/models.py:126 -#: catalog/common/models.py:139 catalog/templates/_sidebar_edit.html:133 +#: catalog/common/models.py:113 catalog/common/models.py:127 +#: catalog/common/models.py:140 catalog/templates/_sidebar_edit.html:133 +#: journal/templates/_sidebar_user_mark_list.html:34 msgid "Movie" msgstr "电影" -#: catalog/common/models.py:113 +#: catalog/common/models.py:114 msgid "Album" msgstr "专辑" -#: catalog/common/models.py:114 catalog/common/models.py:129 -#: catalog/common/models.py:142 common/templates/_header.html:41 +#: catalog/common/models.py:115 catalog/common/models.py:130 +#: catalog/common/models.py:143 common/templates/_header.html:41 +#: journal/templates/_sidebar_user_mark_list.html:47 msgid "Game" msgstr "游戏" -#: catalog/common/models.py:115 +#: catalog/common/models.py:116 msgid "Podcast Program" msgstr "播客节目" -#: catalog/common/models.py:116 +#: catalog/common/models.py:117 msgid "Podcast Episode" msgstr "播客单集" -#: catalog/common/models.py:117 catalog/common/models.py:131 -#: catalog/common/models.py:144 common/templates/_header.html:45 +#: catalog/common/models.py:118 catalog/common/models.py:132 +#: catalog/common/models.py:145 common/templates/_header.html:45 +#: journal/templates/_sidebar_user_mark_list.html:51 msgid "Performance" msgstr "演出" -#: catalog/common/models.py:118 +#: catalog/common/models.py:119 msgid "Production" msgstr "上演" -#: catalog/common/models.py:119 +#: catalog/common/models.py:120 msgid "Fanfic" msgstr "网文" -#: catalog/common/models.py:120 catalog/common/models.py:133 +#: catalog/common/models.py:121 catalog/common/models.py:134 msgid "Exhibition" msgstr "展览" -#: catalog/common/models.py:121 catalog/common/models.py:134 +#: catalog/common/models.py:122 catalog/common/models.py:135 #: journal/templates/collection.html:15 journal/templates/collection.html:22 #: journal/templates/collection_edit.html:9 #: journal/templates/collection_share.html:12 msgid "Collection" msgstr "收藏单" -#: catalog/common/models.py:127 catalog/common/models.py:140 +#: catalog/common/models.py:128 catalog/common/models.py:141 +#: journal/templates/_sidebar_user_mark_list.html:37 msgid "TV" msgstr "剧集" -#: catalog/common/models.py:128 catalog/common/models.py:141 +#: catalog/common/models.py:129 catalog/common/models.py:142 #: common/templates/_header.html:37 +#: journal/templates/_sidebar_user_mark_list.html:44 msgid "Music" msgstr "音乐" -#: catalog/common/models.py:130 catalog/common/models.py:143 +#: catalog/common/models.py:131 catalog/common/models.py:144 #: catalog/templates/_sidebar_edit.html:152 common/templates/_header.html:33 +#: journal/templates/_sidebar_user_mark_list.html:41 msgid "Podcast" msgstr "播客" -#: catalog/common/models.py:132 +#: catalog/common/models.py:133 msgid "FanFic" msgstr "网文" -#: catalog/common/models.py:255 journal/models/collection.py:48 +#: catalog/common/models.py:256 journal/models/collection.py:48 msgid "title" msgstr "标题" -#: catalog/common/models.py:256 journal/models/collection.py:49 +#: catalog/common/models.py:257 journal/models/collection.py:49 msgid "description" msgstr "描述" -#: catalog/common/models.py:258 catalog/forms.py:26 +#: catalog/common/models.py:259 catalog/forms.py:26 msgid "Primary ID Type" msgstr "主要标识类型" -#: catalog/common/models.py:261 catalog/forms.py:31 +#: catalog/common/models.py:262 catalog/forms.py:31 msgid "Primary ID Value" msgstr "主要标识数据" -#: catalog/common/models.py:267 +#: catalog/common/models.py:268 msgid "metadata" msgstr "元数据" -#: catalog/common/models.py:269 +#: catalog/common/models.py:270 msgid "cover" msgstr "封面" -#: catalog/common/models.py:563 +#: catalog/common/models.py:566 msgid "source site" msgstr "来源站点" -#: catalog/common/models.py:565 +#: catalog/common/models.py:568 msgid "ID on source site" msgstr "来源站点标识" -#: catalog/common/models.py:567 +#: catalog/common/models.py:570 msgid "source url" msgstr "来源站点网址" -#: catalog/common/models.py:579 +#: catalog/common/models.py:582 msgid "IdType of the source site" msgstr "来源站点的主要标识类型" -#: catalog/common/models.py:585 +#: catalog/common/models.py:588 msgid "Primary Id on the source site" msgstr "来源站点的主要标识数据" -#: catalog/common/models.py:588 +#: catalog/common/models.py:591 msgid "url to the resource" msgstr "指向外部资源的网址" @@ -481,6 +488,7 @@ msgid "release date" msgstr "发布日期" #: catalog/movie/models.py:115 catalog/tv/models.py:339 +#: journal/templates/_sidebar_user_mark_list.html:62 msgid "date" msgstr "日期" @@ -632,6 +640,7 @@ msgstr "所属" #: catalog/templates/_item_comments_by_episode.html:13 #: catalog/templates/search_results.html:28 #: catalog/templates/search_results.html:30 +#: journal/templates/_sidebar_user_mark_list.html:55 #: social/templates/notification.html:26 msgid "all" msgstr "全部" @@ -669,6 +678,7 @@ msgstr "写该集短评" #: journal/models/shelf.py:97 journal/models/shelf.py:132 #: journal/models/shelf.py:167 journal/models/shelf.py:202 #: journal/models/shelf.py:237 journal/models/shelf.py:267 +#: journal/templates/_sidebar_user_mark_list.html:26 msgid "review" msgstr "评论" @@ -1034,9 +1044,10 @@ msgstr "创建" #: catalog/templates/catalog_edit.html:50 #: developer/templates/oauth2_provider/application_form.html:35 #: journal/templates/add_to_collection.html:35 -#: journal/templates/collection_edit.html:38 journal/templates/mark.html:142 -#: journal/templates/review_edit.html:40 journal/templates/tag_edit.html:60 -#: users/templates/users/account.html:43 users/templates/users/account.html:104 +#: journal/templates/collection_edit.html:38 journal/templates/comment.html:69 +#: journal/templates/mark.html:142 journal/templates/review_edit.html:40 +#: journal/templates/tag_edit.html:60 users/templates/users/account.html:43 +#: users/templates/users/account.html:104 #: users/templates/users/preferences.html:170 #: users/templates/users/preferences.html:195 msgid "Save" @@ -1167,6 +1178,7 @@ msgstr "简介" #: common/templates/_sidebar.html:197 journal/templates/collection_items.html:8 #: journal/templates/profile.html:109 journal/templates/profile.html:151 #: journal/templates/profile.html:187 journal/templates/replies.html:46 +#: journal/templates/user_collection_list.html:43 #: journal/templates/user_item_list_base.html:25 #: journal/templates/user_tag_list.html:29 social/templates/events.html:46 #: users/templates/users/announcements.html:53 @@ -1361,11 +1373,11 @@ msgstr "{show_title} 第{season_number}季" msgid "{season_title} E{episode_number}" msgstr "{season_title} 第{episode_number}集" -#: catalog/views.py:49 catalog/views.py:72 +#: catalog/views.py:48 catalog/views.py:71 msgid "Item not found" msgstr "条目不存在" -#: catalog/views.py:53 catalog/views.py:80 +#: catalog/views.py:52 catalog/views.py:79 msgid "Item no longer exists" msgstr "条目已不存在" @@ -1385,7 +1397,7 @@ msgstr "权限不足" #: catalog/views_edit.py:200 journal/views/collection.py:229 #: journal/views/collection.py:296 journal/views/common.py:81 -#: journal/views/mark.py:139 journal/views/post.py:41 journal/views/post.py:55 +#: journal/views/mark.py:140 journal/views/post.py:41 journal/views/post.py:55 #: journal/views/review.py:93 journal/views/review.py:96 users/views.py:169 msgid "Invalid parameter" msgstr "无效参数" @@ -2111,10 +2123,25 @@ msgstr "添加标记" msgid "update mark" msgstr "更新标记" +#: journal/templates/_list_item.html:75 journal/templates/review.html:14 +#: journal/templates/review.html:22 journal/templates/review.html:52 +#: journal/templates/review_edit.html:10 +#: journal/templates/user_review_list.html:7 +msgid "Review" +msgstr "评论" + #: journal/templates/_list_item.html:89 msgid "Update note" msgstr "修改备注" +#: journal/templates/_sidebar_user_mark_list.html:61 +msgid "sorting" +msgstr "排序" + +#: journal/templates/_sidebar_user_mark_list.html:63 +msgid "rating" +msgstr "评分" + #: journal/templates/action_boost_post.html:10 #: users/templates/users/preferences.html:111 msgid "boost" @@ -2150,6 +2177,54 @@ msgstr "创建新收藏单" msgid "Note" msgstr "备注" +#: journal/templates/calendar_data.html:8 +msgid "JAN" +msgstr "一月" + +#: journal/templates/calendar_data.html:8 +msgid "FEB" +msgstr "二月" + +#: journal/templates/calendar_data.html:8 +msgid "MAR" +msgstr "三月" + +#: journal/templates/calendar_data.html:8 +msgid "APR" +msgstr "四月" + +#: journal/templates/calendar_data.html:8 +msgid "MAY" +msgstr "五月" + +#: journal/templates/calendar_data.html:8 +msgid "JUN" +msgstr "六月" + +#: journal/templates/calendar_data.html:8 +msgid "JUL" +msgstr "七月" + +#: journal/templates/calendar_data.html:8 +msgid "AUG" +msgstr "八月" + +#: journal/templates/calendar_data.html:8 +msgid "SEP" +msgstr "九月" + +#: journal/templates/calendar_data.html:8 +msgid "OCT" +msgstr "十月" + +#: journal/templates/calendar_data.html:8 +msgid "NOV" +msgstr "十一月" + +#: journal/templates/calendar_data.html:8 +msgid "DEC" +msgstr "十二月" + #: journal/templates/collection.html:40 #: journal/templates/collection_share.html:12 #: journal/templates/collection_share.html:66 @@ -2250,12 +2325,6 @@ msgstr "喜欢的收藏单" msgid "add a reply" msgstr "添加回应" -#: journal/templates/review.html:14 journal/templates/review.html:22 -#: journal/templates/review.html:52 journal/templates/review_edit.html:10 -#: journal/templates/user_review_list.html:7 -msgid "Review" -msgstr "评论" - #: journal/templates/review.html:62 msgid "The author has set it to be viewable only by logged-in users." msgstr "作者已设置仅限已登录用户查看" @@ -2293,6 +2362,16 @@ msgstr "" msgid "Delete this tag" msgstr "删除这个标签" +#: journal/templates/user_collection_list.html:14 +#: journal/templates/user_collection_list.html:24 +msgid "Liked Collections" +msgstr "喜欢的收藏单" + +#: journal/templates/user_collection_list.html:14 +#: journal/templates/user_collection_list.html:24 +msgid "Collections" +msgstr "收藏单" + #: journal/templates/user_tag_list.html:12 #: journal/templates/user_tagmember_list.html:4 #: journal/templates/user_tagmember_list.html:14 @@ -2386,7 +2465,7 @@ msgstr "找不到条目,请使用本站条目网址。" msgid "Login required" msgstr "登录后访问" -#: journal/views/common.py:33 journal/views/mark.py:116 +#: journal/views/common.py:33 journal/views/mark.py:117 msgid "Data saved but unable to repost to Fediverse instance." msgstr "数据已保存但未能转发到联邦实例。" @@ -2398,11 +2477,11 @@ msgstr "正在重定向到你的联邦实例以重新认证。" msgid "List not found." msgstr "列表未找到" -#: journal/views/mark.py:107 +#: journal/views/mark.py:108 msgid "Content too long for your Fediverse instance." msgstr "内容过长,超出了你的联邦实例的限制。" -#: journal/views/mark.py:161 journal/views/review.py:30 +#: journal/views/mark.py:162 journal/views/review.py:30 msgid "Content not found" msgstr "内容未找到" diff --git a/pyproject.toml b/pyproject.toml index 3fce726e..e3b6bd9c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,6 +5,11 @@ reportUnusedImport = false reportUnknownVariableType = false reportConstantRedefinition = false reportUnusedCallResult = false +reportUnknownMemberType = false +reportUnknownArgumentType = false +reportAny = false +reportImplicitOverride = false +reportUninitializedInstanceVariable = false [tool.djlint] ignore="T002,T003,H005,H006,H019,H020,H021,H023,H030,H031,D018" diff --git a/takahe/models.py b/takahe/models.py index 9d3fbe8b..518a1131 100644 --- a/takahe/models.py +++ b/takahe/models.py @@ -98,7 +98,7 @@ class Snowflake: if t > cls.EPOCH: now: int = int((t - cls.EPOCH) * 1000) else: - now: int = int(t) if t > 0 else 0 + now = int(t) if t > 0 else 0 # Generate random data rand_seq: int = secrets.randbits(19) # Compose them together diff --git a/users/models/__init__.py b/users/models/__init__.py index deae32bb..07af5d16 100644 --- a/users/models/__init__.py +++ b/users/models/__init__.py @@ -2,3 +2,5 @@ from .apidentity import APIdentity from .preference import Preference from .task import Task from .user import User + +__all__ = ["APIdentity", "Preference", "Task", "User"] diff --git a/users/templates/users/account.html b/users/templates/users/account.html index 541680bd..ac2b968e 100644 --- a/users/templates/users/account.html +++ b/users/templates/users/account.html @@ -177,7 +177,6 @@ {% if request.user.mastodon_last_refresh %} {% trans "Last updated" %} {{ request.user.mastodon_last_refresh }} {% endif %} - 上次更新时间 @@ -185,11 +184,9 @@
{% trans 'Delete Account' %} - 删除数据和账号信息
- 账号数据一旦删除后将无法恢复。确认删除吗? {% csrf_token %}
{% blocktrans %}Enter full username@instance.social or email@domain.com to confirm deletion.{% endblocktrans %}