Welcome to BGmi's documentation!

BGmi v3 是 BGmi 的新版本

在v3版本,番剧更新以 Subscription 为单位。 一个 Subscription 可以包含来自多个数据源的多个 series。 这跟之前版本的 BGmi 不同,所以也不能由旧版本升级而来。

所有的数据源和下载工具都是插件化的,可以通过 pip 安装新的数据源。

配置BGmi

使用toml格式配置BGmi

待处理

提供一个quick start来生成配置文件

[bgmi]

[bgmi.output]

[bgmi.output.aria2]
url = "http://127.0.0.1:6800/rpc"
secret = "token:233"

[bgmi.output.notify]

[bgmi.output.notify.smtp]
from = "bgmi@trim21.me"
to = "notify@trim21.me"
host = "smtp.example.com"
port = 25
password = 2333
tls = true

[bgmi.source]
hello = { a = 233 } # this will enable plugin `hello` with options {'a': 233}

# this will enable plugin `world` with empty options
[bgmi.source.world]

[bgmi.source.dmhy]
mirror = 'https://my.mirror.domain'

添加数据源

数据源应该是可以通过pip安装,由pypi分发的python package。尽量不内置在 BGmi 中。

需要继承 bgmi.protocol.source.Base,并且实现所有的抽象方法,并且提供所有所需的类属性。

确保你的类可以实例化,对应的metaclass会是否实现了所有的抽象方法。

返回的 bgmi.protocol.source.Episode 等数据类型用到了 pydantic。 可以查阅 pydantic的文档 了解更多用法。

from typing import List, Tuple

import bgmi.protocol.source
from bgmi.protocol import source


class MySource(source.Base):
    name = "my source"
    id = "my-source"

    def fetch_series_and_subtitle_group(
        self,
    ) -> Tuple[List[source.Series], List[source.Subtitle]]:
        return (
            [
                bgmi.protocol.source.Series.parse_obj(
                    {
                        "id": "1",
                        "status": 0,
                        "update_time": "mon",
                        "subtitle_group": ["1", "2"],
                        "name": "ID:INVADED",
                    }
                ),
                bgmi.protocol.source.Series.parse_obj(
                    {
                        "id": "2",
                        "update_time": "Fri",
                        "subtitle_group": ["1"],
                        "name": "科学的超电磁炮T",
                    }
                ),
            ],
            [
                source.Subtitle(id="1", name="subtitle group 1"),
                source.Subtitle(id="2", name="subtitle group 2"),
            ],
        )

    def fetch_episode_of_series(
        self, series_id: str, subtitle_list: List[str] = None
    ) -> List[source.Episode]:
        return [
            source.Episode.parse_obj(
                {
                    "title": "title",
                    "download": "magnet:?xt=urn:btih:233",
                    "episode": 1,
                    "time": 1582200671,
                    "subtitle_group": "1",
                }
            ),
            source.Episode.parse_obj(
                {
                    "title": "title",
                    "download": "https://example.com/a.torrent",
                    "episode": 2,
                    "time": "2019-12-15",
                }
            ),
        ]

    def search_by_keyword(
        self, keyword: str, max_page: int = None
    ) -> List[source.Episode]:
        return [
            source.Episode.parse_obj(
                {
                    "title": "title",
                    "download": "https://example.com/a.torrent",
                    "episode": 2,
                    "time": "2019-12-15",
                }
            ),
        ]

setup.py:

from setuptools import setup

setup(
    name="my plugin name",
    entry_points={"bgmi.extensions.source": ["my-plugin-id = my_source:MySource"]},
)

待处理

应该有一个github template repo,不应该把 setup.py 的例子也放在这个仓库中

输出下载结果

import os
import os.path

import requests

import bgmi.exc
from bgmi.core import Subscription
from bgmi.protocol import output


class MyOutput(output.Base):
    @classmethod
    def require(cls) -> None:
        pass

    def __init__(self, config: dict) -> None:
        super().__init__(config)

    def execute(
        self, subscription: "Subscription", torrent: str, save_path: str
    ) -> None:
        if not torrent.startswith("http"):
            return
        try:
            r = requests.get(torrent)
        except requests.ConnectionError as e:
            raise bgmi.exc.ConnectError from e
        filename = os.path.basename(torrent)
        with open(os.path.join(save_path, filename), "wb") as f:
            f.write(r.content)

