Module mangdl.api.providers.templates.wordpress

Expand source code
from functools import partial
from importlib import import_module
from types import ModuleType
from typing import Any, Callable, Dict, List, Union
from urllib.parse import quote_plus
from ast import literal_eval

from bs4 import BeautifulSoup

from ....utils.utils import dt, sanitize_text
from ...base import Ch, Downloader, Manga, soup, urel

class ch_num_fn:
    def breadcrumb(soup: BeautifulSoup):
        return literal_eval(soup.select_one("ol.breadcrumb .active").text.split()[-1])

    def wmcc(soup):
        return literal_eval(".".join(soup.select_one("#wp-manga-current-chap")["value"].split("-")[1:]))

class manga_id_fn:
    def setsu(soup) -> str:
        return soup.select_one("#manga-chapters-holder")["data-id"]

class rch_fn:
    def msa(url: str, base_url: str, **kwargs: Dict[str, Any]):
        url = f"{base_url}/manga/{urel(url).parts[2]}/ajax/chapters/"
        return soup(url, method="post")
    def setsu(url: str, base_url: str, manga_id_fn: Callable[[BeautifulSoup], Union[int, float]], **kwargs: Dict[str, Any]):
        data = {"action": "manga_get_chapters", "manga": str(manga_id_fn(soup(url)))}
        return soup(f"{base_url}/wp-admin/admin-ajax.php", method="post", data=data)

class rch_num_fn:
    def tdo(url):
        return literal_eval(".".join(urel(url).parts[3].split("-")[1:]))

