i18n wip
This commit is contained in:
parent
07e7dd2dd2
commit
4fb4e2834a
17 changed files with 284 additions and 245 deletions
|
@ -1,6 +1,7 @@
|
|||
import os
|
||||
|
||||
import environ
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from boofilsic import __version__
|
||||
|
||||
|
@ -34,7 +35,10 @@ env = environ.FileAwareEnv(
|
|||
NEODB_USER_ICON=(str, "/s/img/avatar.svg"),
|
||||
NEODB_SITE_INTRO=(str, ""),
|
||||
NEODB_SITE_HEAD=(str, ""),
|
||||
NEODB_SITE_DESCRIPTION=(str, "一个自由、开放、互联的书籍、电影、音乐和游戏收藏评论交流社区"),
|
||||
NEODB_SITE_DESCRIPTION=(
|
||||
str,
|
||||
"reviews about book, film, music, podcast and game.",
|
||||
),
|
||||
# Links in site footer
|
||||
NEODB_SITE_LINKS=(dict, {}),
|
||||
# Invite only mode
|
||||
|
@ -384,6 +388,11 @@ MARKDOWNX_MARKDOWNIFY_FUNCTION = "journal.models.render_md"
|
|||
# https://docs.djangoproject.com/en/3.0/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = "zh-hans"
|
||||
LOCALE_PATHS = [os.path.join(BASE_DIR, "locale")]
|
||||
# LANGUAGES = (
|
||||
# ("en", _("English")),
|
||||
# ("zh-hans", _("Simplified Chinese")),
|
||||
# )
|
||||
|
||||
TIME_ZONE = env("NEODB_TIMEZONE", default="Asia/Shanghai") # type: ignore
|
||||
|
||||
|
|
|
@ -61,7 +61,6 @@ class EditionSchema(EditionInSchema, BaseSchema):
|
|||
class Edition(Item):
|
||||
category = ItemCategory.Book
|
||||
url_path = "book"
|
||||
demonstrative = _("这本书")
|
||||
|
||||
isbn = PrimaryLookupIdDescriptor(IdType.ISBN)
|
||||
asin = PrimaryLookupIdDescriptor(IdType.ASIN)
|
||||
|
@ -88,53 +87,53 @@ class Edition(Item):
|
|||
"contents",
|
||||
]
|
||||
subtitle = jsondata.CharField(
|
||||
_("副标题"), null=True, blank=True, default=None, max_length=500
|
||||
_("subtitle"), null=True, blank=True, default=None, max_length=500
|
||||
)
|
||||
orig_title = jsondata.CharField(
|
||||
_("原名"), null=True, blank=True, default=None, max_length=500
|
||||
_("original title"), null=True, blank=True, default=None, max_length=500
|
||||
)
|
||||
author = jsondata.ArrayField(
|
||||
verbose_name=_("作者"),
|
||||
verbose_name=_("author"),
|
||||
base_field=models.CharField(max_length=500),
|
||||
null=False,
|
||||
blank=False,
|
||||
default=list,
|
||||
)
|
||||
translator = jsondata.ArrayField(
|
||||
verbose_name=_("译者"),
|
||||
verbose_name=_("translator"),
|
||||
base_field=models.CharField(max_length=500),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
language = jsondata.CharField(
|
||||
_("语言"), null=True, blank=True, default=None, max_length=500
|
||||
_("language"), null=True, blank=True, default=None, max_length=500
|
||||
)
|
||||
pub_house = jsondata.CharField(
|
||||
_("出版社"), null=True, blank=False, default=None, max_length=500
|
||||
_("publisher"), null=True, blank=False, default=None, max_length=500
|
||||
)
|
||||
pub_year = jsondata.IntegerField(
|
||||
_("出版年份"),
|
||||
_("publication year"),
|
||||
null=True,
|
||||
blank=False,
|
||||
validators=[MinValueValidator(1), MaxValueValidator(2999)],
|
||||
)
|
||||
pub_month = jsondata.IntegerField(
|
||||
_("出版月份"),
|
||||
_("publication month"),
|
||||
null=True,
|
||||
blank=True,
|
||||
validators=[MinValueValidator(1), MaxValueValidator(12)],
|
||||
)
|
||||
binding = jsondata.CharField(
|
||||
_("装订"), null=True, blank=True, default=None, max_length=500
|
||||
_("binding"), null=True, blank=True, default=None, max_length=500
|
||||
)
|
||||
pages = jsondata.IntegerField(_("页数"), blank=True, default=None)
|
||||
pages = jsondata.IntegerField(_("pages"), blank=True, default=None)
|
||||
series = jsondata.CharField(
|
||||
_("丛书"), null=True, blank=True, default=None, max_length=500
|
||||
_("series"), null=True, blank=True, default=None, max_length=500
|
||||
)
|
||||
contents = jsondata.TextField(_("目录"), null=True, blank=True, default=None)
|
||||
price = jsondata.CharField(_("价格"), null=True, blank=True, max_length=500)
|
||||
imprint = jsondata.CharField(_("出品方"), null=True, blank=True, max_length=500)
|
||||
contents = jsondata.TextField(_("contents"), null=True, blank=True, default=None)
|
||||
price = jsondata.CharField(_("price"), null=True, blank=True, max_length=500)
|
||||
imprint = jsondata.CharField(_("imprint"), null=True, blank=True, max_length=500)
|
||||
|
||||
@property
|
||||
def isbn10(self):
|
||||
|
|
|
@ -244,7 +244,7 @@ class URLField(JSONFieldMixin, fields.URLField):
|
|||
|
||||
class ArrayField(JSONFieldMixin, DJANGO_ArrayField):
|
||||
# def __init__(self, *args, **kwargs):
|
||||
# kwargs["help_text"] = _("多项之间以英文逗号分隔")
|
||||
# kwargs["help_text"] = _("comma separated list of values")
|
||||
# super().__init__(*args, **kwargs)
|
||||
|
||||
def from_json(self, value): # backward compatible with dirty legacy data
|
||||
|
|
|
@ -22,19 +22,17 @@ from .mixins import SoftDeleteMixin
|
|||
from .utils import DEFAULT_ITEM_COVER, item_cover_path, resource_cover_path
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from django.utils.functional import _StrOrPromise
|
||||
|
||||
from users.models import User
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SiteName(models.TextChoices):
|
||||
Unknown = "unknown", _("未知站点")
|
||||
Douban = "douban", _("豆瓣")
|
||||
Unknown = "unknown", _("Unknown")
|
||||
Douban = "douban", _("Douban")
|
||||
Goodreads = "goodreads", _("Goodreads")
|
||||
GoogleBooks = "googlebooks", _("谷歌图书")
|
||||
BooksTW = "bookstw", _("博客来")
|
||||
GoogleBooks = "googlebooks", _("Google Books")
|
||||
BooksTW = "bookstw", _("BooksTW")
|
||||
IMDB = "imdb", _("IMDb")
|
||||
TMDB = "tmdb", _("TMDB")
|
||||
Bandcamp = "bandcamp", _("Bandcamp")
|
||||
|
@ -43,57 +41,57 @@ class SiteName(models.TextChoices):
|
|||
Steam = "steam", _("Steam")
|
||||
Bangumi = "bangumi", _("Bangumi")
|
||||
BGG = "bgg", _("BGG")
|
||||
# ApplePodcast = "apple_podcast", _("苹果播客")
|
||||
# ApplePodcast = "apple_podcast", _("Apple Podcast")
|
||||
RSS = "rss", _("RSS")
|
||||
Discogs = "discogs", _("Discogs")
|
||||
AppleMusic = "apple_music", _("苹果音乐")
|
||||
Fediverse = "fedi", _("联邦实例")
|
||||
AppleMusic = "apple_music", _("Apple Music")
|
||||
Fediverse = "fedi", _("Fediverse")
|
||||
|
||||
|
||||
class IdType(models.TextChoices):
|
||||
WikiData = "wikidata", _("维基数据")
|
||||
WikiData = "wikidata", _("WikiData")
|
||||
ISBN10 = "isbn10", _("ISBN10")
|
||||
ISBN = "isbn", _("ISBN") # ISBN 13
|
||||
ASIN = "asin", _("ASIN")
|
||||
ISSN = "issn", _("ISSN")
|
||||
CUBN = "cubn", _("统一书号")
|
||||
CUBN = "cubn", _("CUBN")
|
||||
ISRC = "isrc", _("ISRC") # only for songs
|
||||
GTIN = "gtin", _("GTIN UPC EAN码") # GTIN-13, ISBN is separate
|
||||
GTIN = "gtin", _("GTIN UPC EAN") # GTIN-13, ISBN is separate
|
||||
RSS = "rss", _("RSS Feed URL")
|
||||
IMDB = "imdb", _("IMDb")
|
||||
TMDB_TV = "tmdb_tv", _("TMDB剧集")
|
||||
TMDB_TVSeason = "tmdb_tvseason", _("TMDB剧集")
|
||||
TMDB_TVEpisode = "tmdb_tvepisode", _("TMDB剧集")
|
||||
TMDB_Movie = "tmdb_movie", _("TMDB电影")
|
||||
TMDB_TV = "tmdb_tv", _("TMDB TV Serie")
|
||||
TMDB_TVSeason = "tmdb_tvseason", _("TMDB TV Season")
|
||||
TMDB_TVEpisode = "tmdb_tvepisode", _("TMDB TV Episode")
|
||||
TMDB_Movie = "tmdb_movie", _("TMDB Movie")
|
||||
Goodreads = "goodreads", _("Goodreads")
|
||||
Goodreads_Work = "goodreads_work", _("Goodreads著作")
|
||||
GoogleBooks = "googlebooks", _("谷歌图书")
|
||||
DoubanBook = "doubanbook", _("豆瓣读书")
|
||||
DoubanBook_Work = "doubanbook_work", _("豆瓣读书著作")
|
||||
DoubanMovie = "doubanmovie", _("豆瓣电影")
|
||||
DoubanMusic = "doubanmusic", _("豆瓣音乐")
|
||||
DoubanGame = "doubangame", _("豆瓣游戏")
|
||||
DoubanDrama = "doubandrama", _("豆瓣舞台剧")
|
||||
DoubanDramaVersion = "doubandrama_version", _("豆瓣舞台剧版本")
|
||||
BooksTW = "bookstw", _("博客来图书")
|
||||
Goodreads_Work = "goodreads_work", _("Goodreads Work")
|
||||
GoogleBooks = "googlebooks", _("Google Books")
|
||||
DoubanBook = "doubanbook", _("Douban Book")
|
||||
DoubanBook_Work = "doubanbook_work", _("Douban Book Work")
|
||||
DoubanMovie = "doubanmovie", _("Douban Movie")
|
||||
DoubanMusic = "doubanmusic", _("Douban Music")
|
||||
DoubanGame = "doubangame", _("Douban Game")
|
||||
DoubanDrama = "doubandrama", _("Douban Drama")
|
||||
DoubanDramaVersion = "doubandrama_version", _("Douban Drama Version")
|
||||
BooksTW = "bookstw", _("BooksTW Book")
|
||||
Bandcamp = "bandcamp", _("Bandcamp")
|
||||
Spotify_Album = "spotify_album", _("Spotify专辑")
|
||||
Spotify_Show = "spotify_show", _("Spotify播客")
|
||||
Spotify_Album = "spotify_album", _("Spotify Album")
|
||||
Spotify_Show = "spotify_show", _("Spotify Podcast")
|
||||
Discogs_Release = "discogs_release", ("Discogs Release")
|
||||
Discogs_Master = "discogs_master", ("Discogs Master")
|
||||
MusicBrainz = "musicbrainz", ("MusicBrainz ID")
|
||||
DoubanBook_Author = "doubanbook_author", _("豆瓣读书作者")
|
||||
DoubanCelebrity = "doubanmovie_celebrity", _("豆瓣电影影人")
|
||||
Goodreads_Author = "goodreads_author", _("Goodreads作者")
|
||||
Spotify_Artist = "spotify_artist", _("Spotify艺术家")
|
||||
TMDB_Person = "tmdb_person", _("TMDB影人")
|
||||
IGDB = "igdb", _("IGDB游戏")
|
||||
BGG = "bgg", _("BGG桌游")
|
||||
Steam = "steam", _("Steam游戏")
|
||||
# DoubanBook_Author = "doubanbook_author", _("豆瓣读书作者")
|
||||
# DoubanCelebrity = "doubanmovie_celebrity", _("豆瓣电影影人")
|
||||
# Goodreads_Author = "goodreads_author", _("Goodreads作者")
|
||||
# Spotify_Artist = "spotify_artist", _("Spotify艺术家")
|
||||
# TMDB_Person = "tmdb_person", _("TMDB影人")
|
||||
IGDB = "igdb", _("IGDB Game")
|
||||
BGG = "bgg", _("BGG Boardgame")
|
||||
Steam = "steam", _("Steam Game")
|
||||
Bangumi = "bangumi", _("Bangumi")
|
||||
ApplePodcast = "apple_podcast", _("苹果播客")
|
||||
AppleMusic = "apple_music", _("苹果音乐")
|
||||
Fediverse = "fedi", _("联邦实例")
|
||||
ApplePodcast = "apple_podcast", _("Apple Podcast")
|
||||
AppleMusic = "apple_music", _("Apple Music")
|
||||
Fediverse = "fedi", _("Fediverse")
|
||||
|
||||
|
||||
IdealIdTypes = [
|
||||
|
@ -109,46 +107,43 @@ IdealIdTypes = [
|
|||
|
||||
|
||||
class ItemType(models.TextChoices):
|
||||
Book = "book", _("书")
|
||||
TVShow = "tvshow", _("剧集")
|
||||
TVSeason = "tvseason", _("剧集分季")
|
||||
TVEpisode = "tvepisode", _("剧集分集")
|
||||
Movie = "movie", _("电影")
|
||||
Album = "music", _("音乐专辑")
|
||||
Game = "game", _("游戏")
|
||||
Podcast = "podcast", _("播客")
|
||||
PodcastEpisode = "podcastepisode", _("播客单集")
|
||||
FanFic = "fanfic", _("网文")
|
||||
Performance = "performance", _("剧目")
|
||||
PerformanceProduction = "production", _("上演")
|
||||
Exhibition = "exhibition", _("展览")
|
||||
Collection = "collection", _("收藏单")
|
||||
Book = "book", _("Book")
|
||||
TVShow = "tvshow", _("TV Serie")
|
||||
TVSeason = "tvseason", _("TV Season")
|
||||
TVEpisode = "tvepisode", _("TV Episode")
|
||||
Movie = "movie", _("Movie")
|
||||
Album = "music", _("Album")
|
||||
Game = "game", _("Game")
|
||||
Podcast = "podcast", _("Podcast Program")
|
||||
PodcastEpisode = "podcastepisode", _("Podcast Episode")
|
||||
Performance = "performance", _("Performance")
|
||||
PerformanceProduction = "production", _("Production")
|
||||
FanFic = "fanfic", _("Fanfix")
|
||||
Exhibition = "exhibition", _("Exhibition")
|
||||
Collection = "collection", _("Collection")
|
||||
|
||||
|
||||
class ItemCategory(models.TextChoices):
|
||||
Book = "book", _("书")
|
||||
Movie = "movie", _("电影")
|
||||
TV = "tv", _("剧集")
|
||||
Music = "music", _("音乐")
|
||||
Game = "game", _("游戏")
|
||||
Podcast = "podcast", _("播客")
|
||||
FanFic = "fanfic", _("网文")
|
||||
Performance = "performance", _("演出")
|
||||
Exhibition = "exhibition", _("展览")
|
||||
Collection = "collection", _("收藏单")
|
||||
Book = "book", _("Book")
|
||||
Movie = "movie", _("Movie")
|
||||
TV = "tv", _("TV")
|
||||
Music = "music", _("Music")
|
||||
Game = "game", _("Game")
|
||||
Podcast = "podcast", _("Podcast")
|
||||
Performance = "performance", _("Performance")
|
||||
FanFic = "fanfic", _("FanFic")
|
||||
Exhibition = "exhibition", _("Exhibition")
|
||||
Collection = "collection", _("Collection")
|
||||
|
||||
|
||||
class AvailableItemCategory(models.TextChoices):
|
||||
Book = "book", _("书")
|
||||
Movie = "movie", _("电影")
|
||||
TV = "tv", _("剧集")
|
||||
Music = "music", _("音乐")
|
||||
Game = "game", _("游戏")
|
||||
Podcast = "podcast", _("播客")
|
||||
Performance = "performance", _("演出")
|
||||
# FanFic = "fanfic", _("网文")
|
||||
# Exhibition = "exhibition", _("展览")
|
||||
# Collection = "collection", _("收藏单")
|
||||
Book = "book", _("Book")
|
||||
Movie = "movie", _("Movie")
|
||||
TV = "tv", _("TV")
|
||||
Music = "music", _("Music")
|
||||
Game = "game", _("Game")
|
||||
Podcast = "podcast", _("Podcast")
|
||||
Performance = "performance", _("Performance")
|
||||
|
||||
|
||||
# class SubItemType(models.TextChoices):
|
||||
|
@ -258,19 +253,22 @@ class Item(SoftDeleteMixin, PolymorphicModel):
|
|||
child_class = None # subclass may specify this to allow link to parent item
|
||||
parent_class = None # subclass may specify this to allow create child item
|
||||
category: ItemCategory # subclass must specify this
|
||||
demonstrative: "_StrOrPromise | None" = None # subclass must specify this
|
||||
uid = models.UUIDField(default=uuid.uuid4, editable=False, db_index=True)
|
||||
title = models.CharField(_("标题"), max_length=1000, default="")
|
||||
brief = models.TextField(_("简介"), blank=True, default="")
|
||||
title = models.CharField(_("title"), max_length=1000, default="")
|
||||
brief = models.TextField(_("description"), blank=True, default="")
|
||||
primary_lookup_id_type = models.CharField(
|
||||
_("主要标识类型"), blank=False, null=True, max_length=50
|
||||
_("Primary ID Type"), blank=False, null=True, max_length=50
|
||||
)
|
||||
primary_lookup_id_value = models.CharField(
|
||||
_("主要标识数值"), blank=False, null=True, max_length=1000
|
||||
_("Primary ID Value"),
|
||||
blank=False,
|
||||
null=True,
|
||||
max_length=1000,
|
||||
help_text="automatically detected, usually no change necessary, left empty if unsure",
|
||||
)
|
||||
metadata = models.JSONField(_("其它信息"), blank=True, null=True, default=dict)
|
||||
metadata = models.JSONField(_("metadata"), blank=True, null=True, default=dict)
|
||||
cover = models.ImageField(
|
||||
_("封面"), upload_to=item_cover_path, default=DEFAULT_ITEM_COVER, blank=True
|
||||
_("cover"), upload_to=item_cover_path, default=DEFAULT_ITEM_COVER, blank=True
|
||||
)
|
||||
created_time = models.DateTimeField(auto_now_add=True)
|
||||
edited_time = models.DateTimeField(auto_now=True)
|
||||
|
@ -552,10 +550,12 @@ class ItemLookupId(models.Model):
|
|||
Item, null=True, on_delete=models.SET_NULL, related_name="lookup_ids"
|
||||
)
|
||||
id_type = models.CharField(
|
||||
_("源网站"), blank=True, choices=IdType.choices, max_length=50
|
||||
_("source site"), blank=True, choices=IdType.choices, max_length=50
|
||||
)
|
||||
id_value = models.CharField(_("ID on source site"), blank=True, max_length=1000)
|
||||
raw_url = models.CharField(
|
||||
_("source url"), blank=True, max_length=1000, unique=True
|
||||
)
|
||||
id_value = models.CharField(_("源网站ID"), blank=True, max_length=1000)
|
||||
raw_url = models.CharField(_("源网站ID"), blank=True, max_length=1000, unique=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = [["id_type", "id_value"]]
|
||||
|
|
|
@ -23,10 +23,13 @@ def _EditForm(item_model):
|
|||
primary_lookup_id_type = forms.ChoiceField(
|
||||
required=False,
|
||||
choices=item_model.lookup_id_type_choices(),
|
||||
label=_("主要标识类型"),
|
||||
label=_("Primary ID Type"),
|
||||
help_text="automatically detected, usually no change necessary",
|
||||
)
|
||||
primary_lookup_id_value = forms.CharField(
|
||||
required=False, label=_("主要标识数据通常由系统自动检测,请勿随意更改现有值,新增条目不确定留空即可")
|
||||
required=False,
|
||||
label=_("Primary ID Value"),
|
||||
help_text="automatically detected, usually no change necessary, left empty if unsure",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -34,7 +34,6 @@ class Game(Item):
|
|||
type = ItemType.Game
|
||||
category = ItemCategory.Game
|
||||
url_path = "game"
|
||||
demonstrative = _("这个游戏")
|
||||
igdb = PrimaryLookupIdDescriptor(IdType.IGDB)
|
||||
steam = PrimaryLookupIdDescriptor(IdType.Steam)
|
||||
douban_game = PrimaryLookupIdDescriptor(IdType.DoubanGame)
|
||||
|
@ -56,7 +55,7 @@ class Game(Item):
|
|||
|
||||
other_title = jsondata.ArrayField(
|
||||
base_field=models.CharField(blank=True, default="", max_length=500),
|
||||
verbose_name=_("其它标题"),
|
||||
verbose_name=_("other title"),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
|
@ -64,7 +63,7 @@ class Game(Item):
|
|||
|
||||
designer = jsondata.ArrayField(
|
||||
base_field=models.CharField(blank=True, default="", max_length=500),
|
||||
verbose_name=_("设计者"),
|
||||
verbose_name=_("designer"),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
|
@ -72,7 +71,7 @@ class Game(Item):
|
|||
|
||||
artist = jsondata.ArrayField(
|
||||
base_field=models.CharField(blank=True, default="", max_length=500),
|
||||
verbose_name=_("艺术家"),
|
||||
verbose_name=_("artist"),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
|
@ -80,7 +79,7 @@ class Game(Item):
|
|||
|
||||
developer = jsondata.ArrayField(
|
||||
base_field=models.CharField(blank=True, default="", max_length=500),
|
||||
verbose_name=_("开发商"),
|
||||
verbose_name=_("developer"),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
|
@ -88,16 +87,18 @@ class Game(Item):
|
|||
|
||||
publisher = jsondata.ArrayField(
|
||||
base_field=models.CharField(blank=True, default="", max_length=500),
|
||||
verbose_name=_("发行商"),
|
||||
verbose_name=_("publisher"),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
|
||||
release_year = jsondata.IntegerField(verbose_name=_("发布年份"), null=True, blank=True)
|
||||
release_year = jsondata.IntegerField(
|
||||
verbose_name=_("year of publication"), null=True, blank=True
|
||||
)
|
||||
|
||||
release_date = jsondata.DateField(
|
||||
verbose_name=_("发布日期"),
|
||||
verbose_name=_("date of publication"),
|
||||
auto_now=False,
|
||||
auto_now_add=False,
|
||||
null=True,
|
||||
|
@ -106,7 +107,7 @@ class Game(Item):
|
|||
)
|
||||
|
||||
genre = jsondata.ArrayField(
|
||||
verbose_name=_("类型"),
|
||||
verbose_name=_("genre"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
null=True,
|
||||
blank=True,
|
||||
|
@ -114,13 +115,13 @@ class Game(Item):
|
|||
)
|
||||
|
||||
platform = jsondata.ArrayField(
|
||||
verbose_name=_("平台"),
|
||||
verbose_name=_("platform"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
default=list,
|
||||
)
|
||||
|
||||
official_site = jsondata.CharField(
|
||||
verbose_name=_("官方网站"), max_length=1000, null=True, blank=True
|
||||
verbose_name=_("website"), max_length=1000, null=True, blank=True
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -3,6 +3,7 @@ from datetime import timedelta
|
|||
from django.core.cache import cache
|
||||
from django.db.models import Count, F
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from loguru import logger
|
||||
|
||||
from catalog.models import *
|
||||
|
@ -87,7 +88,7 @@ class DiscoverGenerator(BaseJob):
|
|||
{
|
||||
"name": "popular_" + category.value,
|
||||
"title": ""
|
||||
+ (category.label if category != ItemCategory.Book else "图书"),
|
||||
+ (category.label if category != ItemCategory.Book else _("Book")),
|
||||
"items": items,
|
||||
}
|
||||
)
|
||||
|
|
|
@ -41,7 +41,6 @@ class Movie(Item):
|
|||
imdb = PrimaryLookupIdDescriptor(IdType.IMDB)
|
||||
tmdb_movie = PrimaryLookupIdDescriptor(IdType.TMDB_Movie)
|
||||
douban_movie = PrimaryLookupIdDescriptor(IdType.DoubanMovie)
|
||||
demonstrative = _("这部电影")
|
||||
|
||||
METADATA_COPY_LIST = [
|
||||
"title",
|
||||
|
@ -63,45 +62,45 @@ class Movie(Item):
|
|||
"brief",
|
||||
]
|
||||
orig_title = jsondata.CharField(
|
||||
verbose_name=_("原始标题"), blank=True, default="", max_length=500
|
||||
verbose_name=_("original title"), blank=True, default="", max_length=500
|
||||
)
|
||||
other_title = jsondata.ArrayField(
|
||||
verbose_name=_("其它标题"),
|
||||
verbose_name=_("other title"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
director = jsondata.ArrayField(
|
||||
verbose_name=_("导演"),
|
||||
verbose_name=_("director"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
playwright = jsondata.ArrayField(
|
||||
verbose_name=_("编剧"),
|
||||
verbose_name=_("playwright"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
actor = jsondata.ArrayField(
|
||||
verbose_name=_("演员"),
|
||||
verbose_name=_("actor"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
genre = jsondata.ArrayField(
|
||||
verbose_name=_("类型"),
|
||||
verbose_name=_("genre"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=50),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
) # , choices=MovieGenreEnum.choices
|
||||
showtime = jsondata.JSONField(
|
||||
_("上映日期"),
|
||||
_("release date"),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
|
@ -113,13 +112,15 @@ class Movie(Item):
|
|||
"keys": {
|
||||
"time": {
|
||||
"type": "string",
|
||||
"title": _("日期"),
|
||||
"placeholder": _("必填"),
|
||||
"title": _("date"),
|
||||
"placeholder": _("required"),
|
||||
},
|
||||
"region": {
|
||||
"type": "string",
|
||||
"title": _("区域或类型"),
|
||||
"placeholder": _("如中国大陆或柏林电影节"),
|
||||
"title": _("region or event"),
|
||||
"placeholder": _(
|
||||
"Germany or Toronto International Film Festival"
|
||||
),
|
||||
},
|
||||
},
|
||||
"required": ["time"],
|
||||
|
@ -127,10 +128,10 @@ class Movie(Item):
|
|||
},
|
||||
)
|
||||
site = jsondata.URLField(
|
||||
verbose_name=_("官方网站"), blank=True, default="", max_length=200
|
||||
verbose_name=_("website"), blank=True, default="", max_length=200
|
||||
)
|
||||
area = jsondata.ArrayField(
|
||||
verbose_name=_("国家地区"),
|
||||
verbose_name=_("region"),
|
||||
base_field=models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
|
@ -141,7 +142,7 @@ class Movie(Item):
|
|||
default=list,
|
||||
)
|
||||
language = jsondata.ArrayField(
|
||||
verbose_name=_("语言"),
|
||||
verbose_name=_("language"),
|
||||
base_field=models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
|
@ -151,9 +152,9 @@ class Movie(Item):
|
|||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
year = jsondata.IntegerField(verbose_name=_("年份"), null=True, blank=True)
|
||||
year = jsondata.IntegerField(verbose_name=_("year"), null=True, blank=True)
|
||||
duration = jsondata.CharField(
|
||||
verbose_name=_("片长"), blank=True, default="", max_length=200
|
||||
verbose_name=_("length"), blank=True, default="", max_length=200
|
||||
)
|
||||
season_number = jsondata.IntegerField(
|
||||
null=True, blank=True
|
||||
|
|
|
@ -36,7 +36,6 @@ class Album(Item):
|
|||
type = ItemType.Album
|
||||
url_path = "album"
|
||||
category = ItemCategory.Music
|
||||
demonstrative = _("这张专辑")
|
||||
barcode = PrimaryLookupIdDescriptor(IdType.GTIN)
|
||||
douban_music = PrimaryLookupIdDescriptor(IdType.DoubanMusic)
|
||||
spotify_album = PrimaryLookupIdDescriptor(IdType.Spotify_Album)
|
||||
|
@ -56,16 +55,18 @@ class Album(Item):
|
|||
"bandcamp_album_id",
|
||||
]
|
||||
release_date = jsondata.DateField(
|
||||
_("发行日期"), null=True, blank=True, help_text=_("YYYY-MM-DD")
|
||||
_("release date"), null=True, blank=True, help_text=_("YYYY-MM-DD")
|
||||
)
|
||||
duration = jsondata.IntegerField(
|
||||
_("length"), null=True, blank=True, help_text=_("milliseconds")
|
||||
)
|
||||
duration = jsondata.IntegerField(_("时长"), null=True, blank=True, help_text=_("毫秒数"))
|
||||
artist = jsondata.ArrayField(
|
||||
models.CharField(blank=True, default="", max_length=200),
|
||||
verbose_name=_("艺术家"),
|
||||
verbose_name=_("artist"),
|
||||
default=list,
|
||||
)
|
||||
genre = jsondata.ArrayField(
|
||||
verbose_name=_("流派"),
|
||||
verbose_name=_("genre"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=50),
|
||||
null=True,
|
||||
blank=True,
|
||||
|
@ -73,23 +74,27 @@ class Album(Item):
|
|||
)
|
||||
company = jsondata.ArrayField(
|
||||
models.CharField(blank=True, default="", max_length=500),
|
||||
verbose_name=_("发行方"),
|
||||
verbose_name=_("publisher"),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
track_list = jsondata.TextField(_("曲目"), blank=True, default="")
|
||||
track_list = jsondata.TextField(_("tracks"), blank=True, default="")
|
||||
other_title = jsondata.ArrayField(
|
||||
verbose_name=_("其它标题"),
|
||||
verbose_name=_("other title"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
album_type = jsondata.CharField(_("专辑类型"), blank=True, default="", max_length=500)
|
||||
media = jsondata.CharField(_("介质"), blank=True, default="", max_length=500)
|
||||
album_type = jsondata.CharField(
|
||||
_("album type"), blank=True, default="", max_length=500
|
||||
)
|
||||
media = jsondata.CharField(_("media type"), blank=True, default="", max_length=500)
|
||||
bandcamp_album_id = jsondata.CharField(blank=True, default="", max_length=500)
|
||||
disc_count = jsondata.IntegerField(_("碟片数"), blank=True, default="", max_length=500)
|
||||
disc_count = jsondata.IntegerField(
|
||||
_("number of disc"), blank=True, default="", max_length=500
|
||||
)
|
||||
|
||||
def get_embed_link(self):
|
||||
for res in self.external_resources.all():
|
||||
|
|
|
@ -4,8 +4,15 @@ from django.db import models
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from ninja import Schema
|
||||
|
||||
from catalog.common import *
|
||||
from catalog.common.models import ItemSchema
|
||||
from catalog.common import (
|
||||
ExternalResource,
|
||||
IdType,
|
||||
Item,
|
||||
ItemCategory,
|
||||
ItemSchema,
|
||||
ItemType,
|
||||
jsondata,
|
||||
)
|
||||
from catalog.common.utils import DEFAULT_ITEM_COVER
|
||||
|
||||
|
||||
|
@ -54,8 +61,8 @@ _CREW_SCHEMA = {
|
|||
"items": {
|
||||
"type": "dict",
|
||||
"keys": {
|
||||
"name": {"type": "string", "title": _("名字")},
|
||||
"role": {"type": "string", "title": _("职能")},
|
||||
"name": {"type": "string", "title": _("name")},
|
||||
"role": {"type": "string", "title": _("role")},
|
||||
},
|
||||
"required": ["role", "name"],
|
||||
},
|
||||
|
@ -67,8 +74,16 @@ _ACTOR_SCHEMA = {
|
|||
"items": {
|
||||
"type": "dict",
|
||||
"keys": {
|
||||
"name": {"type": "string", "title": _("名字"), "placeholder": _("演员名字,必填")},
|
||||
"role": {"type": "string", "title": _("角色"), "placeholder": _("也可不填写")},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": _("name"),
|
||||
"placeholder": _("required"),
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"title": _("role"),
|
||||
"placeholder": _("optional"),
|
||||
},
|
||||
},
|
||||
"required": ["name"],
|
||||
},
|
||||
|
@ -89,109 +104,108 @@ class Performance(Item):
|
|||
child_class = "PerformanceProduction"
|
||||
category = ItemCategory.Performance
|
||||
url_path = "performance"
|
||||
demonstrative = _("这部剧作")
|
||||
orig_title = jsondata.CharField(
|
||||
verbose_name=_("原名"), blank=True, default="", max_length=500
|
||||
verbose_name=_("original name"), blank=True, default="", max_length=500
|
||||
)
|
||||
other_title = jsondata.ArrayField(
|
||||
verbose_name=_("其它标题"),
|
||||
verbose_name=_("other title"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=200),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
genre = jsondata.ArrayField(
|
||||
verbose_name=_("类型"),
|
||||
verbose_name=_("genre"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=200),
|
||||
null=False,
|
||||
blank=False,
|
||||
default=list,
|
||||
)
|
||||
language = jsondata.ArrayField(
|
||||
verbose_name=_("语言"),
|
||||
verbose_name=_("language"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=200),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
director = jsondata.ArrayField(
|
||||
verbose_name=_("导演"),
|
||||
verbose_name=_("director"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
playwright = jsondata.ArrayField(
|
||||
verbose_name=_("编剧"),
|
||||
verbose_name=_("playwright"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
orig_creator = jsondata.ArrayField(
|
||||
verbose_name=_("原作者"),
|
||||
verbose_name=_("original creator"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
composer = jsondata.ArrayField(
|
||||
verbose_name=_("作曲"),
|
||||
verbose_name=_("composer"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
choreographer = jsondata.ArrayField(
|
||||
verbose_name=_("编舞"),
|
||||
verbose_name=_("choreographer"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
actor = jsondata.JSONField(
|
||||
verbose_name=_("演员"),
|
||||
verbose_name=_("actor"),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
schema=_ACTOR_SCHEMA,
|
||||
)
|
||||
performer = jsondata.ArrayField(
|
||||
verbose_name=_("表演者"),
|
||||
verbose_name=_("performer"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
troupe = jsondata.ArrayField(
|
||||
verbose_name=_("剧团"),
|
||||
verbose_name=_("troupe"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
crew = jsondata.JSONField(
|
||||
verbose_name=_("其他演职人员和团体"),
|
||||
verbose_name=_("crew"),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
schema=_CREW_SCHEMA,
|
||||
)
|
||||
location = jsondata.ArrayField(
|
||||
verbose_name=_("剧场空间"),
|
||||
verbose_name=_("theater"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
opening_date = jsondata.CharField(
|
||||
verbose_name=_("首演日期"), max_length=100, null=True, blank=True
|
||||
verbose_name=_("opening date"), max_length=100, null=True, blank=True
|
||||
)
|
||||
closing_date = jsondata.CharField(
|
||||
verbose_name=_("结束日期"), max_length=100, null=True, blank=True
|
||||
verbose_name=_("closing date"), max_length=100, null=True, blank=True
|
||||
)
|
||||
official_site = jsondata.CharField(
|
||||
verbose_name=_("官方网站"), max_length=1000, null=True, blank=True
|
||||
verbose_name=_("website"), max_length=1000, null=True, blank=True
|
||||
)
|
||||
METADATA_COPY_LIST = [
|
||||
"title",
|
||||
|
@ -236,105 +250,104 @@ class PerformanceProduction(Item):
|
|||
type = ItemType.PerformanceProduction
|
||||
category = ItemCategory.Performance
|
||||
url_path = "performance/production"
|
||||
demonstrative = _("这次上演")
|
||||
show = models.ForeignKey(
|
||||
Performance, null=True, on_delete=models.SET_NULL, related_name="productions"
|
||||
)
|
||||
orig_title = jsondata.CharField(
|
||||
verbose_name=_("原名"), blank=True, default="", max_length=500
|
||||
verbose_name=_("original title"), blank=True, default="", max_length=500
|
||||
)
|
||||
other_title = jsondata.ArrayField(
|
||||
verbose_name=_("其它标题"),
|
||||
verbose_name=_("other title"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=200),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
language = jsondata.ArrayField(
|
||||
verbose_name=_("语言"),
|
||||
verbose_name=_("language"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=200),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
director = jsondata.ArrayField(
|
||||
verbose_name=_("导演"),
|
||||
verbose_name=_("director"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
playwright = jsondata.ArrayField(
|
||||
verbose_name=_("编剧"),
|
||||
verbose_name=_("playwright"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
orig_creator = jsondata.ArrayField(
|
||||
verbose_name=_("原作者"),
|
||||
verbose_name=_("original creator"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
composer = jsondata.ArrayField(
|
||||
verbose_name=_("作曲"),
|
||||
verbose_name=_("composer"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
choreographer = jsondata.ArrayField(
|
||||
verbose_name=_("编舞"),
|
||||
verbose_name=_("choreographer"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
actor = jsondata.JSONField(
|
||||
verbose_name=_("演员"),
|
||||
verbose_name=_("actor"),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
schema=_ACTOR_SCHEMA,
|
||||
)
|
||||
performer = jsondata.ArrayField(
|
||||
verbose_name=_("表演者"),
|
||||
verbose_name=_("performer"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
troupe = jsondata.ArrayField(
|
||||
verbose_name=_("剧团"),
|
||||
verbose_name=_("troupe"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
crew = jsondata.JSONField(
|
||||
verbose_name=_("其他演职人员和团体"),
|
||||
verbose_name=_("crew"),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
schema=_CREW_SCHEMA,
|
||||
)
|
||||
location = jsondata.ArrayField(
|
||||
verbose_name=_("剧场空间"),
|
||||
verbose_name=_("theater"),
|
||||
base_field=models.CharField(blank=False, default="", max_length=500),
|
||||
null=False,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
opening_date = jsondata.CharField(
|
||||
verbose_name=_("首演日期"), max_length=100, null=True, blank=False
|
||||
verbose_name=_("opening date"), max_length=100, null=True, blank=False
|
||||
)
|
||||
closing_date = jsondata.CharField(
|
||||
verbose_name=_("结束日期"), max_length=100, null=True, blank=True
|
||||
verbose_name=_("closing date"), max_length=100, null=True, blank=True
|
||||
)
|
||||
official_site = jsondata.CharField(
|
||||
verbose_name=_("官方网站"), max_length=1000, null=True, blank=True
|
||||
verbose_name=_("website"), max_length=1000, null=True, blank=True
|
||||
)
|
||||
METADATA_COPY_LIST = [
|
||||
"title",
|
||||
|
|
|
@ -29,12 +29,11 @@ class Podcast(Item):
|
|||
category = ItemCategory.Podcast
|
||||
child_class = "PodcastEpisode"
|
||||
url_path = "podcast"
|
||||
demonstrative = _("这档播客")
|
||||
# apple_podcast = PrimaryLookupIdDescriptor(IdType.ApplePodcast)
|
||||
# ximalaya = LookupIdDescriptor(IdType.Ximalaya)
|
||||
# xiaoyuzhou = LookupIdDescriptor(IdType.Xiaoyuzhou)
|
||||
genre = jsondata.ArrayField(
|
||||
verbose_name=_("类型"),
|
||||
verbose_name=_("genre"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
null=True,
|
||||
blank=True,
|
||||
|
@ -42,13 +41,13 @@ class Podcast(Item):
|
|||
)
|
||||
|
||||
hosts = jsondata.ArrayField(
|
||||
verbose_name=_("主播"),
|
||||
verbose_name=_("host"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
default=list,
|
||||
)
|
||||
|
||||
official_site = jsondata.CharField(
|
||||
verbose_name=_("官方网站"), max_length=1000, null=True, blank=True
|
||||
verbose_name=_("website"), max_length=1000, null=True, blank=True
|
||||
)
|
||||
|
||||
METADATA_COPY_LIST = [
|
||||
|
@ -87,12 +86,11 @@ class Podcast(Item):
|
|||
class PodcastEpisode(Item):
|
||||
category = ItemCategory.Podcast
|
||||
url_path = "podcast/episode"
|
||||
demonstrative = _("这集节目")
|
||||
# uid = models.UUIDField(default=uuid.uuid4, editable=False, db_index=True)
|
||||
program = models.ForeignKey(Podcast, models.CASCADE, related_name="episodes")
|
||||
guid = models.CharField(null=True, max_length=1000)
|
||||
pub_date = models.DateTimeField(
|
||||
verbose_name=_("发布时间"), help_text="yyyy/mm/dd hh:mm"
|
||||
verbose_name=_("date of publication"), help_text="yyyy/mm/dd hh:mm"
|
||||
)
|
||||
media_url = models.CharField(null=True, max_length=1000)
|
||||
# title = models.CharField(default="", max_length=1000)
|
||||
|
|
|
@ -141,7 +141,7 @@
|
|||
<div class="item-edit">
|
||||
<span class="action inline">
|
||||
<a href="{% url 'catalog:edit' item.url_path item.uuid %}"
|
||||
title="{% trans '编辑' %}{{ item.demonstrative }}"><i class="fa-solid fa-pen-to-square"></i></a>
|
||||
title="{% trans '编辑这个条目' %}"><i class="fa-solid fa-pen-to-square"></i></a>
|
||||
</span>
|
||||
{% if item.last_editor and item.last_editor.preference.show_last_edit %}
|
||||
<span>
|
||||
|
|
|
@ -94,13 +94,14 @@ class TVShow(Item):
|
|||
child_class = "TVSeason"
|
||||
category = ItemCategory.TV
|
||||
url_path = "tv"
|
||||
demonstrative = _("这部剧集")
|
||||
imdb = PrimaryLookupIdDescriptor(IdType.IMDB)
|
||||
tmdb_tv = PrimaryLookupIdDescriptor(IdType.TMDB_TV)
|
||||
imdb = PrimaryLookupIdDescriptor(IdType.IMDB)
|
||||
season_count = models.IntegerField(verbose_name=_("总季数"), null=True, blank=True)
|
||||
season_count = models.IntegerField(
|
||||
verbose_name=_("number of seasons"), null=True, blank=True
|
||||
)
|
||||
episode_count = models.PositiveIntegerField(
|
||||
verbose_name=_("总集数"), null=True, blank=True
|
||||
verbose_name=_("number of episodes"), null=True, blank=True
|
||||
)
|
||||
|
||||
METADATA_COPY_LIST = [
|
||||
|
@ -123,45 +124,45 @@ class TVShow(Item):
|
|||
"single_episode_length",
|
||||
]
|
||||
orig_title = jsondata.CharField(
|
||||
verbose_name=_("原始标题"), blank=True, default="", max_length=500
|
||||
verbose_name=_("original title"), blank=True, default="", max_length=500
|
||||
)
|
||||
other_title = jsondata.ArrayField(
|
||||
base_field=models.CharField(blank=True, default="", max_length=500),
|
||||
verbose_name=_("其它标题"),
|
||||
verbose_name=_("other title"),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
director = jsondata.ArrayField(
|
||||
verbose_name=_("导演"),
|
||||
verbose_name=_("director"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
playwright = jsondata.ArrayField(
|
||||
verbose_name=_("编剧"),
|
||||
verbose_name=_("playwright"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
actor = jsondata.ArrayField(
|
||||
verbose_name=_("演员"),
|
||||
verbose_name=_("actor"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
genre = jsondata.ArrayField(
|
||||
verbose_name=_("类型"),
|
||||
verbose_name=_("genre"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=50),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
) # , choices=MovieGenreEnum.choices
|
||||
showtime = jsondata.JSONField(
|
||||
_("播出日期"),
|
||||
_("show time"),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
|
@ -173,13 +174,15 @@ class TVShow(Item):
|
|||
"keys": {
|
||||
"time": {
|
||||
"type": "string",
|
||||
"title": _("日期"),
|
||||
"placeholder": _("必填"),
|
||||
"title": _("Date"),
|
||||
"placeholder": _("YYYY-MM-DD"),
|
||||
},
|
||||
"region": {
|
||||
"type": "string",
|
||||
"title": _("区域或类型"),
|
||||
"placeholder": _("如中国大陆或柏林电影节"),
|
||||
"title": _("Region or Event"),
|
||||
"placeholder": _(
|
||||
"Germany or Toronto International Film Festival"
|
||||
),
|
||||
},
|
||||
},
|
||||
"required": ["time"],
|
||||
|
@ -187,10 +190,10 @@ class TVShow(Item):
|
|||
},
|
||||
)
|
||||
site = jsondata.URLField(
|
||||
verbose_name=_("官方网站"), blank=True, default="", max_length=200
|
||||
verbose_name=_("website"), blank=True, default="", max_length=200
|
||||
)
|
||||
area = jsondata.ArrayField(
|
||||
verbose_name=_("国家地区"),
|
||||
verbose_name=_("region"),
|
||||
base_field=models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
|
@ -201,7 +204,7 @@ class TVShow(Item):
|
|||
default=list,
|
||||
)
|
||||
language = jsondata.ArrayField(
|
||||
verbose_name=_("语言"),
|
||||
verbose_name=_("language"),
|
||||
base_field=models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
|
@ -211,9 +214,9 @@ class TVShow(Item):
|
|||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
year = jsondata.IntegerField(verbose_name=_("年份"), null=True, blank=True)
|
||||
year = jsondata.IntegerField(verbose_name=_("year"), null=True, blank=True)
|
||||
single_episode_length = jsondata.IntegerField(
|
||||
verbose_name=_("单集长度"), null=True, blank=True
|
||||
verbose_name=_("episode length"), null=True, blank=True
|
||||
)
|
||||
season_number = jsondata.IntegerField(
|
||||
null=True, blank=True
|
||||
|
@ -249,7 +252,6 @@ class TVSeason(Item):
|
|||
type = ItemType.TVSeason
|
||||
category = ItemCategory.TV
|
||||
url_path = "tv/season"
|
||||
demonstrative = _("这季剧集")
|
||||
child_class = "TVEpisode"
|
||||
douban_movie = PrimaryLookupIdDescriptor(IdType.DoubanMovie)
|
||||
imdb = PrimaryLookupIdDescriptor(IdType.IMDB)
|
||||
|
@ -257,8 +259,12 @@ class TVSeason(Item):
|
|||
show = models.ForeignKey(
|
||||
TVShow, null=True, on_delete=models.SET_NULL, related_name="seasons"
|
||||
)
|
||||
season_number = models.PositiveIntegerField(verbose_name=_("本季序号"), null=True)
|
||||
episode_count = models.PositiveIntegerField(verbose_name=_("本季集数"), null=True)
|
||||
season_number = models.PositiveIntegerField(
|
||||
verbose_name=_("season number"), null=True
|
||||
)
|
||||
episode_count = models.PositiveIntegerField(
|
||||
verbose_name=_("number of episodes"), null=True
|
||||
)
|
||||
|
||||
METADATA_COPY_LIST = [
|
||||
"title",
|
||||
|
@ -280,45 +286,45 @@ class TVSeason(Item):
|
|||
"brief",
|
||||
]
|
||||
orig_title = jsondata.CharField(
|
||||
verbose_name=_("原始标题"), blank=True, default="", max_length=500
|
||||
verbose_name=_("original title"), blank=True, default="", max_length=500
|
||||
)
|
||||
other_title = jsondata.ArrayField(
|
||||
verbose_name=_("其它标题"),
|
||||
verbose_name=_("other title"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=500),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
director = jsondata.ArrayField(
|
||||
verbose_name=_("导演"),
|
||||
verbose_name=_("director"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
playwright = jsondata.ArrayField(
|
||||
verbose_name=_("编剧"),
|
||||
verbose_name=_("playwright"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
actor = jsondata.ArrayField(
|
||||
verbose_name=_("演员"),
|
||||
verbose_name=_("actor"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=200),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
genre = jsondata.ArrayField(
|
||||
verbose_name=_("类型"),
|
||||
verbose_name=_("genre"),
|
||||
base_field=models.CharField(blank=True, default="", max_length=50),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
) # , choices=MovieGenreEnum.choices
|
||||
showtime = jsondata.JSONField(
|
||||
_("播出日期"),
|
||||
_("show time"),
|
||||
null=True,
|
||||
blank=True,
|
||||
default=list,
|
||||
|
@ -330,13 +336,15 @@ class TVSeason(Item):
|
|||
"keys": {
|
||||
"time": {
|
||||
"type": "string",
|
||||
"title": _("日期"),
|
||||
"placeholder": _("必填"),
|
||||
"title": _("date"),
|
||||
"placeholder": _("required"),
|
||||
},
|
||||
"region": {
|
||||
"type": "string",
|
||||
"title": _("区域或类型"),
|
||||
"placeholder": _("如中国大陆或柏林电影节"),
|
||||
"title": _("region or event"),
|
||||
"placeholder": _(
|
||||
"Germany or Toronto International Film Festival"
|
||||
),
|
||||
},
|
||||
},
|
||||
"required": ["time"],
|
||||
|
@ -344,10 +352,10 @@ class TVSeason(Item):
|
|||
},
|
||||
)
|
||||
site = jsondata.URLField(
|
||||
verbose_name=_("官方网站"), blank=True, default="", max_length=200
|
||||
verbose_name=_("website"), blank=True, default="", max_length=200
|
||||
)
|
||||
area = jsondata.ArrayField(
|
||||
verbose_name=_("国家地区"),
|
||||
verbose_name=_("region"),
|
||||
base_field=models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
|
@ -358,7 +366,7 @@ class TVSeason(Item):
|
|||
default=list,
|
||||
)
|
||||
language = jsondata.ArrayField(
|
||||
verbose_name=_("语言"),
|
||||
verbose_name=_("language"),
|
||||
base_field=models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
|
@ -368,9 +376,9 @@ class TVSeason(Item):
|
|||
blank=True,
|
||||
default=list,
|
||||
)
|
||||
year = jsondata.IntegerField(verbose_name=_("年份"), null=True, blank=True)
|
||||
year = jsondata.IntegerField(verbose_name=_("year"), null=True, blank=True)
|
||||
single_episode_length = jsondata.IntegerField(
|
||||
verbose_name=_("单集长度"), null=True, blank=True
|
||||
verbose_name=_("episode length"), null=True, blank=True
|
||||
)
|
||||
duration = jsondata.CharField(
|
||||
blank=True, default="", max_length=200
|
||||
|
|
|
@ -234,7 +234,7 @@ def fetch_tvepisodes(request, item_path, item_uuid):
|
|||
django_rq.get_queue("crawl").enqueue(
|
||||
fetch_episodes_for_season_task, item.uuid, request.user
|
||||
)
|
||||
messages.add_message(request, messages.INFO, _("已开始更新单集信息"))
|
||||
messages.add_message(request, messages.INFO, _("Updating episodes"))
|
||||
return redirect(item.url)
|
||||
|
||||
|
||||
|
@ -257,10 +257,11 @@ def merge(request, item_path, item_uuid):
|
|||
if request.POST.get("new_item_url"):
|
||||
new_item = Item.get_by_url(request.POST.get("new_item_url"))
|
||||
if not new_item or new_item.is_deleted or new_item.merged_to_item_id:
|
||||
raise BadRequest(_("不能合并到一个被删除或合并过的条目。"))
|
||||
raise BadRequest(_("Cannot be merged to an item already deleted or merged"))
|
||||
if new_item.class_name != item.class_name:
|
||||
raise BadRequest(
|
||||
_("不能合并不同类的条目") + f" ({item.class_name} to {new_item.class_name})"
|
||||
_("Cannot merge items in different categories")
|
||||
+ f" ({item.class_name} to {new_item.class_name})"
|
||||
)
|
||||
_logger.warn(f"{request.user} merges {item} to {new_item}")
|
||||
item.merge_to(new_item)
|
||||
|
|
|
@ -28,7 +28,7 @@ def duration_format(value, unit):
|
|||
s = duration % 60
|
||||
return f"{h}:{m:02}:{s:02}" if h else f"{m:02}:{s:02}"
|
||||
# return (f"{h}小时 " if h else "") + (f"{m}分钟" if m else "")
|
||||
except:
|
||||
except Exception:
|
||||
return f"{value} (format error)"
|
||||
|
||||
|
||||
|
|
|
@ -39,10 +39,10 @@ def current_user_relationship(context, target_identity: "APIdentity"):
|
|||
r["following"] = current_identity.is_following(target_identity)
|
||||
if r["following"]:
|
||||
if current_identity.is_followed_by(target_identity):
|
||||
r["status"] = _("互相关注")
|
||||
r["status"] = _("mutual followed")
|
||||
else:
|
||||
r["status"] = _("已关注")
|
||||
r["status"] = _("followed")
|
||||
else:
|
||||
if current_identity.is_followed_by(target_identity):
|
||||
r["status"] = _("被ta关注")
|
||||
r["status"] = _("following you")
|
||||
return r
|
||||
|
|
|
@ -15,14 +15,14 @@ class ReviewForm(forms.ModelForm):
|
|||
"item": forms.TextInput(attrs={"hidden": ""}),
|
||||
}
|
||||
|
||||
title = forms.CharField(label=_("评论标题"))
|
||||
body = MarkdownxFormField(label=_("评论正文 (Markdown格式可参考下方语法范例)"), strip=False)
|
||||
title = forms.CharField(label=_("Title"))
|
||||
body = MarkdownxFormField(label=_("Content (Markdown)"), strip=False)
|
||||
share_to_mastodon = forms.BooleanField(
|
||||
label=_("分享到联邦宇宙"), initial=False, required=False
|
||||
label=_("Post to Fediverse"), initial=False, required=False
|
||||
)
|
||||
id = forms.IntegerField(required=False, widget=forms.HiddenInput())
|
||||
visibility = forms.TypedChoiceField(
|
||||
label=_("可见性"),
|
||||
label=_("Visibility"),
|
||||
initial=0,
|
||||
coerce=int,
|
||||
choices=VisibilityType.choices,
|
||||
|
@ -31,25 +31,25 @@ class ReviewForm(forms.ModelForm):
|
|||
|
||||
|
||||
COLLABORATIVE_CHOICES = [
|
||||
(0, _("仅限创建者")),
|
||||
(1, _("创建者及其互关用户")),
|
||||
(0, _("creator only")),
|
||||
(1, _("creator and their mutuals")),
|
||||
]
|
||||
|
||||
|
||||
class CollectionForm(forms.ModelForm):
|
||||
# id = forms.IntegerField(required=False, widget=forms.HiddenInput())
|
||||
title = forms.CharField(label=_("标题"))
|
||||
brief = MarkdownxFormField(label=_("介绍 (Markdown)"), strip=False)
|
||||
title = forms.CharField(label=_("Title"))
|
||||
brief = MarkdownxFormField(label=_("Content (Markdown)"), strip=False)
|
||||
# share_to_mastodon = forms.BooleanField(label=_("分享到联邦宇宙"), initial=True, required=False)
|
||||
visibility = forms.TypedChoiceField(
|
||||
label=_("可见性"),
|
||||
label=_("Visibility"),
|
||||
initial=0,
|
||||
coerce=int,
|
||||
choices=VisibilityType.choices,
|
||||
widget=forms.RadioSelect,
|
||||
)
|
||||
collaborative = forms.TypedChoiceField(
|
||||
label=_("协作整理权限"),
|
||||
label=_("Collaborative editing"),
|
||||
initial=0,
|
||||
coerce=int,
|
||||
choices=COLLABORATIVE_CHOICES,
|
||||
|
|
Loading…
Add table
Reference in a new issue