警告

输出的具体格式还没有想好,因为不确定除了最简单的下载之外还要支持什么功能。

API Reference

This page contains auto-generated API reference documentation 1.

bgmi

A CLI tool for subscribed bangumi.

Project Home

Subpackages

bgmi.core

BGmi core

app manager Subscription

a Subscription has many Series

Subscription is created by application.

Series is created by source

bgmi.core Submodules
bgmi.core.application

application

class bgmi.core.application.BGmi(config: bgmi.model.config.Config, backend: bgmi.protocol.backend.Base, logger: logging.Logger = <Logger BGmi (WARNING)>, source_mgr: List[bgmi.protocol.source.Base] = <factory>, output_mgr: List[bgmi.protocol.output.Base] = <factory>, subscriptions: List[bgmi.core.subscription.Subscription] = <factory>)[源代码]

BGmi Core

example:

bgmi = BGmi(config=Config())
subscription_name = "超炮"
bgmi.create(subscription_name)
bgmi.add(sub_name=subscription_name, source="mikan", name="科学的超电磁炮T")
bgmi.remove(subscription_name, "mikan")
bgmi.delete(subscription_name)
create(name: str) → bgmi.core.subscription.Subscription[源代码]

create a subscription

if a subscription with same name has existed, return existed subscription

参数

name -- subscription name

返回

Subscription just created

delete(name: str) → None[源代码]

delete subscription

参数

name -- subscription name

add(sub_name: str, source_name: str, name: str) → bgmi.core.series.Series[源代码]

add series to subscription

参数
  • sub_name -- subscription name

  • source_name -- which source from

  • name -- name in source

返回

series just added

引发
remove(sub_name: str, source_name: str) → None[源代码]

remove series from subscription

参数
  • sub_name -- subscription name

  • source_name -- source id

classmethod load_source() → List[bgmi.protocol.source.Base][源代码]

load add source from entry_points

返回

return a list contains enabled sources

bgmi.core.namespace

namespace for entry point

bgmi.core.namespace.SOURCE = 'bgmi.extensions.source'[源代码]

entry point for source plugin

bgmi.core.namespace.OUTPUT = 'bgmi.extensions.output'[源代码]

entry point for output plugin

bgmi.exc

exceptions

exception bgmi.exc.BGmiException[源代码]

Base Exception for all BGmi exception

exception bgmi.exc.BGmiConnectionException[源代码]

Base Exception for all connection error

exception bgmi.exc.SubscriptionNotFollowed[源代码]

Subscription not found when lookup

exception bgmi.exc.SeriesNotFollowed[源代码]

Series not found when lookup

exception bgmi.exc.RequireNotSatisfiedError(message: str)[源代码]

exception when missing config or deps for a output plugin

__init__(message: str)[源代码]

init

参数

message -- error detail message for user

exception bgmi.exc.ConnectError[源代码]

exception when output get a connection error

exception bgmi.exc.AuthError[源代码]

exception when output require correct auth

exception bgmi.exc.ConfigNotValid[源代码]

exception when config is not valid

bgmi.model

export

bgmi.protocol

Protocol

all bgmi source and output plugin should implement abc from this package

bgmi.protocol Submodules
bgmi.protocol.backend

Abstract Base Classes for Backend

class bgmi.protocol.backend.Base(config: dict)[源代码]

base class for backend

version: str = <bgmi.helper.abstract.AbstractAttribute object>[源代码]

class attribute for attribute version

__init__(config: dict)[源代码]

Initialize self. See help(type(self)) for accurate signature.

abstract classmethod install(config: dict) → None[源代码]

install backend, like create tables, only will be called after Backend change

参数

config -- backend config

abstract add_subscription(sub: bgmi.core.subscription.Subscription) → None[源代码]

save a subscription to backend

参数

sub -- subscription name

