Merge branch 'op+': use '+' for 2-element string concatenations
This commit is contained in:
@@ -20,12 +20,12 @@ class _2chThreadExtractor(Extractor):
|
||||
directory_fmt = ("{category}", "{board}", "{thread} {title}")
|
||||
filename_fmt = "{tim}{filename:? //}.{extension}"
|
||||
archive_fmt = "{board}_{thread}_{tim}"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/res/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/res/(\d+)"
|
||||
example = "https://2ch.org/a/res/12345.html"
|
||||
|
||||
def __init__(self, match):
|
||||
tld = match[1]
|
||||
self.root = f"https://2ch.{'org' if tld == 'hk' else tld}"
|
||||
self.root = "https://2ch." + ("org" if tld == "hk" else tld)
|
||||
Extractor.__init__(self, match)
|
||||
|
||||
def items(self):
|
||||
@@ -66,19 +66,19 @@ class _2chBoardExtractor(Extractor):
|
||||
category = "2ch"
|
||||
subcategory = "board"
|
||||
root = "https://2ch.org"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/?$"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/?$"
|
||||
example = "https://2ch.org/a/"
|
||||
|
||||
def __init__(self, match):
|
||||
tld = match[1]
|
||||
self.root = f"https://2ch.{'su' if tld == 'hk' else tld}"
|
||||
self.root = "https://2ch." + ("org" if tld == "hk" else tld)
|
||||
Extractor.__init__(self, match)
|
||||
|
||||
def items(self):
|
||||
base = f"{self.root}/{self.groups[1]}"
|
||||
|
||||
# index page
|
||||
url = f"{base}/index.json"
|
||||
url = base + "/index.json"
|
||||
index = self.request_json(url)
|
||||
index["_extractor"] = _2chThreadExtractor
|
||||
for thread in index["threads"]:
|
||||
|
||||
@@ -34,7 +34,7 @@ class _2chenThreadExtractor(_2chenExtractor):
|
||||
directory_fmt = ("{category}", "{board}", "{thread} {title}")
|
||||
filename_fmt = "{time} {filename}.{extension}"
|
||||
archive_fmt = "{board}_{thread}_{no}_{time}"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/(\d+)"
|
||||
example = "https://sturdychan.help/a/12345/"
|
||||
|
||||
def items(self):
|
||||
@@ -84,7 +84,7 @@ class _2chenThreadExtractor(_2chenExtractor):
|
||||
class _2chenBoardExtractor(_2chenExtractor):
|
||||
"""Extractor for 2chen boards"""
|
||||
subcategory = "board"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)(?:/catalog|/?$)"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)(?:/catalog|/?$)"
|
||||
example = "https://sturdychan.help/a/"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -92,7 +92,7 @@ class _500pxExtractor(Extractor):
|
||||
class _500pxUserExtractor(_500pxExtractor):
|
||||
"""Extractor for photos from a user's photostream on 500px.com"""
|
||||
subcategory = "user"
|
||||
pattern = rf"{BASE_PATTERN}/(?!photo/|liked)(?:p/)?([^/?#]+)/?(?:$|[?#])"
|
||||
pattern = BASE_PATTERN + r"/(?!photo/|liked)(?:p/)?([^/?#]+)/?(?:$|[?#])"
|
||||
example = "https://500px.com/USER"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -121,8 +121,8 @@ class _500pxGalleryExtractor(_500pxExtractor):
|
||||
"""Extractor for photo galleries on 500px.com"""
|
||||
subcategory = "gallery"
|
||||
directory_fmt = ("{category}", "{user[username]}", "{gallery[name]}")
|
||||
pattern = (rf"{BASE_PATTERN}/(?!photo/)(?:p/)?"
|
||||
rf"([^/?#]+)/galleries/([^/?#]+)")
|
||||
pattern = (BASE_PATTERN + r"/(?!photo/)(?:p/)?"
|
||||
r"([^/?#]+)/galleries/([^/?#]+)")
|
||||
example = "https://500px.com/USER/galleries/GALLERY"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -178,7 +178,7 @@ class _500pxGalleryExtractor(_500pxExtractor):
|
||||
class _500pxFavoriteExtractor(_500pxExtractor):
|
||||
"""Extractor for favorite 500px photos"""
|
||||
subcategory = "favorite"
|
||||
pattern = rf"{BASE_PATTERN}/liked/?$"
|
||||
pattern = BASE_PATTERN + r"/liked/?$"
|
||||
example = "https://500px.com/liked"
|
||||
|
||||
def photos(self):
|
||||
@@ -202,7 +202,7 @@ class _500pxFavoriteExtractor(_500pxExtractor):
|
||||
class _500pxImageExtractor(_500pxExtractor):
|
||||
"""Extractor for individual images from 500px.com"""
|
||||
subcategory = "image"
|
||||
pattern = rf"{BASE_PATTERN}/photo/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/photo/(\d+)"
|
||||
example = "https://500px.com/photo/12345/TITLE"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -69,7 +69,7 @@ class _8chanThreadExtractor(_8chanExtractor):
|
||||
"{threadId} {subject[:50]}")
|
||||
filename_fmt = "{postId}{num:?-//} {filename[:200]}.{extension}"
|
||||
archive_fmt = "{boardUri}_{postId}_{num}"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/(?:res|last)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/(?:res|last)/(\d+)"
|
||||
example = "https://8chan.moe/a/res/12345.html"
|
||||
|
||||
def items(self):
|
||||
@@ -107,7 +107,7 @@ class _8chanThreadExtractor(_8chanExtractor):
|
||||
class _8chanBoardExtractor(_8chanExtractor):
|
||||
"""Extractor for 8chan boards"""
|
||||
subcategory = "board"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/(?:(\d+)\.html)?$"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/(?:(\d+)\.html)?$"
|
||||
example = "https://8chan.moe/a/"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -81,7 +81,7 @@ class AgnphTagExtractor(AgnphExtractor):
|
||||
subcategory = "tag"
|
||||
directory_fmt = ("{category}", "{search_tags}")
|
||||
archive_fmt = "t_{search_tags}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/gallery/post/(?:\?([^#]+))?$"
|
||||
pattern = BASE_PATTERN + r"/gallery/post/(?:\?([^#]+))?$"
|
||||
example = "https://agn.ph/gallery/post/?search=TAG"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -99,7 +99,7 @@ class AgnphTagExtractor(AgnphExtractor):
|
||||
class AgnphPostExtractor(AgnphExtractor):
|
||||
subcategory = "post"
|
||||
archive_fmt = "{id}"
|
||||
pattern = rf"{BASE_PATTERN}/gallery/post/show/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/gallery/post/show/(\d+)"
|
||||
example = "https://agn.ph/gallery/post/show/12345/"
|
||||
|
||||
def posts(self):
|
||||
|
||||
@@ -118,7 +118,7 @@ class Ao3WorkExtractor(Ao3Extractor):
|
||||
directory_fmt = ("{category}", "{author}")
|
||||
filename_fmt = "{id} {title}.{extension}"
|
||||
archive_fmt = "{id}.{extension}"
|
||||
pattern = rf"{BASE_PATTERN}/works/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/works/(\d+)"
|
||||
example = "https://archiveofourown.org/works/12345"
|
||||
|
||||
def _init(self):
|
||||
@@ -233,28 +233,28 @@ class Ao3WorkExtractor(Ao3Extractor):
|
||||
class Ao3SeriesExtractor(Ao3Extractor):
|
||||
"""Extractor for AO3 works of a series"""
|
||||
subcategory = "series"
|
||||
pattern = rf"{BASE_PATTERN}(/series/(\d+))"
|
||||
pattern = BASE_PATTERN + r"(/series/(\d+))"
|
||||
example = "https://archiveofourown.org/series/12345"
|
||||
|
||||
|
||||
class Ao3TagExtractor(Ao3Extractor):
|
||||
"""Extractor for AO3 works by tag"""
|
||||
subcategory = "tag"
|
||||
pattern = rf"{BASE_PATTERN}(/tags/([^/?#]+)/works(?:/?\?.+)?)"
|
||||
pattern = BASE_PATTERN + r"(/tags/([^/?#]+)/works(?:/?\?.+)?)"
|
||||
example = "https://archiveofourown.org/tags/TAG/works"
|
||||
|
||||
|
||||
class Ao3SearchExtractor(Ao3Extractor):
|
||||
"""Extractor for AO3 search results"""
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}(/works/search/?\?.+)"
|
||||
pattern = BASE_PATTERN + r"(/works/search/?\?.+)"
|
||||
example = "https://archiveofourown.org/works/search?work_search[query]=air"
|
||||
|
||||
|
||||
class Ao3UserExtractor(Dispatch, Ao3Extractor):
|
||||
"""Extractor for an AO3 user profile"""
|
||||
pattern = (rf"{BASE_PATTERN}/users/([^/?#]+(?:/pseuds/[^/?#]+)?)"
|
||||
rf"(?:/profile)?/?(?:$|\?|#)")
|
||||
pattern = (BASE_PATTERN + r"/users/([^/?#]+(?:/pseuds/[^/?#]+)?)"
|
||||
r"(?:/profile)?/?(?:$|\?|#)")
|
||||
example = "https://archiveofourown.org/users/USER"
|
||||
|
||||
def items(self):
|
||||
@@ -269,16 +269,16 @@ class Ao3UserExtractor(Dispatch, Ao3Extractor):
|
||||
class Ao3UserWorksExtractor(Ao3Extractor):
|
||||
"""Extractor for works of an AO3 user"""
|
||||
subcategory = "user-works"
|
||||
pattern = (rf"{BASE_PATTERN}(/users/([^/?#]+)/(?:pseuds/([^/?#]+)/)?"
|
||||
rf"works(?:/?\?.+)?)")
|
||||
pattern = (BASE_PATTERN + r"(/users/([^/?#]+)/(?:pseuds/([^/?#]+)/)?"
|
||||
r"works(?:/?\?.+)?)")
|
||||
example = "https://archiveofourown.org/users/USER/works"
|
||||
|
||||
|
||||
class Ao3UserSeriesExtractor(Ao3Extractor):
|
||||
"""Extractor for series of an AO3 user"""
|
||||
subcategory = "user-series"
|
||||
pattern = (rf"{BASE_PATTERN}(/users/([^/?#]+)/(?:pseuds/([^/?#]+)/)?"
|
||||
rf"series(?:/?\?.+)?)")
|
||||
pattern = (BASE_PATTERN + r"(/users/([^/?#]+)/(?:pseuds/([^/?#]+)/)?"
|
||||
r"series(?:/?\?.+)?)")
|
||||
example = "https://archiveofourown.org/users/USER/series"
|
||||
|
||||
def items(self):
|
||||
@@ -297,8 +297,8 @@ class Ao3UserSeriesExtractor(Ao3Extractor):
|
||||
class Ao3UserBookmarkExtractor(Ao3Extractor):
|
||||
"""Extractor for bookmarked works of an AO3 user"""
|
||||
subcategory = "user-bookmark"
|
||||
pattern = (rf"{BASE_PATTERN}(/users/([^/?#]+)/(?:pseuds/([^/?#]+)/)?"
|
||||
rf"bookmarks(?:/?\?.+)?)")
|
||||
pattern = (BASE_PATTERN + r"(/users/([^/?#]+)/(?:pseuds/([^/?#]+)/)?"
|
||||
r"bookmarks(?:/?\?.+)?)")
|
||||
example = "https://archiveofourown.org/users/USER/bookmarks"
|
||||
|
||||
def items(self):
|
||||
@@ -308,7 +308,7 @@ class Ao3UserBookmarkExtractor(Ao3Extractor):
|
||||
class Ao3SubscriptionsExtractor(Ao3Extractor):
|
||||
"""Extractor for your AO3 account's subscriptions"""
|
||||
subcategory = "subscriptions"
|
||||
pattern = rf"{BASE_PATTERN}(/users/([^/?#]+)/subscriptions(?:/?\?.+)?)"
|
||||
pattern = BASE_PATTERN + r"(/users/([^/?#]+)/subscriptions(?:/?\?.+)?)"
|
||||
example = "https://archiveofourown.org/users/USER/subscriptions"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -36,7 +36,7 @@ class ArcalivePostExtractor(ArcaliveExtractor):
|
||||
directory_fmt = ("{category}", "{boardSlug}")
|
||||
filename_fmt = "{id}_{num}{title:? //[b:230]}.{extension}"
|
||||
archive_fmt = "{id}_{num}"
|
||||
pattern = rf"{BASE_PATTERN}/b/(?:\w+)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/b/(?:\w+)/(\d+)"
|
||||
example = "https://arca.live/b/breaking/123456789"
|
||||
|
||||
def items(self):
|
||||
@@ -84,7 +84,7 @@ class ArcalivePostExtractor(ArcaliveExtractor):
|
||||
url = src
|
||||
|
||||
fallback = ()
|
||||
query = f"?type=orig&{query}"
|
||||
query = "?type=orig&" + query
|
||||
if orig := text.extr(media, 'data-orig="', '"'):
|
||||
path, _, ext = url.rpartition(".")
|
||||
if ext != orig:
|
||||
@@ -115,7 +115,7 @@ class ArcalivePostExtractor(ArcaliveExtractor):
|
||||
class ArcaliveBoardExtractor(ArcaliveExtractor):
|
||||
"""Extractor for an arca.live board's posts"""
|
||||
subcategory = "board"
|
||||
pattern = rf"{BASE_PATTERN}/b/([^/?#]+)/?(?:\?([^#]+))?$"
|
||||
pattern = BASE_PATTERN + r"/b/([^/?#]+)/?(?:\?([^#]+))?$"
|
||||
example = "https://arca.live/b/breaking"
|
||||
|
||||
def articles(self):
|
||||
@@ -127,7 +127,7 @@ class ArcaliveBoardExtractor(ArcaliveExtractor):
|
||||
class ArcaliveUserExtractor(ArcaliveExtractor):
|
||||
"""Extractor for an arca.live users's posts"""
|
||||
subcategory = "user"
|
||||
pattern = rf"{BASE_PATTERN}/u/@([^/?#]+)/?(?:\?([^#]+))?$"
|
||||
pattern = BASE_PATTERN + r"/u/@([^/?#]+)/?(?:\?([^#]+))?$"
|
||||
example = "https://arca.live/u/@USER"
|
||||
|
||||
def articles(self):
|
||||
@@ -169,8 +169,11 @@ class ArcaliveAPI():
|
||||
return data
|
||||
|
||||
self.log.debug("Server response: %s", data)
|
||||
msg = f": {msg}" if (msg := data.get("message")) else ""
|
||||
raise exception.AbortExtraction(f"API request failed{msg}")
|
||||
if msg := data.get("message"):
|
||||
msg = "API request failed: " + msg
|
||||
else:
|
||||
msg = "API request failed"
|
||||
raise exception.AbortExtraction(msg)
|
||||
|
||||
def _pagination(self, endpoint, params, key):
|
||||
while True:
|
||||
|
||||
@@ -24,8 +24,8 @@ class ArenaChannelExtractor(GalleryExtractor):
|
||||
example = "https://are.na/evan-collins-1522646491/cassette-futurism"
|
||||
|
||||
def metadata(self, page):
|
||||
channel = self.request_json(
|
||||
f"https://api.are.na/v2/channels/{self.groups[0]}")
|
||||
url = "https://api.are.na/v2/channels/" + self.groups[0]
|
||||
channel = self.request_json(url)
|
||||
|
||||
channel["date"] = self.parse_datetime_iso(
|
||||
channel["created_at"])
|
||||
|
||||
@@ -95,7 +95,7 @@ class ArtstationExtractor(Extractor):
|
||||
if not self.external:
|
||||
return
|
||||
asset["extension"] = "mp4"
|
||||
return f"ytdl:{url}"
|
||||
return "ytdl:" + url
|
||||
|
||||
self.log.debug(player)
|
||||
self.log.warning("Failed to extract embedded player URL (%s)",
|
||||
@@ -328,9 +328,9 @@ class ArtstationChallengeExtractor(ArtstationExtractor):
|
||||
|
||||
def items(self):
|
||||
base = f"{self.root}/contests/_/challenges/{self.challenge_id}"
|
||||
challenge_url = f"{base}.json"
|
||||
submission_url = f"{base}/submissions.json"
|
||||
update_url = f"{self.root}/contests/submission_updates.json"
|
||||
challenge_url = base + ".json"
|
||||
submission_url = base + "/submissions.json"
|
||||
update_url = self.root + "/contests/submission_updates.json"
|
||||
|
||||
challenge = self.request_json(challenge_url)
|
||||
yield Message.Directory, "", {"challenge": challenge}
|
||||
@@ -388,7 +388,7 @@ class ArtstationSearchExtractor(ArtstationExtractor):
|
||||
"value" : value.split(","),
|
||||
})
|
||||
|
||||
url = f"{self.root}/api/v2/search/projects.json"
|
||||
url = self.root + "/api/v2/search/projects.json"
|
||||
data = {
|
||||
"query" : self.query,
|
||||
"page" : None,
|
||||
@@ -419,7 +419,7 @@ class ArtstationArtworkExtractor(ArtstationExtractor):
|
||||
return {"artwork": self.query}
|
||||
|
||||
def projects(self):
|
||||
url = f"{self.root}/projects.json"
|
||||
url = self.root + "/projects.json"
|
||||
return self._pagination(url, self.query.copy())
|
||||
|
||||
|
||||
|
||||
@@ -211,7 +211,7 @@ class AryionGalleryExtractor(AryionExtractor):
|
||||
"""Extractor for a user's gallery on eka's portal"""
|
||||
subcategory = "gallery"
|
||||
categorytransfer = True
|
||||
pattern = rf"{BASE_PATTERN}/(?:gallery/|user/|latest.php\?name=)([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/(?:gallery/|user/|latest.php\?name=)([^/?#]+)"
|
||||
example = "https://aryion.com/g4/gallery/USER"
|
||||
|
||||
def _init(self):
|
||||
@@ -238,7 +238,7 @@ class AryionFavoriteExtractor(AryionExtractor):
|
||||
subcategory = "favorite"
|
||||
directory_fmt = ("{category}", "{user!l}", "favorites", "{folder}")
|
||||
archive_fmt = "f_{user}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/favorites/([^/?#]+)(?:/([^?#]+))?"
|
||||
pattern = BASE_PATTERN + r"/favorites/([^/?#]+)(?:/([^?#]+))?"
|
||||
example = "https://aryion.com/g4/favorites/USER"
|
||||
|
||||
def _init(self):
|
||||
@@ -253,7 +253,7 @@ class AryionWatchExtractor(AryionExtractor):
|
||||
"""Extractor for your watched users and tags"""
|
||||
subcategory = "watch"
|
||||
directory_fmt = ("{category}", "{user!l}",)
|
||||
pattern = rf"{BASE_PATTERN}/messagepage\.php()"
|
||||
pattern = BASE_PATTERN + r"/messagepage\.php()"
|
||||
example = "https://aryion.com/g4/messagepage.php"
|
||||
|
||||
def posts(self):
|
||||
@@ -271,7 +271,7 @@ class AryionTagExtractor(AryionExtractor):
|
||||
subcategory = "tag"
|
||||
directory_fmt = ("{category}", "tags", "{search_tags}")
|
||||
archive_fmt = "t_{search_tags}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/tags\.php\?([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/tags\.php\?([^#]+)"
|
||||
example = "https://aryion.com/g4/tags.php?tag=TAG"
|
||||
|
||||
def _init(self):
|
||||
@@ -293,7 +293,7 @@ class AryionSearchExtractor(AryionExtractor):
|
||||
"{search[q]|search[tags]|search[user]}")
|
||||
archive_fmt = ("s_{search[prefix]}"
|
||||
"{search[q]|search[tags]|search[user]}_{id}")
|
||||
pattern = rf"{BASE_PATTERN}/search\.php\?([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/search\.php\?([^#]+)"
|
||||
example = "https://aryion.com/g4/search.php?q=TEXT&tags=TAGS&user=USER"
|
||||
|
||||
def metadata(self):
|
||||
@@ -313,7 +313,7 @@ class AryionSearchExtractor(AryionExtractor):
|
||||
class AryionPostExtractor(AryionExtractor):
|
||||
"""Extractor for individual posts on eka's portal"""
|
||||
subcategory = "post"
|
||||
pattern = rf"{BASE_PATTERN}/view/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/view/(\d+)"
|
||||
example = "https://aryion.com/g4/view/12345"
|
||||
|
||||
def posts(self):
|
||||
|
||||
@@ -103,7 +103,7 @@ class AudiochanExtractor(Extractor):
|
||||
|
||||
class AudiochanAudioExtractor(AudiochanExtractor):
|
||||
subcategory = "audio"
|
||||
pattern = rf"{BASE_PATTERN}/a/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/a/([^/?#]+)"
|
||||
example = "https://audiochan.com/a/SLUG"
|
||||
|
||||
def posts(self):
|
||||
@@ -114,7 +114,7 @@ class AudiochanAudioExtractor(AudiochanExtractor):
|
||||
|
||||
class AudiochanUserExtractor(AudiochanExtractor):
|
||||
subcategory = "user"
|
||||
pattern = rf"{BASE_PATTERN}/u/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/u/([^/?#]+)"
|
||||
example = "https://audiochan.com/u/USER"
|
||||
|
||||
def posts(self):
|
||||
@@ -130,7 +130,7 @@ class AudiochanUserExtractor(AudiochanExtractor):
|
||||
|
||||
class AudiochanCollectionExtractor(AudiochanExtractor):
|
||||
subcategory = "collection"
|
||||
pattern = rf"{BASE_PATTERN}/c/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/c/([^/?#]+)"
|
||||
example = "https://audiochan.com/c/SLUG"
|
||||
|
||||
def posts(self):
|
||||
@@ -146,7 +146,7 @@ class AudiochanCollectionExtractor(AudiochanExtractor):
|
||||
|
||||
class AudiochanSearchExtractor(AudiochanExtractor):
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}/search/?\?([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/search/?\?([^#]+)"
|
||||
example = "https://audiochan.com/search?q=QUERY"
|
||||
|
||||
def posts(self):
|
||||
|
||||
@@ -80,7 +80,7 @@ class BatotoBase():
|
||||
class BatotoChapterExtractor(BatotoBase, ChapterExtractor):
|
||||
"""Extractor for batoto manga chapters"""
|
||||
archive_fmt = "{chapter_id}_{page}"
|
||||
pattern = rf"{BASE_PATTERN}/(?:title/[^/?#]+|chapter)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/(?:title/[^/?#]+|chapter)/(\d+)"
|
||||
example = "https://xbato.org/title/12345-MANGA/54321"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -139,8 +139,8 @@ class BatotoMangaExtractor(BatotoBase, MangaExtractor):
|
||||
"""Extractor for batoto manga"""
|
||||
reverse = False
|
||||
chapterclass = BatotoChapterExtractor
|
||||
pattern = (rf"{BASE_PATTERN}"
|
||||
rf"/(?:title/(\d+)[^/?#]*|series/(\d+)(?:/[^/?#]*)?)/?$")
|
||||
pattern = (BASE_PATTERN +
|
||||
r"/(?:title/(\d+)[^/?#]*|series/(\d+)(?:/[^/?#]*)?)/?$")
|
||||
example = "https://xbato.org/title/12345-MANGA/"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -21,7 +21,7 @@ class BbcGalleryExtractor(GalleryExtractor):
|
||||
directory_fmt = ("{category}", "{path:I}")
|
||||
filename_fmt = "{num:>02}.{extension}"
|
||||
archive_fmt = "{programme}_{num}"
|
||||
pattern = rf"{BASE_PATTERN}[^/?#]+(?!/galleries)(?:/[^/?#]+)?)$"
|
||||
pattern = BASE_PATTERN + r"[^/?#]+(?!/galleries)(?:/[^/?#]+)?)$"
|
||||
example = "https://www.bbc.co.uk/programmes/PATH"
|
||||
|
||||
def metadata(self, page):
|
||||
@@ -71,7 +71,7 @@ class BbcProgrammeExtractor(Extractor):
|
||||
category = "bbc"
|
||||
subcategory = "programme"
|
||||
root = "https://www.bbc.co.uk"
|
||||
pattern = rf"{BASE_PATTERN}[^/?#]+/galleries)(?:/?\?page=(\d+))?"
|
||||
pattern = BASE_PATTERN + r"[^/?#]+/galleries)(?:/?\?page=(\d+))?"
|
||||
example = "https://www.bbc.co.uk/programmes/ID/galleries"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -24,7 +24,7 @@ class BellazonExtractor(Extractor):
|
||||
archive_fmt = "{post[id]}/{id}_{filename}"
|
||||
|
||||
def items(self):
|
||||
native = (f"{self.root}/", f"{self.root[6:]}/")
|
||||
native = (self.root + "/", self.root[6:] + "/")
|
||||
extract_urls = text.re(
|
||||
r'(?s)<('
|
||||
r'(?:video .*?<source [^>]*?src|a [^>]*?href)="([^"]+).*?</a>'
|
||||
@@ -82,7 +82,7 @@ class BellazonExtractor(Extractor):
|
||||
dc["extension"] = text.ext_from_url(url)
|
||||
|
||||
if url[0] == "/":
|
||||
url = f"https:{url}"
|
||||
url = "https:" + url
|
||||
yield Message.Url, url, dc
|
||||
|
||||
else:
|
||||
@@ -91,10 +91,10 @@ class BellazonExtractor(Extractor):
|
||||
yield Message.Queue, url, data
|
||||
|
||||
def _pagination(self, base, pnum=None):
|
||||
base = f"{self.root}{base}"
|
||||
base = self.root + base
|
||||
|
||||
if pnum is None:
|
||||
url = f"{base}/"
|
||||
url = base + "/"
|
||||
pnum = 1
|
||||
else:
|
||||
url = f"{base}/page/{pnum}/"
|
||||
@@ -112,7 +112,7 @@ class BellazonExtractor(Extractor):
|
||||
url = f"{base}/page/{pnum}/"
|
||||
|
||||
def _pagination_reverse(self, base, pnum=None):
|
||||
base = f"{self.root}{base}"
|
||||
base = self.root + base
|
||||
|
||||
url = f"{base}/page/{'9999' if pnum is None else pnum}/"
|
||||
with self.request(url) as response:
|
||||
@@ -127,7 +127,7 @@ class BellazonExtractor(Extractor):
|
||||
if pnum > 1:
|
||||
url = f"{base}/page/{pnum}/"
|
||||
elif pnum == 1:
|
||||
url = f"{base}/"
|
||||
url = base + "/"
|
||||
else:
|
||||
return
|
||||
|
||||
@@ -192,15 +192,15 @@ class BellazonExtractor(Extractor):
|
||||
|
||||
class BellazonPostExtractor(BellazonExtractor):
|
||||
subcategory = "post"
|
||||
pattern = (rf"{BASE_PATTERN}(/topic/\d+-[\w-]+(?:/page/\d+)?)"
|
||||
rf"/?#(?:findC|c)omment-(\d+)")
|
||||
pattern = (BASE_PATTERN + r"(/topic/\d+-[\w-]+(?:/page/\d+)?)"
|
||||
r"/?#(?:findC|c)omment-(\d+)")
|
||||
example = "https://www.bellazon.com/main/topic/123-SLUG/#findComment-12345"
|
||||
|
||||
def posts(self):
|
||||
path, post_id = self.groups
|
||||
page = self.request(f"{self.root}{path}").text
|
||||
page = self.request(self.root + path).text
|
||||
|
||||
pos = page.find(f'id="elComment_{post_id}')
|
||||
pos = page.find('id="elComment_' + post_id)
|
||||
if pos < 0:
|
||||
raise exception.NotFoundError("post")
|
||||
html = text.extract(page, "<article ", "</article>", pos-100)[0]
|
||||
@@ -211,7 +211,7 @@ class BellazonPostExtractor(BellazonExtractor):
|
||||
|
||||
class BellazonThreadExtractor(BellazonExtractor):
|
||||
subcategory = "thread"
|
||||
pattern = rf"{BASE_PATTERN}(/topic/\d+-[\w-]+)(?:/page/(\d+))?"
|
||||
pattern = BASE_PATTERN + r"(/topic/\d+-[\w-]+)(?:/page/(\d+))?"
|
||||
example = "https://www.bellazon.com/main/topic/123-SLUG/"
|
||||
|
||||
def posts(self):
|
||||
@@ -236,7 +236,7 @@ class BellazonThreadExtractor(BellazonExtractor):
|
||||
|
||||
class BellazonForumExtractor(BellazonExtractor):
|
||||
subcategory = "forum"
|
||||
pattern = rf"{BASE_PATTERN}(/forum/\d+-[\w-]+)(?:/page/(\d+))?"
|
||||
pattern = BASE_PATTERN + r"(/forum/\d+-[\w-]+)(?:/page/(\d+))?"
|
||||
example = "https://www.bellazon.com/main/forum/123-SLUG/"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -146,7 +146,7 @@ class BilibiliAPI():
|
||||
except Exception:
|
||||
if "window._riskdata_" not in page:
|
||||
raise exception.AbortExtraction(
|
||||
f"{article_id}: Unable to extract INITIAL_STATE data")
|
||||
article_id + ": Unable to extract INITIAL_STATE data")
|
||||
self.extractor.wait(seconds=300)
|
||||
|
||||
def user_favlist(self):
|
||||
|
||||
@@ -117,7 +117,7 @@ BASE_PATTERN = BloggerExtractor.update({
|
||||
class BloggerPostExtractor(BloggerExtractor):
|
||||
"""Extractor for a single blog post"""
|
||||
subcategory = "post"
|
||||
pattern = rf"{BASE_PATTERN}(/\d\d\d\d/\d\d/[^/?#]+\.html)"
|
||||
pattern = BASE_PATTERN + r"(/\d\d\d\d/\d\d/[^/?#]+\.html)"
|
||||
example = "https://BLOG.blogspot.com/1970/01/TITLE.html"
|
||||
|
||||
def posts(self, blog):
|
||||
@@ -127,7 +127,7 @@ class BloggerPostExtractor(BloggerExtractor):
|
||||
class BloggerBlogExtractor(BloggerExtractor):
|
||||
"""Extractor for an entire Blogger blog"""
|
||||
subcategory = "blog"
|
||||
pattern = rf"{BASE_PATTERN}/?$"
|
||||
pattern = BASE_PATTERN + r"/?$"
|
||||
example = "https://BLOG.blogspot.com/"
|
||||
|
||||
def posts(self, blog):
|
||||
@@ -137,7 +137,7 @@ class BloggerBlogExtractor(BloggerExtractor):
|
||||
class BloggerSearchExtractor(BloggerExtractor):
|
||||
"""Extractor for Blogger search resuls"""
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}/search/?\?q=([^&#]+)"
|
||||
pattern = BASE_PATTERN + r"/search/?\?q=([^&#]+)"
|
||||
example = "https://BLOG.blogspot.com/search?q=QUERY"
|
||||
|
||||
def metadata(self):
|
||||
@@ -151,7 +151,7 @@ class BloggerSearchExtractor(BloggerExtractor):
|
||||
class BloggerLabelExtractor(BloggerExtractor):
|
||||
"""Extractor for Blogger posts by label"""
|
||||
subcategory = "label"
|
||||
pattern = rf"{BASE_PATTERN}/search/label/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/search/label/([^/?#]+)"
|
||||
example = "https://BLOG.blogspot.com/search/label/LABEL"
|
||||
|
||||
def metadata(self):
|
||||
|
||||
@@ -14,7 +14,7 @@ from ..cache import cache, memcache
|
||||
|
||||
BASE_PATTERN = (r"(?:https?://)?"
|
||||
r"(?:(?:www\.)?(?:c|[fv]x)?bs[ky]y[ex]?\.app|main\.bsky\.dev)")
|
||||
USER_PATTERN = rf"{BASE_PATTERN}/profile/([^/?#]+)"
|
||||
USER_PATTERN = BASE_PATTERN + r"/profile/([^/?#]+)"
|
||||
|
||||
|
||||
class BlueskyExtractor(Extractor):
|
||||
@@ -216,7 +216,7 @@ class BlueskyExtractor(Extractor):
|
||||
|
||||
|
||||
class BlueskyUserExtractor(Dispatch, BlueskyExtractor):
|
||||
pattern = rf"{USER_PATTERN}$"
|
||||
pattern = USER_PATTERN + r"$"
|
||||
example = "https://bsky.app/profile/HANDLE"
|
||||
|
||||
def items(self):
|
||||
@@ -237,7 +237,7 @@ class BlueskyUserExtractor(Dispatch, BlueskyExtractor):
|
||||
|
||||
class BlueskyPostsExtractor(BlueskyExtractor):
|
||||
subcategory = "posts"
|
||||
pattern = rf"{USER_PATTERN}/posts"
|
||||
pattern = USER_PATTERN + r"/posts"
|
||||
example = "https://bsky.app/profile/HANDLE/posts"
|
||||
|
||||
def posts(self):
|
||||
@@ -247,7 +247,7 @@ class BlueskyPostsExtractor(BlueskyExtractor):
|
||||
|
||||
class BlueskyRepliesExtractor(BlueskyExtractor):
|
||||
subcategory = "replies"
|
||||
pattern = rf"{USER_PATTERN}/replies"
|
||||
pattern = USER_PATTERN + r"/replies"
|
||||
example = "https://bsky.app/profile/HANDLE/replies"
|
||||
|
||||
def posts(self):
|
||||
@@ -257,7 +257,7 @@ class BlueskyRepliesExtractor(BlueskyExtractor):
|
||||
|
||||
class BlueskyMediaExtractor(BlueskyExtractor):
|
||||
subcategory = "media"
|
||||
pattern = rf"{USER_PATTERN}/media"
|
||||
pattern = USER_PATTERN + r"/media"
|
||||
example = "https://bsky.app/profile/HANDLE/media"
|
||||
|
||||
def posts(self):
|
||||
@@ -267,7 +267,7 @@ class BlueskyMediaExtractor(BlueskyExtractor):
|
||||
|
||||
class BlueskyVideoExtractor(BlueskyExtractor):
|
||||
subcategory = "video"
|
||||
pattern = rf"{USER_PATTERN}/video"
|
||||
pattern = USER_PATTERN + r"/video"
|
||||
example = "https://bsky.app/profile/HANDLE/video"
|
||||
|
||||
def posts(self):
|
||||
@@ -277,7 +277,7 @@ class BlueskyVideoExtractor(BlueskyExtractor):
|
||||
|
||||
class BlueskyLikesExtractor(BlueskyExtractor):
|
||||
subcategory = "likes"
|
||||
pattern = rf"{USER_PATTERN}/likes"
|
||||
pattern = USER_PATTERN + r"/likes"
|
||||
example = "https://bsky.app/profile/HANDLE/likes"
|
||||
|
||||
def posts(self):
|
||||
@@ -288,7 +288,7 @@ class BlueskyLikesExtractor(BlueskyExtractor):
|
||||
|
||||
class BlueskyFeedExtractor(BlueskyExtractor):
|
||||
subcategory = "feed"
|
||||
pattern = rf"{USER_PATTERN}/feed/([^/?#]+)"
|
||||
pattern = USER_PATTERN + r"/feed/([^/?#]+)"
|
||||
example = "https://bsky.app/profile/HANDLE/feed/NAME"
|
||||
|
||||
def posts(self):
|
||||
@@ -298,7 +298,7 @@ class BlueskyFeedExtractor(BlueskyExtractor):
|
||||
|
||||
class BlueskyListExtractor(BlueskyExtractor):
|
||||
subcategory = "list"
|
||||
pattern = rf"{USER_PATTERN}/lists/([^/?#]+)"
|
||||
pattern = USER_PATTERN + r"/lists/([^/?#]+)"
|
||||
example = "https://bsky.app/profile/HANDLE/lists/ID"
|
||||
|
||||
def posts(self):
|
||||
@@ -308,7 +308,7 @@ class BlueskyListExtractor(BlueskyExtractor):
|
||||
|
||||
class BlueskyFollowingExtractor(BlueskyExtractor):
|
||||
subcategory = "following"
|
||||
pattern = rf"{USER_PATTERN}/follows"
|
||||
pattern = USER_PATTERN + r"/follows"
|
||||
example = "https://bsky.app/profile/HANDLE/follows"
|
||||
|
||||
def items(self):
|
||||
@@ -320,7 +320,7 @@ class BlueskyFollowingExtractor(BlueskyExtractor):
|
||||
|
||||
class BlueskyPostExtractor(BlueskyExtractor):
|
||||
subcategory = "post"
|
||||
pattern = rf"{USER_PATTERN}/post/([^/?#]+)"
|
||||
pattern = USER_PATTERN + r"/post/([^/?#]+)"
|
||||
example = "https://bsky.app/profile/HANDLE/post/ID"
|
||||
|
||||
def posts(self):
|
||||
@@ -330,7 +330,7 @@ class BlueskyPostExtractor(BlueskyExtractor):
|
||||
|
||||
class BlueskyInfoExtractor(BlueskyExtractor):
|
||||
subcategory = "info"
|
||||
pattern = rf"{USER_PATTERN}/info"
|
||||
pattern = USER_PATTERN + r"/info"
|
||||
example = "https://bsky.app/profile/HANDLE/info"
|
||||
|
||||
def items(self):
|
||||
@@ -342,7 +342,7 @@ class BlueskyInfoExtractor(BlueskyExtractor):
|
||||
class BlueskyAvatarExtractor(BlueskyExtractor):
|
||||
subcategory = "avatar"
|
||||
filename_fmt = "avatar_{post_id}.{extension}"
|
||||
pattern = rf"{USER_PATTERN}/avatar"
|
||||
pattern = USER_PATTERN + r"/avatar"
|
||||
example = "https://bsky.app/profile/HANDLE/avatar"
|
||||
|
||||
def posts(self):
|
||||
@@ -352,7 +352,7 @@ class BlueskyAvatarExtractor(BlueskyExtractor):
|
||||
class BlueskyBackgroundExtractor(BlueskyExtractor):
|
||||
subcategory = "background"
|
||||
filename_fmt = "background_{post_id}.{extension}"
|
||||
pattern = rf"{USER_PATTERN}/ba(?:nner|ckground)"
|
||||
pattern = USER_PATTERN + r"/ba(?:nner|ckground)"
|
||||
example = "https://bsky.app/profile/HANDLE/banner"
|
||||
|
||||
def posts(self):
|
||||
@@ -361,7 +361,7 @@ class BlueskyBackgroundExtractor(BlueskyExtractor):
|
||||
|
||||
class BlueskySearchExtractor(BlueskyExtractor):
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}/search(?:/|\?q=)(.+)"
|
||||
pattern = BASE_PATTERN + r"/search(?:/|\?q=)(.+)"
|
||||
example = "https://bsky.app/search?q=QUERY"
|
||||
|
||||
def posts(self):
|
||||
@@ -371,7 +371,7 @@ class BlueskySearchExtractor(BlueskyExtractor):
|
||||
|
||||
class BlueskyHashtagExtractor(BlueskyExtractor):
|
||||
subcategory = "hashtag"
|
||||
pattern = rf"{BASE_PATTERN}/hashtag/([^/?#]+)(?:/(top|latest))?"
|
||||
pattern = BASE_PATTERN + r"/hashtag/([^/?#]+)(?:/(top|latest))?"
|
||||
example = "https://bsky.app/hashtag/NAME"
|
||||
|
||||
def posts(self):
|
||||
@@ -381,7 +381,7 @@ class BlueskyHashtagExtractor(BlueskyExtractor):
|
||||
|
||||
class BlueskyBookmarkExtractor(BlueskyExtractor):
|
||||
subcategory = "bookmark"
|
||||
pattern = rf"{BASE_PATTERN}/saved"
|
||||
pattern = BASE_PATTERN + r"/saved"
|
||||
example = "https://bsky.app/saved"
|
||||
|
||||
def posts(self):
|
||||
|
||||
@@ -163,7 +163,7 @@ class BoostyExtractor(Extractor):
|
||||
class BoostyUserExtractor(BoostyExtractor):
|
||||
"""Extractor for boosty.to user profiles"""
|
||||
subcategory = "user"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)(?:\?([^#]+))?$"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)(?:\?([^#]+))?$"
|
||||
example = "https://boosty.to/USER"
|
||||
|
||||
def posts(self):
|
||||
@@ -179,7 +179,7 @@ class BoostyMediaExtractor(BoostyExtractor):
|
||||
subcategory = "media"
|
||||
directory_fmt = "{category}", "{user[blogUrl]} ({user[id]})", "media"
|
||||
filename_fmt = "{post[id]}_{num}.{extension}"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/media/([^/?#]+)(?:\?([^#]+))?"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/media/([^/?#]+)(?:\?([^#]+))?"
|
||||
example = "https://boosty.to/USER/media/all"
|
||||
|
||||
def posts(self):
|
||||
@@ -192,7 +192,7 @@ class BoostyMediaExtractor(BoostyExtractor):
|
||||
class BoostyFeedExtractor(BoostyExtractor):
|
||||
"""Extractor for your boosty.to subscription feed"""
|
||||
subcategory = "feed"
|
||||
pattern = rf"{BASE_PATTERN}/(?:\?([^#]+))?(?:$|#)"
|
||||
pattern = BASE_PATTERN + r"/(?:\?([^#]+))?(?:$|#)"
|
||||
example = "https://boosty.to/"
|
||||
|
||||
def posts(self):
|
||||
@@ -203,7 +203,7 @@ class BoostyFeedExtractor(BoostyExtractor):
|
||||
class BoostyPostExtractor(BoostyExtractor):
|
||||
"""Extractor for boosty.to posts"""
|
||||
subcategory = "post"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/posts/([0-9a-f-]+)"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/posts/([0-9a-f-]+)"
|
||||
example = "https://boosty.to/USER/posts/01234567-89ab-cdef-0123-456789abcd"
|
||||
|
||||
def posts(self):
|
||||
@@ -216,7 +216,7 @@ class BoostyPostExtractor(BoostyExtractor):
|
||||
class BoostyFollowingExtractor(BoostyExtractor):
|
||||
"""Extractor for your boosty.to subscribed users"""
|
||||
subcategory = "following"
|
||||
pattern = rf"{BASE_PATTERN}/app/settings/subscriptions"
|
||||
pattern = BASE_PATTERN + r"/app/settings/subscriptions"
|
||||
example = "https://boosty.to/app/settings/subscriptions"
|
||||
|
||||
def items(self):
|
||||
@@ -231,7 +231,7 @@ class BoostyDirectMessagesExtractor(BoostyExtractor):
|
||||
subcategory = "direct-messages"
|
||||
directory_fmt = ("{category}", "{user[blogUrl]} ({user[id]})",
|
||||
"Direct Messages")
|
||||
pattern = rf"{BASE_PATTERN}/app/messages/?\?dialogId=(\d+)"
|
||||
pattern = BASE_PATTERN + r"/app/messages/?\?dialogId=(\d+)"
|
||||
example = "https://boosty.to/app/messages?dialogId=12345"
|
||||
|
||||
def items(self):
|
||||
@@ -424,7 +424,7 @@ class BoostyAPI():
|
||||
params["offset"] = offset
|
||||
|
||||
def dialog(self, dialog_id):
|
||||
endpoint = f"/v1/dialog/{dialog_id}"
|
||||
endpoint = "/v1/dialog/" + dialog_id
|
||||
return self._call(endpoint)
|
||||
|
||||
def dialog_messages(self, dialog_id, limit=300, offset=None):
|
||||
|
||||
@@ -116,7 +116,7 @@ class BoothShopExtractor(BoothExtractor):
|
||||
BoothExtractor.__init__(self, match)
|
||||
|
||||
def shop_items(self):
|
||||
return self._pagination(f"{self.root}/items")
|
||||
return self._pagination(self.root + "/items")
|
||||
|
||||
|
||||
def _fallback(url):
|
||||
|
||||
@@ -64,7 +64,7 @@ class BunkrAlbumExtractor(LolisafeAlbumExtractor):
|
||||
root_dl = "https://get.bunkrr.su"
|
||||
root_api = "https://apidl.bunkr.ru"
|
||||
archive_fmt = "{album_id}_{id|id_url|slug}"
|
||||
pattern = rf"{BASE_PATTERN}/a/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/a/([^/?#]+)"
|
||||
example = "https://bunkr.si/a/ID"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -189,7 +189,7 @@ class BunkrAlbumExtractor(LolisafeAlbumExtractor):
|
||||
json={"id": data_id})
|
||||
|
||||
if data.get("encrypted"):
|
||||
key = f"SECRET_KEY_{data['timestamp'] // 3600}"
|
||||
key = "SECRET_KEY_" + str(data["timestamp"] // 3600)
|
||||
file_url = util.decrypt_xor(data["url"], key.encode())
|
||||
else:
|
||||
file_url = data["url"]
|
||||
@@ -216,12 +216,12 @@ class BunkrMediaExtractor(BunkrAlbumExtractor):
|
||||
"""Extractor for bunkr.si media links"""
|
||||
subcategory = "media"
|
||||
directory_fmt = ("{category}",)
|
||||
pattern = rf"{BASE_PATTERN}(/[fvid]/[^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"(/[fvid]/[^/?#]+)"
|
||||
example = "https://bunkr.si/f/FILENAME"
|
||||
|
||||
def fetch_album(self, album_id):
|
||||
try:
|
||||
page = self.request(f"{self.root}{album_id}").text
|
||||
page = self.request(self.root + album_id).text
|
||||
data_id = text.extr(page, 'data-file-id="', '"')
|
||||
file = self._extract_file(data_id)
|
||||
file["name"] = text.unquote(text.unescape(text.extr(
|
||||
|
||||
@@ -60,7 +60,7 @@ BASE_PATTERN = CheveretoExtractor.update({
|
||||
class CheveretoImageExtractor(CheveretoExtractor):
|
||||
"""Extractor for chevereto images"""
|
||||
subcategory = "image"
|
||||
pattern = rf"{BASE_PATTERN}(/im(?:g|age)/[^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"(/im(?:g|age)/[^/?#]+)"
|
||||
example = "https://jpg7.cr/img/TITLE.ID"
|
||||
|
||||
def items(self):
|
||||
@@ -98,7 +98,7 @@ class CheveretoImageExtractor(CheveretoExtractor):
|
||||
class CheveretoVideoExtractor(CheveretoExtractor):
|
||||
"""Extractor for chevereto videos"""
|
||||
subcategory = "video"
|
||||
pattern = rf"{BASE_PATTERN}(/video/[^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"(/video/[^/?#]+)"
|
||||
example = "https://imagepond.net/video/TITLE.ID"
|
||||
|
||||
def items(self):
|
||||
@@ -145,7 +145,7 @@ class CheveretoVideoExtractor(CheveretoExtractor):
|
||||
class CheveretoAlbumExtractor(CheveretoExtractor):
|
||||
"""Extractor for chevereto albums"""
|
||||
subcategory = "album"
|
||||
pattern = rf"{BASE_PATTERN}(/a(?:lbum)?/[^/?#]+(?:/sub)?)"
|
||||
pattern = BASE_PATTERN + r"(/a(?:lbum)?/[^/?#]+(?:/sub)?)"
|
||||
example = "https://jpg7.cr/album/TITLE.ID"
|
||||
|
||||
def items(self):
|
||||
@@ -182,7 +182,7 @@ class CheveretoAlbumExtractor(CheveretoExtractor):
|
||||
class CheveretoCategoryExtractor(CheveretoExtractor):
|
||||
"""Extractor for chevereto galleries"""
|
||||
subcategory = "category"
|
||||
pattern = rf"{BASE_PATTERN}(/category/[^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"(/category/[^/?#]+)"
|
||||
example = "https://imglike.com/category/TITLE"
|
||||
|
||||
def items(self):
|
||||
@@ -194,7 +194,7 @@ class CheveretoCategoryExtractor(CheveretoExtractor):
|
||||
class CheveretoUserExtractor(CheveretoExtractor):
|
||||
"""Extractor for chevereto users"""
|
||||
subcategory = "user"
|
||||
pattern = rf"{BASE_PATTERN}(/[^/?#]+(?:/albums)?)"
|
||||
pattern = BASE_PATTERN + r"(/[^/?#]+(?:/albums)?)"
|
||||
example = "https://jpg7.cr/USER"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -48,7 +48,7 @@ class CienArticleExtractor(CienExtractor):
|
||||
filename_fmt = "{num:>02} {filename}.{extension}"
|
||||
directory_fmt = ("{category}", "{author[name]}", "{post_id} {name}")
|
||||
archive_fmt = "{post_id}_{num}"
|
||||
pattern = rf"{BASE_PATTERN}/creator/(\d+)/article/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/creator/(\d+)/article/(\d+)"
|
||||
example = "https://ci-en.net/creator/123/article/12345"
|
||||
|
||||
def items(self):
|
||||
@@ -160,7 +160,7 @@ class CienArticleExtractor(CienExtractor):
|
||||
|
||||
class CienCreatorExtractor(CienExtractor):
|
||||
subcategory = "creator"
|
||||
pattern = rf"{BASE_PATTERN}/creator/(\d+)(?:/article(?:\?([^#]+))?)?/?$"
|
||||
pattern = BASE_PATTERN + r"/creator/(\d+)(?:/article(?:\?([^#]+))?)?/?$"
|
||||
example = "https://ci-en.net/creator/123"
|
||||
|
||||
def items(self):
|
||||
@@ -172,7 +172,7 @@ class CienCreatorExtractor(CienExtractor):
|
||||
|
||||
class CienRecentExtractor(CienExtractor):
|
||||
subcategory = "recent"
|
||||
pattern = rf"{BASE_PATTERN}/mypage/recent(?:\?([^#]+))?"
|
||||
pattern = BASE_PATTERN + r"/mypage/recent(?:\?([^#]+))?"
|
||||
example = "https://ci-en.net/mypage/recent"
|
||||
|
||||
def items(self):
|
||||
@@ -183,7 +183,7 @@ class CienRecentExtractor(CienExtractor):
|
||||
|
||||
class CienFollowingExtractor(CienExtractor):
|
||||
subcategory = "following"
|
||||
pattern = rf"{BASE_PATTERN}/mypage/subscription(/following)?"
|
||||
pattern = BASE_PATTERN + r"/mypage/subscription(/following)?"
|
||||
example = "https://ci-en.net/mypage/subscription"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -15,7 +15,7 @@ import itertools
|
||||
import time
|
||||
|
||||
BASE_PATTERN = r"(?:https?://)?civitai\.com"
|
||||
USER_PATTERN = rf"{BASE_PATTERN}/user/([^/?#]+)"
|
||||
USER_PATTERN = BASE_PATTERN + r"/user/([^/?#]+)"
|
||||
|
||||
|
||||
class CivitaiExtractor(Extractor):
|
||||
@@ -258,7 +258,7 @@ class CivitaiModelExtractor(CivitaiExtractor):
|
||||
directory_fmt = ("{category}", "{user[username]}",
|
||||
"{model[id]}{model[name]:? //}",
|
||||
"{version[id]}{version[name]:? //}")
|
||||
pattern = rf"{BASE_PATTERN}/models/(\d+)(?:/?\?modelVersionId=(\d+))?"
|
||||
pattern = BASE_PATTERN + r"/models/(\d+)(?:/?\?modelVersionId=(\d+))?"
|
||||
example = "https://civitai.com/models/12345/TITLE"
|
||||
|
||||
def items(self):
|
||||
@@ -375,7 +375,7 @@ class CivitaiModelExtractor(CivitaiExtractor):
|
||||
|
||||
class CivitaiImageExtractor(CivitaiExtractor):
|
||||
subcategory = "image"
|
||||
pattern = rf"{BASE_PATTERN}/images/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/images/(\d+)"
|
||||
example = "https://civitai.com/images/12345"
|
||||
|
||||
def images(self):
|
||||
@@ -386,7 +386,7 @@ class CivitaiCollectionExtractor(CivitaiExtractor):
|
||||
subcategory = "collection"
|
||||
directory_fmt = ("{category}", "{user_collection[username]}",
|
||||
"collections", "{collection[id]}{collection[name]:? //}")
|
||||
pattern = rf"{BASE_PATTERN}/collections/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/collections/(\d+)"
|
||||
example = "https://civitai.com/collections/12345"
|
||||
|
||||
def images(self):
|
||||
@@ -408,7 +408,7 @@ class CivitaiPostExtractor(CivitaiExtractor):
|
||||
subcategory = "post"
|
||||
directory_fmt = ("{category}", "{username|user[username]}", "posts",
|
||||
"{post[id]}{post[title]:? //}")
|
||||
pattern = rf"{BASE_PATTERN}/posts/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/posts/(\d+)"
|
||||
example = "https://civitai.com/posts/12345"
|
||||
|
||||
def posts(self):
|
||||
@@ -417,7 +417,7 @@ class CivitaiPostExtractor(CivitaiExtractor):
|
||||
|
||||
class CivitaiTagExtractor(CivitaiExtractor):
|
||||
subcategory = "tag"
|
||||
pattern = rf"{BASE_PATTERN}/tag/([^/?&#]+)"
|
||||
pattern = BASE_PATTERN + r"/tag/([^/?&#]+)"
|
||||
example = "https://civitai.com/tag/TAG"
|
||||
|
||||
def models(self):
|
||||
@@ -427,7 +427,7 @@ class CivitaiTagExtractor(CivitaiExtractor):
|
||||
|
||||
class CivitaiSearchModelsExtractor(CivitaiExtractor):
|
||||
subcategory = "search-models"
|
||||
pattern = rf"{BASE_PATTERN}/search/models\?([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/search/models\?([^#]+)"
|
||||
example = "https://civitai.com/search/models?query=QUERY"
|
||||
|
||||
def models(self):
|
||||
@@ -438,7 +438,7 @@ class CivitaiSearchModelsExtractor(CivitaiExtractor):
|
||||
|
||||
class CivitaiSearchImagesExtractor(CivitaiExtractor):
|
||||
subcategory = "search-images"
|
||||
pattern = rf"{BASE_PATTERN}/search/images\?([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/search/images\?([^#]+)"
|
||||
example = "https://civitai.com/search/images?query=QUERY"
|
||||
|
||||
def images(self):
|
||||
@@ -449,7 +449,7 @@ class CivitaiSearchImagesExtractor(CivitaiExtractor):
|
||||
|
||||
class CivitaiModelsExtractor(CivitaiExtractor):
|
||||
subcategory = "models"
|
||||
pattern = rf"{BASE_PATTERN}/models(?:/?\?([^#]+))?(?:$|#)"
|
||||
pattern = BASE_PATTERN + r"/models(?:/?\?([^#]+))?(?:$|#)"
|
||||
example = "https://civitai.com/models"
|
||||
|
||||
def models(self):
|
||||
@@ -459,7 +459,7 @@ class CivitaiModelsExtractor(CivitaiExtractor):
|
||||
|
||||
class CivitaiImagesExtractor(CivitaiExtractor):
|
||||
subcategory = "images"
|
||||
pattern = rf"{BASE_PATTERN}/images(?:/?\?([^#]+))?(?:$|#)"
|
||||
pattern = BASE_PATTERN + r"/images(?:/?\?([^#]+))?(?:$|#)"
|
||||
example = "https://civitai.com/images"
|
||||
|
||||
def images(self):
|
||||
@@ -470,7 +470,7 @@ class CivitaiImagesExtractor(CivitaiExtractor):
|
||||
|
||||
class CivitaiVideosExtractor(CivitaiExtractor):
|
||||
subcategory = "videos"
|
||||
pattern = rf"{BASE_PATTERN}/videos(?:/?\?([^#]+))?(?:$|#)"
|
||||
pattern = BASE_PATTERN + r"/videos(?:/?\?([^#]+))?(?:$|#)"
|
||||
example = "https://civitai.com/videos"
|
||||
|
||||
def images(self):
|
||||
@@ -481,7 +481,7 @@ class CivitaiVideosExtractor(CivitaiExtractor):
|
||||
|
||||
class CivitaiPostsExtractor(CivitaiExtractor):
|
||||
subcategory = "posts"
|
||||
pattern = rf"{BASE_PATTERN}/posts(?:/?\?([^#]+))?(?:$|#)"
|
||||
pattern = BASE_PATTERN + r"/posts(?:/?\?([^#]+))?(?:$|#)"
|
||||
example = "https://civitai.com/posts"
|
||||
|
||||
def posts(self):
|
||||
@@ -490,7 +490,7 @@ class CivitaiPostsExtractor(CivitaiExtractor):
|
||||
|
||||
|
||||
class CivitaiUserExtractor(Dispatch, CivitaiExtractor):
|
||||
pattern = rf"{USER_PATTERN}/?(?:$|\?|#)"
|
||||
pattern = USER_PATTERN + r"/?(?:$|\?|#)"
|
||||
example = "https://civitai.com/user/USER"
|
||||
|
||||
def items(self):
|
||||
@@ -506,7 +506,7 @@ class CivitaiUserExtractor(Dispatch, CivitaiExtractor):
|
||||
|
||||
class CivitaiUserModelsExtractor(CivitaiExtractor):
|
||||
subcategory = "user-models"
|
||||
pattern = rf"{USER_PATTERN}/models/?(?:\?([^#]+))?"
|
||||
pattern = USER_PATTERN + r"/models/?(?:\?([^#]+))?"
|
||||
example = "https://civitai.com/user/USER/models"
|
||||
|
||||
def models(self):
|
||||
@@ -520,7 +520,7 @@ class CivitaiUserPostsExtractor(CivitaiExtractor):
|
||||
subcategory = "user-posts"
|
||||
directory_fmt = ("{category}", "{username|user[username]}", "posts",
|
||||
"{post[id]}{post[title]:? //}")
|
||||
pattern = rf"{USER_PATTERN}/posts/?(?:\?([^#]+))?"
|
||||
pattern = USER_PATTERN + r"/posts/?(?:\?([^#]+))?"
|
||||
example = "https://civitai.com/user/USER/posts"
|
||||
|
||||
def posts(self):
|
||||
@@ -532,7 +532,7 @@ class CivitaiUserPostsExtractor(CivitaiExtractor):
|
||||
|
||||
class CivitaiUserImagesExtractor(CivitaiExtractor):
|
||||
subcategory = "user-images"
|
||||
pattern = rf"{USER_PATTERN}/images/?(?:\?([^#]+))?"
|
||||
pattern = USER_PATTERN + r"/images/?(?:\?([^#]+))?"
|
||||
example = "https://civitai.com/user/USER/images"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -553,7 +553,7 @@ class CivitaiUserImagesExtractor(CivitaiExtractor):
|
||||
class CivitaiUserVideosExtractor(CivitaiExtractor):
|
||||
subcategory = "user-videos"
|
||||
directory_fmt = ("{category}", "{username|user[username]}", "videos")
|
||||
pattern = rf"{USER_PATTERN}/videos/?(?:\?([^#]+))?"
|
||||
pattern = USER_PATTERN + r"/videos/?(?:\?([^#]+))?"
|
||||
example = "https://civitai.com/user/USER/videos"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -572,7 +572,7 @@ class CivitaiUserVideosExtractor(CivitaiExtractor):
|
||||
|
||||
class CivitaiUserCollectionsExtractor(CivitaiExtractor):
|
||||
subcategory = "user-collections"
|
||||
pattern = rf"{USER_PATTERN}/collections/?(?:\?([^#]+))?"
|
||||
pattern = USER_PATTERN + r"/collections/?(?:\?([^#]+))?"
|
||||
example = "https://civitai.com/user/USER/collections"
|
||||
|
||||
def items(self):
|
||||
@@ -580,10 +580,10 @@ class CivitaiUserCollectionsExtractor(CivitaiExtractor):
|
||||
params = self._parse_query(query)
|
||||
params["userId"] = self.api.user(text.unquote(user))[0]["id"]
|
||||
|
||||
base = f"{self.root}/collections/"
|
||||
base = self.root + "/collections/"
|
||||
for collection in self.api.collections(params):
|
||||
collection["_extractor"] = CivitaiCollectionExtractor
|
||||
yield Message.Queue, f"{base}{collection['id']}", collection
|
||||
yield Message.Queue, base + str(collection["id"]), collection
|
||||
|
||||
|
||||
class CivitaiGeneratedExtractor(CivitaiExtractor):
|
||||
@@ -591,7 +591,7 @@ class CivitaiGeneratedExtractor(CivitaiExtractor):
|
||||
subcategory = "generated"
|
||||
filename_fmt = "{filename}.{extension}"
|
||||
directory_fmt = ("{category}", "generated")
|
||||
pattern = rf"{BASE_PATTERN}/generate"
|
||||
pattern = BASE_PATTERN + "/generate"
|
||||
example = "https://civitai.com/generate"
|
||||
|
||||
def items(self):
|
||||
@@ -647,12 +647,12 @@ class CivitaiRestAPI():
|
||||
})
|
||||
|
||||
def model(self, model_id):
|
||||
endpoint = f"/v1/models/{model_id}"
|
||||
endpoint = "/v1/models/" + str(model_id)
|
||||
return self._call(endpoint)
|
||||
|
||||
@memcache(keyarg=1)
|
||||
def model_version(self, model_version_id):
|
||||
endpoint = f"/v1/model-versions/{model_version_id}"
|
||||
endpoint = "/v1/model-versions/" + str(model_version_id)
|
||||
return self._call(endpoint)
|
||||
|
||||
def models(self, params):
|
||||
@@ -945,7 +945,7 @@ class CivitaiSearchAPI():
|
||||
|
||||
if auth := extractor.config("token"):
|
||||
if " " not in auth:
|
||||
auth = f"Bearer {auth}"
|
||||
auth = "Bearer " + auth
|
||||
else:
|
||||
auth = ("Bearer 8c46eb2508e21db1e9828a97968d"
|
||||
"91ab1ca1caa5f70a00e88a2ba1e286603b61")
|
||||
|
||||
@@ -27,7 +27,7 @@ class ComickCoversExtractor(ComickBase, GalleryExtractor):
|
||||
directory_fmt = ("{category}", "{manga}", "Covers")
|
||||
filename_fmt = "{volume:>02}_{lang}.{extension}"
|
||||
archive_fmt = "c_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/comic/([\w-]+)/cover"
|
||||
pattern = BASE_PATTERN + r"/comic/([\w-]+)/cover"
|
||||
example = "https://comick.io/comic/MANGA/cover"
|
||||
|
||||
def metadata(self, page):
|
||||
@@ -44,7 +44,7 @@ class ComickCoversExtractor(ComickBase, GalleryExtractor):
|
||||
covers.reverse()
|
||||
|
||||
return [
|
||||
(f"https://meo.comick.pictures/{cover['b2key']}", {
|
||||
("https://meo.comick.pictures/" + cover["b2key"], {
|
||||
"id" : cover["id"],
|
||||
"width" : cover["w"],
|
||||
"height": cover["h"],
|
||||
@@ -60,7 +60,7 @@ class ComickCoversExtractor(ComickBase, GalleryExtractor):
|
||||
class ComickChapterExtractor(ComickBase, ChapterExtractor):
|
||||
"""Extractor for comick.io manga chapters"""
|
||||
archive_fmt = "{chapter_hid}_{page}"
|
||||
pattern = (rf"{BASE_PATTERN}/comic/([\w-]+)"
|
||||
pattern = (BASE_PATTERN + r"/comic/([\w-]+)"
|
||||
r"/(\w+(?:-(?:chapter|volume)-[^/?#]+)?)")
|
||||
example = "https://comick.io/comic/MANGA/ID-chapter-123-en"
|
||||
|
||||
@@ -128,7 +128,7 @@ class ComickChapterExtractor(ComickBase, ChapterExtractor):
|
||||
return ()
|
||||
|
||||
return [
|
||||
(f"https://meo.comick.pictures/{img['b2key']}", {
|
||||
("https://meo.comick.pictures/" + img["b2key"], {
|
||||
"width" : img["w"],
|
||||
"height" : img["h"],
|
||||
"size" : img["s"],
|
||||
@@ -140,7 +140,7 @@ class ComickChapterExtractor(ComickBase, ChapterExtractor):
|
||||
|
||||
class ComickMangaExtractor(ComickBase, MangaExtractor):
|
||||
"""Extractor for comick.io manga"""
|
||||
pattern = rf"{BASE_PATTERN}/comic/([\w-]+)/?(?:\?([^#]+))?"
|
||||
pattern = BASE_PATTERN + r"/comic/([\w-]+)/?(?:\?([^#]+))?"
|
||||
example = "https://comick.io/comic/MANGA"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -766,7 +766,7 @@ class GalleryExtractor(Extractor):
|
||||
Extractor.__init__(self, match)
|
||||
|
||||
if url is None and (path := self.groups[0]) and path[0] == "/":
|
||||
self.page_url = f"{self.root}{path}"
|
||||
self.page_url = self.root + path
|
||||
else:
|
||||
self.page_url = url
|
||||
|
||||
@@ -863,7 +863,7 @@ class MangaExtractor(Extractor):
|
||||
Extractor.__init__(self, match)
|
||||
|
||||
if url is None and (path := self.groups[0]) and path[0] == "/":
|
||||
self.page_url = f"{self.root}{path}"
|
||||
self.page_url = self.root + path
|
||||
else:
|
||||
self.page_url = url
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ class CyberdropAlbumExtractor(lolisafe.LolisafeAlbumExtractor):
|
||||
category = "cyberdrop"
|
||||
root = "https://cyberdrop.cr"
|
||||
root_api = "https://api.cyberdrop.cr"
|
||||
pattern = rf"{BASE_PATTERN}/a/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/a/([^/?#]+)"
|
||||
example = "https://cyberdrop.cr/a/ID"
|
||||
|
||||
def items(self):
|
||||
@@ -76,7 +76,7 @@ class CyberdropMediaExtractor(CyberdropAlbumExtractor):
|
||||
"""Extractor for cyberdrop media links"""
|
||||
subcategory = "media"
|
||||
directory_fmt = ("{category}",)
|
||||
pattern = rf"{BASE_PATTERN}/f/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/f/([^/?#]+)"
|
||||
example = "https://cyberdrop.cr/f/ID"
|
||||
|
||||
def fetch_album(self, album_id):
|
||||
|
||||
@@ -20,7 +20,7 @@ class CyberfileExtractor(Extractor):
|
||||
root = "https://cyberfile.me"
|
||||
|
||||
def request_api(self, endpoint, data):
|
||||
url = f"{self.root}{endpoint}"
|
||||
url = self.root + endpoint
|
||||
headers = {
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"Origin": self.root,
|
||||
@@ -29,7 +29,7 @@ class CyberfileExtractor(Extractor):
|
||||
url, method="POST", headers=headers, data=data)
|
||||
|
||||
if "albumPasswordModel" in resp.get("javascript", ""):
|
||||
url_pw = f"{self.root}/ajax/folder_password_process"
|
||||
url_pw = self.root + "/ajax/folder_password_process"
|
||||
data_pw = {
|
||||
"folderPassword": self._get_auth_info(password=True)[1],
|
||||
"folderId": text.extr(
|
||||
@@ -48,7 +48,7 @@ class CyberfileExtractor(Extractor):
|
||||
|
||||
class CyberfileFolderExtractor(CyberfileExtractor):
|
||||
subcategory = "folder"
|
||||
pattern = rf"{BASE_PATTERN}/folder/([0-9a-f]+)"
|
||||
pattern = BASE_PATTERN + r"/folder/([0-9a-f]+)"
|
||||
example = "https://cyberfile.me/folder/0123456789abcdef/NAME"
|
||||
|
||||
def items(self):
|
||||
@@ -97,7 +97,7 @@ class CyberfileFolderExtractor(CyberfileExtractor):
|
||||
|
||||
class CyberfileSharedExtractor(CyberfileExtractor):
|
||||
subcategory = "shared"
|
||||
pattern = rf"{BASE_PATTERN}/shared/([a-zA-Z0-9]+)"
|
||||
pattern = BASE_PATTERN + r"/shared/([a-zA-Z0-9]+)"
|
||||
example = "https://cyberfile.me/shared/AbCdEfGhIjK"
|
||||
|
||||
def items(self):
|
||||
@@ -129,7 +129,7 @@ class CyberfileSharedExtractor(CyberfileExtractor):
|
||||
class CyberfileFileExtractor(CyberfileExtractor):
|
||||
subcategory = "file"
|
||||
directory_fmt = ("{category}", "{uploader}", "{folder}")
|
||||
pattern = rf"{BASE_PATTERN}/([a-zA-Z0-9]+)"
|
||||
pattern = BASE_PATTERN + r"/([a-zA-Z0-9]+)"
|
||||
example = "https://cyberfile.me/AbCdE"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -155,7 +155,7 @@ class DanbooruExtractor(BaseExtractor):
|
||||
return
|
||||
|
||||
if prefix:
|
||||
params["page"] = f"{prefix}{posts[-1]['id']}"
|
||||
params["page"] = prefix + str(posts[-1]["id"])
|
||||
elif params["page"]:
|
||||
params["page"] += 1
|
||||
else:
|
||||
@@ -174,9 +174,8 @@ class DanbooruExtractor(BaseExtractor):
|
||||
else:
|
||||
ext = data["ZIP:ZipFileName"].rpartition(".")[2]
|
||||
|
||||
fmt = ("{:>06}." + ext).format
|
||||
delays = data["Ugoira:FrameDelays"]
|
||||
return [{"file": fmt(index), "delay": delay}
|
||||
return [{"file": f"{index:>06}.{ext}", "delay": delay}
|
||||
for index, delay in enumerate(delays)]
|
||||
|
||||
def _collection_posts(self, cid, ctype):
|
||||
@@ -251,7 +250,7 @@ class DanbooruTagExtractor(DanbooruExtractor):
|
||||
subcategory = "tag"
|
||||
directory_fmt = ("{category}", "{search_tags}")
|
||||
archive_fmt = "t_{search_tags}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/posts\?(?:[^&#]*&)*tags=([^&#]*)"
|
||||
pattern = BASE_PATTERN + r"/posts\?(?:[^&#]*&)*tags=([^&#]*)"
|
||||
example = "https://danbooru.donmai.us/posts?tags=TAG"
|
||||
|
||||
def metadata(self):
|
||||
@@ -279,7 +278,7 @@ class DanbooruTagExtractor(DanbooruExtractor):
|
||||
class DanbooruRandomExtractor(DanbooruTagExtractor):
|
||||
"""Extractor for a random danbooru post"""
|
||||
subcategory = "random"
|
||||
pattern = rf"{BASE_PATTERN}/posts/random(?:\?(?:[^&#]*&)*tags=([^&#]*))?"
|
||||
pattern = BASE_PATTERN + r"/posts/random(?:\?(?:[^&#]*&)*tags=([^&#]*))?"
|
||||
example = "https://danbooru.donmai.us/posts/random?tags=TAG"
|
||||
|
||||
def metadata(self):
|
||||
@@ -299,7 +298,7 @@ class DanbooruPoolExtractor(DanbooruExtractor):
|
||||
directory_fmt = ("{category}", "pool", "{pool[id]} {pool[name]}")
|
||||
filename_fmt = "{num:>04}_{id}_{filename}.{extension}"
|
||||
archive_fmt = "p_{pool[id]}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/pool(?:s|/show)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/pool(?:s|/show)/(\d+)"
|
||||
example = "https://danbooru.donmai.us/pools/12345"
|
||||
|
||||
def metadata(self):
|
||||
@@ -317,7 +316,7 @@ class DanbooruFavgroupExtractor(DanbooruExtractor):
|
||||
"{favgroup[id]} {favgroup[name]}")
|
||||
filename_fmt = "{num:>04}_{id}_{filename}.{extension}"
|
||||
archive_fmt = "fg_{favgroup[id]}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/favorite_group(?:s|/show)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/favorite_group(?:s|/show)/(\d+)"
|
||||
example = "https://danbooru.donmai.us/favorite_groups/12345"
|
||||
|
||||
def metadata(self):
|
||||
@@ -332,7 +331,7 @@ class DanbooruPostExtractor(DanbooruExtractor):
|
||||
"""Extractor for single danbooru posts"""
|
||||
subcategory = "post"
|
||||
archive_fmt = "{id}"
|
||||
pattern = rf"{BASE_PATTERN}/post(?:s|/show)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/post(?:s|/show)/(\d+)"
|
||||
example = "https://danbooru.donmai.us/posts/12345"
|
||||
|
||||
def posts(self):
|
||||
@@ -349,7 +348,7 @@ class DanbooruMediaassetExtractor(DanbooruExtractor):
|
||||
subcategory = "media-asset"
|
||||
filename_fmt = "{category}_ma{id}_{filename}.{extension}"
|
||||
archive_fmt = "m{id}"
|
||||
pattern = rf"{BASE_PATTERN}/media_assets/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/media_assets/(\d+)"
|
||||
example = "https://danbooru.donmai.us/media_assets/12345"
|
||||
|
||||
def posts(self):
|
||||
@@ -375,7 +374,7 @@ class DanbooruPopularExtractor(DanbooruExtractor):
|
||||
subcategory = "popular"
|
||||
directory_fmt = ("{category}", "popular", "{scale}", "{date}")
|
||||
archive_fmt = "P_{scale[0]}_{date}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/(?:explore/posts/)?popular(?:\?([^#]*))?"
|
||||
pattern = BASE_PATTERN + r"/(?:explore/posts/)?popular(?:\?([^#]*))?"
|
||||
example = "https://danbooru.donmai.us/explore/posts/popular"
|
||||
|
||||
def metadata(self):
|
||||
@@ -398,7 +397,7 @@ class DanbooruPopularExtractor(DanbooruExtractor):
|
||||
class DanbooruArtistExtractor(DanbooruExtractor):
|
||||
"""Extractor for danbooru artists"""
|
||||
subcategory = "artist"
|
||||
pattern = rf"{BASE_PATTERN}/artists/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/artists/(\d+)"
|
||||
example = "https://danbooru.donmai.us/artists/12345"
|
||||
|
||||
items = DanbooruExtractor.items_artists
|
||||
@@ -411,7 +410,7 @@ class DanbooruArtistExtractor(DanbooruExtractor):
|
||||
class DanbooruArtistSearchExtractor(DanbooruExtractor):
|
||||
"""Extractor for danbooru artist searches"""
|
||||
subcategory = "artist-search"
|
||||
pattern = rf"{BASE_PATTERN}/artists/?\?([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/artists/?\?([^#]+)"
|
||||
example = "https://danbooru.donmai.us/artists?QUERY"
|
||||
|
||||
items = DanbooruExtractor.items_artists
|
||||
|
||||
@@ -22,7 +22,7 @@ class DandadanBase():
|
||||
|
||||
class DandadanChapterExtractor(DandadanBase, ChapterExtractor):
|
||||
"""Extractor for dandadan manga chapters"""
|
||||
pattern = rf"{BASE_PATTERN}(/manga/dandadan-chapter-([^/?#]+)/?)"
|
||||
pattern = BASE_PATTERN + r"(/manga/dandadan-chapter-([^/?#]+)/?)"
|
||||
example = "https://dandadan.net/manga/dandadan-chapter-123/"
|
||||
|
||||
def metadata(self, page):
|
||||
@@ -31,7 +31,7 @@ class DandadanChapterExtractor(DandadanBase, ChapterExtractor):
|
||||
return {
|
||||
"manga" : "Dandadan",
|
||||
"chapter" : text.parse_int(chapter),
|
||||
"chapter_minor": f"{sep}{minor}",
|
||||
"chapter_minor": sep + minor,
|
||||
"lang" : "en",
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ class DandadanChapterExtractor(DandadanBase, ChapterExtractor):
|
||||
class DandadanMangaExtractor(DandadanBase, MangaExtractor):
|
||||
"""Extractor for dandadan manga"""
|
||||
chapterclass = DandadanChapterExtractor
|
||||
pattern = rf"{BASE_PATTERN}(/)"
|
||||
pattern = BASE_PATTERN + r"(/)"
|
||||
example = "https://dandadan.net/"
|
||||
|
||||
def chapters(self, page):
|
||||
|
||||
@@ -28,13 +28,13 @@ class DankefuerslesenBase():
|
||||
|
||||
class DankefuerslesenChapterExtractor(DankefuerslesenBase, ChapterExtractor):
|
||||
"""Extractor for Danke fürs Lesen manga chapters"""
|
||||
pattern = rf"{BASE_PATTERN}/read/manga/([\w-]+)/([\w-]+)"
|
||||
pattern = BASE_PATTERN + r"/read/manga/([\w-]+)/([\w-]+)"
|
||||
example = "https://danke.moe/read/manga/TITLE/123/1/"
|
||||
|
||||
def _init(self):
|
||||
self.zip = self.config("zip", False)
|
||||
if self.zip:
|
||||
self.filename_fmt = f"{self.directory_fmt[-1]}.{{extension}}"
|
||||
self.filename_fmt = self.directory_fmt[-1] + ".{extension}"
|
||||
self.directory_fmt = self.directory_fmt[:-1]
|
||||
|
||||
def metadata(self, page):
|
||||
@@ -95,7 +95,7 @@ class DankefuerslesenMangaExtractor(DankefuerslesenBase, MangaExtractor):
|
||||
"""Extractor for Danke fürs Lesen manga"""
|
||||
chapterclass = DankefuerslesenChapterExtractor
|
||||
reverse = False
|
||||
pattern = rf"{BASE_PATTERN}/read/manga/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/read/manga/([^/?#]+)"
|
||||
example = "https://danke.moe/read/manga/TITLE/"
|
||||
|
||||
def chapters(self, page):
|
||||
|
||||
@@ -22,7 +22,7 @@ class DesktopographyExtractor(Extractor):
|
||||
class DesktopographySiteExtractor(DesktopographyExtractor):
|
||||
"""Extractor for all desktopography exhibitions """
|
||||
subcategory = "site"
|
||||
pattern = rf"{BASE_PATTERN}/$"
|
||||
pattern = BASE_PATTERN + r"/$"
|
||||
example = "https://desktopography.net/"
|
||||
|
||||
def items(self):
|
||||
@@ -41,7 +41,7 @@ class DesktopographySiteExtractor(DesktopographyExtractor):
|
||||
class DesktopographyExhibitionExtractor(DesktopographyExtractor):
|
||||
"""Extractor for a yearly desktopography exhibition"""
|
||||
subcategory = "exhibition"
|
||||
pattern = rf"{BASE_PATTERN}/exhibition-([^/?#]+)/"
|
||||
pattern = BASE_PATTERN + r"/exhibition-([^/?#]+)/"
|
||||
example = "https://desktopography.net/exhibition-2020/"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -70,7 +70,7 @@ class DesktopographyExhibitionExtractor(DesktopographyExtractor):
|
||||
class DesktopographyEntryExtractor(DesktopographyExtractor):
|
||||
"""Extractor for all resolutions of a desktopography wallpaper"""
|
||||
subcategory = "entry"
|
||||
pattern = rf"{BASE_PATTERN}/portfolios/([\w-]+)"
|
||||
pattern = BASE_PATTERN + r"/portfolios/([\w-]+)"
|
||||
example = "https://desktopography.net/portfolios/NAME/"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -66,7 +66,7 @@ class DeviantartExtractor(Extractor):
|
||||
self.quality = "-fullview.png?"
|
||||
self.quality_sub = text.re(r"-fullview\.[a-z0-9]+\?").sub
|
||||
else:
|
||||
self.quality = f",q_{self.quality}"
|
||||
self.quality = ",q_" + str(self.quality)
|
||||
self.quality_sub = text.re(r",q_\d+").sub
|
||||
|
||||
if self.intermediary:
|
||||
@@ -864,7 +864,7 @@ x2="45.4107524%" y2="71.4898596%" id="app-root-3">\
|
||||
|
||||
class DeviantartUserExtractor(Dispatch, DeviantartExtractor):
|
||||
"""Extractor for an artist's user profile"""
|
||||
pattern = rf"{BASE_PATTERN}/?$"
|
||||
pattern = BASE_PATTERN + r"/?$"
|
||||
example = "https://www.deviantart.com/USER"
|
||||
|
||||
def items(self):
|
||||
@@ -887,7 +887,7 @@ class DeviantartGalleryExtractor(DeviantartExtractor):
|
||||
"""Extractor for all deviations from an artist's gallery"""
|
||||
subcategory = "gallery"
|
||||
archive_fmt = "g_{_username}_{index}.{extension}"
|
||||
pattern = (rf"{BASE_PATTERN}/gallery"
|
||||
pattern = (BASE_PATTERN + r"/gallery"
|
||||
r"(?:/all|/recommended-for-you)?/?(\?(?!q=).*)?$")
|
||||
example = "https://www.deviantart.com/USER/gallery/"
|
||||
|
||||
@@ -902,7 +902,7 @@ class DeviantartAvatarExtractor(DeviantartExtractor):
|
||||
"""Extractor for an artist's avatar"""
|
||||
subcategory = "avatar"
|
||||
archive_fmt = "a_{_username}_{index}"
|
||||
pattern = rf"{BASE_PATTERN}/avatar"
|
||||
pattern = BASE_PATTERN + r"/avatar"
|
||||
example = "https://www.deviantart.com/USER/avatar/"
|
||||
|
||||
def deviations(self):
|
||||
@@ -956,7 +956,7 @@ class DeviantartBackgroundExtractor(DeviantartExtractor):
|
||||
"""Extractor for an artist's banner"""
|
||||
subcategory = "background"
|
||||
archive_fmt = "b_{index}"
|
||||
pattern = rf"{BASE_PATTERN}/ba(?:nner|ckground)"
|
||||
pattern = BASE_PATTERN + r"/ba(?:nner|ckground)"
|
||||
example = "https://www.deviantart.com/USER/banner/"
|
||||
|
||||
def deviations(self):
|
||||
@@ -972,7 +972,7 @@ class DeviantartFolderExtractor(DeviantartExtractor):
|
||||
subcategory = "folder"
|
||||
directory_fmt = ("{category}", "{username}", "{folder[title]}")
|
||||
archive_fmt = "F_{folder[uuid]}_{index}.{extension}"
|
||||
pattern = rf"{BASE_PATTERN}/gallery/([^/?#]+)/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/gallery/([^/?#]+)/([^/?#]+)"
|
||||
example = "https://www.deviantart.com/USER/gallery/12345/TITLE"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -1088,7 +1088,7 @@ class DeviantartFavoriteExtractor(DeviantartExtractor):
|
||||
subcategory = "favorite"
|
||||
directory_fmt = ("{category}", "{username}", "Favourites")
|
||||
archive_fmt = "f_{_username}_{index}.{extension}"
|
||||
pattern = rf"{BASE_PATTERN}/favourites(?:/all|/?\?catpath=)?/?$"
|
||||
pattern = BASE_PATTERN + r"/favourites(?:/all|/?\?catpath=)?/?$"
|
||||
example = "https://www.deviantart.com/USER/favourites/"
|
||||
|
||||
def deviations(self):
|
||||
@@ -1105,7 +1105,7 @@ class DeviantartCollectionExtractor(DeviantartExtractor):
|
||||
directory_fmt = ("{category}", "{username}", "Favourites",
|
||||
"{collection[title]}")
|
||||
archive_fmt = "C_{collection[uuid]}_{index}.{extension}"
|
||||
pattern = rf"{BASE_PATTERN}/favourites/([^/?#]+)/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/favourites/([^/?#]+)/([^/?#]+)"
|
||||
example = "https://www.deviantart.com/USER/favourites/12345/TITLE"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -1136,7 +1136,7 @@ class DeviantartJournalExtractor(DeviantartExtractor):
|
||||
subcategory = "journal"
|
||||
directory_fmt = ("{category}", "{username}", "Journal")
|
||||
archive_fmt = "j_{_username}_{index}.{extension}"
|
||||
pattern = rf"{BASE_PATTERN}/(?:posts(?:/journals)?|journal)/?(?:\?.*)?$"
|
||||
pattern = BASE_PATTERN + r"/(?:posts(?:/journals)?|journal)/?(?:\?.*)?$"
|
||||
example = "https://www.deviantart.com/USER/posts/journals/"
|
||||
|
||||
def deviations(self):
|
||||
@@ -1149,7 +1149,7 @@ class DeviantartStatusExtractor(DeviantartExtractor):
|
||||
directory_fmt = ("{category}", "{username}", "Status")
|
||||
filename_fmt = "{category}_{index}_{title}_{date}.{extension}"
|
||||
archive_fmt = "S_{_username}_{index}.{extension}"
|
||||
pattern = rf"{BASE_PATTERN}/posts/statuses"
|
||||
pattern = BASE_PATTERN + r"/posts/statuses"
|
||||
example = "https://www.deviantart.com/USER/posts/statuses/"
|
||||
|
||||
def deviations(self):
|
||||
@@ -1253,7 +1253,7 @@ class DeviantartDeviationExtractor(DeviantartExtractor):
|
||||
"""Extractor for single deviations"""
|
||||
subcategory = "deviation"
|
||||
archive_fmt = "g_{_username}_{index}.{extension}"
|
||||
pattern = (rf"{BASE_PATTERN}/(art|journal)/(?:[^/?#]+-)?(\d+)"
|
||||
pattern = (BASE_PATTERN + r"/(art|journal)/(?:[^/?#]+-)?(\d+)"
|
||||
r"|(?:https?://)?(?:www\.)?(?:fx)?deviantart\.com/"
|
||||
r"(?:view/|deviation/|view(?:-full)?\.php/*\?(?:[^#]+&)?id=)"
|
||||
r"(\d+)" # bare deviation ID without slug
|
||||
@@ -1315,7 +1315,7 @@ class DeviantartScrapsExtractor(DeviantartExtractor):
|
||||
subcategory = "scraps"
|
||||
directory_fmt = ("{category}", "{username}", "Scraps")
|
||||
archive_fmt = "s_{_username}_{index}.{extension}"
|
||||
pattern = rf"{BASE_PATTERN}/gallery/(?:\?catpath=)?scraps\b"
|
||||
pattern = BASE_PATTERN + r"/gallery/(?:\?catpath=)?scraps\b"
|
||||
example = "https://www.deviantart.com/USER/gallery/scraps"
|
||||
|
||||
def deviations(self):
|
||||
@@ -1382,7 +1382,7 @@ class DeviantartGallerySearchExtractor(DeviantartExtractor):
|
||||
"""Extractor for deviantart gallery searches"""
|
||||
subcategory = "gallery-search"
|
||||
archive_fmt = "g_{_username}_{index}.{extension}"
|
||||
pattern = rf"{BASE_PATTERN}/gallery/?\?(q=[^#]+)"
|
||||
pattern = BASE_PATTERN + r"/gallery/?\?(q=[^#]+)"
|
||||
example = "https://www.deviantart.com/USER/gallery?q=QUERY"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -1412,7 +1412,7 @@ class DeviantartGallerySearchExtractor(DeviantartExtractor):
|
||||
class DeviantartFollowingExtractor(DeviantartExtractor):
|
||||
"""Extractor for user's watched users"""
|
||||
subcategory = "following"
|
||||
pattern = rf"{BASE_PATTERN}/(?:about#)?watching"
|
||||
pattern = BASE_PATTERN + "/(?:about#)?watching"
|
||||
example = "https://www.deviantart.com/USER/about#watching"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -238,7 +238,7 @@ class DiscordExtractor(Extractor):
|
||||
|
||||
class DiscordChannelExtractor(DiscordExtractor):
|
||||
subcategory = "channel"
|
||||
pattern = rf"{BASE_PATTERN}/channels/(\d+)/(?:\d+/threads/)?(\d+)/?$"
|
||||
pattern = BASE_PATTERN + r"/channels/(\d+)/(?:\d+/threads/)?(\d+)/?$"
|
||||
example = "https://discord.com/channels/1234567890/9876543210"
|
||||
|
||||
def items(self):
|
||||
@@ -251,7 +251,7 @@ class DiscordChannelExtractor(DiscordExtractor):
|
||||
|
||||
class DiscordMessageExtractor(DiscordExtractor):
|
||||
subcategory = "message"
|
||||
pattern = rf"{BASE_PATTERN}/channels/(\d+)/(\d+)/(\d+)/?$"
|
||||
pattern = BASE_PATTERN + r"/channels/(\d+)/(\d+)/(\d+)/?$"
|
||||
example = "https://discord.com/channels/1234567890/9876543210/2468013579"
|
||||
|
||||
def items(self):
|
||||
@@ -268,7 +268,7 @@ class DiscordMessageExtractor(DiscordExtractor):
|
||||
|
||||
class DiscordServerExtractor(DiscordExtractor):
|
||||
subcategory = "server"
|
||||
pattern = rf"{BASE_PATTERN}/channels/(\d+)/?$"
|
||||
pattern = BASE_PATTERN + r"/channels/(\d+)/?$"
|
||||
example = "https://discord.com/channels/1234567890"
|
||||
|
||||
def items(self):
|
||||
@@ -286,7 +286,7 @@ class DiscordDirectMessagesExtractor(DiscordExtractor):
|
||||
subcategory = "direct-messages"
|
||||
directory_fmt = ("{category}", "Direct Messages",
|
||||
"{channel_id}_{recipients:J,}")
|
||||
pattern = rf"{BASE_PATTERN}/channels/@me/(\d+)/?$"
|
||||
pattern = BASE_PATTERN + r"/channels/@me/(\d+)/?$"
|
||||
example = "https://discord.com/channels/@me/1234567890"
|
||||
|
||||
def items(self):
|
||||
@@ -297,7 +297,7 @@ class DiscordDirectMessageExtractor(DiscordExtractor):
|
||||
subcategory = "direct-message"
|
||||
directory_fmt = ("{category}", "Direct Messages",
|
||||
"{channel_id}_{recipients:J,}")
|
||||
pattern = rf"{BASE_PATTERN}/channels/@me/(\d+)/(\d+)/?$"
|
||||
pattern = BASE_PATTERN + r"/channels/@me/(\d+)/(\d+)/?$"
|
||||
example = "https://discord.com/channels/@me/1234567890/9876543210"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -41,7 +41,7 @@ class DynastyscansBase():
|
||||
|
||||
class DynastyscansChapterExtractor(DynastyscansBase, ChapterExtractor):
|
||||
"""Extractor for manga-chapters from dynasty-scans.com"""
|
||||
pattern = rf"{BASE_PATTERN}(/chapters/[^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"(/chapters/[^/?#]+)"
|
||||
example = "https://dynasty-scans.com/chapters/NAME"
|
||||
|
||||
def metadata(self, page):
|
||||
@@ -81,7 +81,7 @@ class DynastyscansChapterExtractor(DynastyscansBase, ChapterExtractor):
|
||||
class DynastyscansMangaExtractor(DynastyscansBase, MangaExtractor):
|
||||
chapterclass = DynastyscansChapterExtractor
|
||||
reverse = False
|
||||
pattern = rf"{BASE_PATTERN}(/series/[^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"(/series/[^/?#]+)"
|
||||
example = "https://dynasty-scans.com/series/NAME"
|
||||
|
||||
def chapters(self, page):
|
||||
@@ -97,7 +97,7 @@ class DynastyscansSearchExtractor(DynastyscansBase, Extractor):
|
||||
directory_fmt = ("{category}", "Images")
|
||||
filename_fmt = "{image_id}.{extension}"
|
||||
archive_fmt = "i_{image_id}"
|
||||
pattern = rf"{BASE_PATTERN}/images/?(?:\?([^#]+))?$"
|
||||
pattern = BASE_PATTERN + r"/images/?(?:\?([^#]+))?$"
|
||||
example = "https://dynasty-scans.com/images?QUERY"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -126,7 +126,7 @@ class DynastyscansSearchExtractor(DynastyscansBase, Extractor):
|
||||
class DynastyscansImageExtractor(DynastyscansSearchExtractor):
|
||||
"""Extractor for individual images on dynasty-scans.com"""
|
||||
subcategory = "image"
|
||||
pattern = rf"{BASE_PATTERN}/images/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/images/(\d+)"
|
||||
example = "https://dynasty-scans.com/images/12345"
|
||||
|
||||
def images(self):
|
||||
@@ -136,7 +136,7 @@ class DynastyscansImageExtractor(DynastyscansSearchExtractor):
|
||||
class DynastyscansAnthologyExtractor(DynastyscansSearchExtractor):
|
||||
"""Extractor for dynasty-scans anthologies"""
|
||||
subcategory = "anthology"
|
||||
pattern = rf"{BASE_PATTERN}/anthologies/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/anthologies/([^/?#]+)"
|
||||
example = "https://dynasty-scans.com/anthologies/TITLE"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -94,13 +94,13 @@ BASE_PATTERN = E621Extractor.update({
|
||||
|
||||
class E621TagExtractor(E621Extractor, danbooru.DanbooruTagExtractor):
|
||||
"""Extractor for e621 posts from tag searches"""
|
||||
pattern = rf"{BASE_PATTERN}/posts?(?:\?[^#]*?tags=|/index/\d+/)([^&#]*)"
|
||||
pattern = BASE_PATTERN + r"/posts?(?:\?[^#]*?tags=|/index/\d+/)([^&#]*)"
|
||||
example = "https://e621.net/posts?tags=TAG"
|
||||
|
||||
|
||||
class E621PoolExtractor(E621Extractor, danbooru.DanbooruPoolExtractor):
|
||||
"""Extractor for e621 pools"""
|
||||
pattern = rf"{BASE_PATTERN}/pool(?:s|/show)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/pool(?:s|/show)/(\d+)"
|
||||
example = "https://e621.net/pools/12345"
|
||||
|
||||
def posts(self):
|
||||
@@ -125,7 +125,7 @@ class E621PoolExtractor(E621Extractor, danbooru.DanbooruPoolExtractor):
|
||||
|
||||
class E621PostExtractor(E621Extractor, danbooru.DanbooruPostExtractor):
|
||||
"""Extractor for single e621 posts"""
|
||||
pattern = rf"{BASE_PATTERN}/post(?:s|/show)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/post(?:s|/show)/(\d+)"
|
||||
example = "https://e621.net/posts/12345"
|
||||
|
||||
def posts(self):
|
||||
@@ -135,7 +135,7 @@ class E621PostExtractor(E621Extractor, danbooru.DanbooruPostExtractor):
|
||||
|
||||
class E621PopularExtractor(E621Extractor, danbooru.DanbooruPopularExtractor):
|
||||
"""Extractor for popular images from e621"""
|
||||
pattern = rf"{BASE_PATTERN}/explore/posts/popular(?:\?([^#]*))?"
|
||||
pattern = BASE_PATTERN + r"/explore/posts/popular(?:\?([^#]*))?"
|
||||
example = "https://e621.net/explore/posts/popular"
|
||||
|
||||
def posts(self):
|
||||
@@ -145,7 +145,7 @@ class E621PopularExtractor(E621Extractor, danbooru.DanbooruPopularExtractor):
|
||||
class E621ArtistExtractor(E621Extractor, danbooru.DanbooruArtistExtractor):
|
||||
"""Extractor for e621 artists"""
|
||||
subcategory = "artist"
|
||||
pattern = rf"{BASE_PATTERN}/artists/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/artists/(\d+)"
|
||||
example = "https://e621.net/artists/12345"
|
||||
|
||||
items = E621Extractor.items_artists
|
||||
@@ -155,7 +155,7 @@ class E621ArtistSearchExtractor(E621Extractor,
|
||||
danbooru.DanbooruArtistSearchExtractor):
|
||||
"""Extractor for e621 artist searches"""
|
||||
subcategory = "artist-search"
|
||||
pattern = rf"{BASE_PATTERN}/artists/?\?([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/artists/?\?([^#]+)"
|
||||
example = "https://e621.net/artists?QUERY"
|
||||
|
||||
items = E621Extractor.items_artists
|
||||
@@ -166,7 +166,7 @@ class E621FavoriteExtractor(E621Extractor):
|
||||
subcategory = "favorite"
|
||||
directory_fmt = ("{category}", "Favorites", "{user_id}")
|
||||
archive_fmt = "f_{user_id}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/favorites(?:\?([^#]*))?"
|
||||
pattern = BASE_PATTERN + r"/favorites(?:\?([^#]*))?"
|
||||
example = "https://e621.net/favorites"
|
||||
|
||||
def metadata(self):
|
||||
|
||||
@@ -25,10 +25,10 @@ class EromeExtractor(Extractor):
|
||||
_cookies = True
|
||||
|
||||
def items(self):
|
||||
base = f"{self.root}/a/"
|
||||
base = self.root + "/a/"
|
||||
data = {"_extractor": EromeAlbumExtractor}
|
||||
for album_id in self.albums():
|
||||
yield Message.Queue, f"{base}{album_id}", data
|
||||
yield Message.Queue, base + album_id, data
|
||||
|
||||
def albums(self):
|
||||
return ()
|
||||
@@ -64,7 +64,7 @@ class EromeExtractor(Extractor):
|
||||
class EromeAlbumExtractor(EromeExtractor):
|
||||
"""Extractor for albums on erome.com"""
|
||||
subcategory = "album"
|
||||
pattern = rf"{BASE_PATTERN}/a/(\w+)"
|
||||
pattern = BASE_PATTERN + r"/a/(\w+)"
|
||||
example = "https://www.erome.com/a/ID"
|
||||
|
||||
def items(self):
|
||||
@@ -121,7 +121,7 @@ class EromeAlbumExtractor(EromeExtractor):
|
||||
|
||||
class EromeUserExtractor(EromeExtractor):
|
||||
subcategory = "user"
|
||||
pattern = rf"{BASE_PATTERN}/(?!a/|search\?)([^/?#]+)(?:/?\?([^#]+))?"
|
||||
pattern = BASE_PATTERN + r"/(?!a/|search\?)([^/?#]+)(?:/?\?([^#]+))?"
|
||||
example = "https://www.erome.com/USER"
|
||||
|
||||
def albums(self):
|
||||
@@ -137,11 +137,11 @@ class EromeUserExtractor(EromeExtractor):
|
||||
|
||||
class EromeSearchExtractor(EromeExtractor):
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}/search/?\?(q=[^#]+)"
|
||||
pattern = BASE_PATTERN + r"/search/?\?(q=[^#]+)"
|
||||
example = "https://www.erome.com/search?q=QUERY"
|
||||
|
||||
def albums(self):
|
||||
url = f"{self.root}/search"
|
||||
url = self.root + "/search"
|
||||
params = text.parse_query(self.groups[0])
|
||||
return self._pagination(url, params)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class EveriaPostExtractor(EveriaExtractor):
|
||||
subcategory = "post"
|
||||
directory_fmt = ("{category}", "{title}")
|
||||
archive_fmt = "{post_url}_{num}"
|
||||
pattern = rf"{BASE_PATTERN}(/\d{{4}}/\d{{2}}/\d{{2}}/[^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"(/\d{4}/\d{2}/\d{2}/[^/?#]+)"
|
||||
example = "https://everia.club/0000/00/00/TITLE"
|
||||
|
||||
def items(self):
|
||||
@@ -72,26 +72,26 @@ class EveriaPostExtractor(EveriaExtractor):
|
||||
|
||||
class EveriaTagExtractor(EveriaExtractor):
|
||||
subcategory = "tag"
|
||||
pattern = rf"{BASE_PATTERN}(/tag/[^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"(/tag/[^/?#]+)"
|
||||
example = "https://everia.club/tag/TAG"
|
||||
|
||||
|
||||
class EveriaCategoryExtractor(EveriaExtractor):
|
||||
subcategory = "category"
|
||||
pattern = rf"{BASE_PATTERN}(/category/[^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"(/category/[^/?#]+)"
|
||||
example = "https://everia.club/category/CATEGORY"
|
||||
|
||||
|
||||
class EveriaDateExtractor(EveriaExtractor):
|
||||
subcategory = "date"
|
||||
pattern = (rf"{BASE_PATTERN}"
|
||||
rf"(/\d{{4}}(?:/\d{{2}})?(?:/\d{{2}})?)(?:/page/\d+)?/?$")
|
||||
pattern = (BASE_PATTERN +
|
||||
r"(/\d{4}(?:/\d{2})?(?:/\d{2})?)(?:/page/\d+)?/?$")
|
||||
example = "https://everia.club/0000/00/00"
|
||||
|
||||
|
||||
class EveriaSearchExtractor(EveriaExtractor):
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}/(?:page/\d+/)?\?s=([^&#]+)"
|
||||
pattern = BASE_PATTERN + r"/(?:page/\d+/)?\?s=([^&#]+)"
|
||||
example = "https://everia.club/?s=SEARCH"
|
||||
|
||||
def posts(self):
|
||||
|
||||
@@ -115,9 +115,9 @@ class ExhentaiExtractor(Extractor):
|
||||
class ExhentaiGalleryExtractor(ExhentaiExtractor):
|
||||
"""Extractor for image galleries from exhentai.org"""
|
||||
subcategory = "gallery"
|
||||
pattern = (rf"{BASE_PATTERN}/(?:"
|
||||
rf"g/(\d+)/([\da-f]{{10}})|"
|
||||
rf"s/([\da-f]{{10}})/(\d+)-(\d+))")
|
||||
pattern = (BASE_PATTERN +
|
||||
r"(?:/g/(\d+)/([\da-f]{10})"
|
||||
r"|/s/([\da-f]{10})/(\d+)-(\d+))")
|
||||
example = "https://e-hentai.org/g/12345/67890abcde/"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -562,7 +562,7 @@ class ExhentaiGalleryExtractor(ExhentaiExtractor):
|
||||
class ExhentaiSearchExtractor(ExhentaiExtractor):
|
||||
"""Extractor for exhentai search results"""
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}/(?:\?([^#]*)|tag/([^/?#]+))"
|
||||
pattern = BASE_PATTERN + r"/(?:\?([^#]*)|tag/([^/?#]+))"
|
||||
example = "https://e-hentai.org/?f_search=QUERY"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -619,7 +619,7 @@ class ExhentaiSearchExtractor(ExhentaiExtractor):
|
||||
class ExhentaiFavoriteExtractor(ExhentaiSearchExtractor):
|
||||
"""Extractor for favorited exhentai galleries"""
|
||||
subcategory = "favorite"
|
||||
pattern = rf"{BASE_PATTERN}/favorites\.php(?:\?([^#]*)())?"
|
||||
pattern = BASE_PATTERN + r"/favorites\.php(?:\?([^#]*)())?"
|
||||
example = "https://e-hentai.org/favorites.php"
|
||||
|
||||
def _init(self):
|
||||
|
||||
@@ -11,9 +11,9 @@ from .. import text, util, exception
|
||||
from ..cache import memcache
|
||||
|
||||
BASE_PATTERN = r"(?:https?://)?(?:[\w-]+\.)?facebook\.com"
|
||||
USER_PATTERN = (rf"{BASE_PATTERN}/"
|
||||
rf"(?!media/|photo/|photo.php|watch/|permalink.php)"
|
||||
rf"(?:profile\.php\?id=|people/[^/?#]+/)?([^/?&#]+)")
|
||||
USER_PATTERN = (BASE_PATTERN +
|
||||
r"/(?!media/|photo/|photo.php|watch/|permalink.php)"
|
||||
r"(?:profile\.php\?id=|people/[^/?#]+/)?([^/?&#]+)")
|
||||
|
||||
|
||||
class FacebookExtractor(Extractor):
|
||||
@@ -237,16 +237,14 @@ class FacebookExtractor(Extractor):
|
||||
|
||||
if res.url.startswith(self.root + "/login"):
|
||||
raise exception.AuthRequired(
|
||||
message=(f"You must be logged in to continue viewing images."
|
||||
f"{LEFT_OFF_TXT}")
|
||||
)
|
||||
message=("You must be logged in to continue viewing images." +
|
||||
LEFT_OFF_TXT))
|
||||
|
||||
if b'{"__dr":"CometErrorRoot.react"}' in res.content:
|
||||
raise exception.AbortExtraction(
|
||||
f"You've been temporarily blocked from viewing images.\n"
|
||||
f"Please try using a different account, "
|
||||
f"using a VPN or waiting before you retry.{LEFT_OFF_TXT}"
|
||||
)
|
||||
"You've been temporarily blocked from viewing images.\n"
|
||||
"Please try using a different account, "
|
||||
"using a VPN or waiting before you retry." + LEFT_OFF_TXT)
|
||||
|
||||
return res
|
||||
|
||||
@@ -395,9 +393,9 @@ class FacebookExtractor(Extractor):
|
||||
class FacebookPhotoExtractor(FacebookExtractor):
|
||||
"""Base class for Facebook Photo extractors"""
|
||||
subcategory = "photo"
|
||||
pattern = (rf"{BASE_PATTERN}/"
|
||||
rf"(?:[^/?#]+/photos/[^/?#]+/|photo(?:.php)?/?\?"
|
||||
rf"(?:[^&#]+&)*fbid=)([^/?&#]+)[^/?#]*(?<!&setextract)$")
|
||||
pattern = (BASE_PATTERN +
|
||||
r"/(?:[^/?#]+/photos/[^/?#]+/|photo(?:.php)?/?\?"
|
||||
r"(?:[^&#]+&)*fbid=)([^/?&#]+)[^/?#]*(?<!&setextract)$")
|
||||
example = "https://www.facebook.com/photo/?fbid=PHOTO_ID"
|
||||
|
||||
def items(self):
|
||||
@@ -433,11 +431,12 @@ class FacebookSetExtractor(FacebookExtractor):
|
||||
"""Base class for Facebook Set extractors"""
|
||||
subcategory = "set"
|
||||
pattern = (
|
||||
rf"{BASE_PATTERN}/"
|
||||
rf"(?:(?:media/set|photo)/?\?(?:[^&#]+&)*set=([^&#]+)"
|
||||
rf"[^/?#]*(?<!&setextract)$"
|
||||
rf"|([^/?#]+/posts/[^/?#]+)"
|
||||
rf"|photo/\?(?:[^&#]+&)*fbid=([^/?&#]+)&set=([^/?&#]+)&setextract)")
|
||||
BASE_PATTERN +
|
||||
r"/(?:(?:media/set|photo)/?\?(?:[^&#]+&)*set=([^&#]+)"
|
||||
r"[^/?#]*(?<!&setextract)$"
|
||||
r"|([^/?#]+/posts/[^/?#]+)"
|
||||
r"|photo/\?(?:[^&#]+&)*fbid=([^/?&#]+)&set=([^/?&#]+)&setextract)"
|
||||
)
|
||||
example = "https://www.facebook.com/media/set/?set=SET_ID"
|
||||
|
||||
def items(self):
|
||||
@@ -460,7 +459,7 @@ class FacebookVideoExtractor(FacebookExtractor):
|
||||
"""Base class for Facebook Video extractors"""
|
||||
subcategory = "video"
|
||||
directory_fmt = ("{category}", "{username}", "{subcategory}")
|
||||
pattern = rf"{BASE_PATTERN}/(?:[^/?#]+/videos/|watch/?\?v=)([^/?&#]+)"
|
||||
pattern = BASE_PATTERN + r"/(?:[^/?#]+/videos/|watch/?\?v=)([^/?&#]+)"
|
||||
example = "https://www.facebook.com/watch/?v=VIDEO_ID"
|
||||
|
||||
def items(self):
|
||||
@@ -487,7 +486,7 @@ class FacebookInfoExtractor(FacebookExtractor):
|
||||
"""Extractor for Facebook Profile data"""
|
||||
subcategory = "info"
|
||||
directory_fmt = ("{category}", "{username}")
|
||||
pattern = rf"{USER_PATTERN}/info"
|
||||
pattern = USER_PATTERN + r"/info"
|
||||
example = "https://www.facebook.com/USERNAME/info"
|
||||
|
||||
def items(self):
|
||||
@@ -498,7 +497,7 @@ class FacebookInfoExtractor(FacebookExtractor):
|
||||
class FacebookAlbumsExtractor(FacebookExtractor):
|
||||
"""Extractor for Facebook Profile albums"""
|
||||
subcategory = "albums"
|
||||
pattern = rf"{USER_PATTERN}/photos_albums(?:/([^/?#]+))?"
|
||||
pattern = USER_PATTERN + r"/photos_albums(?:/([^/?#]+))?"
|
||||
example = "https://www.facebook.com/USERNAME/photos_albums"
|
||||
|
||||
def items(self):
|
||||
@@ -531,7 +530,7 @@ class FacebookAlbumsExtractor(FacebookExtractor):
|
||||
class FacebookPhotosExtractor(FacebookExtractor):
|
||||
"""Extractor for Facebook Profile Photos"""
|
||||
subcategory = "photos"
|
||||
pattern = rf"{USER_PATTERN}/photos(?:_by)?"
|
||||
pattern = USER_PATTERN + r"/photos(?:_by)?"
|
||||
example = "https://www.facebook.com/USERNAME/photos"
|
||||
|
||||
def items(self):
|
||||
@@ -548,7 +547,7 @@ class FacebookPhotosExtractor(FacebookExtractor):
|
||||
class FacebookAvatarExtractor(FacebookExtractor):
|
||||
"""Extractor for Facebook Profile Avatars"""
|
||||
subcategory = "avatar"
|
||||
pattern = rf"{USER_PATTERN}/avatar"
|
||||
pattern = USER_PATTERN + r"/avatar"
|
||||
example = "https://www.facebook.com/USERNAME/avatar"
|
||||
|
||||
def items(self):
|
||||
@@ -570,7 +569,7 @@ class FacebookAvatarExtractor(FacebookExtractor):
|
||||
|
||||
class FacebookUserExtractor(Dispatch, FacebookExtractor):
|
||||
"""Extractor for Facebook Profiles"""
|
||||
pattern = rf"{USER_PATTERN}/?(?:$|\?|#)"
|
||||
pattern = USER_PATTERN + r"/?(?:$|\?|#)"
|
||||
example = "https://www.facebook.com/USERNAME"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -340,7 +340,7 @@ class FanboxExtractor(Extractor):
|
||||
url = (f"https://docs.google.com/forms/d/e/"
|
||||
f"{content_id}/viewform?usp=sf_link")
|
||||
else:
|
||||
self.log.warning(f"service not recognized: {provider}")
|
||||
self.log.warning("service not recognized: %s", provider)
|
||||
|
||||
if url:
|
||||
final_post["embed"] = embed
|
||||
@@ -355,7 +355,7 @@ class FanboxExtractor(Extractor):
|
||||
class FanboxCreatorExtractor(FanboxExtractor):
|
||||
"""Extractor for a Fanbox creator's works"""
|
||||
subcategory = "creator"
|
||||
pattern = rf"{USER_PATTERN}(?:/posts)?/?$"
|
||||
pattern = USER_PATTERN + r"(?:/posts)?/?$"
|
||||
example = "https://USER.fanbox.cc/"
|
||||
|
||||
def posts(self):
|
||||
@@ -384,7 +384,7 @@ class FanboxCreatorExtractor(FanboxExtractor):
|
||||
class FanboxPostExtractor(FanboxExtractor):
|
||||
"""Extractor for media from a single Fanbox post"""
|
||||
subcategory = "post"
|
||||
pattern = rf"{USER_PATTERN}/posts/(\d+)"
|
||||
pattern = USER_PATTERN + r"/posts/(\d+)"
|
||||
example = "https://USER.fanbox.cc/posts/12345"
|
||||
|
||||
def posts(self):
|
||||
@@ -394,7 +394,7 @@ class FanboxPostExtractor(FanboxExtractor):
|
||||
class FanboxHomeExtractor(FanboxExtractor):
|
||||
"""Extractor for your Fanbox home feed"""
|
||||
subcategory = "home"
|
||||
pattern = rf"{BASE_PATTERN}/?$"
|
||||
pattern = BASE_PATTERN + r"/?$"
|
||||
example = "https://fanbox.cc/"
|
||||
|
||||
def posts(self):
|
||||
@@ -405,7 +405,7 @@ class FanboxHomeExtractor(FanboxExtractor):
|
||||
class FanboxSupportingExtractor(FanboxExtractor):
|
||||
"""Extractor for your supported Fanbox users feed"""
|
||||
subcategory = "supporting"
|
||||
pattern = rf"{BASE_PATTERN}/home/supporting"
|
||||
pattern = BASE_PATTERN + r"/home/supporting"
|
||||
example = "https://fanbox.cc/home/supporting"
|
||||
|
||||
def posts(self):
|
||||
|
||||
@@ -135,7 +135,7 @@ class FanslyExtractor(Extractor):
|
||||
|
||||
files.append({
|
||||
"file": file,
|
||||
"url": f"ytdl:{location['location']}",
|
||||
"url": "ytdl:" + location["location"],
|
||||
"_fallback": fallback,
|
||||
"_ytdl_manifest":
|
||||
"dash" if mime == "application/dash+xml" else "hls",
|
||||
@@ -155,7 +155,7 @@ class FanslyExtractor(Extractor):
|
||||
|
||||
class FanslyPostExtractor(FanslyExtractor):
|
||||
subcategory = "post"
|
||||
pattern = rf"{BASE_PATTERN}/post/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/post/(\d+)"
|
||||
example = "https://fansly.com/post/1234567890"
|
||||
|
||||
def posts(self):
|
||||
@@ -164,7 +164,7 @@ class FanslyPostExtractor(FanslyExtractor):
|
||||
|
||||
class FanslyHomeExtractor(FanslyExtractor):
|
||||
subcategory = "home"
|
||||
pattern = rf"{BASE_PATTERN}/home(?:/(?:subscribed()|list/(\d+)))?"
|
||||
pattern = BASE_PATTERN + r"/home(?:/(?:subscribed()|list/(\d+)))?"
|
||||
example = "https://fansly.com/home"
|
||||
|
||||
def posts(self):
|
||||
@@ -180,11 +180,11 @@ class FanslyHomeExtractor(FanslyExtractor):
|
||||
|
||||
class FanslyListExtractor(FanslyExtractor):
|
||||
subcategory = "list"
|
||||
pattern = rf"{BASE_PATTERN}/lists/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/lists/(\d+)"
|
||||
example = "https://fansly.com/lists/1234567890"
|
||||
|
||||
def items(self):
|
||||
base = f"{self.root}/"
|
||||
base = self.root + "/"
|
||||
for account in self.api.lists_itemsnew(self.groups[0]):
|
||||
account["_extractor"] = FanslyCreatorPostsExtractor
|
||||
url = f"{base}{account['username']}/posts"
|
||||
@@ -193,11 +193,11 @@ class FanslyListExtractor(FanslyExtractor):
|
||||
|
||||
class FanslyListsExtractor(FanslyExtractor):
|
||||
subcategory = "lists"
|
||||
pattern = rf"{BASE_PATTERN}/lists"
|
||||
pattern = BASE_PATTERN + r"/lists"
|
||||
example = "https://fansly.com/lists"
|
||||
|
||||
def items(self):
|
||||
base = f"{self.root}/lists/"
|
||||
base = self.root + "/lists/"
|
||||
for list in self.api.lists_account():
|
||||
list["_extractor"] = FanslyListExtractor
|
||||
url = f"{base}{list['id']}#{list['label']}"
|
||||
@@ -206,7 +206,7 @@ class FanslyListsExtractor(FanslyExtractor):
|
||||
|
||||
class FanslyCreatorPostsExtractor(FanslyExtractor):
|
||||
subcategory = "creator-posts"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/posts(?:/wall/(\d+))?"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/posts(?:/wall/(\d+))?"
|
||||
example = "https://fansly.com/CREATOR/posts"
|
||||
|
||||
def posts_wall(self, account, wall):
|
||||
@@ -215,7 +215,7 @@ class FanslyCreatorPostsExtractor(FanslyExtractor):
|
||||
|
||||
class FanslyCreatorMediaExtractor(FanslyExtractor):
|
||||
subcategory = "creator-media"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/media(?:/wall/(\d+))?"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/media(?:/wall/(\d+))?"
|
||||
example = "https://fansly.com/CREATOR/media"
|
||||
|
||||
def posts_wall(self, account, wall):
|
||||
@@ -308,7 +308,7 @@ class FanslyAPI():
|
||||
return self._pagination(endpoint, params)
|
||||
|
||||
def timeline_new(self, account_id, wall_id):
|
||||
endpoint = f"/v1/timelinenew/{account_id}"
|
||||
endpoint = "/v1/timelinenew/" + str(account_id)
|
||||
params = {
|
||||
"before" : "0",
|
||||
"after" : "0",
|
||||
|
||||
@@ -20,7 +20,7 @@ class FapelloPostExtractor(Extractor):
|
||||
directory_fmt = ("{category}", "{model}")
|
||||
filename_fmt = "{model}_{id}.{extension}"
|
||||
archive_fmt = "{type}_{model}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/(?!search/|popular_videos/)([^/?#]+)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/(?!search/|popular_videos/)([^/?#]+)/(\d+)"
|
||||
example = "https://fapello.com/MODEL/12345/"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -52,9 +52,9 @@ class FapelloModelExtractor(Extractor):
|
||||
"""Extractor for all posts from a fapello model"""
|
||||
category = "fapello"
|
||||
subcategory = "model"
|
||||
pattern = (rf"{BASE_PATTERN}/(?!top-(?:likes|followers)|popular_videos"
|
||||
rf"|videos|trending|search/?$)"
|
||||
rf"([^/?#]+)/?$")
|
||||
pattern = (BASE_PATTERN + r"/(?!top-(?:likes|followers)|popular_videos"
|
||||
r"|videos|trending|search/?$)"
|
||||
r"([^/?#]+)/?$")
|
||||
example = "https://fapello.com/model/"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -85,9 +85,9 @@ class FapelloPathExtractor(Extractor):
|
||||
"""Extractor for models and posts from fapello.com paths"""
|
||||
category = "fapello"
|
||||
subcategory = "path"
|
||||
pattern = (rf"{BASE_PATTERN}/(?!search/?$)"
|
||||
rf"(top-(?:likes|followers)|videos|trending"
|
||||
rf"|popular_videos/[^/?#]+)/?$")
|
||||
pattern = (BASE_PATTERN +
|
||||
r"/(?!search/?$)(top-(?:likes|followers)|videos|trending"
|
||||
r"|popular_videos/[^/?#]+)/?$")
|
||||
example = "https://fapello.com/trending/"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -67,7 +67,7 @@ class FikfapExtractor(Extractor):
|
||||
|
||||
class FikfapPostExtractor(FikfapExtractor):
|
||||
subcategory = "post"
|
||||
pattern = rf"{BASE_PATTERN}/user/(\w+)/post/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/user/(\w+)/post/(\d+)"
|
||||
example = "https://fikfap.com/user/USER/post/12345"
|
||||
|
||||
def posts(self):
|
||||
@@ -86,7 +86,7 @@ class FikfapPostExtractor(FikfapExtractor):
|
||||
|
||||
class FikfapUserExtractor(FikfapExtractor):
|
||||
subcategory = "user"
|
||||
pattern = rf"{BASE_PATTERN}/user/(\w+)"
|
||||
pattern = BASE_PATTERN + r"/user/(\w+)"
|
||||
example = "https://fikfap.com/user/USER"
|
||||
|
||||
def posts(self):
|
||||
|
||||
@@ -50,7 +50,7 @@ class FitnakedgirlsGalleryExtractor(GalleryExtractor, FitnakedgirlsExtractor):
|
||||
directory_fmt = ("{category}", "{title}")
|
||||
filename_fmt = "{filename}.{extension}"
|
||||
archive_fmt = "{gallery_id}_{filename}"
|
||||
pattern = rf"{BASE_PATTERN}/photos/gallery/([\w-]+)/?$"
|
||||
pattern = BASE_PATTERN + r"/photos/gallery/([\w-]+)/?$"
|
||||
example = "https://fitnakedgirls.com/photos/gallery/MODEL-nude/"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -110,7 +110,7 @@ class FitnakedgirlsGalleryExtractor(GalleryExtractor, FitnakedgirlsExtractor):
|
||||
class FitnakedgirlsCategoryExtractor(FitnakedgirlsExtractor):
|
||||
"""Extractor for fitnakedgirls category pages"""
|
||||
subcategory = "category"
|
||||
pattern = rf"{BASE_PATTERN}/photos/gallery/category/([\w-]+)"
|
||||
pattern = BASE_PATTERN + r"/photos/gallery/category/([\w-]+)"
|
||||
example = "https://fitnakedgirls.com/photos/gallery/category/CATEGORY/"
|
||||
|
||||
def galleries(self):
|
||||
@@ -121,7 +121,7 @@ class FitnakedgirlsCategoryExtractor(FitnakedgirlsExtractor):
|
||||
class FitnakedgirlsTagExtractor(FitnakedgirlsExtractor):
|
||||
"""Extractor for fitnakedgirls tag pages"""
|
||||
subcategory = "tag"
|
||||
pattern = rf"{BASE_PATTERN}/photos/gallery/tag/([\w-]+)"
|
||||
pattern = BASE_PATTERN + r"/photos/gallery/tag/([\w-]+)"
|
||||
example = "https://fitnakedgirls.com/photos/gallery/tag/TAG/"
|
||||
|
||||
def galleries(self):
|
||||
@@ -135,7 +135,7 @@ class FitnakedgirlsVideoExtractor(FitnakedgirlsExtractor):
|
||||
directory_fmt = ("{category}", "{title}")
|
||||
filename_fmt = "{filename}.{extension}"
|
||||
archive_fmt = "{video_id}_{filename}"
|
||||
pattern = rf"{BASE_PATTERN}/videos/(\d+)/(\d+)/([\w-]+)"
|
||||
pattern = BASE_PATTERN + r"/videos/(\d+)/(\d+)/([\w-]+)"
|
||||
example = "https://fitnakedgirls.com/videos/2025/08/VIDEO-TITLE/"
|
||||
|
||||
def items(self):
|
||||
@@ -168,7 +168,7 @@ class FitnakedgirlsBlogExtractor(FitnakedgirlsExtractor):
|
||||
directory_fmt = ("{category}", "{title}")
|
||||
filename_fmt = "{filename}.{extension}"
|
||||
archive_fmt = "{post_id}_{filename}"
|
||||
pattern = rf"{BASE_PATTERN}/fitblog/([\w-]+)"
|
||||
pattern = BASE_PATTERN + r"/fitblog/([\w-]+)"
|
||||
example = "https://fitnakedgirls.com/fitblog/MODEL-NAME/"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -124,7 +124,7 @@ class FlickrAlbumExtractor(FlickrExtractor):
|
||||
directory_fmt = ("{category}", "{user[username]}",
|
||||
"Albums", "{album[id]} {album[title]}")
|
||||
archive_fmt = "a_{album[id]}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/photos/([^/?#]+)/(?:album|set)s(?:/(\d+))?"
|
||||
pattern = BASE_PATTERN + r"/photos/([^/?#]+)/(?:album|set)s(?:/(\d+))?"
|
||||
example = "https://www.flickr.com/photos/USER/albums/12345"
|
||||
|
||||
def items(self):
|
||||
@@ -166,7 +166,7 @@ class FlickrGalleryExtractor(FlickrExtractor):
|
||||
directory_fmt = ("{category}", "{user[username]}",
|
||||
"Galleries", "{gallery[gallery_id]} {gallery[title]}")
|
||||
archive_fmt = "g_{gallery[id]}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/photos/([^/?#]+)/galleries/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/photos/([^/?#]+)/galleries/(\d+)"
|
||||
example = "https://www.flickr.com/photos/USER/galleries/12345/"
|
||||
|
||||
def metadata(self):
|
||||
@@ -184,7 +184,7 @@ class FlickrGroupExtractor(FlickrExtractor):
|
||||
subcategory = "group"
|
||||
directory_fmt = ("{category}", "Groups", "{group[groupname]}")
|
||||
archive_fmt = "G_{group[nsid]}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/groups/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/groups/([^/?#]+)"
|
||||
example = "https://www.flickr.com/groups/NAME/"
|
||||
|
||||
def metadata(self):
|
||||
@@ -199,7 +199,7 @@ class FlickrUserExtractor(FlickrExtractor):
|
||||
"""Extractor for the photostream of a flickr user"""
|
||||
subcategory = "user"
|
||||
archive_fmt = "u_{user[nsid]}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/photos/([^/?#]+)/?$"
|
||||
pattern = BASE_PATTERN + r"/photos/([^/?#]+)/?$"
|
||||
example = "https://www.flickr.com/photos/USER/"
|
||||
|
||||
def photos(self):
|
||||
@@ -211,7 +211,7 @@ class FlickrFavoriteExtractor(FlickrExtractor):
|
||||
subcategory = "favorite"
|
||||
directory_fmt = ("{category}", "{user[username]}", "Favorites")
|
||||
archive_fmt = "f_{user[nsid]}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/photos/([^/?#]+)/favorites"
|
||||
pattern = BASE_PATTERN + r"/photos/([^/?#]+)/favorites"
|
||||
example = "https://www.flickr.com/photos/USER/favorites"
|
||||
|
||||
def photos(self):
|
||||
@@ -223,7 +223,7 @@ class FlickrSearchExtractor(FlickrExtractor):
|
||||
subcategory = "search"
|
||||
directory_fmt = ("{category}", "Search", "{search[text]}")
|
||||
archive_fmt = "s_{search}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/search/?\?([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/search/?\?([^#]+)"
|
||||
example = "https://flickr.com/search/?text=QUERY"
|
||||
|
||||
def metadata(self):
|
||||
@@ -456,7 +456,7 @@ class FlickrAPI(oauth.OAuth1API):
|
||||
except ValueError:
|
||||
data = {"code": -1, "message": response.content}
|
||||
if "code" in data:
|
||||
msg = data.get("message")
|
||||
msg = data.get("message", "")
|
||||
self.log.debug("Server response: %s", data)
|
||||
if data["code"] == 1:
|
||||
raise exception.NotFoundError(self.extractor.subcategory)
|
||||
@@ -466,7 +466,7 @@ class FlickrAPI(oauth.OAuth1API):
|
||||
raise exception.AuthenticationError(msg)
|
||||
elif data["code"] == 99:
|
||||
raise exception.AuthorizationError(msg)
|
||||
raise exception.AbortExtraction(f"API request failed: {msg}")
|
||||
raise exception.AbortExtraction("API request failed: " + msg)
|
||||
return data
|
||||
|
||||
def _pagination(self, method, params, key="photos"):
|
||||
|
||||
@@ -147,7 +147,7 @@ class FoolfuukaThreadExtractor(FoolfuukaExtractor):
|
||||
subcategory = "thread"
|
||||
directory_fmt = ("{category}", "{board[shortname]}",
|
||||
"{thread_num} {title|comment[:50]}")
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/thread/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/thread/(\d+)"
|
||||
example = "https://archived.moe/a/thread/12345/"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -174,7 +174,7 @@ class FoolfuukaThreadExtractor(FoolfuukaExtractor):
|
||||
class FoolfuukaBoardExtractor(FoolfuukaExtractor):
|
||||
"""Base extractor for FoolFuuka based boards/archives"""
|
||||
subcategory = "board"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)(?:/(?:page/)?(\d*))?$"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)(?:/(?:page/)?(\d*))?$"
|
||||
example = "https://archived.moe/a/"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -210,7 +210,7 @@ class FoolfuukaSearchExtractor(FoolfuukaExtractor):
|
||||
"""Base extractor for search results on FoolFuuka based boards/archives"""
|
||||
subcategory = "search"
|
||||
directory_fmt = ("{category}", "search", "{search}")
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/search((?:/[^/?#]+/[^/?#]+)+)"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/search((?:/[^/?#]+/[^/?#]+)+)"
|
||||
example = "https://archived.moe/_/search/text/QUERY/"
|
||||
request_interval = (0.5, 1.5)
|
||||
|
||||
@@ -265,7 +265,7 @@ class FoolfuukaGalleryExtractor(FoolfuukaExtractor):
|
||||
"""Base extractor for FoolFuuka galleries"""
|
||||
subcategory = "gallery"
|
||||
directory_fmt = ("{category}", "{board}", "gallery")
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/gallery(?:/(\d+))?"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/gallery(?:/(\d+))?"
|
||||
example = "https://archived.moe/a/gallery"
|
||||
|
||||
def metadata(self):
|
||||
@@ -278,7 +278,7 @@ class FoolfuukaGalleryExtractor(FoolfuukaExtractor):
|
||||
base = f"{self.root}/_/api/chan/gallery/?board={self.board}&page="
|
||||
|
||||
for pnum in pages:
|
||||
posts = self.request_json(f"{base}{pnum}")
|
||||
posts = self.request_json(base + str(pnum))
|
||||
if not posts:
|
||||
return
|
||||
yield from posts
|
||||
|
||||
@@ -47,7 +47,7 @@ class FoolslideChapterExtractor(FoolslideExtractor):
|
||||
filename_fmt = (
|
||||
"{manga}_c{chapter:>03}{chapter_minor:?//}_{page:>03}.{extension}")
|
||||
archive_fmt = "{id}"
|
||||
pattern = rf"{BASE_PATTERN}(/read/[^/?#]+/[a-z-]+/\d+/\d+(?:/\d+)?)"
|
||||
pattern = BASE_PATTERN + r"(/read/[^/?#]+/[a-z-]+/\d+/\d+(?:/\d+)?)"
|
||||
example = "https://read.powermanga.org/read/MANGA/en/0/123/"
|
||||
|
||||
def items(self):
|
||||
@@ -91,7 +91,7 @@ class FoolslideMangaExtractor(FoolslideExtractor):
|
||||
"""Base class for manga extractors for FoOlSlide based sites"""
|
||||
subcategory = "manga"
|
||||
categorytransfer = True
|
||||
pattern = rf"{BASE_PATTERN}(/series/[^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"(/series/[^/?#]+)"
|
||||
example = "https://read.powermanga.org/series/MANGA/"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -231,7 +231,7 @@ class FuraffinityExtractor(Extractor):
|
||||
class FuraffinityGalleryExtractor(FuraffinityExtractor):
|
||||
"""Extractor for a furaffinity user's gallery"""
|
||||
subcategory = "gallery"
|
||||
pattern = rf"{BASE_PATTERN}/gallery/([^/?#]+)(?:$|/(?!folder/))"
|
||||
pattern = BASE_PATTERN + r"/gallery/([^/?#]+)(?:$|/(?!folder/))"
|
||||
example = "https://www.furaffinity.net/gallery/USER/"
|
||||
|
||||
def posts(self):
|
||||
@@ -243,7 +243,7 @@ class FuraffinityFolderExtractor(FuraffinityExtractor):
|
||||
subcategory = "folder"
|
||||
directory_fmt = ("{category}", "{user!l}",
|
||||
"Folders", "{folder_id}{folder_name:? //}")
|
||||
pattern = rf"{BASE_PATTERN}/gallery/([^/?#]+)/folder/(\d+)(?:/([^/?#]+))?"
|
||||
pattern = BASE_PATTERN + r"/gallery/([^/?#]+)/folder/(\d+)(?:/([^/?#]+))?"
|
||||
example = "https://www.furaffinity.net/gallery/USER/folder/12345/FOLDER"
|
||||
|
||||
def metadata(self):
|
||||
@@ -260,7 +260,7 @@ class FuraffinityScrapsExtractor(FuraffinityExtractor):
|
||||
"""Extractor for a furaffinity user's scraps"""
|
||||
subcategory = "scraps"
|
||||
directory_fmt = ("{category}", "{user!l}", "Scraps")
|
||||
pattern = rf"{BASE_PATTERN}/scraps/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/scraps/([^/?#]+)"
|
||||
example = "https://www.furaffinity.net/scraps/USER/"
|
||||
|
||||
def posts(self):
|
||||
@@ -271,7 +271,7 @@ class FuraffinityFavoriteExtractor(FuraffinityExtractor):
|
||||
"""Extractor for a furaffinity user's favorites"""
|
||||
subcategory = "favorite"
|
||||
directory_fmt = ("{category}", "{user!l}", "Favorites")
|
||||
pattern = rf"{BASE_PATTERN}/favorites/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/favorites/([^/?#]+)"
|
||||
example = "https://www.furaffinity.net/favorites/USER/"
|
||||
|
||||
def posts(self):
|
||||
@@ -287,7 +287,7 @@ class FuraffinitySearchExtractor(FuraffinityExtractor):
|
||||
"""Extractor for furaffinity search results"""
|
||||
subcategory = "search"
|
||||
directory_fmt = ("{category}", "Search", "{search}")
|
||||
pattern = rf"{BASE_PATTERN}/search(?:/([^/?#]+))?/?[?&]([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/search(?:/([^/?#]+))?/?[?&]([^#]+)"
|
||||
example = "https://www.furaffinity.net/search/?q=QUERY"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -306,7 +306,7 @@ class FuraffinitySearchExtractor(FuraffinityExtractor):
|
||||
class FuraffinityPostExtractor(FuraffinityExtractor):
|
||||
"""Extractor for individual posts on furaffinity"""
|
||||
subcategory = "post"
|
||||
pattern = rf"{BASE_PATTERN}/(?:view|full)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/(?:view|full)/(\d+)"
|
||||
example = "https://www.furaffinity.net/view/12345/"
|
||||
|
||||
def posts(self):
|
||||
@@ -317,12 +317,12 @@ class FuraffinityPostExtractor(FuraffinityExtractor):
|
||||
|
||||
class FuraffinityUserExtractor(Dispatch, FuraffinityExtractor):
|
||||
"""Extractor for furaffinity user profiles"""
|
||||
pattern = rf"{BASE_PATTERN}/user/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/user/([^/?#]+)"
|
||||
example = "https://www.furaffinity.net/user/USER/"
|
||||
|
||||
def items(self):
|
||||
base = self.root
|
||||
user = f"{self.user}/"
|
||||
user = self.user + "/"
|
||||
return self._dispatch_extractors((
|
||||
(FuraffinityGalleryExtractor , f"{base}/gallery/{user}"),
|
||||
(FuraffinityScrapsExtractor , f"{base}/scraps/{user}"),
|
||||
@@ -333,7 +333,7 @@ class FuraffinityUserExtractor(Dispatch, FuraffinityExtractor):
|
||||
class FuraffinityFollowingExtractor(FuraffinityExtractor):
|
||||
"""Extractor for a furaffinity user's watched users"""
|
||||
subcategory = "following"
|
||||
pattern = rf"{BASE_PATTERN}/watchlist/by/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + "/watchlist/by/([^/?#]+)"
|
||||
example = "https://www.furaffinity.net/watchlist/by/USER/"
|
||||
|
||||
def items(self):
|
||||
@@ -355,7 +355,7 @@ class FuraffinityFollowingExtractor(FuraffinityExtractor):
|
||||
class FuraffinitySubmissionsExtractor(FuraffinityExtractor):
|
||||
"""Extractor for new furaffinity submissions"""
|
||||
subcategory = "submissions"
|
||||
pattern = rf"{BASE_PATTERN}(/msg/submissions(?:/[^/?#]+)?)"
|
||||
pattern = BASE_PATTERN + r"(/msg/submissions(?:/[^/?#]+)?)"
|
||||
example = "https://www.furaffinity.net/msg/submissions"
|
||||
|
||||
def posts(self):
|
||||
|
||||
@@ -97,7 +97,7 @@ class Furry34Extractor(BooruExtractor):
|
||||
class Furry34PostExtractor(Furry34Extractor):
|
||||
subcategory = "post"
|
||||
archive_fmt = "{id}"
|
||||
pattern = rf"{BASE_PATTERN}/post/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/post/(\d+)"
|
||||
example = "https://furry34.com/post/12345"
|
||||
|
||||
def posts(self):
|
||||
@@ -108,7 +108,7 @@ class Furry34PlaylistExtractor(Furry34Extractor):
|
||||
subcategory = "playlist"
|
||||
directory_fmt = ("{category}", "{playlist_id}")
|
||||
archive_fmt = "p_{playlist_id}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/playlists/view/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/playlists/view/(\d+)"
|
||||
example = "https://furry34.com/playlists/view/12345"
|
||||
|
||||
def metadata(self):
|
||||
@@ -123,7 +123,7 @@ class Furry34TagExtractor(Furry34Extractor):
|
||||
subcategory = "tag"
|
||||
directory_fmt = ("{category}", "{search_tags}")
|
||||
archive_fmt = "t_{search_tags}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/(?:([^/?#]+))?(?:/?\?([^#]+))?(?:$|#)"
|
||||
pattern = BASE_PATTERN + r"/(?:([^/?#]+))?(?:/?\?([^#]+))?(?:$|#)"
|
||||
example = "https://furry34.com/TAG"
|
||||
|
||||
def _init(self):
|
||||
|
||||
@@ -148,7 +148,7 @@ class GelbooruBase():
|
||||
class GelbooruTagExtractor(GelbooruBase,
|
||||
gelbooru_v02.GelbooruV02TagExtractor):
|
||||
"""Extractor for images from gelbooru.com based on search-tags"""
|
||||
pattern = rf"{BASE_PATTERN}page=post&s=list&tags=([^&#]*)"
|
||||
pattern = BASE_PATTERN + r"page=post&s=list&tags=([^&#]*)"
|
||||
example = "https://gelbooru.com/index.php?page=post&s=list&tags=TAG"
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ class GelbooruPoolExtractor(GelbooruBase,
|
||||
gelbooru_v02.GelbooruV02PoolExtractor):
|
||||
"""Extractor for gelbooru pools"""
|
||||
per_page = 45
|
||||
pattern = rf"{BASE_PATTERN}page=pool&s=show&id=(\d+)"
|
||||
pattern = BASE_PATTERN + r"page=pool&s=show&id=(\d+)"
|
||||
example = "https://gelbooru.com/index.php?page=pool&s=show&id=12345"
|
||||
|
||||
skip = GelbooruBase._skip_offset
|
||||
@@ -187,7 +187,7 @@ class GelbooruFavoriteExtractor(GelbooruBase,
|
||||
gelbooru_v02.GelbooruV02FavoriteExtractor):
|
||||
"""Extractor for gelbooru favorites"""
|
||||
per_page = 100
|
||||
pattern = rf"{BASE_PATTERN}page=favorites&s=view&id=(\d+)"
|
||||
pattern = BASE_PATTERN + r"page=favorites&s=view&id=(\d+)"
|
||||
example = "https://gelbooru.com/index.php?page=favorites&s=view&id=12345"
|
||||
|
||||
skip = GelbooruBase._skip_offset
|
||||
@@ -284,10 +284,10 @@ class GelbooruFavoriteExtractor(GelbooruBase,
|
||||
class GelbooruPostExtractor(GelbooruBase,
|
||||
gelbooru_v02.GelbooruV02PostExtractor):
|
||||
"""Extractor for single images from gelbooru.com"""
|
||||
pattern = (rf"{BASE_PATTERN}"
|
||||
rf"(?=(?:[^#]+&)?page=post(?:&|#|$))"
|
||||
rf"(?=(?:[^#]+&)?s=view(?:&|#|$))"
|
||||
rf"(?:[^#]+&)?id=(\d+)")
|
||||
pattern = (BASE_PATTERN +
|
||||
r"(?=(?:[^#]+&)?page=post(?:&|#|$))"
|
||||
r"(?=(?:[^#]+&)?s=view(?:&|#|$))"
|
||||
r"(?:[^#]+&)?id=(\d+)")
|
||||
example = "https://gelbooru.com/index.php?page=post&s=view&id=12345"
|
||||
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ class GelbooruV01TagExtractor(GelbooruV01Extractor):
|
||||
subcategory = "tag"
|
||||
directory_fmt = ("{category}", "{search_tags}")
|
||||
archive_fmt = "t_{search_tags}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/index\.php\?page=post&s=list&tags=([^&#]+)"
|
||||
pattern = BASE_PATTERN + r"/index\.php\?page=post&s=list&tags=([^&#]+)"
|
||||
example = "https://allgirl.booru.org/index.php?page=post&s=list&tags=TAG"
|
||||
|
||||
def metadata(self):
|
||||
@@ -104,7 +104,7 @@ class GelbooruV01FavoriteExtractor(GelbooruV01Extractor):
|
||||
directory_fmt = ("{category}", "favorites", "{favorite_id}")
|
||||
archive_fmt = "f_{favorite_id}_{id}"
|
||||
per_page = 50
|
||||
pattern = rf"{BASE_PATTERN}/index\.php\?page=favorites&s=view&id=(\d+)"
|
||||
pattern = BASE_PATTERN + r"/index\.php\?page=favorites&s=view&id=(\d+)"
|
||||
example = "https://allgirl.booru.org/index.php?page=favorites&s=view&id=1"
|
||||
|
||||
def metadata(self):
|
||||
@@ -120,7 +120,7 @@ class GelbooruV01FavoriteExtractor(GelbooruV01Extractor):
|
||||
class GelbooruV01PostExtractor(GelbooruV01Extractor):
|
||||
subcategory = "post"
|
||||
archive_fmt = "{id}"
|
||||
pattern = rf"{BASE_PATTERN}/index\.php\?page=post&s=view&id=(\d+)"
|
||||
pattern = BASE_PATTERN + r"/index\.php\?page=post&s=view&id=(\d+)"
|
||||
example = "https://allgirl.booru.org/index.php?page=post&s=view&id=12345"
|
||||
|
||||
def posts(self):
|
||||
|
||||
@@ -190,7 +190,7 @@ class GelbooruV02TagExtractor(GelbooruV02Extractor):
|
||||
subcategory = "tag"
|
||||
directory_fmt = ("{category}", "{search_tags}")
|
||||
archive_fmt = "t_{search_tags}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/index\.php\?page=post&s=list&tags=([^&#]*)"
|
||||
pattern = BASE_PATTERN + r"/index\.php\?page=post&s=list&tags=([^&#]*)"
|
||||
example = "https://safebooru.org/index.php?page=post&s=list&tags=TAG"
|
||||
|
||||
def posts(self):
|
||||
@@ -206,7 +206,7 @@ class GelbooruV02PoolExtractor(GelbooruV02Extractor):
|
||||
subcategory = "pool"
|
||||
directory_fmt = ("{category}", "pool", "{pool}")
|
||||
archive_fmt = "p_{pool}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/index\.php\?page=pool&s=show&id=(\d+)"
|
||||
pattern = BASE_PATTERN + r"/index\.php\?page=pool&s=show&id=(\d+)"
|
||||
example = "https://safebooru.org/index.php?page=pool&s=show&id=12345"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -257,7 +257,7 @@ class GelbooruV02FavoriteExtractor(GelbooruV02Extractor):
|
||||
directory_fmt = ("{category}", "favorites", "{favorite_id}")
|
||||
archive_fmt = "f_{favorite_id}_{id}"
|
||||
per_page = 50
|
||||
pattern = rf"{BASE_PATTERN}/index\.php\?page=favorites&s=view&id=(\d+)"
|
||||
pattern = BASE_PATTERN + r"/index\.php\?page=favorites&s=view&id=(\d+)"
|
||||
example = "https://safebooru.org/index.php?page=favorites&s=view&id=12345"
|
||||
|
||||
def metadata(self):
|
||||
@@ -275,7 +275,7 @@ class GelbooruV02FavoriteExtractor(GelbooruV02Extractor):
|
||||
class GelbooruV02PostExtractor(GelbooruV02Extractor):
|
||||
subcategory = "post"
|
||||
archive_fmt = "{id}"
|
||||
pattern = rf"{BASE_PATTERN}/index\.php\?page=post&s=view&id=(\d+)"
|
||||
pattern = BASE_PATTERN + r"/index\.php\?page=post&s=view&id=(\d+)"
|
||||
example = "https://safebooru.org/index.php?page=post&s=view&id=12345"
|
||||
|
||||
def posts(self):
|
||||
|
||||
@@ -22,14 +22,14 @@ class GirlsreleasedExtractor(Extractor):
|
||||
|
||||
def items(self):
|
||||
data = {"_extractor": GirlsreleasedSetExtractor}
|
||||
base = f"{self.root}/set/"
|
||||
base = self.root + "/set/"
|
||||
for set in self._pagination():
|
||||
yield Message.Queue, f"{base}{set[0]}", data
|
||||
yield Message.Queue, base + set[0], data
|
||||
|
||||
def _pagination(self):
|
||||
base = f"{self.root}/api/0.2/sets/{self._path}/{self.groups[0]}/page/"
|
||||
for pnum in itertools.count():
|
||||
sets = self.request_json(f"{base}{pnum}")["sets"]
|
||||
sets = self.request_json(base + str(pnum))["sets"]
|
||||
if not sets:
|
||||
return
|
||||
|
||||
@@ -41,7 +41,7 @@ class GirlsreleasedExtractor(Extractor):
|
||||
class GirlsreleasedSetExtractor(GirlsreleasedExtractor):
|
||||
"""Extractor for girlsreleased galleries"""
|
||||
subcategory = "set"
|
||||
pattern = rf"{BASE_PATTERN}/set/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/set/(\d+)"
|
||||
example = "https://girlsreleased.com/set/12345"
|
||||
|
||||
def items(self):
|
||||
@@ -65,12 +65,12 @@ class GirlsreleasedSetExtractor(GirlsreleasedExtractor):
|
||||
class GirlsreleasedModelExtractor(GirlsreleasedExtractor):
|
||||
"""Extractor for girlsreleased models"""
|
||||
subcategory = _path = "model"
|
||||
pattern = rf"{BASE_PATTERN}/model/(\d+(?:/.+)?)"
|
||||
pattern = BASE_PATTERN + r"/model/(\d+(?:/.+)?)"
|
||||
example = "https://girlsreleased.com/model/12345/MODEL"
|
||||
|
||||
|
||||
class GirlsreleasedSiteExtractor(GirlsreleasedExtractor):
|
||||
"""Extractor for girlsreleased sites"""
|
||||
subcategory = _path = "site"
|
||||
pattern = rf"{BASE_PATTERN}/site/([^/?#]+(?:/model/\d+/?.*)?)"
|
||||
pattern = BASE_PATTERN + r"/site/([^/?#]+(?:/model/\d+/?.*)?)"
|
||||
example = "https://girlsreleased.com/site/SITE"
|
||||
|
||||
@@ -60,7 +60,7 @@ class GirlswithmuscleExtractor(Extractor):
|
||||
class GirlswithmusclePostExtractor(GirlswithmuscleExtractor):
|
||||
"""Extractor for individual posts on girlswithmuscle.com"""
|
||||
subcategory = "post"
|
||||
pattern = rf"{BASE_PATTERN}/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/(\d+)"
|
||||
example = "https://www.girlswithmuscle.com/12345/"
|
||||
|
||||
def items(self):
|
||||
@@ -143,7 +143,7 @@ class GirlswithmusclePostExtractor(GirlswithmuscleExtractor):
|
||||
class GirlswithmuscleSearchExtractor(GirlswithmuscleExtractor):
|
||||
"""Extractor for search results on girlswithmuscle.com"""
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}/images/(.*)"
|
||||
pattern = BASE_PATTERN + r"/images/(.*)"
|
||||
example = "https://www.girlswithmuscle.com/images/?name=MODEL"
|
||||
|
||||
def pages(self):
|
||||
|
||||
@@ -123,7 +123,7 @@ class HatenablogEntriesExtractor(HatenablogExtractor):
|
||||
class HatenablogEntryExtractor(HatenablogExtractor):
|
||||
"""Extractor for a single entry URL"""
|
||||
subcategory = "entry"
|
||||
pattern = rf"{BASE_PATTERN}/entry/([^?#]+){QUERY_RE}"
|
||||
pattern = BASE_PATTERN + r"/entry/([^?#]+)" + QUERY_RE
|
||||
example = "https://BLOG.hatenablog.com/entry/PATH"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -146,21 +146,21 @@ class HatenablogEntryExtractor(HatenablogExtractor):
|
||||
class HatenablogHomeExtractor(HatenablogEntriesExtractor):
|
||||
"""Extractor for a blog's home page"""
|
||||
subcategory = "home"
|
||||
pattern = rf"{BASE_PATTERN}(/?){QUERY_RE}"
|
||||
pattern = BASE_PATTERN + r"(/?)" + QUERY_RE
|
||||
example = "https://BLOG.hatenablog.com"
|
||||
|
||||
|
||||
class HatenablogArchiveExtractor(HatenablogEntriesExtractor):
|
||||
"""Extractor for a blog's archive page"""
|
||||
subcategory = "archive"
|
||||
pattern = (rf"{BASE_PATTERN}(/archive(?:/\d+(?:/\d+(?:/\d+)?)?"
|
||||
rf"|/category/[^?#]+)?){QUERY_RE}")
|
||||
pattern = (BASE_PATTERN + r"(/archive(?:/\d+(?:/\d+(?:/\d+)?)?"
|
||||
r"|/category/[^?#]+)?)" + QUERY_RE)
|
||||
example = "https://BLOG.hatenablog.com/archive/2024"
|
||||
|
||||
|
||||
class HatenablogSearchExtractor(HatenablogEntriesExtractor):
|
||||
"""Extractor for a blog's search results"""
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}(/search){QUERY_RE}"
|
||||
pattern = BASE_PATTERN + r"(/search)" + QUERY_RE
|
||||
example = "https://BLOG.hatenablog.com/search?q=QUERY"
|
||||
allowed_parameters = ("q",)
|
||||
|
||||
@@ -23,19 +23,19 @@ class HdoujinBase():
|
||||
|
||||
class HdoujinGalleryExtractor(
|
||||
HdoujinBase, schalenetwork.SchalenetworkGalleryExtractor):
|
||||
pattern = rf"{BASE_PATTERN}/(?:g|reader)/(\d+)/(\w+)"
|
||||
pattern = BASE_PATTERN + r"/(?:g|reader)/(\d+)/(\w+)"
|
||||
example = "https://hdoujin.org/g/12345/67890abcdef/"
|
||||
|
||||
|
||||
class HdoujinSearchExtractor(
|
||||
HdoujinBase, schalenetwork.SchalenetworkSearchExtractor):
|
||||
pattern = rf"{BASE_PATTERN}/(?:tag/([^/?#]+)|browse)?(?:/?\?([^#]*))?$"
|
||||
pattern = BASE_PATTERN + r"/(?:tag/([^/?#]+)|browse)?(?:/?\?([^#]*))?$"
|
||||
example = "https://hdoujin.org/browse?s=QUERY"
|
||||
|
||||
|
||||
class HdoujinFavoriteExtractor(
|
||||
HdoujinBase, schalenetwork.SchalenetworkFavoriteExtractor):
|
||||
pattern = rf"{BASE_PATTERN}/favorites(?:\?([^#]*))?"
|
||||
pattern = BASE_PATTERN + r"/favorites(?:\?([^#]*))?"
|
||||
example = "https://hdoujin.org/favorites"
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class HentaicosplaysGalleryExtractor(
|
||||
directory_fmt = ("{site}", "{title}")
|
||||
filename_fmt = "{filename}.{extension}"
|
||||
archive_fmt = "{title}_{filename}"
|
||||
pattern = rf"{BASE_PATTERN}/(?:image|story)/([\w-]+)"
|
||||
pattern = BASE_PATTERN + r"/(?:image|story)/([\w-]+)"
|
||||
example = "https://hentai-cosplay-xxx.com/image/TITLE/"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -214,7 +214,7 @@ class HentaifoundryExtractor(Extractor):
|
||||
|
||||
class HentaifoundryUserExtractor(Dispatch, HentaifoundryExtractor):
|
||||
"""Extractor for a hentaifoundry user profile"""
|
||||
pattern = rf"{BASE_PATTERN}/user/([^/?#]+)/profile"
|
||||
pattern = BASE_PATTERN + r"/user/([^/?#]+)/profile"
|
||||
example = "https://www.hentai-foundry.com/user/USER/profile"
|
||||
|
||||
def items(self):
|
||||
@@ -235,7 +235,7 @@ class HentaifoundryUserExtractor(Dispatch, HentaifoundryExtractor):
|
||||
class HentaifoundryPicturesExtractor(HentaifoundryExtractor):
|
||||
"""Extractor for all pictures of a hentaifoundry user"""
|
||||
subcategory = "pictures"
|
||||
pattern = rf"{BASE_PATTERN}/pictures/user/([^/?#]+)(?:/page/(\d+))?/?$"
|
||||
pattern = BASE_PATTERN + r"/pictures/user/([^/?#]+)(?:/page/(\d+))?/?$"
|
||||
example = "https://www.hentai-foundry.com/pictures/user/USER"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -247,7 +247,7 @@ class HentaifoundryScrapsExtractor(HentaifoundryExtractor):
|
||||
"""Extractor for scraps of a hentaifoundry user"""
|
||||
subcategory = "scraps"
|
||||
directory_fmt = ("{category}", "{user}", "Scraps")
|
||||
pattern = rf"{BASE_PATTERN}/pictures/user/([^/?#]+)/scraps"
|
||||
pattern = BASE_PATTERN + r"/pictures/user/([^/?#]+)/scraps"
|
||||
example = "https://www.hentai-foundry.com/pictures/user/USER/scraps"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -260,7 +260,7 @@ class HentaifoundryFavoriteExtractor(HentaifoundryExtractor):
|
||||
subcategory = "favorite"
|
||||
directory_fmt = ("{category}", "{user}", "Favorites")
|
||||
archive_fmt = "f_{user}_{index}"
|
||||
pattern = rf"{BASE_PATTERN}/user/([^/?#]+)/faves/pictures"
|
||||
pattern = BASE_PATTERN + r"/user/([^/?#]+)/faves/pictures"
|
||||
example = "https://www.hentai-foundry.com/user/USER/faves/pictures"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -273,7 +273,7 @@ class HentaifoundryTagExtractor(HentaifoundryExtractor):
|
||||
subcategory = "tag"
|
||||
directory_fmt = ("{category}", "{search_tags}")
|
||||
archive_fmt = "t_{search_tags}_{index}"
|
||||
pattern = rf"{BASE_PATTERN}/pictures/tagged/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/pictures/tagged/([^/?#]+)"
|
||||
example = "https://www.hentai-foundry.com/pictures/tagged/TAG"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -289,7 +289,7 @@ class HentaifoundryRecentExtractor(HentaifoundryExtractor):
|
||||
subcategory = "recent"
|
||||
directory_fmt = ("{category}", "Recent Pictures", "{date}")
|
||||
archive_fmt = "r_{index}"
|
||||
pattern = rf"{BASE_PATTERN}/pictures/recent/(\d\d\d\d-\d\d-\d\d)"
|
||||
pattern = BASE_PATTERN + r"/pictures/recent/(\d\d\d\d-\d\d-\d\d)"
|
||||
example = "https://www.hentai-foundry.com/pictures/recent/1970-01-01"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -305,7 +305,7 @@ class HentaifoundryPopularExtractor(HentaifoundryExtractor):
|
||||
subcategory = "popular"
|
||||
directory_fmt = ("{category}", "Popular Pictures")
|
||||
archive_fmt = "p_{index}"
|
||||
pattern = rf"{BASE_PATTERN}/pictures/popular()"
|
||||
pattern = BASE_PATTERN + r"/pictures/popular()"
|
||||
example = "https://www.hentai-foundry.com/pictures/popular"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -339,7 +339,7 @@ class HentaifoundryStoriesExtractor(HentaifoundryExtractor):
|
||||
"""Extractor for stories of a hentaifoundry user"""
|
||||
subcategory = "stories"
|
||||
archive_fmt = "s_{index}"
|
||||
pattern = rf"{BASE_PATTERN}/stories/user/([^/?#]+)(?:/page/(\d+))?/?$"
|
||||
pattern = BASE_PATTERN + r"/stories/user/([^/?#]+)(?:/page/(\d+))?/?$"
|
||||
example = "https://www.hentai-foundry.com/stories/user/USER"
|
||||
|
||||
def items(self):
|
||||
@@ -358,7 +358,7 @@ class HentaifoundryStoryExtractor(HentaifoundryExtractor):
|
||||
"""Extractor for a hentaifoundry story"""
|
||||
subcategory = "story"
|
||||
archive_fmt = "s_{index}"
|
||||
pattern = rf"{BASE_PATTERN}/stories/user/([^/?#]+)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/stories/user/([^/?#]+)/(\d+)"
|
||||
example = "https://www.hentai-foundry.com/stories/user/USER/12345/TITLE"
|
||||
|
||||
skip = Extractor.skip
|
||||
|
||||
@@ -67,7 +67,7 @@ class HiperdexBase():
|
||||
|
||||
class HiperdexChapterExtractor(HiperdexBase, ChapterExtractor):
|
||||
"""Extractor for hiperdex manga chapters"""
|
||||
pattern = rf"{BASE_PATTERN}(/mangas?/([^/?#]+)/([^/?#]+))"
|
||||
pattern = BASE_PATTERN + r"(/mangas?/([^/?#]+)/([^/?#]+))"
|
||||
example = "https://hiperdex.com/manga/MANGA/CHAPTER/"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -89,7 +89,7 @@ class HiperdexChapterExtractor(HiperdexBase, ChapterExtractor):
|
||||
class HiperdexMangaExtractor(HiperdexBase, MangaExtractor):
|
||||
"""Extractor for hiperdex manga"""
|
||||
chapterclass = HiperdexChapterExtractor
|
||||
pattern = rf"{BASE_PATTERN}(/mangas?/([^/?#]+))/?$"
|
||||
pattern = BASE_PATTERN + r"(/mangas?/([^/?#]+))/?$"
|
||||
example = "https://hiperdex.com/manga/MANGA/"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -125,7 +125,7 @@ class HiperdexArtistExtractor(HiperdexBase, MangaExtractor):
|
||||
categorytransfer = False
|
||||
chapterclass = HiperdexMangaExtractor
|
||||
reverse = False
|
||||
pattern = rf"{BASE_PATTERN}(/manga-a(?:rtist|uthor)/(?:[^/?#]+))"
|
||||
pattern = BASE_PATTERN + r"(/manga-a(?:rtist|uthor)/(?:[^/?#]+))"
|
||||
example = "https://hiperdex.com/manga-artist/NAME/"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -32,14 +32,14 @@ class HitomiExtractor(Extractor):
|
||||
language = tag
|
||||
tag = "index"
|
||||
else:
|
||||
ns = f"{ns}/"
|
||||
ns += "/"
|
||||
|
||||
url = (f"https://ltn.{self.domain}/n/{ns}"
|
||||
f"/{tag.replace('_', ' ')}-{language}.nozomi")
|
||||
if headers is None:
|
||||
headers = {}
|
||||
headers["Origin"] = self.root
|
||||
headers["Referer"] = f"{self.root}/"
|
||||
headers["Referer"] = self.root + "/"
|
||||
return decode_nozomi(self.request(url, headers=headers).content)
|
||||
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ def decode_video_url(url):
|
||||
class HotleakPostExtractor(HotleakExtractor):
|
||||
"""Extractor for individual posts on hotleak"""
|
||||
subcategory = "post"
|
||||
pattern = (rf"{BASE_PATTERN}/(?!(?:hot|creators|videos|photos)(?:$|/))"
|
||||
pattern = (BASE_PATTERN + r"/(?!(?:hot|creators|videos|photos)(?:$|/))"
|
||||
r"([^/]+)/(photo|video)/(\d+)")
|
||||
example = "https://hotleak.vip/MODEL/photo/12345"
|
||||
|
||||
@@ -96,7 +96,7 @@ class HotleakPostExtractor(HotleakExtractor):
|
||||
class HotleakCreatorExtractor(HotleakExtractor):
|
||||
"""Extractor for all posts from a hotleak creator"""
|
||||
subcategory = "creator"
|
||||
pattern = (rf"{BASE_PATTERN}/(?!(?:hot|creators|videos|photos)(?:$|/))"
|
||||
pattern = (BASE_PATTERN + r"/(?!(?:hot|creators|videos|photos)(?:$|/))"
|
||||
r"([^/?#]+)/?$")
|
||||
example = "https://hotleak.vip/MODEL"
|
||||
|
||||
@@ -150,7 +150,7 @@ class HotleakCreatorExtractor(HotleakExtractor):
|
||||
class HotleakCategoryExtractor(HotleakExtractor):
|
||||
"""Extractor for hotleak categories"""
|
||||
subcategory = "category"
|
||||
pattern = rf"{BASE_PATTERN}/(hot|creators|videos|photos)(?:/?\?([^#]+))?"
|
||||
pattern = BASE_PATTERN + r"/(hot|creators|videos|photos)(?:/?\?([^#]+))?"
|
||||
example = "https://hotleak.vip/photos"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -172,7 +172,7 @@ class HotleakCategoryExtractor(HotleakExtractor):
|
||||
class HotleakSearchExtractor(HotleakExtractor):
|
||||
"""Extractor for hotleak search results"""
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}/search(?:/?\?([^#]+))"
|
||||
pattern = BASE_PATTERN + r"/search(?:/?\?([^#]+))"
|
||||
example = "https://hotleak.vip/search?search=QUERY"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -29,17 +29,17 @@ class IdolcomplexBase():
|
||||
|
||||
class IdolcomplexTagExtractor(IdolcomplexBase, sankaku.SankakuTagExtractor):
|
||||
"""Extractor for idolcomplex tag searches"""
|
||||
pattern = rf"{BASE_PATTERN}(?:/posts)?/?\?([^#]*)"
|
||||
pattern = BASE_PATTERN + r"(?:/posts)?/?\?([^#]*)"
|
||||
example = "https://www.idolcomplex.com/en/posts?tags=TAGS"
|
||||
|
||||
|
||||
class IdolcomplexPoolExtractor(IdolcomplexBase, sankaku.SankakuPoolExtractor):
|
||||
"""Extractor for idolcomplex pools"""
|
||||
pattern = rf"{BASE_PATTERN}/pools?/(?:show/)?(\w+)"
|
||||
pattern = BASE_PATTERN + r"/pools?/(?:show/)?(\w+)"
|
||||
example = "https://www.idolcomplex.com/en/pools/0123456789abcdef"
|
||||
|
||||
|
||||
class IdolcomplexPostExtractor(IdolcomplexBase, sankaku.SankakuPostExtractor):
|
||||
"""Extractor for individual idolcomplex posts"""
|
||||
pattern = rf"{BASE_PATTERN}/posts?(?:/show)?/(\w+)"
|
||||
pattern = BASE_PATTERN + r"/posts?(?:/show)?/(\w+)"
|
||||
example = "https://www.idolcomplex.com/en/posts/0123456789abcdef"
|
||||
|
||||
@@ -19,7 +19,7 @@ class ImagechestGalleryExtractor(GalleryExtractor):
|
||||
"""Extractor for image galleries from imgchest.com"""
|
||||
category = "imagechest"
|
||||
root = "https://imgchest.com"
|
||||
pattern = rf"{BASE_PATTERN}/p/([A-Za-z0-9]{{11}})"
|
||||
pattern = BASE_PATTERN + r"/p/([A-Za-z0-9]{11})"
|
||||
example = "https://imgchest.com/p/abcdefghijk"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -78,7 +78,7 @@ class ImagechestUserExtractor(Extractor):
|
||||
category = "imagechest"
|
||||
subcategory = "user"
|
||||
root = "https://imgchest.com"
|
||||
pattern = rf"{BASE_PATTERN}/u/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/u/([^/?#]+)"
|
||||
example = "https://imgchest.com/u/USER"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -39,7 +39,7 @@ class ImagefapExtractor(Extractor):
|
||||
class ImagefapGalleryExtractor(ImagefapExtractor):
|
||||
"""Extractor for image galleries from imagefap.com"""
|
||||
subcategory = "gallery"
|
||||
pattern = rf"{BASE_PATTERN}/(?:gallery\.php\?gid=|gallery/|pictures/)(\d+)"
|
||||
pattern = BASE_PATTERN + r"/(?:gallery\.php\?gid=|gallery/|pictures/)(\d+)"
|
||||
example = "https://www.imagefap.com/gallery/12345"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -110,7 +110,7 @@ class ImagefapGalleryExtractor(ImagefapExtractor):
|
||||
class ImagefapImageExtractor(ImagefapExtractor):
|
||||
"""Extractor for single images from imagefap.com"""
|
||||
subcategory = "image"
|
||||
pattern = rf"{BASE_PATTERN}/photo/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/photo/(\d+)"
|
||||
example = "https://www.imagefap.com/photo/12345"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -148,9 +148,9 @@ class ImagefapImageExtractor(ImagefapExtractor):
|
||||
class ImagefapFolderExtractor(ImagefapExtractor):
|
||||
"""Extractor for imagefap user folders"""
|
||||
subcategory = "folder"
|
||||
pattern = (rf"{BASE_PATTERN}/(?:organizer/|"
|
||||
rf"(?:usergallery\.php\?user(id)?=([^&#]+)&"
|
||||
rf"|profile/([^/?#]+)/galleries\?)folderid=)(\d+|-1)")
|
||||
pattern = (BASE_PATTERN + r"/(?:organizer/|"
|
||||
r"(?:usergallery\.php\?user(id)?=([^&#]+)&"
|
||||
r"|profile/([^/?#]+)/galleries\?)folderid=)(\d+|-1)")
|
||||
example = "https://www.imagefap.com/organizer/12345"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -206,9 +206,9 @@ class ImagefapFolderExtractor(ImagefapExtractor):
|
||||
class ImagefapUserExtractor(ImagefapExtractor):
|
||||
"""Extractor for an imagefap user profile"""
|
||||
subcategory = "user"
|
||||
pattern = (rf"{BASE_PATTERN}/(?:"
|
||||
rf"profile(?:\.php\?user=|/)([^/?#]+)(?:/galleries)?|"
|
||||
rf"usergallery\.php\?userid=(\d+))(?:$|#)")
|
||||
pattern = (BASE_PATTERN +
|
||||
r"/(?:profile(?:\.php\?user=|/)([^/?#]+)(?:/galleries)?"
|
||||
r"|usergallery\.php\?userid=(\d+))(?:$|#)")
|
||||
example = "https://www.imagefap.com/profile/USER"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -28,10 +28,7 @@ class ImagehostImageExtractor(Extractor):
|
||||
|
||||
def __init__(self, match):
|
||||
Extractor.__init__(self, match)
|
||||
if self.root:
|
||||
self.page_url = f"{self.root}{match[1]}"
|
||||
else:
|
||||
self.page_url = f"http{'s' if self._https else ''}://{match[1]}"
|
||||
self.page_url = (self.root or "https://") + match[1]
|
||||
self.token = match[2]
|
||||
|
||||
if self._params == "simple":
|
||||
@@ -461,8 +458,8 @@ class ImgdriveImageExtractor(ImagehostImageExtractor):
|
||||
|
||||
def __init__(self, match):
|
||||
path, category, self.token = match.groups()
|
||||
self.page_url = f"https://{path}"
|
||||
self.category = f"img{category}"
|
||||
self.page_url = "https://" + path
|
||||
self.category = "img" + category
|
||||
Extractor.__init__(self, match)
|
||||
|
||||
def get_info(self, page):
|
||||
|
||||
@@ -136,8 +136,8 @@ class ImgbbAlbumExtractor(ImgbbExtractor):
|
||||
'data-text="image-count">', "<")),
|
||||
}
|
||||
|
||||
url = f"{self.root}/json"
|
||||
params["pathname"] = f"/album/{album['id']}"
|
||||
url = self.root + "/json"
|
||||
params["pathname"] = "/album/" + album["id"]
|
||||
return self._pagination(page, url, params)
|
||||
|
||||
|
||||
@@ -190,11 +190,11 @@ class ImgbbUserExtractor(ImgbbExtractor):
|
||||
|
||||
if response.status_code < 300:
|
||||
params["pathname"] = "/"
|
||||
return self._pagination(response.text, f"{url}json", params)
|
||||
return self._pagination(response.text, url + "json", params)
|
||||
|
||||
if response.status_code == 301:
|
||||
raise exception.NotFoundError("user")
|
||||
redirect = f"HTTP redirect to {response.headers.get('Location')}"
|
||||
redirect = "HTTP redirect to " + response.headers.get("Location", "")
|
||||
if response.status_code == 302:
|
||||
raise exception.AuthRequired(
|
||||
("username & password", "authenticated cookies"),
|
||||
|
||||
@@ -22,13 +22,10 @@ class ImgpileExtractor(Extractor):
|
||||
"{post[title]} ({post[id_slug]})")
|
||||
archive_fmt = "{post[id_slug]}_{id}"
|
||||
|
||||
def items(self):
|
||||
pass
|
||||
|
||||
|
||||
class ImgpilePostExtractor(ImgpileExtractor):
|
||||
subcategory = "post"
|
||||
pattern = rf"{BASE_PATTERN}/p/(\w+)"
|
||||
pattern = BASE_PATTERN + r"/p/(\w+)"
|
||||
example = "https://imgpile.com/p/AbCdEfG"
|
||||
|
||||
def items(self):
|
||||
@@ -71,24 +68,23 @@ class ImgpilePostExtractor(ImgpileExtractor):
|
||||
"id_slug": text.extr(media, 'data-id="', '"'),
|
||||
"id" : text.parse_int(text.extr(
|
||||
media, 'data-media-id="', '"')),
|
||||
"url": f"""http{text.extr(media, '<a href="http', '"')}""",
|
||||
"url": "http" + text.extr(media, '<a href="http', '"'),
|
||||
})
|
||||
return files
|
||||
|
||||
|
||||
class ImgpileUserExtractor(ImgpileExtractor):
|
||||
subcategory = "user"
|
||||
pattern = rf"{BASE_PATTERN}/u/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/u/([^/?#]+)"
|
||||
example = "https://imgpile.com/u/USER"
|
||||
|
||||
def items(self):
|
||||
url = f"{self.root}/api/v1/posts"
|
||||
url = self.root + "/api/v1/posts"
|
||||
params = {
|
||||
"limit" : "100",
|
||||
"sort" : "latest",
|
||||
"period" : "all",
|
||||
"visibility": "public",
|
||||
# "moderation_status": "approved",
|
||||
"username" : self.groups[0],
|
||||
}
|
||||
headers = {
|
||||
@@ -101,7 +97,7 @@ class ImgpileUserExtractor(ImgpileExtractor):
|
||||
"Sec-Fetch-Site": "same-origin",
|
||||
}
|
||||
|
||||
base = f"{self.root}/p/"
|
||||
base = self.root + "/p/"
|
||||
while True:
|
||||
data = self.request_json(url, params=params, headers=headers)
|
||||
|
||||
@@ -111,7 +107,7 @@ class ImgpileUserExtractor(ImgpileExtractor):
|
||||
|
||||
for item in data["data"]:
|
||||
item["_extractor"] = ImgpilePostExtractor
|
||||
url = f"{base}{item['slug']}"
|
||||
url = base + item["slug"]
|
||||
yield Message.Queue, url, item
|
||||
|
||||
url = data["links"].get("next")
|
||||
|
||||
@@ -67,7 +67,7 @@ class ImgurImageExtractor(ImgurExtractor):
|
||||
subcategory = "image"
|
||||
filename_fmt = "{category}_{id}{title:?_//}.{extension}"
|
||||
archive_fmt = "{id}"
|
||||
pattern = (rf"{BASE_PATTERN}/(?!gallery|search)"
|
||||
pattern = (BASE_PATTERN + r"/(?!gallery|search)"
|
||||
r"(?:r/\w+/)?(?:[^/?#]+-)?(\w{7}|\w{5})[sbtmlh]?")
|
||||
example = "https://imgur.com/abcdefg"
|
||||
|
||||
@@ -93,7 +93,7 @@ class ImgurAlbumExtractor(ImgurExtractor):
|
||||
directory_fmt = ("{category}", "{album[id]}{album[title]:? - //}")
|
||||
filename_fmt = "{category}_{album[id]}_{num:>03}_{id}.{extension}"
|
||||
archive_fmt = "{album[id]}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/a/(?:[^/?#]+-)?(\w{{7}}|\w{{5}})"
|
||||
pattern = BASE_PATTERN + r"/a/(?:[^/?#]+-)?(\w{7}|\w{5})"
|
||||
example = "https://imgur.com/a/abcde"
|
||||
|
||||
def items(self):
|
||||
@@ -126,8 +126,7 @@ class ImgurAlbumExtractor(ImgurExtractor):
|
||||
class ImgurGalleryExtractor(ImgurExtractor):
|
||||
"""Extractor for imgur galleries"""
|
||||
subcategory = "gallery"
|
||||
pattern = (rf"{BASE_PATTERN}/"
|
||||
rf"(?:gallery|t/\w+)/(?:[^/?#]+-)?(\w{{7}}|\w{{5}})")
|
||||
pattern = BASE_PATTERN + r"/(?:gallery|t/\w+)/(?:[^/?#]+-)?(\w{7}|\w{5})"
|
||||
example = "https://imgur.com/gallery/abcde"
|
||||
|
||||
def items(self):
|
||||
@@ -143,7 +142,7 @@ class ImgurGalleryExtractor(ImgurExtractor):
|
||||
class ImgurUserExtractor(ImgurExtractor):
|
||||
"""Extractor for all images posted by a user"""
|
||||
subcategory = "user"
|
||||
pattern = (rf"{BASE_PATTERN}/user/(?!me(?:/|$|\?|#))"
|
||||
pattern = (BASE_PATTERN + r"/user/(?!me(?:/|$|\?|#))"
|
||||
r"([^/?#]+)(?:/posts|/submitted)?/?$")
|
||||
example = "https://imgur.com/user/USER"
|
||||
|
||||
@@ -154,7 +153,7 @@ class ImgurUserExtractor(ImgurExtractor):
|
||||
class ImgurFavoriteExtractor(ImgurExtractor):
|
||||
"""Extractor for a user's favorites"""
|
||||
subcategory = "favorite"
|
||||
pattern = rf"{BASE_PATTERN}/user/([^/?#]+)/favorites/?$"
|
||||
pattern = BASE_PATTERN + r"/user/([^/?#]+)/favorites/?$"
|
||||
example = "https://imgur.com/user/USER/favorites"
|
||||
|
||||
def items(self):
|
||||
@@ -164,7 +163,7 @@ class ImgurFavoriteExtractor(ImgurExtractor):
|
||||
class ImgurFavoriteFolderExtractor(ImgurExtractor):
|
||||
"""Extractor for a user's favorites folder"""
|
||||
subcategory = "favorite-folder"
|
||||
pattern = rf"{BASE_PATTERN}/user/([^/?#]+)/favorites/folder/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/user/([^/?#]+)/favorites/folder/(\d+)"
|
||||
example = "https://imgur.com/user/USER/favorites/folder/12345/TITLE"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -179,7 +178,7 @@ class ImgurFavoriteFolderExtractor(ImgurExtractor):
|
||||
class ImgurMeExtractor(ImgurExtractor):
|
||||
"""Extractor for your personal uploads"""
|
||||
subcategory = "me"
|
||||
pattern = rf"{BASE_PATTERN}/user/me(?:/posts)?(/hidden)?"
|
||||
pattern = BASE_PATTERN + r"/user/me(?:/posts)?(/hidden)?"
|
||||
example = "https://imgur.com/user/me"
|
||||
|
||||
def items(self):
|
||||
@@ -196,7 +195,7 @@ class ImgurMeExtractor(ImgurExtractor):
|
||||
class ImgurSubredditExtractor(ImgurExtractor):
|
||||
"""Extractor for a subreddits's imgur links"""
|
||||
subcategory = "subreddit"
|
||||
pattern = rf"{BASE_PATTERN}/r/([^/?#]+)/?$"
|
||||
pattern = BASE_PATTERN + r"/r/([^/?#]+)/?$"
|
||||
example = "https://imgur.com/r/SUBREDDIT"
|
||||
|
||||
def items(self):
|
||||
@@ -206,7 +205,7 @@ class ImgurSubredditExtractor(ImgurExtractor):
|
||||
class ImgurTagExtractor(ImgurExtractor):
|
||||
"""Extractor for imgur tag searches"""
|
||||
subcategory = "tag"
|
||||
pattern = rf"{BASE_PATTERN}/t/([^/?#]+)$"
|
||||
pattern = BASE_PATTERN + r"/t/([^/?#]+)$"
|
||||
example = "https://imgur.com/t/TAG"
|
||||
|
||||
def items(self):
|
||||
@@ -216,7 +215,7 @@ class ImgurTagExtractor(ImgurExtractor):
|
||||
class ImgurSearchExtractor(ImgurExtractor):
|
||||
"""Extractor for imgur search results"""
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}/search(?:/[^?#]+)?/?\?q=([^&#]+)"
|
||||
pattern = BASE_PATTERN + r"/search(?:/[^?#]+)?/?\?q=([^&#]+)"
|
||||
example = "https://imgur.com/search?q=UERY"
|
||||
|
||||
def items(self):
|
||||
@@ -270,11 +269,11 @@ class ImgurAPI():
|
||||
return self._pagination(endpoint, params)
|
||||
|
||||
def gallery_subreddit(self, subreddit):
|
||||
endpoint = f"/3/gallery/r/{subreddit}"
|
||||
endpoint = "/3/gallery/r/" + subreddit
|
||||
return self._pagination(endpoint)
|
||||
|
||||
def gallery_tag(self, tag):
|
||||
endpoint = f"/3/gallery/t/{tag}"
|
||||
endpoint = "/3/gallery/t/" + tag
|
||||
return self._pagination(endpoint, key="items")
|
||||
|
||||
def image(self, image_hash):
|
||||
|
||||
@@ -79,7 +79,7 @@ BASE_PATTERN = ImhentaiExtractor.update({
|
||||
|
||||
class ImhentaiGalleryExtractor(ImhentaiExtractor, GalleryExtractor):
|
||||
"""Extractor for imhentai galleries"""
|
||||
pattern = rf"{BASE_PATTERN}/(?:gallery|view)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/(?:gallery|view)/(\d+)"
|
||||
example = "https://imhentai.xxx/gallery/12345/"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -141,7 +141,7 @@ class ImhentaiGalleryExtractor(ImhentaiExtractor, GalleryExtractor):
|
||||
class ImhentaiTagExtractor(ImhentaiExtractor):
|
||||
"""Extractor for imhentai tag searches"""
|
||||
subcategory = "tag"
|
||||
pattern = (rf"{BASE_PATTERN}(/(?:"
|
||||
pattern = (BASE_PATTERN + r"(/(?:"
|
||||
r"artist|category|character|group|language|parody|tag"
|
||||
r")/([^/?#]+))")
|
||||
example = "https://imhentai.xxx/tag/TAG/"
|
||||
@@ -154,7 +154,7 @@ class ImhentaiTagExtractor(ImhentaiExtractor):
|
||||
class ImhentaiSearchExtractor(ImhentaiExtractor):
|
||||
"""Extractor for imhentai search results"""
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}(/(?:advanced-)?search/?\?[^#]+|/[^/?#]+/?)"
|
||||
pattern = BASE_PATTERN + r"(/(?:advanced-)?search/?\?[^#]+|/[^/?#]+/?)"
|
||||
example = "https://imhentai.xxx/search/?key=QUERY"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -71,7 +71,7 @@ class InkbunnyExtractor(Extractor):
|
||||
class InkbunnyUserExtractor(InkbunnyExtractor):
|
||||
"""Extractor for inkbunny user profiles"""
|
||||
subcategory = "user"
|
||||
pattern = rf"{BASE_PATTERN}/(?!s/)(gallery/|scraps/)?(\w+)(?:$|[/?#])"
|
||||
pattern = BASE_PATTERN + r"/(?!s/)(gallery/|scraps/)?(\w+)(?:$|[/?#])"
|
||||
example = "https://inkbunny.net/USER"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -101,7 +101,7 @@ class InkbunnyUserExtractor(InkbunnyExtractor):
|
||||
class InkbunnyPoolExtractor(InkbunnyExtractor):
|
||||
"""Extractor for inkbunny pools"""
|
||||
subcategory = "pool"
|
||||
pattern = (rf"{BASE_PATTERN}/(?:"
|
||||
pattern = (BASE_PATTERN + r"/(?:"
|
||||
r"poolview_process\.php\?pool_id=(\d+)|"
|
||||
r"submissionsviewall\.php"
|
||||
r"\?((?:[^#]+&)?mode=pool(?:&[^#]+)?))")
|
||||
@@ -132,7 +132,7 @@ class InkbunnyFavoriteExtractor(InkbunnyExtractor):
|
||||
"""Extractor for inkbunny user favorites"""
|
||||
subcategory = "favorite"
|
||||
directory_fmt = ("{category}", "{favs_username!l}", "Favorites")
|
||||
pattern = (rf"{BASE_PATTERN}/(?:"
|
||||
pattern = (BASE_PATTERN + r"/(?:"
|
||||
r"userfavorites_process\.php\?favs_user_id=(\d+)|"
|
||||
r"submissionsviewall\.php"
|
||||
r"\?((?:[^#]+&)?mode=userfavs(?:&[^#]+)?))")
|
||||
@@ -175,7 +175,7 @@ class InkbunnyFavoriteExtractor(InkbunnyExtractor):
|
||||
class InkbunnyUnreadExtractor(InkbunnyExtractor):
|
||||
"""Extractor for unread inkbunny submissions"""
|
||||
subcategory = "unread"
|
||||
pattern = (rf"{BASE_PATTERN}/submissionsviewall\.php"
|
||||
pattern = (BASE_PATTERN + r"/submissionsviewall\.php"
|
||||
r"\?((?:[^#]+&)?mode=unreadsubs(?:&[^#]+)?)")
|
||||
example = ("https://inkbunny.net/submissionsviewall.php"
|
||||
"?text=&mode=unreadsubs&type=")
|
||||
@@ -195,7 +195,7 @@ class InkbunnyUnreadExtractor(InkbunnyExtractor):
|
||||
class InkbunnySearchExtractor(InkbunnyExtractor):
|
||||
"""Extractor for inkbunny search results"""
|
||||
subcategory = "search"
|
||||
pattern = (rf"{BASE_PATTERN}/submissionsviewall\.php"
|
||||
pattern = (BASE_PATTERN + r"/submissionsviewall\.php"
|
||||
r"\?((?:[^#]+&)?mode=search(?:&[^#]+)?)")
|
||||
example = ("https://inkbunny.net/submissionsviewall.php"
|
||||
"?text=TAG&mode=search&type=")
|
||||
@@ -229,7 +229,7 @@ class InkbunnySearchExtractor(InkbunnyExtractor):
|
||||
class InkbunnyFollowingExtractor(InkbunnyExtractor):
|
||||
"""Extractor for inkbunny user watches"""
|
||||
subcategory = "following"
|
||||
pattern = (rf"{BASE_PATTERN}/(?:"
|
||||
pattern = (BASE_PATTERN + r"/(?:"
|
||||
r"watchlist_process\.php\?mode=watching&user_id=(\d+)|"
|
||||
r"usersviewall\.php"
|
||||
r"\?((?:[^#]+&)?mode=watching(?:&[^#]+)?))")
|
||||
@@ -268,7 +268,7 @@ class InkbunnyFollowingExtractor(InkbunnyExtractor):
|
||||
class InkbunnyPostExtractor(InkbunnyExtractor):
|
||||
"""Extractor for individual Inkbunny posts"""
|
||||
subcategory = "post"
|
||||
pattern = rf"{BASE_PATTERN}/s/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/s/(\d+)"
|
||||
example = "https://inkbunny.net/s/12345"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -16,7 +16,7 @@ import itertools
|
||||
import binascii
|
||||
|
||||
BASE_PATTERN = r"(?:https?://)?(?:www\.)?instagram\.com"
|
||||
USER_PATTERN = rf"{BASE_PATTERN}/(?!(?:p|tv|reel|explore|stories)/)([^/?#]+)"
|
||||
USER_PATTERN = BASE_PATTERN + r"/(?!(?:p|tv|reel|explore|stories)/)([^/?#]+)"
|
||||
|
||||
|
||||
class InstagramExtractor(Extractor):
|
||||
@@ -505,7 +505,7 @@ class InstagramPostExtractor(InstagramExtractor):
|
||||
|
||||
class InstagramUserExtractor(Dispatch, InstagramExtractor):
|
||||
"""Extractor for an Instagram user profile"""
|
||||
pattern = rf"{USER_PATTERN}/?(?:$|[?#])"
|
||||
pattern = USER_PATTERN + r"/?(?:$|[?#])"
|
||||
example = "https://www.instagram.com/USER/"
|
||||
|
||||
def items(self):
|
||||
@@ -525,7 +525,7 @@ class InstagramUserExtractor(Dispatch, InstagramExtractor):
|
||||
class InstagramPostsExtractor(InstagramExtractor):
|
||||
"""Extractor for an Instagram user's posts"""
|
||||
subcategory = "posts"
|
||||
pattern = rf"{USER_PATTERN}/posts"
|
||||
pattern = USER_PATTERN + r"/posts"
|
||||
example = "https://www.instagram.com/USER/posts/"
|
||||
|
||||
def posts(self):
|
||||
@@ -542,7 +542,7 @@ class InstagramPostsExtractor(InstagramExtractor):
|
||||
class InstagramReelsExtractor(InstagramExtractor):
|
||||
"""Extractor for an Instagram user's reels"""
|
||||
subcategory = "reels"
|
||||
pattern = rf"{USER_PATTERN}/reels"
|
||||
pattern = USER_PATTERN + r"/reels"
|
||||
example = "https://www.instagram.com/USER/reels/"
|
||||
|
||||
def posts(self):
|
||||
@@ -559,7 +559,7 @@ class InstagramReelsExtractor(InstagramExtractor):
|
||||
class InstagramTaggedExtractor(InstagramExtractor):
|
||||
"""Extractor for an Instagram user's tagged posts"""
|
||||
subcategory = "tagged"
|
||||
pattern = rf"{USER_PATTERN}/tagged"
|
||||
pattern = USER_PATTERN + r"/tagged"
|
||||
example = "https://www.instagram.com/USER/tagged/"
|
||||
|
||||
def metadata(self):
|
||||
@@ -585,7 +585,7 @@ class InstagramTaggedExtractor(InstagramExtractor):
|
||||
class InstagramGuideExtractor(InstagramExtractor):
|
||||
"""Extractor for an Instagram guide"""
|
||||
subcategory = "guide"
|
||||
pattern = rf"{USER_PATTERN}/guide/[^/?#]+/(\d+)"
|
||||
pattern = USER_PATTERN + r"/guide/[^/?#]+/(\d+)"
|
||||
example = "https://www.instagram.com/USER/guide/NAME/12345"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -602,7 +602,7 @@ class InstagramGuideExtractor(InstagramExtractor):
|
||||
class InstagramSavedExtractor(InstagramExtractor):
|
||||
"""Extractor for an Instagram user's saved media"""
|
||||
subcategory = "saved"
|
||||
pattern = rf"{USER_PATTERN}/saved(?:/all-posts)?/?$"
|
||||
pattern = USER_PATTERN + r"/saved(?:/all-posts)?/?$"
|
||||
example = "https://www.instagram.com/USER/saved/"
|
||||
|
||||
def posts(self):
|
||||
@@ -612,7 +612,7 @@ class InstagramSavedExtractor(InstagramExtractor):
|
||||
class InstagramCollectionExtractor(InstagramExtractor):
|
||||
"""Extractor for Instagram collection"""
|
||||
subcategory = "collection"
|
||||
pattern = rf"{USER_PATTERN}/saved/([^/?#]+)/([^/?#]+)"
|
||||
pattern = USER_PATTERN + r"/saved/([^/?#]+)/([^/?#]+)"
|
||||
example = "https://www.instagram.com/USER/saved/COLLECTION/12345"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -632,11 +632,11 @@ class InstagramCollectionExtractor(InstagramExtractor):
|
||||
class InstagramStoriesTrayExtractor(InstagramExtractor):
|
||||
"""Extractor for your Instagram account's stories tray"""
|
||||
subcategory = "stories-tray"
|
||||
pattern = rf"{BASE_PATTERN}/stories/me/?$()"
|
||||
pattern = BASE_PATTERN + r"/stories/me/?$()"
|
||||
example = "https://www.instagram.com/stories/me/"
|
||||
|
||||
def items(self):
|
||||
base = f"{self.root}/stories/id:"
|
||||
base = self.root + "/stories/id:"
|
||||
for story in self.api.reels_tray():
|
||||
story["date"] = self.parse_timestamp(story["latest_reel_media"])
|
||||
story["_extractor"] = InstagramStoriesExtractor
|
||||
@@ -696,7 +696,7 @@ class InstagramStoriesExtractor(InstagramExtractor):
|
||||
class InstagramHighlightsExtractor(InstagramExtractor):
|
||||
"""Extractor for an Instagram user's story highlights"""
|
||||
subcategory = "highlights"
|
||||
pattern = rf"{USER_PATTERN}/highlights"
|
||||
pattern = USER_PATTERN + r"/highlights"
|
||||
example = "https://www.instagram.com/USER/highlights/"
|
||||
|
||||
def posts(self):
|
||||
@@ -707,7 +707,7 @@ class InstagramHighlightsExtractor(InstagramExtractor):
|
||||
class InstagramFollowersExtractor(InstagramExtractor):
|
||||
"""Extractor for an Instagram user's followers"""
|
||||
subcategory = "followers"
|
||||
pattern = rf"{USER_PATTERN}/followers"
|
||||
pattern = USER_PATTERN + r"/followers"
|
||||
example = "https://www.instagram.com/USER/followers/"
|
||||
|
||||
def items(self):
|
||||
@@ -721,7 +721,7 @@ class InstagramFollowersExtractor(InstagramExtractor):
|
||||
class InstagramFollowingExtractor(InstagramExtractor):
|
||||
"""Extractor for an Instagram user's followed users"""
|
||||
subcategory = "following"
|
||||
pattern = rf"{USER_PATTERN}/following"
|
||||
pattern = USER_PATTERN + r"/following"
|
||||
example = "https://www.instagram.com/USER/following/"
|
||||
|
||||
def items(self):
|
||||
@@ -736,7 +736,7 @@ class InstagramTagExtractor(InstagramExtractor):
|
||||
"""Extractor for Instagram tags"""
|
||||
subcategory = "tag"
|
||||
directory_fmt = ("{category}", "{subcategory}", "{tag}")
|
||||
pattern = rf"{BASE_PATTERN}/explore/tags/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/explore/tags/([^/?#]+)"
|
||||
example = "https://www.instagram.com/explore/tags/TAG/"
|
||||
|
||||
def metadata(self):
|
||||
@@ -749,7 +749,7 @@ class InstagramTagExtractor(InstagramExtractor):
|
||||
class InstagramInfoExtractor(InstagramExtractor):
|
||||
"""Extractor for an Instagram user's profile data"""
|
||||
subcategory = "info"
|
||||
pattern = rf"{USER_PATTERN}/info"
|
||||
pattern = USER_PATTERN + r"/info"
|
||||
example = "https://www.instagram.com/USER/info/"
|
||||
|
||||
def items(self):
|
||||
@@ -765,7 +765,7 @@ class InstagramInfoExtractor(InstagramExtractor):
|
||||
class InstagramAvatarExtractor(InstagramExtractor):
|
||||
"""Extractor for an Instagram user's avatar"""
|
||||
subcategory = "avatar"
|
||||
pattern = rf"{USER_PATTERN}/avatar"
|
||||
pattern = USER_PATTERN + r"/avatar"
|
||||
example = "https://www.instagram.com/USER/avatar/"
|
||||
|
||||
def posts(self):
|
||||
|
||||
@@ -13,7 +13,7 @@ from ..cache import memcache
|
||||
from .. import text, util
|
||||
|
||||
BASE_PATTERN = r"(?:https?://)?itaku\.ee"
|
||||
USER_PATTERN = rf"{BASE_PATTERN}/profile/([^/?#]+)"
|
||||
USER_PATTERN = BASE_PATTERN + r"/profile/([^/?#]+)"
|
||||
|
||||
|
||||
class ItakuExtractor(Extractor):
|
||||
@@ -34,7 +34,7 @@ class ItakuExtractor(Extractor):
|
||||
for image in images:
|
||||
image["date"] = self.parse_datetime_iso(image["date_added"])
|
||||
for category, tags in image.pop("categorized_tags").items():
|
||||
image[f"tags_{category.lower()}"] = [
|
||||
image["tags_" + category.lower()] = [
|
||||
t["name"] for t in tags]
|
||||
image["tags"] = [t["name"] for t in image["tags"]]
|
||||
|
||||
@@ -73,9 +73,9 @@ class ItakuExtractor(Extractor):
|
||||
return
|
||||
|
||||
if users := self.users():
|
||||
base = f"{self.root}/profile/"
|
||||
base = self.root + "/profile/"
|
||||
for user in users:
|
||||
url = f"{base}{user['owner_username']}"
|
||||
url = base + user["owner_username"]
|
||||
user["_extractor"] = ItakuUserExtractor
|
||||
yield Message.Queue, url, user
|
||||
return
|
||||
@@ -86,7 +86,7 @@ class ItakuExtractor(Extractor):
|
||||
class ItakuGalleryExtractor(ItakuExtractor):
|
||||
"""Extractor for an itaku user's gallery"""
|
||||
subcategory = "gallery"
|
||||
pattern = rf"{USER_PATTERN}/gallery(?:/(\d+))?"
|
||||
pattern = USER_PATTERN + r"/gallery(?:/(\d+))?"
|
||||
example = "https://itaku.ee/profile/USER/gallery"
|
||||
|
||||
def images(self):
|
||||
@@ -104,7 +104,7 @@ class ItakuPostsExtractor(ItakuExtractor):
|
||||
"{id}{title:? //}")
|
||||
filename_fmt = "{file[id]}{file[title]:? //}.{extension}"
|
||||
archive_fmt = "{id}_{file[id]}"
|
||||
pattern = rf"{USER_PATTERN}/posts(?:/(\d+))?"
|
||||
pattern = USER_PATTERN + r"/posts(?:/(\d+))?"
|
||||
example = "https://itaku.ee/profile/USER/posts"
|
||||
|
||||
def posts(self):
|
||||
@@ -118,7 +118,7 @@ class ItakuPostsExtractor(ItakuExtractor):
|
||||
class ItakuStarsExtractor(ItakuExtractor):
|
||||
"""Extractor for an itaku user's starred images"""
|
||||
subcategory = "stars"
|
||||
pattern = rf"{USER_PATTERN}/stars(?:/(\d+))?"
|
||||
pattern = USER_PATTERN + r"/stars(?:/(\d+))?"
|
||||
example = "https://itaku.ee/profile/USER/stars"
|
||||
|
||||
def images(self):
|
||||
@@ -132,7 +132,7 @@ class ItakuStarsExtractor(ItakuExtractor):
|
||||
|
||||
class ItakuFollowingExtractor(ItakuExtractor):
|
||||
subcategory = "following"
|
||||
pattern = rf"{USER_PATTERN}/following"
|
||||
pattern = USER_PATTERN + r"/following"
|
||||
example = "https://itaku.ee/profile/USER/following"
|
||||
|
||||
def users(self):
|
||||
@@ -143,7 +143,7 @@ class ItakuFollowingExtractor(ItakuExtractor):
|
||||
|
||||
class ItakuFollowersExtractor(ItakuExtractor):
|
||||
subcategory = "followers"
|
||||
pattern = rf"{USER_PATTERN}/followers"
|
||||
pattern = USER_PATTERN + r"/followers"
|
||||
example = "https://itaku.ee/profile/USER/followers"
|
||||
|
||||
def users(self):
|
||||
@@ -155,7 +155,7 @@ class ItakuFollowersExtractor(ItakuExtractor):
|
||||
class ItakuBookmarksExtractor(ItakuExtractor):
|
||||
"""Extractor for an itaku bookmarks folder"""
|
||||
subcategory = "bookmarks"
|
||||
pattern = rf"{USER_PATTERN}/bookmarks/(image|user)/(\d+)"
|
||||
pattern = USER_PATTERN + r"/bookmarks/(image|user)/(\d+)"
|
||||
example = "https://itaku.ee/profile/USER/bookmarks/image/12345"
|
||||
|
||||
def _init(self):
|
||||
@@ -176,23 +176,23 @@ class ItakuBookmarksExtractor(ItakuExtractor):
|
||||
|
||||
class ItakuUserExtractor(Dispatch, ItakuExtractor):
|
||||
"""Extractor for itaku user profiles"""
|
||||
pattern = rf"{USER_PATTERN}/?(?:$|\?|#)"
|
||||
pattern = USER_PATTERN + r"/?(?:$|\?|#)"
|
||||
example = "https://itaku.ee/profile/USER"
|
||||
|
||||
def items(self):
|
||||
base = f"{self.root}/profile/{self.groups[0]}/"
|
||||
return self._dispatch_extractors((
|
||||
(ItakuGalleryExtractor , f"{base}gallery"),
|
||||
(ItakuPostsExtractor , f"{base}posts"),
|
||||
(ItakuFollowersExtractor, f"{base}followers"),
|
||||
(ItakuFollowingExtractor, f"{base}following"),
|
||||
(ItakuStarsExtractor , f"{base}stars"),
|
||||
(ItakuGalleryExtractor , base + "gallery"),
|
||||
(ItakuPostsExtractor , base + "posts"),
|
||||
(ItakuFollowersExtractor, base + "followers"),
|
||||
(ItakuFollowingExtractor, base + "following"),
|
||||
(ItakuStarsExtractor , base + "stars"),
|
||||
), ("gallery",))
|
||||
|
||||
|
||||
class ItakuImageExtractor(ItakuExtractor):
|
||||
subcategory = "image"
|
||||
pattern = rf"{BASE_PATTERN}/images/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/images/(\d+)"
|
||||
example = "https://itaku.ee/images/12345"
|
||||
|
||||
def images(self):
|
||||
@@ -205,7 +205,7 @@ class ItakuPostExtractor(ItakuExtractor):
|
||||
"{id}{title:? //}")
|
||||
filename_fmt = "{file[id]}{file[title]:? //}.{extension}"
|
||||
archive_fmt = "{id}_{file[id]}"
|
||||
pattern = rf"{BASE_PATTERN}/posts/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/posts/(\d+)"
|
||||
example = "https://itaku.ee/posts/12345"
|
||||
|
||||
def posts(self):
|
||||
@@ -214,7 +214,7 @@ class ItakuPostExtractor(ItakuExtractor):
|
||||
|
||||
class ItakuSearchExtractor(ItakuExtractor):
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}/home/images/?\?([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/home/images/?\?([^#]+)"
|
||||
example = "https://itaku.ee/home/images?tags=SEARCH"
|
||||
|
||||
def images(self):
|
||||
@@ -246,7 +246,7 @@ class ItakuAPI():
|
||||
|
||||
def __init__(self, extractor):
|
||||
self.extractor = extractor
|
||||
self.root = f"{extractor.root}/api"
|
||||
self.root = extractor.root + "/api"
|
||||
self.headers = {
|
||||
"Accept": "application/json, text/plain, */*",
|
||||
}
|
||||
@@ -309,7 +309,7 @@ class ItakuAPI():
|
||||
|
||||
def _call(self, endpoint, params=None):
|
||||
if not endpoint.startswith("http"):
|
||||
endpoint = f"{self.root}{endpoint}"
|
||||
endpoint = self.root + endpoint
|
||||
return self.extractor.request_json(
|
||||
endpoint, params=params, headers=self.headers)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from ..cache import cache, memcache
|
||||
import hashlib
|
||||
|
||||
BASE_PATTERN = r"(?:https?://)?(?:www\.)?iwara\.tv"
|
||||
USER_PATTERN = rf"{BASE_PATTERN}/profile/([^/?#]+)"
|
||||
USER_PATTERN = BASE_PATTERN + r"/profile/([^/?#]+)"
|
||||
|
||||
|
||||
class IwaraExtractor(Extractor):
|
||||
@@ -79,10 +79,10 @@ class IwaraExtractor(Extractor):
|
||||
continue
|
||||
|
||||
yield Message.Directory, "", info
|
||||
yield Message.Url, f"https:{download_url}", info
|
||||
yield Message.Url, "https:" + download_url, info
|
||||
|
||||
def items_user(self, users, key=None):
|
||||
base = f"{self.root}/profile/"
|
||||
base = self.root + "/profile/"
|
||||
for user in users:
|
||||
if key is not None:
|
||||
user = user[key]
|
||||
@@ -90,7 +90,7 @@ class IwaraExtractor(Extractor):
|
||||
continue
|
||||
user["type"] = "user"
|
||||
user["_extractor"] = IwaraUserExtractor
|
||||
yield Message.Queue, f"{base}{username}", user
|
||||
yield Message.Queue, base + username, user
|
||||
|
||||
def items_by_type(self, type, results):
|
||||
if type == "image":
|
||||
@@ -158,21 +158,21 @@ class IwaraExtractor(Extractor):
|
||||
|
||||
class IwaraUserExtractor(Dispatch, IwaraExtractor):
|
||||
"""Extractor for iwara.tv profile pages"""
|
||||
pattern = rf"{USER_PATTERN}/?$"
|
||||
pattern = USER_PATTERN + r"/?$"
|
||||
example = "https://www.iwara.tv/profile/USERNAME"
|
||||
|
||||
def items(self):
|
||||
base = f"{self.root}/profile/{self.groups[0]}/"
|
||||
return self._dispatch_extractors((
|
||||
(IwaraUserImagesExtractor , f"{base}images"),
|
||||
(IwaraUserVideosExtractor , f"{base}videos"),
|
||||
(IwaraUserPlaylistsExtractor, f"{base}playlists"),
|
||||
(IwaraUserImagesExtractor , base + "images"),
|
||||
(IwaraUserVideosExtractor , base + "videos"),
|
||||
(IwaraUserPlaylistsExtractor, base + "playlists"),
|
||||
), ("user-images", "user-videos"))
|
||||
|
||||
|
||||
class IwaraUserImagesExtractor(IwaraExtractor):
|
||||
subcategory = "user-images"
|
||||
pattern = rf"{USER_PATTERN}/images(?:\?([^#]+))?"
|
||||
pattern = USER_PATTERN + r"/images(?:\?([^#]+))?"
|
||||
example = "https://www.iwara.tv/profile/USERNAME/images"
|
||||
|
||||
def items(self):
|
||||
@@ -182,7 +182,7 @@ class IwaraUserImagesExtractor(IwaraExtractor):
|
||||
|
||||
class IwaraUserVideosExtractor(IwaraExtractor):
|
||||
subcategory = "user-videos"
|
||||
pattern = rf"{USER_PATTERN}/videos(?:\?([^#]+))?"
|
||||
pattern = USER_PATTERN + r"/videos(?:\?([^#]+))?"
|
||||
example = "https://www.iwara.tv/profile/USERNAME/videos"
|
||||
|
||||
def items(self):
|
||||
@@ -192,22 +192,22 @@ class IwaraUserVideosExtractor(IwaraExtractor):
|
||||
|
||||
class IwaraUserPlaylistsExtractor(IwaraExtractor):
|
||||
subcategory = "user-playlists"
|
||||
pattern = rf"{USER_PATTERN}/playlists(?:\?([^#]+))?"
|
||||
pattern = USER_PATTERN + r"/playlists(?:\?([^#]+))?"
|
||||
example = "https://www.iwara.tv/profile/USERNAME/playlists"
|
||||
|
||||
def items(self):
|
||||
base = f"{self.root}/playlist/"
|
||||
base = self.root + "/playlist/"
|
||||
|
||||
for playlist in self.api.playlists(self._user_params()[1]):
|
||||
playlist["type"] = "playlist"
|
||||
playlist["_extractor"] = IwaraPlaylistExtractor
|
||||
url = f"{base}{playlist['id']}"
|
||||
url = base + playlist["id"]
|
||||
yield Message.Queue, url, playlist
|
||||
|
||||
|
||||
class IwaraFollowingExtractor(IwaraExtractor):
|
||||
subcategory = "following"
|
||||
pattern = rf"{USER_PATTERN}/following"
|
||||
pattern = USER_PATTERN + r"/following"
|
||||
example = "https://www.iwara.tv/profile/USERNAME/following"
|
||||
|
||||
def items(self):
|
||||
@@ -217,7 +217,7 @@ class IwaraFollowingExtractor(IwaraExtractor):
|
||||
|
||||
class IwaraFollowersExtractor(IwaraExtractor):
|
||||
subcategory = "followers"
|
||||
pattern = rf"{USER_PATTERN}/followers"
|
||||
pattern = USER_PATTERN + r"/followers"
|
||||
example = "https://www.iwara.tv/profile/USERNAME/followers"
|
||||
|
||||
def items(self):
|
||||
@@ -228,7 +228,7 @@ class IwaraFollowersExtractor(IwaraExtractor):
|
||||
class IwaraImageExtractor(IwaraExtractor):
|
||||
"""Extractor for individual iwara.tv image pages"""
|
||||
subcategory = "image"
|
||||
pattern = rf"{BASE_PATTERN}/image/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/image/([^/?#]+)"
|
||||
example = "https://www.iwara.tv/image/ID"
|
||||
|
||||
def items(self):
|
||||
@@ -238,7 +238,7 @@ class IwaraImageExtractor(IwaraExtractor):
|
||||
class IwaraVideoExtractor(IwaraExtractor):
|
||||
"""Extractor for individual iwara.tv videos"""
|
||||
subcategory = "video"
|
||||
pattern = rf"{BASE_PATTERN}/video/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/video/([^/?#]+)"
|
||||
example = "https://www.iwara.tv/video/ID"
|
||||
|
||||
def items(self):
|
||||
@@ -248,7 +248,7 @@ class IwaraVideoExtractor(IwaraExtractor):
|
||||
class IwaraPlaylistExtractor(IwaraExtractor):
|
||||
"""Extractor for individual iwara.tv playlist pages"""
|
||||
subcategory = "playlist"
|
||||
pattern = rf"{BASE_PATTERN}/playlist/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"/playlist/([^/?#]+)"
|
||||
example = "https://www.iwara.tv/playlist/ID"
|
||||
|
||||
def items(self):
|
||||
@@ -257,7 +257,7 @@ class IwaraPlaylistExtractor(IwaraExtractor):
|
||||
|
||||
class IwaraFavoriteExtractor(IwaraExtractor):
|
||||
subcategory = "favorite"
|
||||
pattern = rf"{BASE_PATTERN}/favorites(?:/(image|video)s)?"
|
||||
pattern = BASE_PATTERN + r"/favorites(?:/(image|video)s)?"
|
||||
example = "https://www.iwara.tv/favorites/videos"
|
||||
|
||||
def items(self):
|
||||
@@ -268,7 +268,7 @@ class IwaraFavoriteExtractor(IwaraExtractor):
|
||||
class IwaraSearchExtractor(IwaraExtractor):
|
||||
"""Extractor for iwara.tv search pages"""
|
||||
subcategory = "search"
|
||||
pattern = rf"{BASE_PATTERN}/search\?([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/search\?([^#]+)"
|
||||
example = "https://www.iwara.tv/search?query=QUERY&type=TYPE"
|
||||
|
||||
def items(self):
|
||||
@@ -281,7 +281,7 @@ class IwaraSearchExtractor(IwaraExtractor):
|
||||
class IwaraTagExtractor(IwaraExtractor):
|
||||
"""Extractor for iwara.tv tag search"""
|
||||
subcategory = "tag"
|
||||
pattern = rf"{BASE_PATTERN}/(image|video)s(?:\?([^#]+))?"
|
||||
pattern = BASE_PATTERN + r"/(image|video)s(?:\?([^#]+))?"
|
||||
example = "https://www.iwara.tv/videos?tags=TAGS"
|
||||
|
||||
def items(self):
|
||||
@@ -298,7 +298,7 @@ class IwaraAPI():
|
||||
def __init__(self, extractor):
|
||||
self.extractor = extractor
|
||||
self.headers = {
|
||||
"Referer" : f"{extractor.root}/",
|
||||
"Referer" : extractor.root + "/",
|
||||
"Content-Type": "application/json",
|
||||
"Origin" : extractor.root,
|
||||
}
|
||||
@@ -308,15 +308,15 @@ class IwaraAPI():
|
||||
self.authenticate = util.noop
|
||||
|
||||
def image(self, image_id):
|
||||
endpoint = f"/image/{image_id}"
|
||||
endpoint = "/image/" + image_id
|
||||
return self._call(endpoint)
|
||||
|
||||
def video(self, video_id):
|
||||
endpoint = f"/video/{video_id}"
|
||||
endpoint = "/video/" + video_id
|
||||
return self._call(endpoint)
|
||||
|
||||
def playlist(self, playlist_id):
|
||||
endpoint = f"/playlist/{playlist_id}"
|
||||
endpoint = "/playlist/" + playlist_id
|
||||
return self._pagination(endpoint)
|
||||
|
||||
def detail(self, media):
|
||||
@@ -356,7 +356,7 @@ class IwaraAPI():
|
||||
|
||||
@memcache(keyarg=1)
|
||||
def profile(self, username):
|
||||
endpoint = f"/profile/{username}"
|
||||
endpoint = "/profile/" + username
|
||||
return self._call(endpoint)
|
||||
|
||||
def user_following(self, user_id):
|
||||
@@ -387,7 +387,7 @@ class IwaraAPI():
|
||||
if refresh_token is None:
|
||||
self.extractor.log.info("Logging in as %s", username)
|
||||
|
||||
url = f"{self.root}/user/login"
|
||||
url = self.root + "/user/login"
|
||||
json = {
|
||||
"email" : username,
|
||||
"password": self.password
|
||||
@@ -403,15 +403,15 @@ class IwaraAPI():
|
||||
|
||||
self.extractor.log.info("Refreshing access token for %s", username)
|
||||
|
||||
url = f"{self.root}/user/token"
|
||||
headers = {"Authorization": f"Bearer {refresh_token}", **self.headers}
|
||||
url = self.root + "/user/token"
|
||||
headers = {"Authorization": "Bearer " + refresh_token, **self.headers}
|
||||
data = self.extractor.request_json(
|
||||
url, method="POST", headers=headers, fatal=False)
|
||||
|
||||
if not (access_token := data.get("accessToken")):
|
||||
self.extractor.log.debug(data)
|
||||
raise exception.AuthenticationError(data.get("message"))
|
||||
return f"Bearer {access_token}"
|
||||
return "Bearer " + access_token
|
||||
|
||||
def _call(self, endpoint, params=None, headers=None):
|
||||
if headers is None:
|
||||
|
||||
@@ -30,7 +30,7 @@ class JschanThreadExtractor(JschanExtractor):
|
||||
"{threadId} {subject|nomarkup[:50]}")
|
||||
filename_fmt = "{postId}{num:?-//} {filename}.{extension}"
|
||||
archive_fmt = "{board}_{postId}_{num}"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/thread/(\d+)\.html"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/thread/(\d+)\.html"
|
||||
example = "https://94chan.org/a/thread/12345.html"
|
||||
|
||||
def items(self):
|
||||
@@ -56,7 +56,7 @@ class JschanThreadExtractor(JschanExtractor):
|
||||
class JschanBoardExtractor(JschanExtractor):
|
||||
"""Extractor for jschan boards"""
|
||||
subcategory = "board"
|
||||
pattern = (rf"{BASE_PATTERN}/([^/?#]+)"
|
||||
pattern = (BASE_PATTERN + r"/([^/?#]+)"
|
||||
r"(?:/index\.html|/catalog\.html|/\d+\.html|/?$)")
|
||||
example = "https://94chan.org/a/"
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class KabeuchiUserExtractor(Extractor):
|
||||
return self._pagination(target_id)
|
||||
|
||||
def _pagination(self, target_id):
|
||||
url = f"{self.root}/get_posts.php"
|
||||
url = self.root + "/get_posts.php"
|
||||
data = {
|
||||
"user_id" : "0",
|
||||
"target_id" : target_id,
|
||||
|
||||
@@ -16,7 +16,7 @@ import json
|
||||
|
||||
BASE_PATTERN = (r"(?:https?://)?(?:www\.|beta\.)?"
|
||||
r"(kemono|coomer)\.(cr|s[tu]|party)")
|
||||
USER_PATTERN = rf"{BASE_PATTERN}/([^/?#]+)/user/([^/?#]+)"
|
||||
USER_PATTERN = BASE_PATTERN + r"/([^/?#]+)/user/([^/?#]+)"
|
||||
HASH_PATTERN = r"/[0-9a-f]{2}/[0-9a-f]{2}/([0-9a-f]{64})"
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@ class KemonoExtractor(Extractor):
|
||||
username = username[0]
|
||||
self.log.info("Logging in as %s", username)
|
||||
|
||||
url = f"{self.root}/api/v1/authentication/login"
|
||||
url = self.root + "/api/v1/authentication/login"
|
||||
data = {"username": username, "password": password}
|
||||
|
||||
response = self.request(url, method="POST", json=data, fatal=False)
|
||||
@@ -322,7 +322,7 @@ def _validate(response):
|
||||
class KemonoUserExtractor(KemonoExtractor):
|
||||
"""Extractor for all posts from a kemono.cr user listing"""
|
||||
subcategory = "user"
|
||||
pattern = rf"{USER_PATTERN}/?(?:\?([^#]+))?(?:$|\?|#)"
|
||||
pattern = USER_PATTERN + r"/?(?:\?([^#]+))?(?:$|\?|#)"
|
||||
example = "https://kemono.cr/SERVICE/user/12345"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -345,7 +345,7 @@ class KemonoUserExtractor(KemonoExtractor):
|
||||
class KemonoPostsExtractor(KemonoExtractor):
|
||||
"""Extractor for kemono.cr post listings"""
|
||||
subcategory = "posts"
|
||||
pattern = rf"{BASE_PATTERN}/posts()()(?:/?\?([^#]+))?"
|
||||
pattern = BASE_PATTERN + r"/posts()()(?:/?\?([^#]+))?"
|
||||
example = "https://kemono.cr/posts"
|
||||
|
||||
def posts(self):
|
||||
@@ -357,7 +357,7 @@ class KemonoPostsExtractor(KemonoExtractor):
|
||||
class KemonoPostExtractor(KemonoExtractor):
|
||||
"""Extractor for a single kemono.cr post"""
|
||||
subcategory = "post"
|
||||
pattern = rf"{USER_PATTERN}/post/([^/?#]+)(/revisions?(?:/(\d*))?)?"
|
||||
pattern = USER_PATTERN + r"/post/([^/?#]+)(/revisions?(?:/(\d*))?)?"
|
||||
example = "https://kemono.cr/SERVICE/user/12345/post/12345"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -390,7 +390,7 @@ class KemonoDiscordExtractor(KemonoExtractor):
|
||||
"{server_id} {server}", "{channel_id} {channel}")
|
||||
filename_fmt = "{id}_{num:>02}_{filename}.{extension}"
|
||||
archive_fmt = "discord_{server_id}_{id}_{num}"
|
||||
pattern = rf"{BASE_PATTERN}/discord/server/(\d+)[/#](?:channel/)?(\d+)"
|
||||
pattern = BASE_PATTERN + r"/discord/server/(\d+)[/#](?:channel/)?(\d+)"
|
||||
example = "https://kemono.cr/discord/server/12345/12345"
|
||||
|
||||
def items(self):
|
||||
@@ -434,7 +434,7 @@ class KemonoDiscordExtractor(KemonoExtractor):
|
||||
attachment["type"] = "attachment"
|
||||
files.append(attachment)
|
||||
for path in find_inline(post["content"] or ""):
|
||||
files.append({"path": f"https://cdn.discordapp.com{path}",
|
||||
files.append({"path": "https://cdn.discordapp.com" + path,
|
||||
"name": path, "type": "inline", "hash": ""})
|
||||
|
||||
post.update(data)
|
||||
@@ -460,7 +460,7 @@ class KemonoDiscordExtractor(KemonoExtractor):
|
||||
|
||||
class KemonoDiscordServerExtractor(KemonoExtractor):
|
||||
subcategory = "discord-server"
|
||||
pattern = rf"{BASE_PATTERN}/discord/server/(\d+)$"
|
||||
pattern = BASE_PATTERN + r"/discord/server/(\d+)$"
|
||||
example = "https://kemono.cr/discord/server/12345"
|
||||
|
||||
def items(self):
|
||||
@@ -488,7 +488,7 @@ def discord_server_info(extr, server_id):
|
||||
class KemonoFavoriteExtractor(KemonoExtractor):
|
||||
"""Extractor for kemono.cr favorites"""
|
||||
subcategory = "favorite"
|
||||
pattern = rf"{BASE_PATTERN}/(?:account/)?favorites()()(?:/?\?([^#]+))?"
|
||||
pattern = BASE_PATTERN + r"/(?:account/)?favorites()()(?:/?\?([^#]+))?"
|
||||
example = "https://kemono.cr/account/favorites/artists"
|
||||
|
||||
def items(self):
|
||||
@@ -536,7 +536,7 @@ class KemonoFavoriteExtractor(KemonoExtractor):
|
||||
class KemonoArtistsExtractor(KemonoExtractor):
|
||||
"""Extractor for kemono artists"""
|
||||
subcategory = "artists"
|
||||
pattern = rf"{BASE_PATTERN}/artists(?:\?([^#]+))?"
|
||||
pattern = BASE_PATTERN + r"/artists(?:\?([^#]+))?"
|
||||
example = "https://kemono.cr/artists"
|
||||
|
||||
def items(self):
|
||||
@@ -577,7 +577,7 @@ class KemonoAPI():
|
||||
|
||||
def __init__(self, extractor):
|
||||
self.extractor = extractor
|
||||
self.root = f"{extractor.root}/api"
|
||||
self.root = extractor.root + "/api"
|
||||
self.headers = {"Accept": "text/css"}
|
||||
|
||||
def posts(self, offset=0, query=None, tags=None):
|
||||
@@ -586,7 +586,7 @@ class KemonoAPI():
|
||||
return self._pagination(endpoint, params, 50, "posts")
|
||||
|
||||
def file(self, file_hash):
|
||||
endpoint = f"/v1/file/{file_hash}"
|
||||
endpoint = "/v1/file/" + file_hash
|
||||
return self._call(endpoint)
|
||||
|
||||
def creators(self):
|
||||
@@ -643,18 +643,18 @@ class KemonoAPI():
|
||||
return self._call(endpoint)
|
||||
|
||||
def discord_channel(self, channel_id, post_count=None):
|
||||
endpoint = f"/v1/discord/channel/{channel_id}"
|
||||
endpoint = "/v1/discord/channel/" + channel_id
|
||||
if post_count is None:
|
||||
return self._pagination(endpoint, {}, 150)
|
||||
else:
|
||||
return self._pagination_reverse(endpoint, {}, 150, post_count)
|
||||
|
||||
def discord_channel_lookup(self, server_id):
|
||||
endpoint = f"/v1/discord/channel/lookup/{server_id}"
|
||||
endpoint = "/v1/discord/channel/lookup/" + server_id
|
||||
return self._call(endpoint)
|
||||
|
||||
def discord_server(self, server_id):
|
||||
endpoint = f"/v1/discord/server/{server_id}"
|
||||
endpoint = "/v1/discord/server/" + server_id
|
||||
return self._call(endpoint)
|
||||
|
||||
def account_favorites(self, type):
|
||||
@@ -669,7 +669,7 @@ class KemonoAPI():
|
||||
headers = {**self.headers, **headers}
|
||||
|
||||
return self.extractor.request_json(
|
||||
f"{self.root}{endpoint}", params=params, headers=headers,
|
||||
self.root + endpoint, params=params, headers=headers,
|
||||
encoding="utf-8", fatal=fatal)
|
||||
|
||||
def _pagination(self, endpoint, params, batch=50, key=None):
|
||||
|
||||
@@ -44,7 +44,7 @@ class KomikcastBase():
|
||||
|
||||
class KomikcastChapterExtractor(KomikcastBase, ChapterExtractor):
|
||||
"""Extractor for komikcast manga chapters"""
|
||||
pattern = rf"{BASE_PATTERN}(/chapter/[^/?#]+/)"
|
||||
pattern = BASE_PATTERN + r"(/chapter/[^/?#]+/)"
|
||||
example = "https://komikcast.li/chapter/TITLE/"
|
||||
|
||||
def metadata(self, page):
|
||||
@@ -64,7 +64,7 @@ class KomikcastChapterExtractor(KomikcastBase, ChapterExtractor):
|
||||
class KomikcastMangaExtractor(KomikcastBase, MangaExtractor):
|
||||
"""Extractor for komikcast manga"""
|
||||
chapterclass = KomikcastChapterExtractor
|
||||
pattern = rf"{BASE_PATTERN}(/(?:komik/)?[^/?#]+/?)$"
|
||||
pattern = BASE_PATTERN + r"(/(?:komik/)?[^/?#]+/?)$"
|
||||
example = "https://komikcast.li/komik/TITLE"
|
||||
|
||||
def chapters(self, page):
|
||||
|
||||
@@ -35,7 +35,7 @@ class LeakgalleryExtractor(Extractor):
|
||||
else:
|
||||
media["creator"] = creator
|
||||
|
||||
media["url"] = url = f"https://cdn.leakgallery.com/{path}"
|
||||
media["url"] = url = "https://cdn.leakgallery.com/" + path
|
||||
text.nameext_from_url(url, media)
|
||||
yield Message.Directory, "", media
|
||||
yield Message.Url, url, media
|
||||
@@ -43,7 +43,7 @@ class LeakgalleryExtractor(Extractor):
|
||||
def _pagination(self, type, base, params=None, creator=None, pnum=1):
|
||||
while True:
|
||||
try:
|
||||
data = self.request_json(f"{base}{pnum}", params=params)
|
||||
data = self.request_json(base + str(pnum), params=params)
|
||||
|
||||
if not data:
|
||||
return
|
||||
@@ -81,7 +81,7 @@ class LeakgalleryUserExtractor(LeakgalleryExtractor):
|
||||
class LeakgalleryTrendingExtractor(LeakgalleryExtractor):
|
||||
"""Extractor for trending posts on leakgallery.com"""
|
||||
subcategory = "trending"
|
||||
pattern = rf"{BASE_PATTERN}/trending-medias(?:/([\w-]+))?"
|
||||
pattern = BASE_PATTERN + r"/trending-medias(?:/([\w-]+))?"
|
||||
example = "https://leakgallery.com/trending-medias/Week"
|
||||
|
||||
def items(self):
|
||||
@@ -93,7 +93,7 @@ class LeakgalleryTrendingExtractor(LeakgalleryExtractor):
|
||||
class LeakgalleryMostlikedExtractor(LeakgalleryExtractor):
|
||||
"""Extractor for most liked posts on leakgallery.com"""
|
||||
subcategory = "mostliked"
|
||||
pattern = rf"{BASE_PATTERN}/most-liked"
|
||||
pattern = BASE_PATTERN + r"/most-liked"
|
||||
example = "https://leakgallery.com/most-liked"
|
||||
|
||||
def items(self):
|
||||
@@ -104,7 +104,7 @@ class LeakgalleryMostlikedExtractor(LeakgalleryExtractor):
|
||||
class LeakgalleryPostExtractor(LeakgalleryExtractor):
|
||||
"""Extractor for individual posts on leakgallery.com"""
|
||||
subcategory = "post"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/(\d+)"
|
||||
example = "https://leakgallery.com/CREATOR/12345"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -31,7 +31,7 @@ class LensdumpBase():
|
||||
|
||||
class LensdumpAlbumExtractor(LensdumpBase, GalleryExtractor):
|
||||
subcategory = "album"
|
||||
pattern = rf"{BASE_PATTERN}/a/(\w+)(?:/?\?([^#]+))?"
|
||||
pattern = BASE_PATTERN + r"/a/(\w+)(?:/?\?([^#]+))?"
|
||||
example = "https://lensdump.com/a/ID"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -76,7 +76,7 @@ class LensdumpAlbumExtractor(LensdumpBase, GalleryExtractor):
|
||||
class LensdumpAlbumsExtractor(LensdumpBase, Extractor):
|
||||
"""Extractor for album list from lensdump.com"""
|
||||
subcategory = "albums"
|
||||
pattern = rf"{BASE_PATTERN}/(?![ai]/)([^/?#]+)(?:/?\?([^#]+))?"
|
||||
pattern = BASE_PATTERN + r"/(?![ai]/)([^/?#]+)(?:/?\?([^#]+))?"
|
||||
example = "https://lensdump.com/USER"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -25,7 +25,7 @@ BASE_PATTERN = LolisafeExtractor.update({
|
||||
|
||||
class LolisafeAlbumExtractor(LolisafeExtractor):
|
||||
subcategory = "album"
|
||||
pattern = rf"{BASE_PATTERN}/a/([^/?#]+)"
|
||||
pattern = BASE_PATTERN + "/a/([^/?#]+)"
|
||||
example = "https://xbunkr.com/a/ID"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -39,7 +39,7 @@ class LynxchanThreadExtractor(LynxchanExtractor):
|
||||
"{threadId} {subject|message[:50]}")
|
||||
filename_fmt = "{postId}{num:?-//} {filename}.{extension}"
|
||||
archive_fmt = "{boardUri}_{postId}_{num}"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)/res/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)/res/(\d+)"
|
||||
example = "https://endchan.org/a/res/12345.html"
|
||||
|
||||
def items(self):
|
||||
@@ -63,7 +63,7 @@ class LynxchanThreadExtractor(LynxchanExtractor):
|
||||
class LynxchanBoardExtractor(LynxchanExtractor):
|
||||
"""Extractor for LynxChan boards"""
|
||||
subcategory = "board"
|
||||
pattern = rf"{BASE_PATTERN}/([^/?#]+)(?:/index|/catalog|/\d+|/?$)"
|
||||
pattern = BASE_PATTERN + r"/([^/?#]+)(?:/index|/catalog|/\d+|/?$)"
|
||||
example = "https://endchan.org/a/"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -25,7 +25,7 @@ class MadokamiMangaExtractor(MadokamiExtractor):
|
||||
subcategory = "manga"
|
||||
directory_fmt = ("{category}", "{manga}")
|
||||
archive_fmt = "{chapter_id}"
|
||||
pattern = rf"{BASE_PATTERN}/Manga/(\w/\w{{2}}/\w{{4}}/.+)"
|
||||
pattern = BASE_PATTERN + r"/Manga/(\w/\w{2}/\w{4}/.+)"
|
||||
example = "https://manga.madokami.al/Manga/A/AB/ABCD/ABCDE_TITLE"
|
||||
|
||||
def items(self):
|
||||
@@ -85,7 +85,7 @@ class MadokamiMangaExtractor(MadokamiExtractor):
|
||||
else:
|
||||
ch["volume"] = ch["chapter"] = ch["chapter_end"] = 0
|
||||
|
||||
url = f"{self.root}{ch['path']}"
|
||||
url = self.root + ch["path"]
|
||||
text.nameext_from_url(url, ch)
|
||||
|
||||
yield Message.Directory, "", ch
|
||||
|
||||
@@ -66,7 +66,7 @@ class MangadexExtractor(Extractor):
|
||||
"title" : cattributes["title"],
|
||||
"volume" : text.parse_int(cattributes["volume"]),
|
||||
"chapter" : text.parse_int(chnum),
|
||||
"chapter_minor": f"{sep}{minor}",
|
||||
"chapter_minor": sep + minor,
|
||||
"chapter_id": chapter["id"],
|
||||
"date" : self.parse_datetime_iso(cattributes["publishAt"]),
|
||||
"group" : [group["attributes"]["name"]
|
||||
@@ -83,8 +83,8 @@ class MangadexCoversExtractor(MangadexExtractor):
|
||||
directory_fmt = ("{category}", "{manga}", "Covers")
|
||||
filename_fmt = "{volume:>02}_{lang}.{extension}"
|
||||
archive_fmt = "c_{cover_id}"
|
||||
pattern = (rf"{BASE_PATTERN}/(?:title|manga)/(?!follows|feed$)([0-9a-f-]+)"
|
||||
rf"(?:/[^/?#]+)?\?tab=art")
|
||||
pattern = (BASE_PATTERN + r"/(?:title|manga)/(?!follows|feed$)([0-9a-f-]+)"
|
||||
r"(?:/[^/?#]+)?\?tab=art")
|
||||
example = ("https://mangadex.org/title"
|
||||
"/01234567-89ab-cdef-0123-456789abcdef?tab=art")
|
||||
|
||||
@@ -96,7 +96,7 @@ class MangadexCoversExtractor(MangadexExtractor):
|
||||
text.nameext_from_url(name, data)
|
||||
data["cover_id"] = data["filename"]
|
||||
yield Message.Directory, "", data
|
||||
yield Message.Url, f"{base}{name}", data
|
||||
yield Message.Url, base + name, data
|
||||
|
||||
def _transform_cover(self, cover):
|
||||
relationships = defaultdict(list)
|
||||
@@ -117,7 +117,7 @@ class MangadexCoversExtractor(MangadexExtractor):
|
||||
class MangadexChapterExtractor(MangadexExtractor):
|
||||
"""Extractor for manga-chapters from mangadex.org"""
|
||||
subcategory = "chapter"
|
||||
pattern = rf"{BASE_PATTERN}/chapter/([0-9a-f-]+)"
|
||||
pattern = BASE_PATTERN + r"/chapter/([0-9a-f-]+)"
|
||||
example = ("https://mangadex.org/chapter"
|
||||
"/01234567-89ab-cdef-0123-456789abcdef")
|
||||
|
||||
@@ -148,15 +148,15 @@ class MangadexChapterExtractor(MangadexExtractor):
|
||||
|
||||
enum = util.enumerate_reversed if self.config(
|
||||
"page-reverse") else enumerate
|
||||
for data["page"], page in enum(chapter[key], 1):
|
||||
text.nameext_from_url(page, data)
|
||||
yield Message.Url, f"{base}{page}", data
|
||||
for data["page"], path in enum(chapter[key], 1):
|
||||
text.nameext_from_url(path, data)
|
||||
yield Message.Url, base + path, data
|
||||
|
||||
|
||||
class MangadexMangaExtractor(MangadexExtractor):
|
||||
"""Extractor for manga from mangadex.org"""
|
||||
subcategory = "manga"
|
||||
pattern = rf"{BASE_PATTERN}/(?:title|manga)/(?!follows|feed$)([0-9a-f-]+)"
|
||||
pattern = BASE_PATTERN + r"/(?:title|manga)/(?!follows|feed$)([0-9a-f-]+)"
|
||||
example = ("https://mangadex.org/title"
|
||||
"/01234567-89ab-cdef-0123-456789abcdef")
|
||||
|
||||
@@ -167,7 +167,7 @@ class MangadexMangaExtractor(MangadexExtractor):
|
||||
class MangadexFeedExtractor(MangadexExtractor):
|
||||
"""Extractor for chapters from your Updates Feed"""
|
||||
subcategory = "feed"
|
||||
pattern = rf"{BASE_PATTERN}/titles?/feed$()"
|
||||
pattern = BASE_PATTERN + r"/titles?/feed$()"
|
||||
example = "https://mangadex.org/title/feed"
|
||||
|
||||
def chapters(self):
|
||||
@@ -177,7 +177,7 @@ class MangadexFeedExtractor(MangadexExtractor):
|
||||
class MangadexFollowingExtractor(MangadexExtractor):
|
||||
"""Extractor for followed manga from your Library"""
|
||||
subcategory = "following"
|
||||
pattern = rf"{BASE_PATTERN}/titles?/follows(?:\?([^#]+))?$"
|
||||
pattern = BASE_PATTERN + r"/titles?/follows(?:\?([^#]+))?$"
|
||||
example = "https://mangadex.org/title/follows"
|
||||
|
||||
items = MangadexExtractor._items_manga
|
||||
@@ -189,8 +189,8 @@ class MangadexFollowingExtractor(MangadexExtractor):
|
||||
class MangadexListExtractor(MangadexExtractor):
|
||||
"""Extractor for mangadex MDLists"""
|
||||
subcategory = "list"
|
||||
pattern = (rf"{BASE_PATTERN}"
|
||||
rf"/list/([0-9a-f-]+)(?:/[^/?#]*)?(?:\?tab=(\w+))?")
|
||||
pattern = (BASE_PATTERN +
|
||||
r"/list/([0-9a-f-]+)(?:/[^/?#]*)?(?:\?tab=(\w+))?")
|
||||
example = ("https://mangadex.org/list"
|
||||
"/01234567-89ab-cdef-0123-456789abcdef/NAME")
|
||||
|
||||
@@ -215,7 +215,7 @@ class MangadexListExtractor(MangadexExtractor):
|
||||
class MangadexAuthorExtractor(MangadexExtractor):
|
||||
"""Extractor for mangadex authors"""
|
||||
subcategory = "author"
|
||||
pattern = rf"{BASE_PATTERN}/author/([0-9a-f-]+)"
|
||||
pattern = BASE_PATTERN + r"/author/([0-9a-f-]+)"
|
||||
example = ("https://mangadex.org/author"
|
||||
"/01234567-89ab-cdef-0123-456789abcdef/NAME")
|
||||
|
||||
@@ -253,22 +253,22 @@ class MangadexAPI():
|
||||
else text.ensure_http_scheme(server).rstrip("/"))
|
||||
|
||||
def athome_server(self, uuid):
|
||||
return self._call(f"/at-home/server/{uuid}")
|
||||
return self._call("/at-home/server/" + uuid)
|
||||
|
||||
def author(self, uuid, manga=False):
|
||||
params = {"includes[]": ("manga",)} if manga else None
|
||||
return self._call(f"/author/{uuid}", params)["data"]
|
||||
return self._call("/author/" + uuid, params)["data"]
|
||||
|
||||
def chapter(self, uuid):
|
||||
params = {"includes[]": ("scanlation_group",)}
|
||||
return self._call(f"/chapter/{uuid}", params)["data"]
|
||||
return self._call("/chapter/" + uuid, params)["data"]
|
||||
|
||||
def covers_manga(self, uuid):
|
||||
params = {"manga[]": uuid}
|
||||
return self._pagination_covers("/cover", params)
|
||||
|
||||
def list(self, uuid):
|
||||
return self._call(f"/list/{uuid}", None, True)["data"]
|
||||
return self._call("/list/" + uuid, None, True)["data"]
|
||||
|
||||
def list_feed(self, uuid):
|
||||
return self._pagination_chapters(f"/list/{uuid}/feed", None, True)
|
||||
@@ -276,7 +276,7 @@ class MangadexAPI():
|
||||
@memcache(keyarg=1)
|
||||
def manga(self, uuid):
|
||||
params = {"includes[]": ("artist", "author")}
|
||||
return self._call(f"/manga/{uuid}", params)["data"]
|
||||
return self._call("/manga/" + uuid, params)["data"]
|
||||
|
||||
def manga_author(self, uuid_author):
|
||||
params = {"authorOrArtist": uuid_author}
|
||||
@@ -339,17 +339,17 @@ class MangadexAPI():
|
||||
_refresh_token_cache.update(
|
||||
(username, "personal"), data["refresh_token"])
|
||||
|
||||
return f"Bearer {access_token}"
|
||||
return "Bearer " + access_token
|
||||
|
||||
@cache(maxage=900, keyarg=1)
|
||||
def _authenticate_impl_legacy(self, username, password):
|
||||
if refresh_token := _refresh_token_cache(username):
|
||||
self.extractor.log.info("Refreshing access token")
|
||||
url = f"{self.root}/auth/refresh"
|
||||
url = self.root + "/auth/refresh"
|
||||
json = {"token": refresh_token}
|
||||
else:
|
||||
self.extractor.log.info("Logging in as %s", username)
|
||||
url = f"{self.root}/auth/login"
|
||||
url = self.root + "/auth/login"
|
||||
json = {"username": username, "password": password}
|
||||
|
||||
self.extractor.log.debug("Using legacy login method")
|
||||
@@ -360,10 +360,10 @@ class MangadexAPI():
|
||||
|
||||
if refresh_token != data["token"]["refresh"]:
|
||||
_refresh_token_cache.update(username, data["token"]["refresh"])
|
||||
return f"Bearer {data['token']['session']}"
|
||||
return "Bearer " + data["token"]["session"]
|
||||
|
||||
def _call(self, endpoint, params=None, auth=False):
|
||||
url = f"{self.root}{endpoint}"
|
||||
url = self.root + endpoint
|
||||
headers = self.headers_auth if auth else self.headers
|
||||
|
||||
while True:
|
||||
|
||||
@@ -31,8 +31,8 @@ class MangafireChapterExtractor(MangafireBase, ChapterExtractor):
|
||||
"{page:>03}.{extension}")
|
||||
archive_fmt = (
|
||||
"{manga_id}_{chapter_id}_{page}")
|
||||
pattern = (rf"{BASE_PATTERN}/read/([\w-]+\.(\w+))/([\w-]+)"
|
||||
rf"/((chapter|volume)-\d+(?:\D.*)?)")
|
||||
pattern = (BASE_PATTERN + r"/read/([\w-]+\.(\w+))/([\w-]+)"
|
||||
r"/((chapter|volume)-\d+(?:\D.*)?)")
|
||||
example = "https://mangafire.to/read/MANGA.ID/LANG/chapter-123"
|
||||
|
||||
def metadata(self, _):
|
||||
@@ -64,7 +64,7 @@ class MangafireChapterExtractor(MangafireBase, ChapterExtractor):
|
||||
class MangafireMangaExtractor(MangafireBase, MangaExtractor):
|
||||
"""Extractor for mangafire manga"""
|
||||
chapterclass = MangafireChapterExtractor
|
||||
pattern = rf"{BASE_PATTERN}/manga/([\w-]+)\.(\w+)"
|
||||
pattern = BASE_PATTERN + r"/manga/([\w-]+)\.(\w+)"
|
||||
example = "https://mangafire.to/manga/MANGA.ID"
|
||||
|
||||
def chapters(self, page):
|
||||
@@ -75,7 +75,7 @@ class MangafireMangaExtractor(MangafireBase, MangaExtractor):
|
||||
chapters = _manga_chapters(self, (manga_id, "chapter", lang))
|
||||
|
||||
return [
|
||||
(f"""{self.root}{text.extr(anchor, 'href="', '"')}""", {
|
||||
(self.root + text.extr(anchor, 'href="', '"'), {
|
||||
**manga,
|
||||
**_chapter_info(anchor),
|
||||
})
|
||||
@@ -160,7 +160,7 @@ def _chapter_info(info):
|
||||
chapter, sep, minor = text.extr(info, 'data-number="', '"').partition(".")
|
||||
return {
|
||||
"chapter" : text.parse_int(chapter),
|
||||
"chapter_minor" : f"{sep}{minor}",
|
||||
"chapter_minor" : sep + minor,
|
||||
"chapter_string": chapter_info,
|
||||
"chapter_id" : text.parse_int(text.extr(info, 'data-id="', '"')),
|
||||
"title" : text.unescape(text.extr(info, 'title="', '"')),
|
||||
|
||||
@@ -18,8 +18,8 @@ class MangafoxChapterExtractor(ChapterExtractor):
|
||||
"""Extractor for manga chapters from fanfox.net"""
|
||||
category = "mangafox"
|
||||
root = "https://m.fanfox.net"
|
||||
pattern = (rf"{BASE_PATTERN}"
|
||||
rf"(/manga/[^/?#]+/((?:v([^/?#]+)/)?c(\d+)([^/?#]*)))")
|
||||
pattern = BASE_PATTERN + \
|
||||
r"(/manga/[^/?#]+/((?:v([^/?#]+)/)?c(\d+)([^/?#]*)))"
|
||||
example = "https://fanfox.net/manga/TITLE/v01/c001/1.html"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -62,7 +62,7 @@ class MangafoxMangaExtractor(MangaExtractor):
|
||||
category = "mangafox"
|
||||
root = "https://m.fanfox.net"
|
||||
chapterclass = MangafoxChapterExtractor
|
||||
pattern = rf"{BASE_PATTERN}(/manga/[^/?#]+)/?$"
|
||||
pattern = BASE_PATTERN + r"(/manga/[^/?#]+)/?$"
|
||||
example = "https://fanfox.net/manga/TITLE"
|
||||
|
||||
def chapters(self, page):
|
||||
|
||||
@@ -28,7 +28,7 @@ class MangahereChapterExtractor(MangahereBase, ChapterExtractor):
|
||||
def __init__(self, match):
|
||||
self.part, self.volume, self.chapter = match.groups()
|
||||
self.base = f"{self.root_mobile}/manga/{self.part}/"
|
||||
ChapterExtractor.__init__(self, match, f"{self.base}1.html")
|
||||
ChapterExtractor.__init__(self, match, self.base + "1.html")
|
||||
|
||||
def _init(self):
|
||||
self.session.headers["Referer"] = self.root_mobile + "/"
|
||||
|
||||
@@ -39,7 +39,7 @@ BASE_PATTERN = ManganeloExtractor.update({
|
||||
|
||||
class ManganeloChapterExtractor(ManganeloExtractor, ChapterExtractor):
|
||||
"""Extractor for manganelo manga chapters"""
|
||||
pattern = rf"{BASE_PATTERN}(/manga/[^/?#]+/chapter-[^/?#]+)"
|
||||
pattern = BASE_PATTERN + r"(/manga/[^/?#]+/chapter-[^/?#]+)"
|
||||
example = "https://www.mangakakalot.gg/manga/MANGA_NAME/chapter-123"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -86,7 +86,7 @@ class ManganeloChapterExtractor(ManganeloExtractor, ChapterExtractor):
|
||||
class ManganeloMangaExtractor(ManganeloExtractor, MangaExtractor):
|
||||
"""Extractor for manganelo manga"""
|
||||
chapterclass = ManganeloChapterExtractor
|
||||
pattern = rf"{BASE_PATTERN}(/manga/[^/?#]+)$"
|
||||
pattern = BASE_PATTERN + r"(/manga/[^/?#]+)$"
|
||||
example = "https://www.mangakakalot.gg/manga/MANGA_NAME"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -70,8 +70,8 @@ class MangaparkBase():
|
||||
|
||||
class MangaparkChapterExtractor(MangaparkBase, ChapterExtractor):
|
||||
"""Extractor for manga-chapters from mangapark.net"""
|
||||
pattern = (rf"{BASE_PATTERN}/"
|
||||
rf"(?:title/[^/?#]+/|comic/\d+/[^/?#]+/[^/?#]+-i)(\d+)")
|
||||
pattern = (BASE_PATTERN +
|
||||
r"/(?:title/[^/?#]+/|comic/\d+/[^/?#]+/[^/?#]+-i)(\d+)")
|
||||
example = "https://mangapark.net/title/MANGA/12345-en-ch.01"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -111,7 +111,7 @@ class MangaparkChapterExtractor(MangaparkBase, ChapterExtractor):
|
||||
class MangaparkMangaExtractor(MangaparkBase, Extractor):
|
||||
"""Extractor for manga from mangapark.net"""
|
||||
subcategory = "manga"
|
||||
pattern = rf"{BASE_PATTERN}/(?:title|comic)/(\d+)(?:[/-][^/?#]*)?/?$"
|
||||
pattern = BASE_PATTERN + r"/(?:title|comic)/(\d+)(?:[/-][^/?#]*)?/?$"
|
||||
example = "https://mangapark.net/title/12345-MANGA"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -31,8 +31,8 @@ class MangareaderChapterExtractor(MangareaderBase, ChapterExtractor):
|
||||
"{page:>03}.{extension}")
|
||||
archive_fmt = (
|
||||
"{manga_id}_{chapter_id}_{page}")
|
||||
pattern = (rf"{BASE_PATTERN}/read/([\w-]+-\d+)/([^/?#]+)"
|
||||
rf"/(chapter|volume)-(\d+[^/?#]*)")
|
||||
pattern = (BASE_PATTERN + r"/read/([\w-]+-\d+)/([^/?#]+)"
|
||||
r"/(chapter|volume)-(\d+[^/?#]*)")
|
||||
example = "https://mangareader.to/read/MANGA-123/LANG/chapter-123"
|
||||
|
||||
def metadata(self, _):
|
||||
@@ -81,7 +81,7 @@ class MangareaderChapterExtractor(MangareaderBase, ChapterExtractor):
|
||||
class MangareaderMangaExtractor(MangareaderBase, MangaExtractor):
|
||||
"""Extractor for mangareader manga"""
|
||||
chapterclass = MangareaderChapterExtractor
|
||||
pattern = rf"{BASE_PATTERN}/([\w-]+-\d+)"
|
||||
pattern = BASE_PATTERN + r"/([\w-]+-\d+)"
|
||||
example = "https://mangareader.to/MANGA-123"
|
||||
|
||||
def chapters(self, page):
|
||||
@@ -138,9 +138,9 @@ def _manga_info(self, manga_path):
|
||||
current[chap] = {
|
||||
"title" : name.partition(":")[2].strip(),
|
||||
"chapter" : text.parse_int(chapter),
|
||||
"chapter_minor" : f"{sep}{minor}",
|
||||
"chapter_minor" : sep + minor,
|
||||
"chapter_string": chap,
|
||||
"chapter_url" : f"{base}{path}",
|
||||
"chapter_url" : base + path,
|
||||
"lang" : lang,
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ def _manga_info(self, manga_path):
|
||||
"chapter" : 0,
|
||||
"chapter_minor" : "",
|
||||
"chapter_string": voln,
|
||||
"chapter_url" : f"{base}{path}",
|
||||
"chapter_url" : base + path,
|
||||
"lang" : lang,
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class MangataroBase():
|
||||
|
||||
class MangataroChapterExtractor(MangataroBase, ChapterExtractor):
|
||||
"""Extractor for mangataro manga chapters"""
|
||||
pattern = rf"{BASE_PATTERN}(/read/([^/?#]+)/(?:[^/?#]*-)?(\d+))"
|
||||
pattern = BASE_PATTERN + r"(/read/([^/?#]+)/(?:[^/?#]*-)?(\d+))"
|
||||
example = "https://mangataro.org/read/MANGA/ch123-12345"
|
||||
|
||||
def metadata(self, page):
|
||||
@@ -59,7 +59,7 @@ class MangataroChapterExtractor(MangataroBase, ChapterExtractor):
|
||||
class MangataroMangaExtractor(MangataroBase, MangaExtractor):
|
||||
"""Extractor for mangataro manga"""
|
||||
chapterclass = MangataroChapterExtractor
|
||||
pattern = rf"{BASE_PATTERN}(/manga/([^/?#]+))"
|
||||
pattern = BASE_PATTERN + r"(/manga/([^/?#]+))"
|
||||
example = "https://mangataro.org/manga/MANGA"
|
||||
|
||||
def chapters(self, page):
|
||||
@@ -75,7 +75,7 @@ class MangataroMangaExtractor(MangataroBase, MangaExtractor):
|
||||
results.append((url, {
|
||||
**manga,
|
||||
"chapter" : text.parse_int(chapter),
|
||||
"chapter_minor": f".{minor}" if sep else "",
|
||||
"chapter_minor": "." + minor if sep else "",
|
||||
"chapter_id" : text.parse_int(chapter_id),
|
||||
}))
|
||||
return results
|
||||
|
||||
@@ -118,7 +118,7 @@ BASE_PATTERN = MastodonExtractor.update({
|
||||
class MastodonUserExtractor(MastodonExtractor):
|
||||
"""Extractor for all images of an account/user"""
|
||||
subcategory = "user"
|
||||
pattern = rf"{BASE_PATTERN}/(?:@|users/)([^/?#]+)(?:/media)?/?$"
|
||||
pattern = BASE_PATTERN + r"/(?:@|users/)([^/?#]+)(?:/media)?/?$"
|
||||
example = "https://mastodon.social/@USER"
|
||||
|
||||
def statuses(self):
|
||||
@@ -138,7 +138,7 @@ class MastodonUserExtractor(MastodonExtractor):
|
||||
class MastodonBookmarkExtractor(MastodonExtractor):
|
||||
"""Extractor for mastodon bookmarks"""
|
||||
subcategory = "bookmark"
|
||||
pattern = rf"{BASE_PATTERN}/bookmarks"
|
||||
pattern = BASE_PATTERN + r"/bookmarks"
|
||||
example = "https://mastodon.social/bookmarks"
|
||||
|
||||
def statuses(self):
|
||||
@@ -148,7 +148,7 @@ class MastodonBookmarkExtractor(MastodonExtractor):
|
||||
class MastodonFavoriteExtractor(MastodonExtractor):
|
||||
"""Extractor for mastodon favorites"""
|
||||
subcategory = "favorite"
|
||||
pattern = rf"{BASE_PATTERN}/favourites"
|
||||
pattern = BASE_PATTERN + r"/favourites"
|
||||
example = "https://mastodon.social/favourites"
|
||||
|
||||
def statuses(self):
|
||||
@@ -158,7 +158,7 @@ class MastodonFavoriteExtractor(MastodonExtractor):
|
||||
class MastodonListExtractor(MastodonExtractor):
|
||||
"""Extractor for mastodon lists"""
|
||||
subcategory = "list"
|
||||
pattern = rf"{BASE_PATTERN}/lists/(\w+)"
|
||||
pattern = BASE_PATTERN + r"/lists/(\w+)"
|
||||
example = "https://mastodon.social/lists/12345"
|
||||
|
||||
def statuses(self):
|
||||
@@ -168,7 +168,7 @@ class MastodonListExtractor(MastodonExtractor):
|
||||
class MastodonHashtagExtractor(MastodonExtractor):
|
||||
"""Extractor for mastodon hashtags"""
|
||||
subcategory = "hashtag"
|
||||
pattern = rf"{BASE_PATTERN}/tags/(\w+)"
|
||||
pattern = BASE_PATTERN + r"/tags/(\w+)"
|
||||
example = "https://mastodon.social/tags/NAME"
|
||||
|
||||
def statuses(self):
|
||||
@@ -178,7 +178,7 @@ class MastodonHashtagExtractor(MastodonExtractor):
|
||||
class MastodonFollowingExtractor(MastodonExtractor):
|
||||
"""Extractor for followed mastodon users"""
|
||||
subcategory = "following"
|
||||
pattern = rf"{BASE_PATTERN}/(?:@|users/)([^/?#]+)/following"
|
||||
pattern = BASE_PATTERN + r"/(?:@|users/)([^/?#]+)/following"
|
||||
example = "https://mastodon.social/@USER/following"
|
||||
|
||||
def items(self):
|
||||
@@ -193,7 +193,7 @@ class MastodonFollowingExtractor(MastodonExtractor):
|
||||
class MastodonStatusExtractor(MastodonExtractor):
|
||||
"""Extractor for images from a status"""
|
||||
subcategory = "status"
|
||||
pattern = (rf"{BASE_PATTERN}/(?:@[^/?#]+|(?:users/[^/?#]+/)?"
|
||||
pattern = (BASE_PATTERN + r"/(?:@[^/?#]+|(?:users/[^/?#]+/)?"
|
||||
r"(?:statuses|notice|objects()))/(?!following)([^/?#]+)")
|
||||
example = "https://mastodon.social/@USER/12345"
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ BASE_PATTERN = MisskeyExtractor.update({
|
||||
class MisskeyUserExtractor(Dispatch, MisskeyExtractor):
|
||||
"""Extractor for all images of a Misskey user"""
|
||||
subcategory = "user"
|
||||
pattern = rf"{BASE_PATTERN}/@([^/?#]+)/?$"
|
||||
pattern = BASE_PATTERN + r"/@([^/?#]+)/?$"
|
||||
example = "https://misskey.io/@USER"
|
||||
|
||||
def items(self):
|
||||
@@ -118,7 +118,7 @@ class MisskeyUserExtractor(Dispatch, MisskeyExtractor):
|
||||
class MisskeyNotesExtractor(MisskeyExtractor):
|
||||
"""Extractor for a Misskey user's notes"""
|
||||
subcategory = "notes"
|
||||
pattern = rf"{BASE_PATTERN}/@([^/?#]+)/notes"
|
||||
pattern = BASE_PATTERN + r"/@([^/?#]+)/notes"
|
||||
example = "https://misskey.io/@USER/notes"
|
||||
|
||||
def notes(self):
|
||||
@@ -129,7 +129,7 @@ class MisskeyNotesExtractor(MisskeyExtractor):
|
||||
class MisskeyInfoExtractor(MisskeyExtractor):
|
||||
"""Extractor for a Misskey user's profile data"""
|
||||
subcategory = "info"
|
||||
pattern = rf"{BASE_PATTERN}/@([^/?#]+)/info"
|
||||
pattern = BASE_PATTERN + r"/@([^/?#]+)/info"
|
||||
example = "https://misskey.io/@USER/info"
|
||||
|
||||
def items(self):
|
||||
@@ -140,7 +140,7 @@ class MisskeyInfoExtractor(MisskeyExtractor):
|
||||
class MisskeyAvatarExtractor(MisskeyExtractor):
|
||||
"""Extractor for a Misskey user's avatar"""
|
||||
subcategory = "avatar"
|
||||
pattern = rf"{BASE_PATTERN}/@([^/?#]+)/avatar"
|
||||
pattern = BASE_PATTERN + r"/@([^/?#]+)/avatar"
|
||||
example = "https://misskey.io/@USER/avatar"
|
||||
|
||||
def notes(self):
|
||||
@@ -152,7 +152,7 @@ class MisskeyAvatarExtractor(MisskeyExtractor):
|
||||
class MisskeyBackgroundExtractor(MisskeyExtractor):
|
||||
"""Extractor for a Misskey user's banner image"""
|
||||
subcategory = "background"
|
||||
pattern = rf"{BASE_PATTERN}/@([^/?#]+)/ba(?:nner|ckground)"
|
||||
pattern = BASE_PATTERN + r"/@([^/?#]+)/ba(?:nner|ckground)"
|
||||
example = "https://misskey.io/@USER/banner"
|
||||
|
||||
def notes(self):
|
||||
@@ -164,7 +164,7 @@ class MisskeyBackgroundExtractor(MisskeyExtractor):
|
||||
class MisskeyFollowingExtractor(MisskeyExtractor):
|
||||
"""Extractor for followed Misskey users"""
|
||||
subcategory = "following"
|
||||
pattern = rf"{BASE_PATTERN}/@([^/?#]+)/following"
|
||||
pattern = BASE_PATTERN + r"/@([^/?#]+)/following"
|
||||
example = "https://misskey.io/@USER/following"
|
||||
|
||||
def items(self):
|
||||
@@ -181,7 +181,7 @@ class MisskeyFollowingExtractor(MisskeyExtractor):
|
||||
class MisskeyNoteExtractor(MisskeyExtractor):
|
||||
"""Extractor for images from a Note"""
|
||||
subcategory = "note"
|
||||
pattern = rf"{BASE_PATTERN}/notes/(\w+)"
|
||||
pattern = BASE_PATTERN + r"/notes/(\w+)"
|
||||
example = "https://misskey.io/notes/98765"
|
||||
|
||||
def notes(self):
|
||||
@@ -191,7 +191,7 @@ class MisskeyNoteExtractor(MisskeyExtractor):
|
||||
class MisskeyFavoriteExtractor(MisskeyExtractor):
|
||||
"""Extractor for favorited notes"""
|
||||
subcategory = "favorite"
|
||||
pattern = rf"{BASE_PATTERN}/(?:my|api/i)/favorites"
|
||||
pattern = BASE_PATTERN + r"/(?:my|api/i)/favorites"
|
||||
example = "https://misskey.io/my/favorites"
|
||||
|
||||
def notes(self):
|
||||
|
||||
@@ -92,7 +92,7 @@ class MoebooruTagExtractor(MoebooruExtractor):
|
||||
subcategory = "tag"
|
||||
directory_fmt = ("{category}", "{search_tags}")
|
||||
archive_fmt = "t_{search_tags}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/post\?(?:[^&#]*&)*tags=([^&#]*)"
|
||||
pattern = BASE_PATTERN + r"/post\?(?:[^&#]*&)*tags=([^&#]*)"
|
||||
example = "https://yande.re/post?tags=TAG"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -104,14 +104,14 @@ class MoebooruTagExtractor(MoebooruExtractor):
|
||||
|
||||
def posts(self):
|
||||
params = {"tags": self.tags}
|
||||
return self._pagination(f"{self.root}/post.json", params)
|
||||
return self._pagination(self.root + "/post.json", params)
|
||||
|
||||
|
||||
class MoebooruPoolExtractor(MoebooruExtractor):
|
||||
subcategory = "pool"
|
||||
directory_fmt = ("{category}", "pool", "{pool}")
|
||||
archive_fmt = "p_{pool}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/pool/show/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/pool/show/(\d+)"
|
||||
example = "https://yande.re/pool/show/12345"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -129,26 +129,26 @@ class MoebooruPoolExtractor(MoebooruExtractor):
|
||||
|
||||
def posts(self):
|
||||
params = {"tags": "pool:" + self.pool_id}
|
||||
return self._pagination(f"{self.root}/post.json", params)
|
||||
return self._pagination(self.root + "/post.json", params)
|
||||
|
||||
|
||||
class MoebooruPostExtractor(MoebooruExtractor):
|
||||
subcategory = "post"
|
||||
archive_fmt = "{id}"
|
||||
pattern = rf"{BASE_PATTERN}/post/show/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/post/show/(\d+)"
|
||||
example = "https://yande.re/post/show/12345"
|
||||
|
||||
def posts(self):
|
||||
params = {"tags": "id:" + self.groups[-1]}
|
||||
return self.request_json(f"{self.root}/post.json", params=params)
|
||||
return self.request_json(self.root + "/post.json", params=params)
|
||||
|
||||
|
||||
class MoebooruPopularExtractor(MoebooruExtractor):
|
||||
subcategory = "popular"
|
||||
directory_fmt = ("{category}", "popular", "{scale}", "{date}")
|
||||
archive_fmt = "P_{scale[0]}_{date}_{id}"
|
||||
pattern = (rf"{BASE_PATTERN}"
|
||||
rf"/post/popular_(by_(?:day|week|month)|recent)(?:\?([^#]*))?")
|
||||
pattern = BASE_PATTERN + \
|
||||
r"/post/popular_(by_(?:day|week|month)|recent)(?:\?([^#]*))?"
|
||||
example = "https://yande.re/post/popular_by_month?year=YYYY&month=MM"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -93,8 +93,8 @@ class MotherlessExtractor(Extractor):
|
||||
title = self._extract_group_title(page, gid)
|
||||
|
||||
return {
|
||||
f"{category}_id": gid,
|
||||
f"{category}_title": title,
|
||||
category + "_id": gid,
|
||||
category + "_title": title,
|
||||
"uploader": text.remove_html(extr(
|
||||
f'class="{category}-member-username">', "</")),
|
||||
"count": text.parse_int(
|
||||
@@ -152,9 +152,9 @@ class MotherlessExtractor(Extractor):
|
||||
class MotherlessMediaExtractor(MotherlessExtractor):
|
||||
"""Extractor for a single image/video from motherless.com"""
|
||||
subcategory = "media"
|
||||
pattern = (rf"{BASE_PATTERN}/("
|
||||
rf"(?:g/[^/?#]+/|G[IV]?[A-Z0-9]+/)?"
|
||||
rf"(?!G)[A-Z0-9]+)")
|
||||
pattern = (BASE_PATTERN +
|
||||
r"/((?:g/[^/?#]+/|G[IV]?[A-Z0-9]+/)?"
|
||||
r"(?!G)[A-Z0-9]+)")
|
||||
example = "https://motherless.com/ABC123"
|
||||
|
||||
def items(self):
|
||||
@@ -170,7 +170,7 @@ class MotherlessGalleryExtractor(MotherlessExtractor):
|
||||
directory_fmt = ("{category}", "{uploader}",
|
||||
"{gallery_id} {gallery_title}")
|
||||
archive_fmt = "{gallery_id}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/G([IVG])?([A-Z0-9]+)/?$"
|
||||
pattern = BASE_PATTERN + "/G([IVG])?([A-Z0-9]+)/?$"
|
||||
example = "https://motherless.com/GABC123"
|
||||
|
||||
def items(self):
|
||||
@@ -206,7 +206,7 @@ class MotherlessGroupExtractor(MotherlessExtractor):
|
||||
directory_fmt = ("{category}", "{uploader}",
|
||||
"{group_id} {group_title}")
|
||||
archive_fmt = "{group_id}_{id}"
|
||||
pattern = rf"{BASE_PATTERN}/g([iv]?)/?([a-z0-9_]+)/?$"
|
||||
pattern = BASE_PATTERN + "/g([iv]?)/?([a-z0-9_]+)/?$"
|
||||
example = "https://motherless.com/g/abc123"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -20,7 +20,7 @@ class MyhentaigalleryBase():
|
||||
class MyhentaigalleryGalleryExtractor(MyhentaigalleryBase, GalleryExtractor):
|
||||
"""Extractor for image galleries from myhentaigallery.com"""
|
||||
directory_fmt = ("{category}", "{gallery_id} {artist:?[/] /J, }{title}")
|
||||
pattern = rf"{BASE_PATTERN}/g(?:allery/(?:thumbnails|show))?/(\d+)"
|
||||
pattern = BASE_PATTERN + r"/g(?:allery/(?:thumbnails|show))?/(\d+)"
|
||||
example = "https://myhentaigallery.com/g/12345"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -62,7 +62,7 @@ class MyhentaigalleryGalleryExtractor(MyhentaigalleryBase, GalleryExtractor):
|
||||
class MyhentaigalleryTagExtractor(MyhentaigalleryBase, Extractor):
|
||||
"""Extractor for myhentaigallery tag searches"""
|
||||
subcategory = "tag"
|
||||
pattern = rf"{BASE_PATTERN}(/g/(artist|category|group|parody)/(\d+).*)"
|
||||
pattern = BASE_PATTERN + r"(/g/(artist|category|group|parody)/(\d+).*)"
|
||||
example = "https://myhentaigallery.com/g/category/123"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -142,7 +142,7 @@ class NaverBlogBlogExtractor(NaverBlogBase, Extractor):
|
||||
)
|
||||
|
||||
# setup params for API calls
|
||||
url = f"{self.root}/PostViewBottomTitleListAsync.nhn"
|
||||
url = self.root + "/PostViewBottomTitleListAsync.nhn"
|
||||
params = {
|
||||
"blogId" : self.blog_id,
|
||||
"logNo" : post_num or "0",
|
||||
|
||||
@@ -27,7 +27,7 @@ class NaverWebtoonEpisodeExtractor(NaverWebtoonBase, GalleryExtractor):
|
||||
directory_fmt = ("{category}", "{comic}")
|
||||
filename_fmt = "{episode:>03}-{num:>02}.{extension}"
|
||||
archive_fmt = "{title_id}_{episode}_{num}"
|
||||
pattern = rf"{BASE_PATTERN}/detail(?:\.nhn)?\?([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/detail(?:\.nhn)?\?([^#]+)"
|
||||
example = "https://comic.naver.com/webtoon/detail?titleId=12345&no=1"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -66,7 +66,7 @@ class NaverWebtoonEpisodeExtractor(NaverWebtoonBase, GalleryExtractor):
|
||||
class NaverWebtoonComicExtractor(NaverWebtoonBase, Extractor):
|
||||
subcategory = "comic"
|
||||
categorytransfer = True
|
||||
pattern = rf"{BASE_PATTERN}/list(?:\.nhn)?\?([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/list(?:\.nhn)?\?([^#]+)"
|
||||
example = "https://comic.naver.com/webtoon/list?titleId=12345"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -12,7 +12,7 @@ from .common import Extractor, Message
|
||||
from .. import text
|
||||
|
||||
BASE_PATTERN = r"(?:https?://)?nekohouse\.su"
|
||||
USER_PATTERN = rf"{BASE_PATTERN}/([^/?#]+)/user/([^/?#]+)"
|
||||
USER_PATTERN = BASE_PATTERN + r"/([^/?#]+)/user/([^/?#]+)"
|
||||
|
||||
|
||||
class NekohouseExtractor(Extractor):
|
||||
@@ -27,7 +27,7 @@ class NekohousePostExtractor(NekohouseExtractor):
|
||||
"{post_id} {date} {title[b:230]}")
|
||||
filename_fmt = "{num:>02} {id|filename}.{extension}"
|
||||
archive_fmt = "{service}_{user_id}_{post_id}_{hash}"
|
||||
pattern = rf"{USER_PATTERN}/post/([^/?#]+)"
|
||||
pattern = USER_PATTERN + r"/post/([^/?#]+)"
|
||||
example = "https://nekohouse.su/SERVICE/user/12345/post/12345"
|
||||
|
||||
def items(self):
|
||||
@@ -98,7 +98,7 @@ class NekohousePostExtractor(NekohouseExtractor):
|
||||
|
||||
class NekohouseUserExtractor(NekohouseExtractor):
|
||||
subcategory = "user"
|
||||
pattern = rf"{USER_PATTERN}/?(?:\?([^#]+))?(?:$|\?|#)"
|
||||
pattern = USER_PATTERN + r"/?(?:\?([^#]+))?(?:$|\?|#)"
|
||||
example = "https://nekohouse.su/SERVICE/user/12345"
|
||||
|
||||
def items(self):
|
||||
|
||||
@@ -412,7 +412,7 @@ class NewgroundsImageExtractor(NewgroundsExtractor):
|
||||
class NewgroundsMediaExtractor(NewgroundsExtractor):
|
||||
"""Extractor for a media file from newgrounds.com"""
|
||||
subcategory = "media"
|
||||
pattern = rf"{BASE_PATTERN}(/(?:portal/view|audio/listen)/\d+)"
|
||||
pattern = BASE_PATTERN + r"(/(?:portal/view|audio/listen)/\d+)"
|
||||
example = "https://www.newgrounds.com/portal/view/12345"
|
||||
|
||||
def __init__(self, match):
|
||||
@@ -427,34 +427,34 @@ class NewgroundsMediaExtractor(NewgroundsExtractor):
|
||||
class NewgroundsArtExtractor(NewgroundsExtractor):
|
||||
"""Extractor for all images of a newgrounds user"""
|
||||
subcategory = _path = "art"
|
||||
pattern = rf"{USER_PATTERN}/art(?:(?:/page/|/?\?page=)(\d+))?/?$"
|
||||
pattern = USER_PATTERN + r"/art(?:(?:/page/|/?\?page=)(\d+))?/?$"
|
||||
example = "https://USER.newgrounds.com/art"
|
||||
|
||||
|
||||
class NewgroundsAudioExtractor(NewgroundsExtractor):
|
||||
"""Extractor for all audio submissions of a newgrounds user"""
|
||||
subcategory = _path = "audio"
|
||||
pattern = rf"{USER_PATTERN}/audio(?:(?:/page/|/?\?page=)(\d+))?/?$"
|
||||
pattern = USER_PATTERN + r"/audio(?:(?:/page/|/?\?page=)(\d+))?/?$"
|
||||
example = "https://USER.newgrounds.com/audio"
|
||||
|
||||
|
||||
class NewgroundsMoviesExtractor(NewgroundsExtractor):
|
||||
"""Extractor for all movies of a newgrounds user"""
|
||||
subcategory = _path = "movies"
|
||||
pattern = rf"{USER_PATTERN}/movies(?:(?:/page/|/?\?page=)(\d+))?/?$"
|
||||
pattern = USER_PATTERN + r"/movies(?:(?:/page/|/?\?page=)(\d+))?/?$"
|
||||
example = "https://USER.newgrounds.com/movies"
|
||||
|
||||
|
||||
class NewgroundsGamesExtractor(NewgroundsExtractor):
|
||||
"""Extractor for a newgrounds user's games"""
|
||||
subcategory = _path = "games"
|
||||
pattern = rf"{USER_PATTERN}/games(?:(?:/page/|/?\?page=)(\d+))?/?$"
|
||||
pattern = USER_PATTERN + r"/games(?:(?:/page/|/?\?page=)(\d+))?/?$"
|
||||
example = "https://USER.newgrounds.com/games"
|
||||
|
||||
|
||||
class NewgroundsUserExtractor(Dispatch, NewgroundsExtractor):
|
||||
"""Extractor for a newgrounds user profile"""
|
||||
pattern = rf"{USER_PATTERN}/?$"
|
||||
pattern = USER_PATTERN + r"/?$"
|
||||
example = "https://USER.newgrounds.com"
|
||||
|
||||
def items(self):
|
||||
@@ -471,7 +471,7 @@ class NewgroundsFavoriteExtractor(NewgroundsExtractor):
|
||||
"""Extractor for posts favorited by a newgrounds user"""
|
||||
subcategory = "favorite"
|
||||
directory_fmt = ("{category}", "{user}", "Favorites")
|
||||
pattern = (rf"{USER_PATTERN}/favorites(?!/following)(?:/(art|audio|movies)"
|
||||
pattern = (USER_PATTERN + r"/favorites(?!/following)(?:/(art|audio|movies)"
|
||||
r"(?:(?:/page/|/?\?page=)(\d+))?)?")
|
||||
example = "https://USER.newgrounds.com/favorites"
|
||||
|
||||
@@ -510,16 +510,15 @@ class NewgroundsFavoriteExtractor(NewgroundsExtractor):
|
||||
def _extract_favorites(self, page):
|
||||
return [
|
||||
self.root + path
|
||||
for path in text.extract_iter(page, f'href="{self.root}', '"')
|
||||
for path in text.extract_iter(page, 'href="' + self.root, '"')
|
||||
]
|
||||
|
||||
|
||||
class NewgroundsFollowingExtractor(NewgroundsFavoriteExtractor):
|
||||
"""Extractor for a newgrounds user's favorited users"""
|
||||
subcategory = "following"
|
||||
pattern = (rf"{USER_PATTERN}/favorites/(following)"
|
||||
pattern = (USER_PATTERN + r"/favorites/(following)"
|
||||
r"(?:(?:/page/|/?\?page=)(\d+))?")
|
||||
|
||||
example = "https://USER.newgrounds.com/favorites/following"
|
||||
|
||||
def items(self):
|
||||
@@ -539,7 +538,7 @@ class NewgroundsSearchExtractor(NewgroundsExtractor):
|
||||
"""Extractor for newgrounds.com search reesults"""
|
||||
subcategory = "search"
|
||||
directory_fmt = ("{category}", "search", "{search_tags}")
|
||||
pattern = rf"{BASE_PATTERN}/search/conduct/([^/?#]+)/?\?([^#]+)"
|
||||
pattern = BASE_PATTERN + r"/search/conduct/([^/?#]+)/?\?([^#]+)"
|
||||
example = "https://www.newgrounds.com/search/conduct/art?terms=QUERY"
|
||||
|
||||
def __init__(self, match):
|
||||
|
||||
@@ -140,7 +140,7 @@ class NijieExtractor(AsynchronousMixin, BaseExtractor):
|
||||
def _login_impl(self, username, password):
|
||||
self.log.info("Logging in as %s", username)
|
||||
|
||||
url = f"{self.root}/login_int.php"
|
||||
url = self.root + "/login_int.php"
|
||||
data = {"email": username, "password": password, "save": "on"}
|
||||
|
||||
response = self.request(url, method="POST", data=data)
|
||||
@@ -178,7 +178,7 @@ BASE_PATTERN = NijieExtractor.update({
|
||||
|
||||
class NijieUserExtractor(Dispatch, NijieExtractor):
|
||||
"""Extractor for nijie user profiles"""
|
||||
pattern = rf"{BASE_PATTERN}/members\.php\?id=(\d+)"
|
||||
pattern = BASE_PATTERN + r"/members\.php\?id=(\d+)"
|
||||
example = "https://nijie.info/members.php?id=12345"
|
||||
|
||||
def items(self):
|
||||
@@ -194,7 +194,7 @@ class NijieUserExtractor(Dispatch, NijieExtractor):
|
||||
class NijieIllustrationExtractor(NijieExtractor):
|
||||
"""Extractor for all illustrations of a nijie-user"""
|
||||
subcategory = "illustration"
|
||||
pattern = rf"{BASE_PATTERN}/members_illust\.php\?id=(\d+)"
|
||||
pattern = BASE_PATTERN + r"/members_illust\.php\?id=(\d+)"
|
||||
example = "https://nijie.info/members_illust.php?id=12345"
|
||||
|
||||
def image_ids(self):
|
||||
@@ -204,7 +204,7 @@ class NijieIllustrationExtractor(NijieExtractor):
|
||||
class NijieDoujinExtractor(NijieExtractor):
|
||||
"""Extractor for doujin entries of a nijie user"""
|
||||
subcategory = "doujin"
|
||||
pattern = rf"{BASE_PATTERN}/members_dojin\.php\?id=(\d+)"
|
||||
pattern = BASE_PATTERN + r"/members_dojin\.php\?id=(\d+)"
|
||||
example = "https://nijie.info/members_dojin.php?id=12345"
|
||||
|
||||
def image_ids(self):
|
||||
@@ -216,7 +216,7 @@ class NijieFavoriteExtractor(NijieExtractor):
|
||||
subcategory = "favorite"
|
||||
directory_fmt = ("{category}", "bookmarks", "{user_id}")
|
||||
archive_fmt = "f_{user_id}_{image_id}_{num}"
|
||||
pattern = rf"{BASE_PATTERN}/user_like_illust_view\.php\?id=(\d+)"
|
||||
pattern = BASE_PATTERN + r"/user_like_illust_view\.php\?id=(\d+)"
|
||||
example = "https://nijie.info/user_like_illust_view.php?id=12345"
|
||||
|
||||
def image_ids(self):
|
||||
@@ -234,7 +234,7 @@ class NijieNuitaExtractor(NijieExtractor):
|
||||
subcategory = "nuita"
|
||||
directory_fmt = ("{category}", "nuita", "{user_id}")
|
||||
archive_fmt = "n_{user_id}_{image_id}_{num}"
|
||||
pattern = rf"{BASE_PATTERN}/history_nuita\.php\?id=(\d+)"
|
||||
pattern = BASE_PATTERN + r"/history_nuita\.php\?id=(\d+)"
|
||||
example = "https://nijie.info/history_nuita.php?id=12345"
|
||||
|
||||
def image_ids(self):
|
||||
@@ -253,7 +253,7 @@ class NijieNuitaExtractor(NijieExtractor):
|
||||
class NijieFeedExtractor(NijieExtractor):
|
||||
"""Extractor for nijie liked user feed"""
|
||||
subcategory = "feed"
|
||||
pattern = rf"{BASE_PATTERN}/like_user_view\.php"
|
||||
pattern = BASE_PATTERN + r"/like_user_view\.php"
|
||||
example = "https://nijie.info/like_user_view.php"
|
||||
|
||||
def image_ids(self):
|
||||
@@ -266,7 +266,7 @@ class NijieFeedExtractor(NijieExtractor):
|
||||
class NijieFollowedExtractor(NijieExtractor):
|
||||
"""Extractor for followed nijie users"""
|
||||
subcategory = "followed"
|
||||
pattern = rf"{BASE_PATTERN}/like_my\.php"
|
||||
pattern = BASE_PATTERN + r"/like_my\.php"
|
||||
example = "https://nijie.info/like_my.php"
|
||||
|
||||
def items(self):
|
||||
@@ -292,7 +292,7 @@ class NijieFollowedExtractor(NijieExtractor):
|
||||
class NijieImageExtractor(NijieExtractor):
|
||||
"""Extractor for a nijie work/image"""
|
||||
subcategory = "image"
|
||||
pattern = rf"{BASE_PATTERN}/view(?:_popup)?\.php\?id=(\d+)"
|
||||
pattern = BASE_PATTERN + r"/view(?:_popup)?\.php\?id=(\d+)"
|
||||
example = "https://nijie.info/view.php?id=12345"
|
||||
|
||||
def image_ids(self):
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user