1
0
mirror of https://github.com/mikf/gallery-dl.git synced 2024-11-22 18:53:21 +01:00
gallery-dl/scripts/supportedsites.py

369 lines
10 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Generate a reStructuredText document with all supported sites"""
import os
import sys
2019-02-20 19:25:41 +01:00
import collections
import util
from gallery_dl import extractor
CATEGORY_MAP = {
2017-07-15 15:01:30 +02:00
"2chan" : "Futaba Channel",
"35photo" : "35PHOTO",
"adultempire" : "Adult Empire",
2017-07-15 15:01:30 +02:00
"archivedmoe" : "Archived.Moe",
"archiveofsins" : "Archive of Sins",
"artstation" : "ArtStation",
"aryion" : "Eka's Portal",
"b4k" : "arch.b4k.co",
"baraag" : "baraag",
"bcy" : "半次元",
"bobx" : "BobX",
"deviantart" : "DeviantArt",
"dokireader" : "Doki Reader",
"dynastyscans" : "Dynasty Reader",
"e621" : "e621",
"erome" : "EroMe",
"e-hentai" : "E-Hentai",
"exhentai" : "ExHentai",
"fallenangels" : "Fallen Angels Scans",
"fashionnova" : "Fashion Nova",
2020-02-11 19:51:24 +01:00
"furaffinity" : "Fur Affinity",
"hbrowse" : "HBrowse",
"hentai2read" : "Hentai2Read",
"hentaicafe" : "Hentai Cafe",
"hentaifoundry" : "Hentai Foundry",
"hentaifox" : "HentaiFox",
"hentaihand" : "HentaiHand",
"hentaihere" : "HentaiHere",
"hitomi" : "Hitomi.la",
"idolcomplex" : "Idol Complex",
"imagebam" : "ImageBam",
"imagefap" : "ImageFap",
2019-07-30 23:02:21 +02:00
"imgbb" : "ImgBB",
"imgbox" : "imgbox",
"imagechest" : "ImageChest",
"imgth" : "imgth",
"imgur" : "imgur",
"jaiminisbox" : "Jaimini's Box",
"kabeuchi" : "かべうち",
"kireicake" : "Kirei Cake",
"kissmanga" : "KissManga",
"lineblog" : "LINE BLOG",
"livedoor" : "livedoor Blog",
"mangadex" : "MangaDex",
"mangafox" : "Manga Fox",
"mangahere" : "Manga Here",
"mangakakalot" : "MangaKakalot",
"mangapark" : "MangaPark",
"mangastream" : "Manga Stream",
"mastodon.social": "mastodon.social",
"myhentaigallery": "My Hentai Gallery",
"myportfolio" : "Adobe Portfolio",
"naverwebtoon" : "NaverWebtoon",
"nhentai" : "nhentai",
"nijie" : "nijie",
"nozomi" : "Nozomi.la",
"nsfwalbum" : "NSFWalbum.com",
2017-07-15 15:01:30 +02:00
"nyafuu" : "Nyafuu Archive",
"paheal" : "rule #34",
2021-01-22 19:41:50 +01:00
"photovogue" : "PhotoVogue",
"powermanga" : "PowerManga",
"readcomiconline": "Read Comic Online",
2017-07-24 10:50:40 +02:00
"rbt" : "RebeccaBlackTech",
2020-05-10 00:31:42 +02:00
"redgifs" : "RedGIFs",
"rule34" : "Rule 34",
"sankaku" : "Sankaku Channel",
"sankakucomplex" : "Sankaku Complex",
"seaotterscans" : "Sea Otter Scans",
"seiga" : "Niconico Seiga",
"senmanga" : "Sen Manga",
"sensescans" : "Sense-Scans",
"sexcom" : "Sex.com",
"simplyhentai" : "Simply Hentai",
2019-06-09 21:59:22 +02:00
"slickpic" : "SlickPic",
"slideshare" : "SlideShare",
"smugmug" : "SmugMug",
"speakerdeck" : "Speaker Deck",
"subscribestar" : "SubscribeStar",
2017-07-24 10:50:40 +02:00
"thebarchive" : "The /b/ Archive",
"tumblrgallery" : "TumblrGallery",
"vanillarock" : "もえぴりあ",
2019-07-22 22:15:36 +02:00
"vsco" : "VSCO",
"webtoons" : "Webtoon",
"wikiart" : "WikiArt.org",
"worldthree" : "World Three",
"xhamster" : "xHamster",
"xvideos" : "XVideos",
"yuki" : "yuki.la 4chan archive",
}
SUBCATEGORY_MAP = {
"doujin" : "Doujin",
"gallery": "Galleries",
"image" : "individual Images",
"index" : "Site Index",
"issue" : "Comic Issues",
"manga" : "Manga",
"popular": "Popular Images",
"recent" : "Recent Images",
"search" : "Search Results",
"status" : "Images from Statuses",
"tag" : "Tag Searches",
"user" : "User Profiles",
"following" : "",
"related-pin" : "related Pins",
"related-board": "",
"artstation": {
"artwork": "Artwork Listings",
},
"deviantart": {
"stash": "Sta.sh",
},
"hentaifoundry": {
"story": "",
},
2020-03-16 22:57:30 +01:00
"instagram": {
"posts": "",
2020-03-16 22:57:30 +01:00
"saved": "Saved Posts",
},
"newgrounds": {
"art" : "Art",
"audio": "Audio",
"media": "Media Files",
},
"pinterest": {
"board": "",
"pinit": "pin.it Links",
},
"pixiv": {
"me" : "pixiv.me Links",
"work": "individual Images",
},
"sankaku": {
"books": "Book Searches",
},
"smugmug": {
"path": "Images from Users and Folders",
},
"twitter": {
"media": "Media Timelines",
"list-members": "List Members",
},
"wallhaven": {
"collections": "",
},
"weasyl": {
"journals" : "",
"submissions": "",
},
"wikiart": {
"artists": "Artist Listings",
},
}
_OAUTH = "`OAuth <https://github.com/mikf/gallery-dl#oauth>`__"
_COOKIES = "`Cookies <https://github.com/mikf/gallery-dl#cookies>`__"
_APIKEY_DB = "`API Key <configuration.rst#extractorderpibooruapi-key>`__"
_APIKEY_WH = "`API Key <configuration.rst#extractorwallhavenapi-key>`__"
_APIKEY_WY = "`API Key <configuration.rst#extractorweasylapi-key>`__"
AUTH_MAP = {
"aryion" : "Supported",
"baraag" : _OAUTH,
"danbooru" : "Supported",
"derpibooru" : _APIKEY_DB,
"deviantart" : _OAUTH,
"e621" : "Supported",
"e-hentai" : "Supported",
"exhentai" : "Supported",
"flickr" : _OAUTH,
"furaffinity" : _COOKIES,
"idolcomplex" : "Supported",
"imgbb" : "Supported",
"inkbunny" : "Supported",
"instagram" : "Supported",
"mangoxo" : "Supported",
"mastodon.social": _OAUTH,
"newgrounds" : "Supported",
"nijie" : "Required",
"patreon" : _COOKIES,
"pawoo" : _OAUTH,
"pinterest" : "Supported",
"pixiv" : _OAUTH,
"reddit" : _OAUTH,
"sankaku" : "Supported",
"seiga" : "Required",
"smugmug" : _OAUTH,
"subscribestar" : "Supported",
"tsumino" : "Supported",
"tumblr" : _OAUTH,
"twitter" : "Supported",
"wallhaven" : _APIKEY_WH,
"weasyl" : _APIKEY_WY,
}
IGNORE_LIST = (
2019-02-20 19:25:41 +01:00
"directlink",
"oauth",
2019-02-20 19:25:41 +01:00
"recursive",
"test",
)
2019-02-20 19:25:41 +01:00
def domain(cls):
"""Return the web-domain related to an extractor class"""
try:
url = sys.modules[cls.__module__].__doc__.split()[-1]
if url.startswith("http"):
return url
except Exception:
pass
2019-02-20 19:25:41 +01:00
if hasattr(cls, "root") and cls.root:
return cls.root + "/"
2018-09-28 12:39:05 +02:00
2019-02-20 19:25:41 +01:00
if hasattr(cls, "https"):
scheme = "https" if cls.https else "http"
netloc = cls.__doc__.split()[-1]
return "{}://{}/".format(scheme, netloc)
2019-02-20 19:25:41 +01:00
test = next(cls._get_tests(), None)
if test:
url = test[0]
return url[:url.find("/", 8)+1]
2019-02-20 19:25:41 +01:00
return ""
2021-02-20 22:31:21 +01:00
def category_text(c):
2019-02-20 19:25:41 +01:00
"""Return a human-readable representation of a category"""
return CATEGORY_MAP.get(c) or c.capitalize()
2018-09-28 12:39:05 +02:00
2021-02-20 22:31:21 +01:00
def subcategory_text(c, sc):
2019-02-20 19:25:41 +01:00
"""Return a human-readable representation of a subcategory"""
if c in SUBCATEGORY_MAP:
scm = SUBCATEGORY_MAP[c]
if sc in scm:
return scm[sc]
2019-02-20 19:25:41 +01:00
if sc in SUBCATEGORY_MAP:
return SUBCATEGORY_MAP[sc]
2019-02-20 19:25:41 +01:00
sc = sc.capitalize()
return sc if sc.endswith("s") else sc + "s"
2021-02-20 22:31:21 +01:00
def category_key(c):
2019-02-20 19:25:41 +01:00
"""Generate sorting keys by category"""
2021-02-20 22:31:21 +01:00
return category_text(c[0]).lower()
2021-02-20 22:31:21 +01:00
def subcategory_key(sc):
2019-02-20 19:25:41 +01:00
"""Generate sorting keys by subcategory"""
2021-02-20 22:31:21 +01:00
return "A" if sc == "issue" else sc
2017-07-15 15:01:30 +02:00
2019-02-20 19:25:41 +01:00
def build_extractor_list():
"""Generate a sorted list of lists of extractor classes"""
2021-02-20 22:31:21 +01:00
categories = collections.defaultdict(list)
domains = {}
2021-02-20 22:31:21 +01:00
for extr in extractor._list_classes():
category = extr.category
if category in IGNORE_LIST:
continue
2021-02-20 22:31:21 +01:00
if category:
categories[category].append(extr.subcategory)
if category not in domains:
domains[category] = domain(extr)
else:
for category, root in extr.instances:
categories[category].append(extr.subcategory)
if category not in domains:
domains[category] = root + "/"
2021-02-20 22:31:21 +01:00
# sort subcategory lists
for subcategories in categories.values():
subcategories.sort(key=subcategory_key)
2021-02-20 22:31:21 +01:00
# add e-hentai.org
categories["e-hentai"] = categories["exhentai"]
domains["e-hentai"] = domains["exhentai"].replace("x", "-")
2021-02-20 22:31:21 +01:00
return categories, domains
2019-02-20 19:25:41 +01:00
# define table columns
COLUMNS = (
("Site", 20,
2021-02-20 22:31:21 +01:00
lambda c, scs, d: category_text(c)),
2019-02-20 19:25:41 +01:00
("URL" , 35,
2021-02-20 22:31:21 +01:00
lambda c, scs, d: d),
2019-02-20 19:25:41 +01:00
("Capabilities", 50,
2021-02-20 22:31:21 +01:00
lambda c, scs, d: ", ".join(subcategory_text(c, sc) for sc in scs
if subcategory_text(c, sc))),
2019-02-20 19:25:41 +01:00
("Authentication", 16,
2021-02-20 22:31:21 +01:00
lambda c, scs, d: AUTH_MAP.get(c, "")),
2019-02-20 19:25:41 +01:00
)
2019-01-09 14:21:19 +01:00
2021-02-20 22:31:21 +01:00
def write_output(fp, columns, categories, domains):
2019-02-20 19:25:41 +01:00
def pad(output, col, category=None):
size = col[1]
output = output if isinstance(output, str) else col[2](output)
if len(output) > size and col[0][0] != "A":
2019-02-20 19:25:41 +01:00
sub = "|{}-{}|".format(category, col[0][0])
subs.append((sub, output))
output = sub
2019-02-20 19:25:41 +01:00
return output + " " * (size - len(output))
2021-02-20 22:31:21 +01:00
w = fp.write
2019-02-20 19:25:41 +01:00
subs = []
2019-02-20 19:25:41 +01:00
# caption
w("Supported Sites\n")
w("===============\n")
w("..\n generated by {}\n\n".format(
"/".join(os.path.normpath(__file__).split(os.sep)[-2:])))
w("Consider all sites to be NSFW, unless otherwise known.\n\n")
2019-02-20 19:25:41 +01:00
# table head
sep = " ".join("=" * c[1] for c in columns) + "\n"
w(sep)
w(" ".join(pad(c[0], c) for c in columns).strip() + "\n")
w(sep)
2019-02-20 19:25:41 +01:00
# table body
2021-02-20 22:31:21 +01:00
clist = sorted(categories.items(), key=category_key)
for category, subcategories in clist:
domain = domains[category]
2019-02-20 19:25:41 +01:00
w(" ".join(
2021-02-20 22:31:21 +01:00
pad(col[2](category, subcategories, domain), col, category)
2019-02-20 19:25:41 +01:00
for col in columns
).strip())
w("\n")
2019-02-20 19:25:41 +01:00
# table bottom
w(sep)
w("\n")
2019-02-20 19:25:41 +01:00
# substitutions
for sub, value in subs:
w(".. {} replace:: {}\n".format(sub, value))
2021-02-20 22:31:21 +01:00
categories, domains = build_extractor_list()
outfile = sys.argv[1] if len(sys.argv) > 1 else "supportedsites.rst"
with open(util.path("docs", outfile), "w") as file:
2021-02-20 22:31:21 +01:00
write_output(file, COLUMNS, categories, domains)