abstract remove_subscription(sub: bgmi.core.subscription.Subscription) → None[源代码]

remove a subscription from backend

do nothing when record doesn't exist

参数

sub -- subscription name

abstract get_subscription(sub_name: str) → bgmi.core.subscription.Subscription[源代码]

get a subscription from backend

参数

sub_name -- subscription name

返回

Subscription matched

引发

bgmi.exc.SubscriptionNotFollowed -- Subscription not found

abstract save_subscription(sub: bgmi.core.subscription.Subscription) → None[源代码]

save or create subscription and it's series to backend

if subscription is not dirty, do nothing

参数

sub -- subscription to save

abstract get_all_subscription(filters: Dict[str, Any] = None) → List[bgmi.core.subscription.Subscription][源代码]

get a subscription from backend

参数

filters -- filter when getting all subscription

返回

Subscription matched

引发

bgmi.exc.SubscriptionNotFollowed -- Subscription not found

abstract get_series(source_id: str, name: str) → bgmi.core.series.Series[源代码]

get a series from backend

参数
  • source_id -- source id

  • name -- series name

返回

Series matched

引发

bgmi.exc.SeriesNotFollowed -- Series not found

bgmi.protocol.output

Base for Data source see 输出下载结果

class bgmi.protocol.output.Base(config: dict)[源代码]

Base class for all output plugin like notify and downloader delegate

abstract __init__(config: dict) → None[源代码]

init

参数

config -- config dict user defined in config file.

abstract classmethod require() → None[源代码]

Implement this classmethod if your download delegate has some additional requires

警告

You should not install python package here, because it may break other packages.

引发

RequireNotSatisfiedError -- If some requirements not satisfied. like missing bin or python package. Don't raise ImportError, catch it and describe it in message.

abstract execute(subscription: Subscription, torrent: str, save_path: str) → None[源代码]

plugin do its works

参数
  • subscription -- subscription

  • torrent -- http(s) or magnet url of torrent file

  • save_path -- video file save path

引发
bgmi.protocol.source

Base for Data source see 添加数据源

class bgmi.protocol.source.Base[源代码]

Base class for all data source

name = <bgmi.helper.abstract.AbstractAttribute object>[源代码]

user readable source name, should be defined as class attribute

id = <bgmi.helper.abstract.AbstractAttribute object>[源代码]

source id, should be defined as class attribute

abstract fetch_series_and_subtitle_group() → Tuple[List[bgmi.protocol.source.Series], List[bgmi.protocol.source.Subtitle]][源代码]

return a list of all bangumi and a list of all subtitle group

list of bangumi dict: update time should be one of ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] (bgmi.model.UpdateTime)

警告

cover should start with http:// or https://

[
    ...,
    bgmi.protocol.source.Series(
        **{
            "id": "1234",
            "status": model.SeriesStatus.UPDATING,
            "subtitle_group": ["123", "456"],  # list of id of subtitle group
            "name": "名侦探柯南",
            "update_time": "mon",
            "cover": "https://www.example.com/data/images/cover1.jpg",
        }
    ),
    ...,
]

list of subtitle group dict:

[
    ...,
    bgmi.protocol.source.Subtitle(id="233", name="bgmi字幕组"),
    ...,
]
返回

list of series, list of subtitile group

返回类型

(list[dict], list[dict])

abstract fetch_episode_of_series(series_id: str, subtitle_list: List[str] = None) → Iterable[bgmi.protocol.source.Episode][源代码]

get all episode by series id

参数
  • series_id -- series_id

  • subtitle_list (list) -- list of subtitle group

返回

list of episode

abstract search_by_keyword(keyword: str, max_page: int = None) → Iterable[bgmi.protocol.source.Episode][源代码]

search torrent by arguments. return a list of dict with at least 4 key: download, name, title, episode. Other keys are omitted.

参数
  • keyword (str) -- search key word

  • max_page (int) -- how many page to fetch from website

返回

list of episode search result

返回类型

List[dict]

bgmi.protocol.strainer

Base for Data source see 输出下载结果

1

Created with sphinx-autoapi