class template:
    def __init__(self, prov: ModuleType) -> None:
        attr = {
            "base_url": None,
            "cover_src": "src",
            "ch_num_fn": ch_num_fn.breadcrumb,
            "date_format": r"%B %d, %Y",
            "manga_id_fn": manga_id_fn.setsu,
            "rch_fn": soup,
            "rch_num_fn": rch_num_fn.tdo,
            "scanlator": None,
            "search_query_string": "post_type=wp-manga",
            "src": "src",
            "title_fn": None,
            "total_cs": ".c-blog__heading h1",
        }
        self.prov = prov
        for k, v in attr.items():
            setattr(self, k, getattr(prov, k, v))
        rfk = ["manga_id_fn"]
        if isinstance(self.rch_fn, str):
            self.rch_fn = partial(
                getattr(rch_fn, self.rch_fn),
                base_url=self.base_url,
                **{i: getattr(self, i, None) for i in rfk}
            )
        for i in ["ch_num_fn", "rch_num_fn"]:
            gi = getattr(self, i)
            if isinstance(gi, str):
                setattr(self, i, getattr(globals()[i], getattr(prov, i, gi), gi))

        self.template = import_module(f".{self.prov.template}", "mangdl.api.providers.templates").template

    def ch_fn(self, url: str) -> List[str]:
        op = []
        for i in soup(f"{url}?style=list").select(".page-break img"):
            op.append(sanitize_text(i[self.src]))
        return op

    def chapter(self, url: str) -> Ch:
        ms = soup(url)
        return Ch(
            url              = url,
            ch               = self.ch_num_fn(ms),
            vol              = None,
            title            = sanitize_text(ms.select_one("ol.breadcrumb .active").text.split("-")[-1]),
            scanlator_groups = [self.scanlator],
            imgs             = self.ch_fn(url),
        )

    def chdls(self, url: str, chs: int=0) -> List[Dict[Union[float, int, None], str]]:
        op = []
        if chs:
            for c in self.rch_fn(url).select("li.wp-manga-chapter    a"):
                cch = c["href"]
                if chs == 2:
                    cch = self.chapter(cch)
                op.append({self.rch_num_fn(c["href"]): cch})
        return op

    def manga(self, url: str, chs: int=0) -> Manga:
        ms = soup(url)
        meta = {}
        for c in ["post-content_item", "post-status"]:
            for m in ms.select(f"div.{c}"):
                v = m.select_one(".summary-content")
                idx = sanitize_text(m.select_one("h5").text)
                if v:
                    meta[idx] = sanitize_text(v.text)
                else:
                    meta[idx] = [sanitize_text(i.text) for i in m.select("a")]

        def mst(s: str, pp: Callable[[str], List[Any]]=lambda x: x):
            return pp(sanitize_text(meta.get(s))) if meta.get(s) else []

        rd = [sanitize_text(i.text) for i in self.rch_fn(url).select(".chapter-release-date")]
        def dates(idx: int):
            op = "1970-01-01T00:00:00"
            if rd:
                rop = rd[idx]
                if rop:
                    op = dt(rop, self.date_format)
            return op
        return Manga(
            url             = url,
            covers          = [ms.select_one(".summary_image img")[self.cover_src]],
            title           = self.title_fn(ms) if self.title_fn else sanitize_text(ms.select_one("div.post-title h1").text),
            alt_titles      = mst("Alternative"),
            author          = mst("Author(s)", lambda x: x.split(",")),
            artist          = mst("Artist(s)", lambda x: x.split(",")),
            status          = {k: v for v, k in enumerate(["ongoing", "completed", "on hold"])}.get(meta["Status"].lower(), -1),
            genres          = mst("Genre(s)", lambda x: x.split(",")),
            updated_at      = dates(0),
            created_at      = dates(-1),
            description     = sanitize_text(getattr(ms.select_one(".summary__content"), "text", "No description available.")),
            chapters        = self.chdls(url, chs),
        )

    def dl_search(self, title: str, **kwargs: Dict[str, Any]):
        global total
        total = 0
        rpa = getattr(self.prov, "rpa", 12)
        cs_manga = getattr(self.prov, "cs_manga", "div.post-title")
        manga_check = getattr(self.prov, "manga_check", lambda x: True)
        title_fn = getattr(self.prov, "title_fn", lambda x: x.select_one("a").text)
        link_fn = getattr(self.prov, "link_fn", lambda x: x.select_one("a")["href"])
        sr = {}
        def pr(num: int):
            global total
            url = f"{self.base_url}/page/{num}?s={quote_plus(title)}&{self.search_query_string}"
            ms = soup(url)
            ts = ms.select(cs_manga)
            if not total:
                total = int(sanitize_text(ms.select_one(self.total_cs).text).split()[0])
            for r in ts:
                if manga_check(r):
                    sr[title_fn(r)] = link_fn(r)
            return len(ts)
        i = 1
        cp = pr(i)
        while cp // rpa and (rpa * i) < total:
            i += 1
            cp = pr(i)
        return sr

    def cli_search(self, title: str, **kwargs: Dict[str, Any]) -> Dict[str, str]:
        return self.dl_search(title, **kwargs)

    def dl(self, url: str, **kwargs: Dict[str, Any]):
        ms = soup(url)
        Downloader(self.ch_fn, **kwargs).dl_chdls(self.chdls(url), sanitize_text(ms.select_one("div.post-title h1").text))

    def cli_dl(self, title: str, **kwargs: Dict[str, Any]):
        Downloader(self.ch_fn, **kwargs).cli(self.template(self.prov).cli_search, partial(self.chdls), title)

Classes

class ch_num_fn
Expand source code
class ch_num_fn:
    def breadcrumb(soup: BeautifulSoup):
        return literal_eval(soup.select_one("ol.breadcrumb .active").text.split()[-1])

    def wmcc(soup):
        return literal_eval(".".join(soup.select_one("#wp-manga-current-chap")["value"].split("-")[1:]))

Methods

def breadcrumb(soup: bs4.BeautifulSoup)
Expand source code
def breadcrumb(soup: BeautifulSoup):
    return literal_eval(soup.select_one("ol.breadcrumb .active").text.split()[-1])
def wmcc(soup)
Expand source code
def wmcc(soup):
    return literal_eval(".".join(soup.select_one("#wp-manga-current-chap")["value"].split("-")[1:]))
class manga_id_fn
Expand source code
class manga_id_fn:
    def setsu(soup) -> str:
        return soup.select_one("#manga-chapters-holder")["data-id"]

Methods

def setsu(soup) ‑> str
Expand source code
def setsu(soup) -> str:
    return soup.select_one("#manga-chapters-holder")["data-id"]
