代码拉取完成,页面将自动刷新
同步操作将从 解优杂货队/smartphotoalbum-kylinos 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
import configparser
import hashlib
import shutil
from typing import List, Dict
from collections import defaultdict
from functools import reduce
import jieba.posseg
import jieba
from numpy import record
from peewee import fn
from itertools import groupby
import operator, glob, os
conf = configparser.ConfigParser()
conf.read('./settings.conf')
def init_name_dict():
"""初始化jieba人名词典
"""
from DatabaseManager import Person
names = [record.name for record in Person.select(Person.name).distinct()]
for name in names:
jieba.add_word(name, tag='nr')
def calc_hash(filepath):
with open(filepath,'rb') as f:
sha1obj = hashlib.sha1()
sha1obj.update(f.read())
hash = sha1obj.hexdigest()
return hash
def read_conf(section: str, option: str) -> str:
"""读取配置文件中的配置
Author: Alex
Args:
section (str): 节
option (str): 属性
Returns:
str: 对应对应节的属性值
"""
return conf.get(section, option)
def write_conf(section: str, option: str, value: str) -> None:
"""将值写入配置文件
Author:alex
Args:
section (str): 节
option (str): 属性
value (str): 值
Returns:
str: None
"""
conf.set(section, option, value)
def _retrieve(cls, fields, filters=True):
return [
{
k: v(record) for k, v in zip(fields, map(lambda x: operator.attrgetter(x), fields))
} for record in cls().select().where(filters)
] if len(fields) > 1 else [
operator.attrgetter(fields[0])(record) for record in cls().select().where(filters)
]
def retrieve_all_photos_ids():
"""获取所有照片ID
Returns:
List[str]: 照片的uuid
"""
from DatabaseManager import Photo
return _retrieve(Photo, ['uuid'])
def retrieve_photos_wrt_date(year, month=None, day=None) -> List[str]:
"""根据拍摄日期返回照片uuid
Returns:
List[str]: 照片uuid列表
"""
from DatabaseManager import Photo
if month and day:
return [record.uuid for record in Photo().select().where((Photo.taken_year == year) & (Photo.taken_month == month) & (Photo.taken_day == day))]
if month:
return [record.uuid for record in Photo().select().where((Photo.taken_year == year) & (Photo.taken_month == month))]
return [record.uuid for record in Photo().select().where((Photo.taken_year == year))]
def retrieve_all_albums():
"""获取所有相册
Returns:
Dict[str, T]: 相册的记录
"""
from DatabaseManager import Album
return _retrieve(Album, ['ID', 'name', 'created_datetime'])
def retrieve_photos_in_albums(album_id) -> List[str]:
"""获取相册中的照片
Args:
album_id (int): 相册id
Returns:
List[str]: 相册中相片列表
"""
from DatabaseManager import Album
return [record.uuid for record in Album(ID=album_id).photos]
def retrieve_collected_photos():
"""获取所有收藏的照片
Returns:
List[uuid]: 所有照片的uuid
"""
from DatabaseManager import Photo
return _retrieve(Photo, ['uuid'], Photo.is_favoriated == True)
def retrieve_all_persons():
"""获取所有的人物
Returns:
List[Dict[str, str]]: 人物的列表信息
"""
from DatabaseManager import Person
return _retrieve(Person, ['ID', 'name'])
def retrieve_face_thumbnail(person_id):
"""获取某个人物人脸缩略图
"""
from DatabaseManager import Person
return Person(ID=person_id).outlook.get().thumbnail
def retrieve_date_range():
"""返回照片的所有时间
"""
from DatabaseManager import Photo
return [(record.taken_year, record.taken_month) for record in Photo.select(Photo.taken_year, Photo.taken_month).where(Photo.taken_year.is_null(False) & Photo.taken_month.is_null(False)).distinct()]
def retrieve_is_favoriated(photo_id: str) -> bool:
"""检查图像是否被收藏
Args:
photo_id (str): 照片id
Returns:
bool: 是否被收藏
"""
from DatabaseManager import Photo
return Photo.get_by_id(photo_id).is_favoriated
def retrieve_photos_with_person(person_id) -> List[str]:
"""获取某个人物出现的所有照片
"""
from DatabaseManager import Person
return [record.uuid for record in Person(ID=person_id).photos]
def retrieve_photos_with_ocr(keyword: str) -> List[str]:
"""获取出现特定文字的图片
"""
from DatabaseManager import Photo
return [record.uuid for record in Photo.raw(f"""
select * from Photo where Photo.ocr like '%{keyword}%'
""")]
def retrieve_photos_with_geo(keyword: str) -> List[str]:
"""返回特定地理关键字的照片
Args:
keyword (str): 地理位置关键字
Returns:
List[str]: 图片列表
"""
from DatabaseManager import Photo
return [record.uuid for record in Photo.raw(f"""
select * from Photo where Photo.taken_place like '%{keyword}%'
""")]
def retrieve_all_places() -> List[str]:
"""返回所有地点
Returns:
List[str]: [description]
"""
from DatabaseManager import Photo
return [record.taken_place['address']['region'] if 'region' in record.taken_place['address'] else record.taken_place['address']['city'] for record in Photo.select() if record.taken_place != '']
def retrieve_photo_categories() -> List[Dict[str, int]]:
"""返回所有照片类别和其对应的数据库ID
Returns:
List[Dict[str, int]]: 照片类别及其ID
"""
from DatabaseManager import ScenceClasses
return _retrieve(ScenceClasses, ['ID', 'name'])
def retrieve_photos_wrt_class(class_id: int) -> List[str]:
"""返回某个类别的照片类别列表
Args:
class_id (int): 类别ID
Returns:
List[str]: 照片ID列表
"""
from DatabaseManager import ScenceClasses
return [record.uuid for record in ScenceClasses(ID=class_id).photos]
def retrieve_all_moments() -> List[Dict]:
"""返回所有时刻名称及其ID
Returns:
List[Dict]: 时刻名称及其ID
"""
from DatabaseManager import Moment
return _retrieve(Moment, ['ID', 'name'])
def retrieve_photos_wrt_moment(moment_id: int) -> List[str]:
"""根据时刻ID返回照片ID
Args:
ID (int): 时刻ID
Returns:
List[str]: 照片ID列表
"""
from DatabaseManager import Moment
return [record.uuid for record in Moment.get(ID=moment_id).photos]
def rename_a_moment(moment_id: int, new_name: str):
"""更改时刻名称
Args:
moment_id (int): 时刻id
new_name (str): 新的时刻名称
"""
from DatabaseManager import Moment
moment = Moment.get_by_id(moment_id)
moment.name = new_name
moment.save()
def remove_a_moment(moment_id: int):
"""删除一个时刻
Args:
moment_id ([type]): 时刻id
"""
from DatabaseManager import Moment
Moment.delete_by_id(moment_id)
def retrieve_matched_photo_classes() -> List[Dict]:
"""获取已经分类好的图像类别,过滤掉从未被分到的类别。
Returns:
List[Dict]: 图像类别ID和名称组成的列表
"""
from DatabaseManager import ScenceClasses
class_ids = [record.scenceclasses_id for record in ScenceClasses.raw("select distinct scenceclasses_id from photo_scence_classes_through")]
return list(filter(lambda x: x['ID'] in class_ids, retrieve_photo_categories()))
def add_to_favorites(photo_id: str):
"""将图片添加至收藏中
Args:
photo_id (str): 照片ID
"""
from DatabaseManager import Photo
photo = Photo.get_by_id(photo_id)
photo.is_favoriated = True
photo.save()
def remove_from_favorites(photo_id: str):
"""将图片从收藏中移除
Args:
photo_id (str): 照片ID
"""
from DatabaseManager import Photo
photo = Photo.get_by_id(photo_id)
photo.is_favoriated = False
photo.save()
def create_an_album(name: str) -> int:
"""创建一个相册
Args:
name (str): 相册名称
Returns:
int: 相册的ID
"""
from DatabaseManager import Album
new_album = Album.create(name=name)
new_album.save()
return new_album.ID
def delete_a_photo(photo_id):
"""删除某张图片
Args:
photo_id (str)): 照片的uuid
"""
from DatabaseManager import Photo
Photo.get(uuid=photo_id).delete_instance()
libpath = r'./photolib'
photopath = glob.glob(os.path.join(libpath, photo_id + '*'))[0]
os.remove(photopath)
def delete_an_album(album_id):
"""删除一个相册
Args:
album_id (int): 相册id
"""
from DatabaseManager import Album
Album(ID=album_id).delete_instance()
def rename_an_album(album_id: int, album_name: str):
"""重命名一个相册
Args:
album_id (int): 相册ID
album_name (str): 相册名称
"""
from DatabaseManager import Album
album = Album.get(ID=album_id)
album.name = album_name
album.save()
def rename_an_person(person_id: int, person_name: str):
"""重命名一个人物名称
Args:
person_id (int): 人物ID
person_name (str): 新的人物名称
"""
from DatabaseManager import Person
person = Person.get(ID=person_id)
person.name = person_name
person.save()
def search(keyword: str) -> List[str]:
"""聚合搜索功能
Args:
keyword (str): 关键字
Returns:
List[str]: 搜索到的图片列表
"""
from DatabaseManager import Person, Photo
seg = list(jieba.posseg.cut(keyword))
ret = defaultdict(list)
# ocr搜索
for segment, _ in seg:
res = retrieve_photos_with_ocr(segment)
if res:
ret['ocr'].extend(res)
# 地理位置搜索
for segment, _ in seg:
res = retrieve_photos_with_geo(segment)
if res:
ret['geo'].extend(res)
# 按照人物名称进行搜索
try:
res = Person.select().where(Person.name ** keyword).get()
if res:
ret['person'].extend([record.uuid for record in res.photos])
except:
pass
for segment, _ in seg:
try:
res = Person.select().where(Person.name ** segment).get()
if res:
ret['person'].extend([record.uuid for record in res.photos])
except:
continue
if ret['person']:
ret['person'] = list(set(ret['person']))
# 人物组合搜索
targets = []
for word, flag in jieba.posseg.cut(keyword):
if flag in ('r', 'nr'):
targets.append(word)
if len(targets) > 1:
target_ids = map(lambda target: Person.select().where(Person.name==target), targets)
target_ids = filter(lambda target: target.count() != 0, target_ids)
target_ids = map(lambda target: target.get().ID, target_ids)
photo_person_model = Photo.persons.get_through_model()
queries = [photo_person_model.select(photo_person_model.photo_id).where(photo_person_model.person_id == ID) for ID in target_ids]
query = reduce(lambda x, y: x & y, queries)
res = list(map(lambda record: record.photo_id, query))
if res:
ret['group'].extend(res)
return ret
def organize_photos():
"""将相片按照时间、地点整理成Moment回忆
"""
from DatabaseManager import Photo, Moment
photos_already_been_organized = [record.uuid for record in Photo.select().where(not Photo.moment.is_null())]
photos_can_be_organized = Photo.select().where((Photo.taken_place != "") & (Photo.taken_day != "") & Photo.uuid.not_in(photos_already_been_organized))
photos_can_be_organized = list(map(lambda x: (x.taken_place['address']['state'] + "," + x.taken_place['address']['region'] if 'region' in x.taken_place['address'] else x.taken_place['address']['city'], str(x.taken_year) + str(x.taken_month) + str(x.taken_day), x.uuid), photos_can_be_organized))
grouped_result = {k: {m: list(map(lambda x: x[1], n)) for m, n in groupby(list(map(lambda x: (x[1], x[2]), v)), key=lambda x: x[0])} for k, v in groupby(photos_can_be_organized, key=lambda x: x[0])}
for _, value in grouped_result.items():
for _, photo_ids in value.items():
if len(photo_ids) > 5:
moment = Moment().create()
moment.save
for photo_id in photo_ids:
photo = Photo.get_by_id(photo_id)
photo.moment = moment
photo.save()
if __name__ == '__main__':
delete_a_photo('86cb6f86854eb7a691e96c003778107229e0c297')
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。