movie-bot-api
Advanced tools
| from moviebotapi.core import utils | ||
| class BaseModel(object): | ||
| def to_json(self, hidden_fields=None): | ||
| """ | ||
| Json序列化 | ||
| :param hidden_fields: 覆盖类属性 hidden_fields | ||
| :return: | ||
| """ | ||
| model_json = {} | ||
| if not hidden_fields: | ||
| hidden_fields = [] | ||
| for column in self.__dict__: | ||
| if column in hidden_fields: | ||
| continue | ||
| if hasattr(self, column): | ||
| model_json[column] = utils.parse_field_value(getattr(self, column)) | ||
| if '_sa_instance_state' in model_json: | ||
| del model_json['_sa_instance_state'] | ||
| return model_json |
| from moviebotapi.core.basemodel import BaseModel | ||
| class ClientTorrent(BaseModel): | ||
| hash: str | ||
| name: str | ||
| save_path: str | ||
| content_path: str | ||
| size: int | ||
| size_str: str | ||
| dl_speed: int | ||
| dl_speed_str: str | ||
| up_speed: int | ||
| up_speed_str: str | ||
| progress: float | ||
| uploaded: int | ||
| uploaded_str: str | ||
| downloaded: int | ||
| downloaded_str: str | ||
| seeding_time: int | ||
| ratio: float | ||
| tracker: str |
| Metadata-Version: 2.1 | ||
| Name: movie-bot-api | ||
| Version: 0.0.54 | ||
| Version: 0.0.55 | ||
| Summary: 智能影音机器人MovieBot的接口SDK | ||
@@ -10,2 +10,3 @@ Home-page: https://github.com/pofey/movie-bot-api | ||
| Keywords: movie bot,movie robot | ||
| Platform: UNKNOWN | ||
| Classifier: License :: OSI Approved :: MIT License | ||
@@ -49,1 +50,2 @@ Classifier: Intended Audience :: Developers | ||
| py -3 -m pip install -U movie-bot-api | ||
@@ -16,2 +16,3 @@ LICENSE | ||
| moviebotapi/douban.py | ||
| moviebotapi/downloader.py | ||
| moviebotapi/event.py | ||
@@ -30,2 +31,3 @@ moviebotapi/ext.py | ||
| moviebotapi/core/__init__.py | ||
| moviebotapi/core/basemodel.py | ||
| moviebotapi/core/country_mapping.txt | ||
@@ -32,0 +34,0 @@ moviebotapi/core/decorators.py |
+24
-6
@@ -5,8 +5,8 @@ from typing import List, Dict, Optional | ||
| from moviebotapi.core import utils | ||
| from moviebotapi.core.basemodel import BaseModel | ||
| from moviebotapi.core.models import MediaType | ||
| from moviebotapi.core.utils import json_object | ||
| @json_object | ||
| class MediaNameMeta: | ||
| class MediaNameMeta(BaseModel): | ||
| filepath: Optional[str] = None | ||
| cn_name: str = None | ||
@@ -23,9 +23,27 @@ aka_names: List[str] = [] | ||
| release_team: str = None | ||
| tmdb_id: int = None | ||
| media_type: MediaType = None | ||
| def __init__(self, data: Dict): | ||
| def __init__(self, data: Dict = None): | ||
| utils.copy_value(data, self) | ||
| @json_object | ||
| class MetaSearchResult: | ||
| class TVMeta(BaseModel): | ||
| season_start: int = None | ||
| season_end: int = None | ||
| season_full_index: List[int] = [] | ||
| ep_start: int = None | ||
| ep_end: int = None | ||
| ep_full_index: List[int] = [] | ||
| season_is_fill: bool = False | ||
| ep_is_fill: bool = False | ||
| contains_complete_ep: bool = False | ||
| contains_complete_season: bool = False | ||
| contains_multiple_season: bool = False | ||
| def __init__(self, data: Dict = None): | ||
| utils.copy_value(data, self) | ||
| class MetaSearchResult(BaseModel): | ||
| tmdb_id: int = None | ||
@@ -32,0 +50,0 @@ douban_id: int = None |
@@ -8,2 +8,4 @@ from enum import Enum | ||
| Collection = 'Collection' | ||
| XX = 'XX' | ||
| Other = '其他' | ||
@@ -19,1 +21,5 @@ @staticmethod | ||
| return MediaType.Collection | ||
| if l == 'xx': | ||
| return MediaType.XX | ||
| else: | ||
| return MediaType.Other |
@@ -9,3 +9,3 @@ from abc import ABCMeta, abstractmethod | ||
| UA = 'moviebotapi/0.0.54' | ||
| UA = 'moviebotapi/0.0.55' | ||
| URLTypes = Union["URL", str] | ||
@@ -12,0 +12,0 @@ HeaderTypes = Union[ |
@@ -14,3 +14,76 @@ import datetime | ||
| def _parse_field_value(field_value): | ||
| def trans_unit_to_mb(size: float, unit: str) -> float: | ||
| """ | ||
| 按文件大小尺寸规格,转换成MB单位的数字 | ||
| :param size: | ||
| :param unit: | ||
| :return: | ||
| """ | ||
| if unit == 'GB' or unit == 'GiB': | ||
| return round(size * 1024, 2) | ||
| elif unit == 'MB' or unit == 'MiB': | ||
| return round(size, 2) | ||
| elif unit == 'KB' or unit == 'KiB': | ||
| return round(size / 1024, 2) | ||
| elif unit == 'TB' or unit == 'TiB': | ||
| return round(size * 1024 * 1024, 2) | ||
| elif unit == 'PB' or unit == 'PiB': | ||
| return round(size * 1024 * 1024 * 1024, 2) | ||
| else: | ||
| return size | ||
| def trans_size_str_to_mb(size: str): | ||
| """ | ||
| 把一个字符串格式的文件尺寸单位,转换成MB单位的标准数字 | ||
| :param size: | ||
| :return: | ||
| """ | ||
| if not size: | ||
| return 0.0 | ||
| s = None | ||
| u = None | ||
| if size.find(' ') != -1: | ||
| arr = size.split(' ') | ||
| s = arr[0] | ||
| u = arr[1] | ||
| else: | ||
| if size.endswith('GB'): | ||
| s = size[0:-2] | ||
| u = 'GB' | ||
| elif size.endswith('GiB'): | ||
| s = size[0:-3] | ||
| u = 'GB' | ||
| elif size.endswith('MB'): | ||
| s = size[0:-2] | ||
| u = 'MB' | ||
| elif size.endswith('MiB'): | ||
| s = size[0:-3] | ||
| u = 'MB' | ||
| elif size.endswith('KB'): | ||
| s = size[0:-2] | ||
| u = 'KB' | ||
| elif size.endswith('KiB'): | ||
| s = size[0:-3] | ||
| u = 'KB' | ||
| elif size.endswith('TB'): | ||
| s = size[0:-2] | ||
| u = 'TB' | ||
| elif size.endswith('TiB'): | ||
| s = size[0:-3] | ||
| u = 'TB' | ||
| elif size.endswith('PB'): | ||
| s = size[0:-2] | ||
| u = 'PB' | ||
| elif size.endswith('PiB'): | ||
| s = size[0:-3] | ||
| u = 'PB' | ||
| if not s: | ||
| return 0.0 | ||
| if s.find(',') != -1: | ||
| s = s.replace(',', '') | ||
| return trans_unit_to_mb(float(s), u) | ||
| def parse_field_value(field_value): | ||
| if isinstance(field_value, decimal.Decimal): # Decimal -> float | ||
@@ -21,3 +94,3 @@ field_value = round(float(field_value), 2) | ||
| elif isinstance(field_value, list): | ||
| field_value = [_parse_field_value(i) for i in field_value] | ||
| field_value = [parse_field_value(i) for i in field_value] | ||
| if hasattr(field_value, 'to_json'): | ||
@@ -30,3 +103,3 @@ field_value = field_value.to_json() | ||
| for key_ in field_value: | ||
| val[key_] = _parse_field_value(field_value[key_]) | ||
| val[key_] = parse_field_value(field_value[key_]) | ||
| field_value = val | ||
@@ -48,3 +121,3 @@ return field_value | ||
| if hasattr(self, column): | ||
| model_json[column] = _parse_field_value(getattr(self, column)) | ||
| model_json[column] = parse_field_value(getattr(self, column)) | ||
| if '_sa_instance_state' in model_json: | ||
@@ -118,3 +191,3 @@ del model_json['_sa_instance_state'] | ||
| def parse_value(func, value): | ||
| def parse_value(func, value, default_value=None): | ||
| if value is not None: | ||
@@ -131,2 +204,4 @@ if func == bool: | ||
| try: | ||
| if isinstance(value, str): | ||
| value = value.replace(',', '') | ||
| return func(value) | ||
@@ -136,4 +211,9 @@ except ValueError: | ||
| elif func == datetime.datetime: | ||
| if value: | ||
| return datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S') | ||
| if isinstance(value, datetime.datetime): | ||
| return value | ||
| elif isinstance(value, str): | ||
| if value: | ||
| return datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S') | ||
| else: | ||
| return None | ||
| else: | ||
@@ -155,3 +235,4 @@ return None | ||
| return func(value) | ||
| return value | ||
| else: | ||
| return default_value | ||
@@ -158,0 +239,0 @@ |
@@ -5,2 +5,3 @@ from typing import List, Dict | ||
| from moviebotapi.core import utils | ||
| from moviebotapi.core.basemodel import BaseModel | ||
| from moviebotapi.core.models import MediaType | ||
@@ -73,2 +74,14 @@ from moviebotapi.core.utils import json_object | ||
| class MediaFolder(BaseModel): | ||
| """媒体服务器配置的影音库文件夹""" | ||
| id: str | ||
| name: str | ||
| path: str | ||
| sub_folders: list | ||
| ListMediaItem = List[MediaItem] | ||
| ListMediaFolder = List[MediaFolder] | ||
| class MediaServerApi: | ||
@@ -75,0 +88,0 @@ def __init__(self, session: Session): |
+114
-8
@@ -7,6 +7,5 @@ import datetime | ||
| from moviebotapi.core import utils | ||
| from moviebotapi.core.utils import json_object | ||
| from moviebotapi.core.basemodel import BaseModel | ||
| @json_object | ||
| class CateLevel1(str, Enum): | ||
@@ -23,3 +22,3 @@ Movie = 'Movie' | ||
| @staticmethod | ||
| def get_type(enum_name: str): | ||
| def get_type(enum_name: str) -> "CateLevel1": | ||
| for item in CateLevel1: | ||
@@ -31,4 +30,20 @@ if item.name == enum_name: | ||
| @json_object | ||
| class Torrent: | ||
| class TVSeries(BaseModel): | ||
| season_start: int = None | ||
| season_end: int = None | ||
| season_full_index: List[int] = [] | ||
| ep_start: int = None | ||
| ep_end: int = None | ||
| ep_full_index: List[int] = [] | ||
| season_is_fill: bool = False | ||
| ep_is_fill: bool = False | ||
| contains_complete_ep: bool = False | ||
| contains_complete_season: bool = False | ||
| contains_multiple_season: bool = False | ||
| def __init__(self, data: Optional[Dict] = None): | ||
| utils.copy_value(data, self) | ||
| class Torrent(BaseModel): | ||
| # 种子id | ||
@@ -76,6 +91,82 @@ id: str | ||
| def __init__(self, data: Dict): | ||
| def __init__(self, data: Optional[Dict] = None): | ||
| utils.copy_value(data, self) | ||
| @staticmethod | ||
| def build_by_parse_item(site_config, item): | ||
| t = Torrent() | ||
| t.site_id = utils.parse_value(str, site_config.get('id')) | ||
| t.id = utils.parse_value(int, item.get('id')) | ||
| t.name = utils.parse_value(str, item.get('title')) | ||
| t.subject = utils.parse_value(str, item.get('description'), '') | ||
| if t.subject: | ||
| t.subject = t.subject.strip() | ||
| t.free_deadline = utils.parse_value(datetime.datetime, item.get('free_deadline')) | ||
| t.imdb_id = utils.parse_value(str, item.get('imdbid')) | ||
| t.upload_count = utils.parse_value(int, item.get('seeders'), 0) | ||
| t.downloading_count = utils.parse_value(int, item.get('leechers'), 0) | ||
| t.download_count = utils.parse_value(int, item.get('grabs'), 0) | ||
| t.download_url = utils.parse_value(str, item.get('download')) | ||
| if t.download_url and not t.download_url.startswith('http'): | ||
| t.download_url = site_config.get('domain') + t.download_url | ||
| t.publish_date = utils.parse_value(datetime.datetime, item.get('date'), datetime.datetime.now()) | ||
| t.cate_id = utils.parse_value(str, item.get('category')) | ||
| for c in site_config.get('category_mappings'): | ||
| cid = t.cate_id | ||
| id_mapping = site_config.get('category_id_mapping') | ||
| if id_mapping: | ||
| for mid in id_mapping: | ||
| if str(mid.get('id')) == str(cid): | ||
| if isinstance(mid.get('mapping'), list): | ||
| cid = mid.get('mapping')[0] | ||
| else: | ||
| cid = mid.get('mapping') | ||
| if str(c.get('id')) == str(cid): | ||
| t.cate_level1 = CateLevel1.get_type(c.get('cate_level1')) | ||
| t.details_url = utils.parse_value(str, item.get('details')) | ||
| if t.details_url: | ||
| t.details_url = site_config.get('domain') + t.details_url | ||
| t.download_volume_factor = utils.parse_value(float, item.get('downloadvolumefactor'), 1) | ||
| t.upload_volume_factor = utils.parse_value(int, item.get('uploadvolumefactor')) | ||
| t.size_mb = utils.trans_size_str_to_mb(utils.parse_value(str, item.get('size'), '0')) | ||
| t.poster_url = utils.parse_value(str, item.get('poster')) | ||
| t.minimum_ratio = utils.parse_value(float, item.get('minimumratio'), 0.0) | ||
| t.minimum_seed_time = utils.parse_value(int, item.get('minimumseedtime'), 0) | ||
| if t.poster_url: | ||
| if t.poster_url.startswith("./"): | ||
| t.poster_url = site_config.get('domain') + t.poster_url[2:] | ||
| elif not t.poster_url.startswith("http"): | ||
| t.poster_url = site_config.get('domain') + t.poster_url | ||
| return t | ||
| class TorrentDetail(BaseModel): | ||
| site_id: str = None | ||
| name: str = None | ||
| subject: str = None | ||
| download_url: str = None | ||
| filename: str = None | ||
| intro: str = None | ||
| publish_date: datetime.datetime = None | ||
| @staticmethod | ||
| def build(site_config, item): | ||
| if not item: | ||
| return | ||
| t = TorrentDetail() | ||
| t.site_id = site_config.get('id') | ||
| t.id = utils.parse_value(int, item.get('id')) | ||
| t.name = utils.parse_value(str, item.get('title'), '') | ||
| t.subject = utils.parse_value(str, item.get('description'), '') | ||
| if t.subject: | ||
| t.subject = t.subject.strip() | ||
| t.download_url = utils.parse_value(str, item.get('download')) | ||
| if t.download_url and not t.download_url.startswith('http'): | ||
| t.download_url = site_config.get('domain') + t.download_url | ||
| t.filename = utils.parse_value(str, item.get('filename')) | ||
| t.intro = utils.parse_value(str, item.get('intro')) | ||
| t.publish_date = utils.parse_value(datetime.datetime, item.get('date')) | ||
| return t | ||
| class SearchType(str, Enum): | ||
@@ -86,3 +177,3 @@ Keyword = 'keyword' | ||
| class SearchQuery: | ||
| class SearchQuery(BaseModel): | ||
| key: SearchType | ||
@@ -107,3 +198,3 @@ value: str | ||
| class Site: | ||
| class Site(BaseModel): | ||
| id: int | ||
@@ -142,2 +233,14 @@ gmt_modified: datetime.datetime | ||
| class SiteUserinfo(BaseModel): | ||
| uid: int | ||
| username: str | ||
| user_group: str | ||
| share_ratio: float | ||
| uploaded: float | ||
| downloaded: float | ||
| seeding: int | ||
| leeching: int | ||
| vip_group: bool = False | ||
| class SiteApi: | ||
@@ -217,1 +320,4 @@ def __init__(self, session: Session): | ||
| return [Torrent(x) for x in torrents] | ||
| TorrentList = List[Torrent] |
+3
-1
| Metadata-Version: 2.1 | ||
| Name: movie-bot-api | ||
| Version: 0.0.54 | ||
| Version: 0.0.55 | ||
| Summary: 智能影音机器人MovieBot的接口SDK | ||
@@ -10,2 +10,3 @@ Home-page: https://github.com/pofey/movie-bot-api | ||
| Keywords: movie bot,movie robot | ||
| Platform: UNKNOWN | ||
| Classifier: License :: OSI Approved :: MIT License | ||
@@ -49,1 +50,2 @@ Classifier: Intended Audience :: Developers | ||
| py -3 -m pip install -U movie-bot-api | ||
+1
-1
@@ -16,3 +16,3 @@ # -*- coding: utf-8 -*- | ||
| name='movie-bot-api', | ||
| version='0.0.54', | ||
| version='0.0.55', | ||
| author='yee', | ||
@@ -19,0 +19,0 @@ author_email='yipengfei329@gmail.com', |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
90521
10.94%38
5.56%2428
11.02%