class rch_fn
Expand source code
class rch_fn:
    def msa(url: str, base_url: str, **kwargs: Dict[str, Any]):
        url = f"{base_url}/manga/{urel(url).parts[2]}/ajax/chapters/"
        return soup(url, method="post")
    def setsu(url: str, base_url: str, manga_id_fn: Callable[[BeautifulSoup], Union[int, float]], **kwargs: Dict[str, Any]):
        data = {"action": "manga_get_chapters", "manga": str(manga_id_fn(soup(url)))}
        return soup(f"{base_url}/wp-admin/admin-ajax.php", method="post", data=data)

Methods

def msa(url: str, base_url: str, **kwargs: Dict[str, Any])
Expand source code
def msa(url: str, base_url: str, **kwargs: Dict[str, Any]):
    url = f"{base_url}/manga/{urel(url).parts[2]}/ajax/chapters/"
    return soup(url, method="post")
def setsu(url: str, base_url: str, manga_id_fn: Callable[[bs4.BeautifulSoup], Union[int, float]], **kwargs: Dict[str, Any])
Expand source code
def setsu(url: str, base_url: str, manga_id_fn: Callable[[BeautifulSoup], Union[int, float]], **kwargs: Dict[str, Any]):
    data = {"action": "manga_get_chapters", "manga": str(manga_id_fn(soup(url)))}
    return soup(f"{base_url}/wp-admin/admin-ajax.php", method="post", data=data)
class rch_num_fn
Expand source code
class rch_num_fn:
    def tdo(url):
        return literal_eval(".".join(urel(url).parts[3].split("-")[1:]))

Methods

def tdo(url)
Expand source code
def tdo(url):
    return literal_eval(".".join(urel(url).parts[3].split("-")[1:]))
