You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

371 lines
10 KiB

1 year ago
'''
persist data to db
'''
from datetime import date
import datetime
import operator
from functools import reduce
import json
from peewee import *
from enum import IntEnum
from collections import defaultdict
from bustag.util import logger, get_data_path, format_datetime, get_now_time, get_full_url
DB_FILE = 'bus.db'
db = SqliteDatabase(get_data_path(DB_FILE), pragmas={
'journal_mode': 'wal'})
class BaseModel(Model):
class Meta:
database = db
legacy_table_names = False
class ExistError(Exception):
pass
class DBError(Exception):
pass
class Item(BaseModel):
'''
item table
'''
title = CharField()
fanhao = CharField(unique=True)
url = CharField(unique=True)
release_date = DateField()
add_date = DateTimeField(default=datetime.datetime.now)
meta_info = TextField()
def __repr__(self):
return f'<Item:{self.fanhao} {self.title}>'
@staticmethod
def saveit(meta_info):
item_release_date = date.fromisoformat(meta_info.pop('release_date'))
item_fanhao = meta_info.pop('fanhao')
item_title = meta_info.pop('title')
item_url = meta_info.pop('url')
item_meta = json.dumps(meta_info)
try:
item = Item.create(fanhao=item_fanhao, title=item_title, url=item_url,
release_date=item_release_date, meta_info=item_meta)
logger.debug(f'save item: {item}')
except IntegrityError:
logger.debug('Item exists: {item_fanhao}')
raise ExistError()
else:
return item
@staticmethod
def loadit(item):
item.url = get_full_url(item.url)
meta = json.loads(item.meta_info)
item.cover_img_url = meta['cover_img_url']
series = item.fanhao.split('-')[0]
item.add_date = format_datetime(item.add_date)
@staticmethod
def getit(id):
item = Item.get_by_id(id)
return item
@staticmethod
def get_by_fanhao(fanhao):
item = Item.get_or_none(Item.fanhao == fanhao)
return item
@staticmethod
def get_tags_dict(item):
tags_dict = defaultdict(list)
for t in item.tags_list:
tags_dict[t.tag.type_].append(t.tag.value)
item.tags_dict = tags_dict
class Tag(BaseModel):
'''
tag table
'''
type_ = CharField(column_name='type')
value = CharField()
url = CharField()
class Meta:
indexes = (
# Specify a unique multi-column index
(('type_', 'value'), True),
)
def __repr__(self):
return f'<Tag {self.value}>'
@staticmethod
def saveit(tag_info):
tag, created = Tag.get_or_create(type_=tag_info.type, value=tag_info.value,
defaults={'url': tag_info.link})
if created:
logger.debug(f'save tag: {tag}')
return tag
class ItemTag(BaseModel):
item = ForeignKeyField(Item, field='fanhao', backref='tags_list')
tag = ForeignKeyField(Tag, backref='items')
class Meta:
indexes = (
# Specify a unique multi-column index
(('item', 'tag'), True),
)
@staticmethod
def saveit(item, tag):
try:
item_tag = ItemTag.create(item=item, tag=tag)
logger.debug(f'save tag_item: {item_tag}')
except Exception as ex:
logger.exception(ex)
else:
return item_tag
def __repr__(self):
return f'<ItemTag {self.item.fanhao} - {self.tag.value}>'
class RATE_TYPE(IntEnum):
NOT_RATE = 0
USER_RATE = 1
SYSTEM_RATE = 2
class RATE_VALUE(IntEnum):
LIKE = 1
DISLIKE = 0
class ItemRate(BaseModel):
rate_type = IntegerField()
rate_value = IntegerField()
item = ForeignKeyField(Item, field='fanhao',
backref='rated_items', unique=True)
rete_time = DateTimeField(default=datetime.datetime.now)
@staticmethod
def saveit(rate_type, rate_value, fanhao):
item_rate = None
try:
item_rate = ItemRate.create(
item=fanhao, rate_type=rate_type, rate_value=rate_value)
logger.debug(f'save ItemRate: {item_rate}')
except IntegrityError:
logger.debug(f'ItemRate exists: {fanhao}')
else:
return item_rate
@staticmethod
def getit(id):
item_rate = ItemRate.get_or_none(ItemRate.id == id)
return item_rate
@staticmethod
def get_by_fanhao(fanhao):
item_rate = ItemRate.get_or_none(ItemRate.item_id == fanhao)
return item_rate
class LocalItem(BaseModel):
'''
local item table
'''
item = ForeignKeyField(Item, field='fanhao',
backref='local_item', unique=True)
path = CharField(null=True)
size = IntegerField(null=True)
add_date = DateTimeField(default=datetime.datetime.now)
last_view_date = DateTimeField(null=True)
view_times = IntegerField(default=0)
@staticmethod
def saveit(fanhao, path):
local_item = None
try:
local_item = LocalItem.create(
item=fanhao, path=path)
logger.debug(f'save LocalItem: {fanhao}')
except IntegrityError:
logger.debug(f'LocalItem exists: {fanhao}')
else:
return local_item
def __repr__(self):
return f'<LocalItem {self.fanhao}({self.path})>'
@staticmethod
def update_play(id):
nrows = (LocalItem
.update({LocalItem.last_view_date: get_now_time(),
LocalItem.view_times: LocalItem.view_times+1})
.where(LocalItem.id == id)
.execute())
logger.debug(f'update LocalItem {id} : rows:{nrows}')
return LocalItem.get_by_id(id)
@staticmethod
def loadit(local_item):
local_item.last_view_date = format_datetime(
local_item.last_view_date) if local_item.last_view_date else ''
def save(meta_info, tags):
item_title = meta_info['title']
tag_objs = []
try:
item = Item.saveit(meta_info)
except ExistError:
logger.debug(f'item exists: {item_title}')
else:
with db.atomic():
for tag_info in tags:
tag = Tag.saveit(tag_info)
if tag:
tag_objs.append(tag)
with db.atomic():
for tag_obj in tag_objs:
ItemTag.saveit(item, tag_obj)
def test_save():
item_url = 'https://www.cdnbus.bid/MADM-116'
item_title = 'test item'
item_fanhao = 'MADM-116'
item_release_date = date(2019, 7, 19)
item_meta_info = ''
item = Item(title=item_title, url=item_url, fanhao=item_fanhao,
release_date=item_release_date, meta_info=item_meta_info)
item.save()
tag1 = Tag.create(type_='genre', value='素人',
url='https://www.cdnbus.bid/genre/s1')
tag2 = Tag.create(type_='star', value='樱田',
url='https://www.cdnbus.bid/star/dbd')
tag3 = Tag.create(type_='genre', value='高清',
url='https://www.cdnbus.bid/genre/x1')
ItemTag.create(item=item, tag=tag1)
ItemTag.create(item=item, tag=tag2)
ItemRate.saveit(RATE_TYPE.USER_RATE, RATE_VALUE.LIKE, item.fanhao)
LocalItem.saveit('MADM-116', '/Download/MADM-116.avi')
def get_items(rate_type=None, rate_value=None, page=1, page_size=10):
'''
get required items based on some conditions
'''
items_list = []
clauses = []
if rate_type is not None:
clauses.append(ItemRate.rate_type == rate_type)
else:
clauses.append(ItemRate.rate_type.is_null())
if rate_value is not None:
clauses.append(ItemRate.rate_value == rate_value)
q = (Item.select(Item, ItemRate)
.join(ItemRate, JOIN.LEFT_OUTER, attr='item_rate')
.where(reduce(operator.and_, clauses))
.order_by(Item.id.desc())
)
total_items = q.count()
if not page is None:
q = q.paginate(page, page_size)
items = get_tags_for_items(q)
for item in items:
Item.loadit(item)
if hasattr(item, 'item_rate'):
item.rate_value = item.item_rate.rate_value
else:
item.rate_value = None
items_list.append(item)
total_pages = (total_items + page_size - 1) // page_size
page_info = (total_items, total_pages, page, page_size)
return items_list, page_info
def get_local_items(page=1, page_size=10):
'''
get local items
'''
items = []
q = (LocalItem.select(LocalItem)
.where(LocalItem.path.is_null(False))
.order_by(LocalItem.id.desc())
)
total_items = q.count()
if not page is None:
q = q.paginate(page, page_size)
item_query = Item.select()
item_tag_query = ItemTag.select()
tag_query = Tag.select()
items_with_tags = prefetch(q, item_query, item_tag_query, tag_query)
for local_item in items_with_tags:
try:
Item.loadit(local_item.item)
Item.get_tags_dict(local_item.item)
items.append(local_item)
except Exception:
pass
total_pages = (total_items + page_size - 1) // page_size
page_info = (total_items, total_pages, page, page_size)
return items, page_info
def get_today_update_count():
now = get_now_time()
year, month, day = now.year, now.month, now.day
q = Item.select().where((Item.add_date.year == year)
& (Item.add_date.month == month)
& (Item.add_date.day == day)
)
return q.count()
def get_today_recommend_count():
now = get_now_time()
year, month, day = now.year, now.month, now.day
q = ItemRate.select().where((ItemRate.rete_time.year == year)
& (ItemRate.rete_time.month == month)
& (ItemRate.rete_time.day == day)
& (ItemRate.rate_type == RATE_TYPE.SYSTEM_RATE)
& (ItemRate.rate_value == RATE_VALUE.LIKE)
)
return q.count()
def get_tags_for_items(items_query):
item_tag_query = ItemTag.select()
tag_query = Tag.select()
items_with_tags = prefetch(items_query, item_tag_query, tag_query)
items = []
for item in items_with_tags:
Item.get_tags_dict(item)
items.append(item)
return items
def init():
db.connect(reuse_if_open=True)
db.create_tables([Item, Tag, ItemTag, ItemRate, LocalItem])
init()