class template (prov: module)
Expand source code
class template:
    def __init__(self, prov: ModuleType) -> None:
        attr = {
            "base_url": None,
            "cover_src": "src",
            "ch_num_fn": ch_num_fn.breadcrumb,
            "date_format": r"%B %d, %Y",
            "manga_id_fn": manga_id_fn.setsu,
            "rch_fn": soup,
            "rch_num_fn": rch_num_fn.tdo,
            "scanlator": None,
            "search_query_string": "post_type=wp-manga",
            "src": "src",
            "title_fn": None,
            "total_cs": ".c-blog__heading h1",
        }
        self.prov = prov
        for k, v in attr.items():
            setattr(self, k, getattr(prov, k, v))
        rfk = ["manga_id_fn"]
        if isinstance(self.rch_fn, str):
            self.rch_fn = partial(
                getattr(rch_fn, self.rch_fn),
                base_url=self.base_url,
                **{i: getattr(self, i, None) for i in rfk}
            )
        for i in ["ch_num_fn", "rch_num_fn"]:
            gi = getattr(self, i)
            if isinstance(gi, str):
                setattr(self, i, getattr(globals()[i], getattr(prov, i, gi), gi))

        self.template = import_module(f".{self.prov.template}", "mangdl.api.providers.templates").template

    def ch_fn(self, url: str) -> List[str]:
        op = []
        for i in soup(f"{url}?style=list").select(".page-break img"):
            op.append(sanitize_text(i[self.src]))
        return op

    def chapter(self, url: str) -> Ch:
        ms = soup(url)
        return Ch(
            url              = url,
            ch               = self.ch_num_fn(ms),
            vol              = None,
            title            = sanitize_text(ms.select_one("ol.breadcrumb .active").text.split("-")[-1]),
            scanlator_groups = [self.scanlator],
            imgs             = self.ch_fn(url),
        )

    def chdls(self, url: str, chs: int=0) -> List[Dict[Union[float, int, None], str]]:
        op = []
        if chs:
            for c in self.rch_fn(url).select("li.wp-manga-chapter    a"):
                cch = c["href"]
                if chs == 2:
                    cch = self.chapter(cch)
                op.append({self.rch_num_fn(c["href"]): cch})
        return op

    def manga(self, url: str, chs: int=0) -> Manga:
        ms = soup(url)
        meta = {}
        for c in ["post-content_item", "post-status"]:
            for m in ms.select(f"div.{c}"):
                v = m.select_one(".summary-content")
                idx = sanitize_text(m.select_one("h5").text)
                if v:
                    meta[idx] = sanitize_text(v.text)
                else:
                    meta[idx] = [sanitize_text(i.text) for i in m.select("a")]

        def mst(s: str, pp: Callable[[str], List[Any]]=lambda x: x):
            return pp(sanitize_text(meta.get(s))) if meta.get(s) else []

        rd = [sanitize_text(i.text) for i in self.rch_fn(url).select(".chapter-release-date")]
        def dates(idx: int):
            op = "1970-01-01T00:00:00"
            if rd:
                rop = rd[idx]
                if rop:
                    op = dt(rop, self.date_format)
            return op
        return Manga(
            url             = url,
            covers          = [ms.select_one(".summary_image img")[self.cover_src]],
            title           = self.title_fn(ms) if self.title_fn else sanitize_text(ms.select_one("div.post-title h1").text),
            alt_titles      = mst("Alternative"),
            author          = mst("Author(s)", lambda x: x.split(",")),
            artist          = mst("Artist(s)", lambda x: x.split(",")),
            status          = {k: v for v, k in enumerate(["ongoing", "completed", "on hold"])}.get(meta["Status"].lower(), -1),
            genres          = mst("Genre(s)", lambda x: x.split(",")),
            updated_at      = dates(0),
            created_at      = dates(-1),
            description     = sanitize_text(getattr(ms.select_one(".summary__content"), "text", "No description available.")),
            chapters        = self.chdls(url, chs),
        )

    def dl_search(self, title: str, **kwargs: Dict[str, Any]):
        global total
        total = 0
        rpa = getattr(self.prov, "rpa", 12)
        cs_manga = getattr(self.prov, "cs_manga", "div.post-title")
        manga_check = getattr(self.prov, "manga_check", lambda x: True)
        title_fn = getattr(self.prov, "title_fn", lambda x: x.select_one("a").text)
        link_fn = getattr(self.prov, "link_fn", lambda x: x.select_one("a")["href"])
        sr = {}
        def pr(num: int):
            global total
            url = f"{self.base_url}/page/{num}?s={quote_plus(title)}&{self.search_query_string}"
            ms = soup(url)
            ts = ms.select(cs_manga)
            if not total:
                total = int(sanitize_text(ms.select_one(self.total_cs).text).split()[0])
            for r in ts:
                if manga_check(r):
                    sr[title_fn(r)] = link_fn(r)
            return len(ts)
        i = 1
        cp = pr(i)
        while cp // rpa and (rpa * i) < total:
            i += 1
            cp = pr(i)
        return sr

    def cli_search(self, title: str, **kwargs: Dict[str, Any]) -> Dict[str, str]:
        return self.dl_search(title, **kwargs)

    def dl(self, url: str, **kwargs: Dict[str, Any]):
        ms = soup(url)
        Downloader(self.ch_fn, **kwargs).dl_chdls(self.chdls(url), sanitize_text(ms.select_one("div.post-title h1").text))

    def cli_dl(self, title: str, **kwargs: Dict[str, Any]):
        Downloader(self.ch_fn, **kwargs).cli(self.template(self.prov).cli_search, partial(self.chdls), title)

Methods

def ch_fn(self, url: str) ‑> List[str]
Expand source code
def ch_fn(self, url: str) -> List[str]:
    op = []
    for i in soup(f"{url}?style=list").select(".page-break img"):
        op.append(sanitize_text(i[self.src]))
    return op
def chapter(self, url: str) ‑> Ch
Expand source code
def chapter(self, url: str) -> Ch:
    ms = soup(url)
    return Ch(
        url              = url,
        ch               = self.ch_num_fn(ms),
        vol              = None,
        title            = sanitize_text(ms.select_one("ol.breadcrumb .active").text.split("-")[-1]),
        scanlator_groups = [self.scanlator],
        imgs             = self.ch_fn(url),
    )
def chdls(self, url: str, chs: int = 0) ‑> List[Dict[Union[float, int, ForwardRef(None)], str]]
Expand source code
def chdls(self, url: str, chs: int=0) -> List[Dict[Union[float, int, None], str]]:
    op = []
    if chs:
        for c in self.rch_fn(url).select("li.wp-manga-chapter    a"):
            cch = c["href"]
            if chs == 2:
                cch = self.chapter(cch)
            op.append({self.rch_num_fn(c["href"]): cch})
    return op
def cli_dl(self, title: str, **kwargs: Dict[str, Any])
Expand source code
def cli_dl(self, title: str, **kwargs: Dict[str, Any]):
    Downloader(self.ch_fn, **kwargs).cli(self.template(self.prov).cli_search, partial(self.chdls), title)
Expand source code
def cli_search(self, title: str, **kwargs: Dict[str, Any]) -> Dict[str, str]:
    return self.dl_search(title, **kwargs)
def dl(self, url: str, **kwargs: Dict[str, Any])
Expand source code
def dl(self, url: str, **kwargs: Dict[str, Any]):
    ms = soup(url)
    Downloader(self.ch_fn, **kwargs).dl_chdls(self.chdls(url), sanitize_text(ms.select_one("div.post-title h1").text))
Expand source code
def dl_search(self, title: str, **kwargs: Dict[str, Any]):
    global total
    total = 0
    rpa = getattr(self.prov, "rpa", 12)
    cs_manga = getattr(self.prov, "cs_manga", "div.post-title")
    manga_check = getattr(self.prov, "manga_check", lambda x: True)
    title_fn = getattr(self.prov, "title_fn", lambda x: x.select_one("a").text)
    link_fn = getattr(self.prov, "link_fn", lambda x: x.select_one("a")["href"])
    sr = {}
    def pr(num: int):
        global total
        url = f"{self.base_url}/page/{num}?s={quote_plus(title)}&{self.search_query_string}"
        ms = soup(url)
        ts = ms.select(cs_manga)
        if not total:
            total = int(sanitize_text(ms.select_one(self.total_cs).text).split()[0])
        for r in ts:
            if manga_check(r):
                sr[title_fn(r)] = link_fn(r)
        return len(ts)
    i = 1
    cp = pr(i)
    while cp // rpa and (rpa * i) < total:
        i += 1
        cp = pr(i)
    return sr
def manga(self, url: str, chs: int = 0) ‑> Manga
Expand source code
def manga(self, url: str, chs: int=0) -> Manga:
    ms = soup(url)
    meta = {}
    for c in ["post-content_item", "post-status"]:
        for m in ms.select(f"div.{c}"):
            v = m.select_one(".summary-content")
            idx = sanitize_text(m.select_one("h5").text)
            if v:
                meta[idx] = sanitize_text(v.text)
            else:
                meta[idx] = [sanitize_text(i.text) for i in m.select("a")]

    def mst(s: str, pp: Callable[[str], List[Any]]=lambda x: x):
        return pp(sanitize_text(meta.get(s))) if meta.get(s) else []

    rd = [sanitize_text(i.text) for i in self.rch_fn(url).select(".chapter-release-date")]
    def dates(idx: int):
        op = "1970-01-01T00:00:00"
        if rd:
            rop = rd[idx]
            if rop:
                op = dt(rop, self.date_format)
        return op
    return Manga(
        url             = url,
        covers          = [ms.select_one(".summary_image img")[self.cover_src]],
        title           = self.title_fn(ms) if self.title_fn else sanitize_text(ms.select_one("div.post-title h1").text),
        alt_titles      = mst("Alternative"),
        author          = mst("Author(s)", lambda x: x.split(",")),
        artist          = mst("Artist(s)", lambda x: x.split(",")),
        status          = {k: v for v, k in enumerate(["ongoing", "completed", "on hold"])}.get(meta["Status"].lower(), -1),
        genres          = mst("Genre(s)", lambda x: x.split(",")),
        updated_at      = dates(0),
        created_at      = dates(-1),
        description     = sanitize_text(getattr(ms.select_one(".summary__content"), "text", "No description available.")),
        chapters        = self.chdls(url, chs),
    )