remove @staticmethod decorators
There might have been a time when calling a static method was faster than a regular method, but that is no longer the case. According to micro-benchmarks, it is 70% slower in CPython 3.13 and it also makes executing the code of a class definition slower.
This commit is contained in:
@@ -273,8 +273,7 @@ def main():
|
|||||||
jobtype = job.UrlJob
|
jobtype = job.UrlJob
|
||||||
jobtype.maxdepth = args.list_urls
|
jobtype.maxdepth = args.list_urls
|
||||||
if config.get(("output",), "fallback", True):
|
if config.get(("output",), "fallback", True):
|
||||||
jobtype.handle_url = \
|
jobtype.handle_url = jobtype.handle_url_fallback
|
||||||
staticmethod(jobtype.handle_url_fallback)
|
|
||||||
elif args.dump_json:
|
elif args.dump_json:
|
||||||
jobtype = job.DataJob
|
jobtype = job.DataJob
|
||||||
jobtype.resolve = args.dump_json - 1
|
jobtype.resolve = args.dump_json - 1
|
||||||
@@ -549,13 +548,11 @@ class InputManager():
|
|||||||
"Unable to update '%s' (%s: %s)",
|
"Unable to update '%s' (%s: %s)",
|
||||||
path, exc.__class__.__name__, exc)
|
path, exc.__class__.__name__, exc)
|
||||||
|
|
||||||
@staticmethod
|
def _action_comment(self, lines, indicies):
|
||||||
def _action_comment(lines, indicies):
|
|
||||||
for i in indicies:
|
for i in indicies:
|
||||||
lines[i] = "# " + lines[i]
|
lines[i] = "# " + lines[i]
|
||||||
|
|
||||||
@staticmethod
|
def _action_delete(self, lines, indicies):
|
||||||
def _action_delete(lines, indicies):
|
|
||||||
for i in indicies:
|
for i in indicies:
|
||||||
lines[i] = ""
|
lines[i] = ""
|
||||||
|
|
||||||
|
|||||||
@@ -524,8 +524,7 @@ class LinuxChromiumCookieDecryptor(ChromiumCookieDecryptor):
|
|||||||
self._cookie_counts = {"v10": 0, "v11": 0, "other": 0}
|
self._cookie_counts = {"v10": 0, "v11": 0, "other": 0}
|
||||||
self._offset = (32 if meta_version >= 24 else 0)
|
self._offset = (32 if meta_version >= 24 else 0)
|
||||||
|
|
||||||
@staticmethod
|
def derive_key(self, password):
|
||||||
def derive_key(password):
|
|
||||||
# values from
|
# values from
|
||||||
# https://chromium.googlesource.com/chromium/src/+/refs/heads
|
# https://chromium.googlesource.com/chromium/src/+/refs/heads
|
||||||
# /main/components/os_crypt/os_crypt_linux.cc
|
# /main/components/os_crypt/os_crypt_linux.cc
|
||||||
@@ -569,8 +568,7 @@ class MacChromiumCookieDecryptor(ChromiumCookieDecryptor):
|
|||||||
self._cookie_counts = {"v10": 0, "other": 0}
|
self._cookie_counts = {"v10": 0, "other": 0}
|
||||||
self._offset = (32 if meta_version >= 24 else 0)
|
self._offset = (32 if meta_version >= 24 else 0)
|
||||||
|
|
||||||
@staticmethod
|
def derive_key(self, password):
|
||||||
def derive_key(password):
|
|
||||||
# values from
|
# values from
|
||||||
# https://chromium.googlesource.com/chromium/src/+/refs/heads
|
# https://chromium.googlesource.com/chromium/src/+/refs/heads
|
||||||
# /main/components/os_crypt/os_crypt_mac.mm
|
# /main/components/os_crypt/os_crypt_mac.mm
|
||||||
|
|||||||
@@ -360,8 +360,7 @@ class HttpDownloader(DownloaderBase):
|
|||||||
"closing the connection anyway", exc.__class__.__name__, exc)
|
"closing the connection anyway", exc.__class__.__name__, exc)
|
||||||
response.close()
|
response.close()
|
||||||
|
|
||||||
@staticmethod
|
def receive(self, fp, content, bytes_total, bytes_start):
|
||||||
def receive(fp, content, bytes_total, bytes_start):
|
|
||||||
write = fp.write
|
write = fp.write
|
||||||
for data in content:
|
for data in content:
|
||||||
write(data)
|
write(data)
|
||||||
@@ -411,8 +410,7 @@ class HttpDownloader(DownloaderBase):
|
|||||||
self.log.warning("Unknown MIME type '%s'", mtype)
|
self.log.warning("Unknown MIME type '%s'", mtype)
|
||||||
return "bin"
|
return "bin"
|
||||||
|
|
||||||
@staticmethod
|
def _adjust_extension(self, pathfmt, file_header):
|
||||||
def _adjust_extension(pathfmt, file_header):
|
|
||||||
"""Check filename extension against file header"""
|
"""Check filename extension against file header"""
|
||||||
if not SIGNATURE_CHECKS[pathfmt.extension](file_header):
|
if not SIGNATURE_CHECKS[pathfmt.extension](file_header):
|
||||||
for ext, check in SIGNATURE_CHECKS.items():
|
for ext, check in SIGNATURE_CHECKS.items():
|
||||||
|
|||||||
@@ -233,8 +233,7 @@ class YoutubeDLDownloader(DownloaderBase):
|
|||||||
int(speed) if speed else 0,
|
int(speed) if speed else 0,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
def _set_outtmpl(self, ytdl_instance, outtmpl):
|
||||||
def _set_outtmpl(ytdl_instance, outtmpl):
|
|
||||||
try:
|
try:
|
||||||
ytdl_instance._parse_outtmpl
|
ytdl_instance._parse_outtmpl
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
|||||||
@@ -74,8 +74,7 @@ class _2chanThreadExtractor(Extractor):
|
|||||||
data["ext"] = "." + data["extension"]
|
data["ext"] = "." + data["extension"]
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@staticmethod
|
def _extract_post(self, post):
|
||||||
def _extract_post(post):
|
|
||||||
return text.extract_all(post, (
|
return text.extract_all(post, (
|
||||||
("post", 'class="csb">' , '<'),
|
("post", 'class="csb">' , '<'),
|
||||||
("name", 'class="cnm">' , '<'),
|
("name", 'class="cnm">' , '<'),
|
||||||
@@ -85,8 +84,7 @@ class _2chanThreadExtractor(Extractor):
|
|||||||
("com" , '>', '</blockquote>'),
|
("com" , '>', '</blockquote>'),
|
||||||
))[0]
|
))[0]
|
||||||
|
|
||||||
@staticmethod
|
def _extract_image(self, post, data):
|
||||||
def _extract_image(post, data):
|
|
||||||
text.extract_all(post, (
|
text.extract_all(post, (
|
||||||
(None , '_blank', ''),
|
(None , '_blank', ''),
|
||||||
("filename", '>', '<'),
|
("filename", '>', '<'),
|
||||||
|
|||||||
@@ -83,8 +83,7 @@ class _35photoExtractor(Extractor):
|
|||||||
info["num"] = 1
|
info["num"] = 1
|
||||||
yield info
|
yield info
|
||||||
|
|
||||||
@staticmethod
|
def _photo_ids(self, page):
|
||||||
def _photo_ids(page):
|
|
||||||
"""Extract unique photo IDs and return them as sorted list"""
|
"""Extract unique photo IDs and return them as sorted list"""
|
||||||
# searching for photo-id="..." doesn't always work (see unit tests)
|
# searching for photo-id="..." doesn't always work (see unit tests)
|
||||||
if not page:
|
if not page:
|
||||||
|
|||||||
@@ -58,8 +58,7 @@ class _4archiveThreadExtractor(Extractor):
|
|||||||
for post in page.split('class="postContainer')[1:]
|
for post in page.split('class="postContainer')[1:]
|
||||||
]
|
]
|
||||||
|
|
||||||
@staticmethod
|
def parse(self, post):
|
||||||
def parse(post):
|
|
||||||
extr = text.extract_from(post)
|
extr = text.extract_from(post)
|
||||||
data = {
|
data = {
|
||||||
"name": extr('class="name">', "</span>"),
|
"name": extr('class="name">', "</span>"),
|
||||||
|
|||||||
@@ -66,8 +66,7 @@ class _4chanarchivesThreadExtractor(Extractor):
|
|||||||
post["extension"] = post["url"].rpartition(".")[2]
|
post["extension"] = post["url"].rpartition(".")[2]
|
||||||
return post
|
return post
|
||||||
|
|
||||||
@staticmethod
|
def _extract_post(self, html):
|
||||||
def _extract_post(html):
|
|
||||||
extr = text.extract_from(html)
|
extr = text.extract_from(html)
|
||||||
return {
|
return {
|
||||||
"no" : text.parse_int(extr('', '"')),
|
"no" : text.parse_int(extr('', '"')),
|
||||||
@@ -77,8 +76,7 @@ class _4chanarchivesThreadExtractor(Extractor):
|
|||||||
html[html.find('<blockquote'):].partition(">")[2]),
|
html[html.find('<blockquote'):].partition(">")[2]),
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
def _extract_file(self, html, post):
|
||||||
def _extract_file(html, post):
|
|
||||||
extr = text.extract_from(html, html.index(">File: <"))
|
extr = text.extract_from(html, html.index(">File: <"))
|
||||||
post["url"] = extr('href="', '"')
|
post["url"] = extr('href="', '"')
|
||||||
post["filename"] = text.unquote(extr(">", "<").rpartition(".")[0])
|
post["filename"] = text.unquote(extr(">", "<").rpartition(".")[0])
|
||||||
|
|||||||
@@ -92,8 +92,7 @@ class _8musesAlbumExtractor(Extractor):
|
|||||||
album["updatedAt"], "%Y-%m-%dT%H:%M:%S.%fZ"),
|
album["updatedAt"], "%Y-%m-%dT%H:%M:%S.%fZ"),
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
def _unobfuscate(self, data):
|
||||||
def _unobfuscate(data):
|
|
||||||
return util.json_loads("".join([
|
return util.json_loads("".join([
|
||||||
chr(33 + (ord(c) + 14) % 94) if "!" <= c <= "~" else c
|
chr(33 + (ord(c) + 14) % 94) if "!" <= c <= "~" else c
|
||||||
for c in text.unescape(data.strip("\t\n\r !"))
|
for c in text.unescape(data.strip("\t\n\r !"))
|
||||||
|
|||||||
@@ -87,8 +87,7 @@ class ArtstationExtractor(Extractor):
|
|||||||
|
|
||||||
yield Message.Url, url, asset
|
yield Message.Url, url, asset
|
||||||
|
|
||||||
@staticmethod
|
def _image_fallback(self, lhs, rhs):
|
||||||
def _image_fallback(lhs, rhs):
|
|
||||||
yield lhs + "/large/" + rhs
|
yield lhs + "/large/" + rhs
|
||||||
yield lhs + "/medium/" + rhs
|
yield lhs + "/medium/" + rhs
|
||||||
yield lhs + "/small/" + rhs
|
yield lhs + "/small/" + rhs
|
||||||
@@ -172,8 +171,7 @@ class ArtstationExtractor(Extractor):
|
|||||||
url, method="POST", headers=headers, json={},
|
url, method="POST", headers=headers, json={},
|
||||||
).json()["public_csrf_token"]
|
).json()["public_csrf_token"]
|
||||||
|
|
||||||
@staticmethod
|
def _no_cache(self, url):
|
||||||
def _no_cache(url):
|
|
||||||
"""Cause a cache miss to prevent Cloudflare 'optimizations'
|
"""Cause a cache miss to prevent Cloudflare 'optimizations'
|
||||||
|
|
||||||
Cloudflare's 'Polish' optimization strips image metadata and may even
|
Cloudflare's 'Polish' optimization strips image metadata and may even
|
||||||
@@ -344,8 +342,7 @@ class ArtstationChallengeExtractor(ArtstationExtractor):
|
|||||||
text.nameext_from_url(url, update)
|
text.nameext_from_url(url, update)
|
||||||
yield Message.Url, self._no_cache(url), update
|
yield Message.Url, self._no_cache(url), update
|
||||||
|
|
||||||
@staticmethod
|
def _id_from_url(self, url):
|
||||||
def _id_from_url(url):
|
|
||||||
"""Get an image's submission ID from its URL"""
|
"""Get an image's submission ID from its URL"""
|
||||||
parts = url.split("/")
|
parts = url.split("/")
|
||||||
return text.parse_int("".join(parts[7:10]))
|
return text.parse_int("".join(parts[7:10]))
|
||||||
|
|||||||
@@ -60,8 +60,7 @@ class BbcGalleryExtractor(GalleryExtractor):
|
|||||||
))
|
))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@staticmethod
|
def _fallback_urls(self, src, max_width):
|
||||||
def _fallback_urls(src, max_width):
|
|
||||||
front, _, back = src.partition("/320x180_b/")
|
front, _, back = src.partition("/320x180_b/")
|
||||||
for width in (1920, 1600, 1280, 976):
|
for width in (1920, 1600, 1280, 976):
|
||||||
if width < max_width:
|
if width < max_width:
|
||||||
|
|||||||
@@ -59,8 +59,7 @@ class ComicvineTagExtractor(BooruExtractor):
|
|||||||
|
|
||||||
_file_url = operator.itemgetter("original")
|
_file_url = operator.itemgetter("original")
|
||||||
|
|
||||||
@staticmethod
|
def _prepare(self, post):
|
||||||
def _prepare(post):
|
|
||||||
post["date"] = text.parse_datetime(
|
post["date"] = text.parse_datetime(
|
||||||
post["dateCreated"], "%a, %b %d %Y")
|
post["dateCreated"], "%a, %b %d %Y")
|
||||||
post["tags"] = [tag["name"] for tag in post["tags"] if tag["name"]]
|
post["tags"] = [tag["name"] for tag in post["tags"] if tag["name"]]
|
||||||
|
|||||||
@@ -280,8 +280,7 @@ class DeviantartExtractor(Extractor):
|
|||||||
deviation["index_base36"],
|
deviation["index_base36"],
|
||||||
))
|
))
|
||||||
|
|
||||||
@staticmethod
|
def commit(self, deviation, target):
|
||||||
def commit(deviation, target):
|
|
||||||
url = target["src"]
|
url = target["src"]
|
||||||
name = target.get("filename") or url
|
name = target.get("filename") or url
|
||||||
target = target.copy()
|
target = target.copy()
|
||||||
@@ -680,8 +679,7 @@ x2="45.4107524%" y2="71.4898596%" id="app-root-3">\
|
|||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
@staticmethod
|
def _find_folder(self, folders, name, uuid):
|
||||||
def _find_folder(folders, name, uuid):
|
|
||||||
if uuid.isdecimal():
|
if uuid.isdecimal():
|
||||||
match = util.re(
|
match = util.re(
|
||||||
"(?i)" + name.replace("-", "[^a-z0-9]+") + "$").match
|
"(?i)" + name.replace("-", "[^a-z0-9]+") + "$").match
|
||||||
@@ -1889,8 +1887,7 @@ class DeviantartOAuthAPI():
|
|||||||
result.extend(self._pagination(endpoint, params, False, key=key))
|
result.extend(self._pagination(endpoint, params, False, key=key))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@staticmethod
|
def _shared_content(self, results):
|
||||||
def _shared_content(results):
|
|
||||||
"""Return an iterable of shared deviations in 'results'"""
|
"""Return an iterable of shared deviations in 'results'"""
|
||||||
for result in results:
|
for result in results:
|
||||||
for item in result.get("items") or ():
|
for item in result.get("items") or ():
|
||||||
|
|||||||
@@ -391,8 +391,7 @@ class DiscordAPI():
|
|||||||
return
|
return
|
||||||
offset += len(data)
|
offset += len(data)
|
||||||
|
|
||||||
@staticmethod
|
def _raise_invalid_token(self):
|
||||||
def _raise_invalid_token():
|
|
||||||
raise exception.AuthenticationError("""Invalid or missing token.
|
raise exception.AuthenticationError("""Invalid or missing token.
|
||||||
Please provide a valid token following these instructions:
|
Please provide a valid token following these instructions:
|
||||||
|
|
||||||
|
|||||||
@@ -534,8 +534,7 @@ class ExhentaiGalleryExtractor(ExhentaiExtractor):
|
|||||||
|
|
||||||
nl = data["_nl"]
|
nl = data["_nl"]
|
||||||
|
|
||||||
@staticmethod
|
def _parse_image_info(self, url):
|
||||||
def _parse_image_info(url):
|
|
||||||
for part in url.split("/")[4:]:
|
for part in url.split("/")[4:]:
|
||||||
try:
|
try:
|
||||||
_, size, width, height, _ = part.split("-")
|
_, size, width, height, _ = part.split("-")
|
||||||
@@ -552,8 +551,7 @@ class ExhentaiGalleryExtractor(ExhentaiExtractor):
|
|||||||
"height": text.parse_int(height),
|
"height": text.parse_int(height),
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
def _parse_original_info(self, info):
|
||||||
def _parse_original_info(info):
|
|
||||||
parts = info.lstrip().split(" ")
|
parts = info.lstrip().split(" ")
|
||||||
size = text.parse_bytes(parts[3] + parts[4][0])
|
size = text.parse_bytes(parts[3] + parts[4][0])
|
||||||
|
|
||||||
|
|||||||
@@ -37,15 +37,13 @@ class FacebookExtractor(Extractor):
|
|||||||
self.videos = self.config("videos", True)
|
self.videos = self.config("videos", True)
|
||||||
self.author_followups = self.config("author-followups", False)
|
self.author_followups = self.config("author-followups", False)
|
||||||
|
|
||||||
@staticmethod
|
def decode_all(self, txt):
|
||||||
def decode_all(txt):
|
|
||||||
return text.unescape(
|
return text.unescape(
|
||||||
txt.encode().decode("unicode_escape")
|
txt.encode().decode("unicode_escape")
|
||||||
.encode("utf_16", "surrogatepass").decode("utf_16")
|
.encode("utf_16", "surrogatepass").decode("utf_16")
|
||||||
).replace("\\/", "/")
|
).replace("\\/", "/")
|
||||||
|
|
||||||
@staticmethod
|
def parse_set_page(self, set_page):
|
||||||
def parse_set_page(set_page):
|
|
||||||
directory = {
|
directory = {
|
||||||
"set_id": text.extr(
|
"set_id": text.extr(
|
||||||
set_page, '"mediaSetToken":"', '"'
|
set_page, '"mediaSetToken":"', '"'
|
||||||
@@ -77,8 +75,7 @@ class FacebookExtractor(Extractor):
|
|||||||
|
|
||||||
return directory
|
return directory
|
||||||
|
|
||||||
@staticmethod
|
def parse_photo_page(self, photo_page):
|
||||||
def parse_photo_page(photo_page):
|
|
||||||
photo = {
|
photo = {
|
||||||
"id": text.extr(
|
"id": text.extr(
|
||||||
photo_page, '"__isNode":"Photo","id":"', '"'
|
photo_page, '"__isNode":"Photo","id":"', '"'
|
||||||
@@ -133,8 +130,7 @@ class FacebookExtractor(Extractor):
|
|||||||
|
|
||||||
return photo
|
return photo
|
||||||
|
|
||||||
@staticmethod
|
def parse_post_page(self, post_page):
|
||||||
def parse_post_page(post_page):
|
|
||||||
first_photo_url = text.extr(
|
first_photo_url = text.extr(
|
||||||
text.extr(
|
text.extr(
|
||||||
post_page, '"__isMedia":"Photo"', '"target_group"'
|
post_page, '"__isMedia":"Photo"', '"target_group"'
|
||||||
@@ -148,8 +144,7 @@ class FacebookExtractor(Extractor):
|
|||||||
|
|
||||||
return post
|
return post
|
||||||
|
|
||||||
@staticmethod
|
def parse_video_page(self, video_page):
|
||||||
def parse_video_page(video_page):
|
|
||||||
video = {
|
video = {
|
||||||
"id": text.extr(
|
"id": text.extr(
|
||||||
video_page, '\\"video_id\\":\\"', '\\"'
|
video_page, '\\"video_id\\":\\"', '\\"'
|
||||||
@@ -410,8 +405,7 @@ class FacebookProfileExtractor(FacebookExtractor):
|
|||||||
)
|
)
|
||||||
example = "https://www.facebook.com/USERNAME"
|
example = "https://www.facebook.com/USERNAME"
|
||||||
|
|
||||||
@staticmethod
|
def get_profile_photos_set_id(self, profile_photos_page):
|
||||||
def get_profile_photos_set_id(profile_photos_page):
|
|
||||||
set_ids_raw = text.extr(
|
set_ids_raw = text.extr(
|
||||||
profile_photos_page, '"pageItems"', '"page_info"'
|
profile_photos_page, '"pageItems"', '"page_info"'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -585,8 +585,7 @@ class FlickrAPI(oauth.OAuth1API):
|
|||||||
if "license" in photo:
|
if "license" in photo:
|
||||||
photo["license_name"] = self.LICENSES.get(photo["license"])
|
photo["license_name"] = self.LICENSES.get(photo["license"])
|
||||||
|
|
||||||
@staticmethod
|
def _clean_info(self, info):
|
||||||
def _clean_info(info):
|
|
||||||
info["title"] = info["title"]["_content"]
|
info["title"] = info["title"]["_content"]
|
||||||
info["description"] = info["description"]["_content"]
|
info["description"] = info["description"]["_content"]
|
||||||
return info
|
return info
|
||||||
|
|||||||
@@ -74,8 +74,7 @@ class FoolfuukaExtractor(BaseExtractor):
|
|||||||
|
|
||||||
return url
|
return url
|
||||||
|
|
||||||
@staticmethod
|
def _remote_direct(self, media):
|
||||||
def _remote_direct(media):
|
|
||||||
return media["remote_media_link"]
|
return media["remote_media_link"]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ class FoolslideExtractor(BaseExtractor):
|
|||||||
return BaseExtractor.request(
|
return BaseExtractor.request(
|
||||||
self, url, encoding="utf-8", method="POST", data={"adult": "true"})
|
self, url, encoding="utf-8", method="POST", data={"adult": "true"})
|
||||||
|
|
||||||
@staticmethod
|
def parse_chapter_url(self, url, data):
|
||||||
def parse_chapter_url(url, data):
|
|
||||||
info = url.partition("/read/")[2].rstrip("/").split("/")
|
info = url.partition("/read/")[2].rstrip("/").split("/")
|
||||||
lang = info[1].partition("-")[0]
|
lang = info[1].partition("-")[0]
|
||||||
data["lang"] = lang
|
data["lang"] = lang
|
||||||
|
|||||||
@@ -152,8 +152,7 @@ class FuraffinityExtractor(Extractor):
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@staticmethod
|
def _process_description(self, description):
|
||||||
def _process_description(description):
|
|
||||||
return text.unescape(text.remove_html(description, "", ""))
|
return text.unescape(text.remove_html(description, "", ""))
|
||||||
|
|
||||||
def _pagination(self, path, folder=None):
|
def _pagination(self, path, folder=None):
|
||||||
|
|||||||
@@ -89,8 +89,7 @@ class GelbooruV02Extractor(booru.BooruExtractor):
|
|||||||
return
|
return
|
||||||
params["pid"] += self.per_page
|
params["pid"] += self.per_page
|
||||||
|
|
||||||
@staticmethod
|
def _prepare(self, post):
|
||||||
def _prepare(post):
|
|
||||||
post["tags"] = post["tags"].strip()
|
post["tags"] = post["tags"].strip()
|
||||||
post["date"] = text.parse_datetime(
|
post["date"] = text.parse_datetime(
|
||||||
post["created_at"], "%a %b %d %H:%M:%S %z %Y")
|
post["created_at"], "%a %b %d %H:%M:%S %z %Y")
|
||||||
|
|||||||
@@ -49,8 +49,7 @@ class HentaihereChapterExtractor(HentaihereBase, ChapterExtractor):
|
|||||||
"language": "English",
|
"language": "English",
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
def images(self, page):
|
||||||
def images(page):
|
|
||||||
images = text.extr(page, "var rff_imageList = ", ";")
|
images = text.extr(page, "var rff_imageList = ", ";")
|
||||||
return [
|
return [
|
||||||
("https://hentaicdn.com/hentai" + part, None)
|
("https://hentaicdn.com/hentai" + part, None)
|
||||||
|
|||||||
@@ -78,8 +78,7 @@ class HentainexusGalleryExtractor(GalleryExtractor):
|
|||||||
pass
|
pass
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@staticmethod
|
def _decode(self, data):
|
||||||
def _decode(data):
|
|
||||||
# https://hentainexus.com/static/js/reader.min.js?r=22
|
# https://hentainexus.com/static/js/reader.min.js?r=22
|
||||||
hostname = "hentainexus.com"
|
hostname = "hentainexus.com"
|
||||||
primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53)
|
primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53)
|
||||||
@@ -118,8 +117,7 @@ class HentainexusGalleryExtractor(GalleryExtractor):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@staticmethod
|
def _join_title(self, data):
|
||||||
def _join_title(data):
|
|
||||||
event = data['event']
|
event = data['event']
|
||||||
artist = data['artist']
|
artist = data['artist']
|
||||||
circle = data['circle']
|
circle = data['circle']
|
||||||
|
|||||||
@@ -63,8 +63,7 @@ class ImagebamGalleryExtractor(ImagebamExtractor):
|
|||||||
image.update(data)
|
image.update(data)
|
||||||
yield Message.Url, image["url"], image
|
yield Message.Url, image["url"], image
|
||||||
|
|
||||||
@staticmethod
|
def metadata(self, page):
|
||||||
def metadata(page):
|
|
||||||
return {"title": text.unescape(text.extr(
|
return {"title": text.unescape(text.extr(
|
||||||
page, 'id="gallery-name">', '<').strip())}
|
page, 'id="gallery-name">', '<').strip())}
|
||||||
|
|
||||||
|
|||||||
@@ -30,18 +30,15 @@ class ImgboxExtractor(Extractor):
|
|||||||
text.nameext_from_url(imgdata["filename"], imgdata)
|
text.nameext_from_url(imgdata["filename"], imgdata)
|
||||||
yield Message.Url, self.get_image_url(imgpage), imgdata
|
yield Message.Url, self.get_image_url(imgpage), imgdata
|
||||||
|
|
||||||
@staticmethod
|
def get_job_metadata(self):
|
||||||
def get_job_metadata():
|
|
||||||
"""Collect metadata for extractor-job"""
|
"""Collect metadata for extractor-job"""
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
@staticmethod
|
def get_image_keys(self):
|
||||||
def get_image_keys():
|
|
||||||
"""Return an iterable containing all image-keys"""
|
"""Return an iterable containing all image-keys"""
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@staticmethod
|
def get_image_metadata(self, page):
|
||||||
def get_image_metadata(page):
|
|
||||||
"""Collect metadata for a downloadable file"""
|
"""Collect metadata for a downloadable file"""
|
||||||
return text.extract_all(page, (
|
return text.extract_all(page, (
|
||||||
("num" , '</a> ', ' of '),
|
("num" , '</a> ', ' of '),
|
||||||
@@ -49,8 +46,7 @@ class ImgboxExtractor(Extractor):
|
|||||||
("filename" , ' title="', '"'),
|
("filename" , ' title="', '"'),
|
||||||
))[0]
|
))[0]
|
||||||
|
|
||||||
@staticmethod
|
def get_image_url(self, page):
|
||||||
def get_image_url(page):
|
|
||||||
"""Extract download-url"""
|
"""Extract download-url"""
|
||||||
return text.extr(page, 'property="og:image" content="', '"')
|
return text.extr(page, 'property="og:image" content="', '"')
|
||||||
|
|
||||||
@@ -102,8 +98,7 @@ class ImgboxImageExtractor(ImgboxExtractor):
|
|||||||
def get_image_keys(self):
|
def get_image_keys(self):
|
||||||
return (self.image_key,)
|
return (self.image_key,)
|
||||||
|
|
||||||
@staticmethod
|
def get_image_metadata(self, page):
|
||||||
def get_image_metadata(page):
|
|
||||||
data = ImgboxExtractor.get_image_metadata(page)
|
data = ImgboxExtractor.get_image_metadata(page)
|
||||||
if not data["filename"]:
|
if not data["filename"]:
|
||||||
raise exception.NotFoundError("image")
|
raise exception.NotFoundError("image")
|
||||||
|
|||||||
@@ -357,8 +357,7 @@ class InstagramExtractor(Extractor):
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@staticmethod
|
def _extract_tagged_users(self, src, dest):
|
||||||
def _extract_tagged_users(src, dest):
|
|
||||||
dest["tagged_users"] = tagged_users = []
|
dest["tagged_users"] = tagged_users = []
|
||||||
|
|
||||||
edges = src.get("edge_media_to_tagged_user")
|
edges = src.get("edge_media_to_tagged_user")
|
||||||
@@ -979,8 +978,7 @@ class InstagramGraphqlAPI():
|
|||||||
self.user_by_id = api.user_by_id
|
self.user_by_id = api.user_by_id
|
||||||
self.user_id = api.user_id
|
self.user_id = api.user_id
|
||||||
|
|
||||||
@staticmethod
|
def _unsupported(self, _=None):
|
||||||
def _unsupported(_=None):
|
|
||||||
raise exception.StopExtraction("Unsupported with GraphQL API")
|
raise exception.StopExtraction("Unsupported with GraphQL API")
|
||||||
|
|
||||||
def highlights_tray(self, user_id):
|
def highlights_tray(self, user_id):
|
||||||
|
|||||||
@@ -121,22 +121,18 @@ class KeenspotComicExtractor(Extractor):
|
|||||||
pos = page.index(self._needle) + len(self._needle)
|
pos = page.index(self._needle) + len(self._needle)
|
||||||
return text.extract(page, 'href="', '"', pos)[0]
|
return text.extract(page, 'href="', '"', pos)[0]
|
||||||
|
|
||||||
@staticmethod
|
def _next_link(self, page):
|
||||||
def _next_link(page):
|
|
||||||
return text.extr(page, '<link rel="next" href="', '"')
|
return text.extr(page, '<link rel="next" href="', '"')
|
||||||
|
|
||||||
@staticmethod
|
def _next_id(self, page):
|
||||||
def _next_id(page):
|
|
||||||
pos = page.find('id="next_')
|
pos = page.find('id="next_')
|
||||||
return text.rextr(page, 'href="', '"', pos) if pos >= 0 else None
|
return text.rextr(page, 'href="', '"', pos) if pos >= 0 else None
|
||||||
|
|
||||||
@staticmethod
|
def _next_lastblood(self, page):
|
||||||
def _next_lastblood(page):
|
|
||||||
pos = page.index("link rel='next'")
|
pos = page.index("link rel='next'")
|
||||||
return text.extract(page, "href='", "'", pos)[0]
|
return text.extract(page, "href='", "'", pos)[0]
|
||||||
|
|
||||||
@staticmethod
|
def _next_brawl(self, page):
|
||||||
def _next_brawl(page):
|
|
||||||
pos = page.index("comic-nav-next")
|
pos = page.index("comic-nav-next")
|
||||||
url = text.rextr(page, 'href="', '"', pos)
|
url = text.rextr(page, 'href="', '"', pos)
|
||||||
return None if "?random" in url else url
|
return None if "?random" in url else url
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ class KomikcastBase():
|
|||||||
category = "komikcast"
|
category = "komikcast"
|
||||||
root = "https://komikcast02.com"
|
root = "https://komikcast02.com"
|
||||||
|
|
||||||
@staticmethod
|
def parse_chapter_string(self, chapter_string, data=None):
|
||||||
def parse_chapter_string(chapter_string, data=None):
|
|
||||||
"""Parse 'chapter_string' value and add its info to 'data'"""
|
"""Parse 'chapter_string' value and add its info to 'data'"""
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
@@ -52,8 +51,7 @@ class KomikcastChapterExtractor(KomikcastBase, ChapterExtractor):
|
|||||||
info = text.extr(page, "<title>", " - Komikcast<")
|
info = text.extr(page, "<title>", " - Komikcast<")
|
||||||
return self.parse_chapter_string(info)
|
return self.parse_chapter_string(info)
|
||||||
|
|
||||||
@staticmethod
|
def images(self, page):
|
||||||
def images(page):
|
|
||||||
readerarea = text.extr(
|
readerarea = text.extr(
|
||||||
page, '<div class="main-reading-area', '</div')
|
page, '<div class="main-reading-area', '</div')
|
||||||
pattern = util.re(r"<img[^>]* src=[\"']([^\"']+)")
|
pattern = util.re(r"<img[^>]* src=[\"']([^\"']+)")
|
||||||
@@ -82,8 +80,7 @@ class KomikcastMangaExtractor(KomikcastBase, MangaExtractor):
|
|||||||
results.append((url, data.copy()))
|
results.append((url, data.copy()))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@staticmethod
|
def metadata(self, page):
|
||||||
def metadata(page):
|
|
||||||
"""Return a dict with general metadata"""
|
"""Return a dict with general metadata"""
|
||||||
manga , pos = text.extract(page, "<title>" , " - Komikcast<")
|
manga , pos = text.extract(page, "<title>" , " - Komikcast<")
|
||||||
genres, pos = text.extract(
|
genres, pos = text.extract(
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ class MangareadBase():
|
|||||||
category = "mangaread"
|
category = "mangaread"
|
||||||
root = "https://www.mangaread.org"
|
root = "https://www.mangaread.org"
|
||||||
|
|
||||||
@staticmethod
|
def parse_chapter_string(self, chapter_string, data):
|
||||||
def parse_chapter_string(chapter_string, data):
|
|
||||||
match = util.re(
|
match = util.re(
|
||||||
r"(?:(.+)\s*-\s*)?[Cc]hapter\s*(\d+)(\.\d+)?(?:\s*-\s*(.+))?"
|
r"(?:(.+)\s*-\s*)?[Cc]hapter\s*(\d+)(\.\d+)?(?:\s*-\s*(.+))?"
|
||||||
).match(text.unescape(chapter_string).strip())
|
).match(text.unescape(chapter_string).strip())
|
||||||
|
|||||||
@@ -53,8 +53,7 @@ class MangoxoExtractor(Extractor):
|
|||||||
raise exception.AuthenticationError(data.get("msg"))
|
raise exception.AuthenticationError(data.get("msg"))
|
||||||
return {"SESSION": self.cookies.get("SESSION")}
|
return {"SESSION": self.cookies.get("SESSION")}
|
||||||
|
|
||||||
@staticmethod
|
def _sign_by_md5(self, username, password, token):
|
||||||
def _sign_by_md5(username, password, token):
|
|
||||||
# https://dns.mangoxo.com/libs/plugins/phoenix-ui/js/phoenix-ui.js
|
# https://dns.mangoxo.com/libs/plugins/phoenix-ui/js/phoenix-ui.js
|
||||||
params = [
|
params = [
|
||||||
("username" , username),
|
("username" , username),
|
||||||
@@ -68,8 +67,7 @@ class MangoxoExtractor(Extractor):
|
|||||||
params.append(("sign", sign.upper()))
|
params.append(("sign", sign.upper()))
|
||||||
return params
|
return params
|
||||||
|
|
||||||
@staticmethod
|
def _total_pages(self, page):
|
||||||
def _total_pages(page):
|
|
||||||
return text.parse_int(text.extract(page, "total :", ",")[0])
|
return text.parse_int(text.extract(page, "total :", ",")[0])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ class MoebooruExtractor(BooruExtractor):
|
|||||||
filename_fmt = "{category}_{id}_{md5}.{extension}"
|
filename_fmt = "{category}_{id}_{md5}.{extension}"
|
||||||
page_start = 1
|
page_start = 1
|
||||||
|
|
||||||
@staticmethod
|
def _prepare(self, post):
|
||||||
def _prepare(post):
|
|
||||||
post["date"] = text.parse_timestamp(post["created_at"])
|
post["date"] = text.parse_timestamp(post["created_at"])
|
||||||
|
|
||||||
def _html(self, post):
|
def _html(self, post):
|
||||||
|
|||||||
@@ -53,8 +53,7 @@ class MyportfolioGalleryExtractor(Extractor):
|
|||||||
for data["num"], url in enumerate(imgs, 1):
|
for data["num"], url in enumerate(imgs, 1):
|
||||||
yield Message.Url, url, text.nameext_from_url(url, data)
|
yield Message.Url, url, text.nameext_from_url(url, data)
|
||||||
|
|
||||||
@staticmethod
|
def metadata(self, page):
|
||||||
def metadata(page):
|
|
||||||
"""Collect general image metadata"""
|
"""Collect general image metadata"""
|
||||||
# og:title contains data as "<user> - <title>", but both
|
# og:title contains data as "<user> - <title>", but both
|
||||||
# <user> and <title> can contain a "-" as well, so we get the title
|
# <user> and <title> can contain a "-" as well, so we get the title
|
||||||
@@ -81,8 +80,7 @@ class MyportfolioGalleryExtractor(Extractor):
|
|||||||
"description": text.unescape(descr),
|
"description": text.unescape(descr),
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
def images(self, page):
|
||||||
def images(page):
|
|
||||||
"""Extract and return a list of all image-urls"""
|
"""Extract and return a list of all image-urls"""
|
||||||
return (
|
return (
|
||||||
list(text.extract_iter(page, 'js-lightbox" data-src="', '"')) or
|
list(text.extract_iter(page, 'js-lightbox" data-src="', '"')) or
|
||||||
|
|||||||
@@ -54,8 +54,7 @@ class NaverwebtoonEpisodeExtractor(NaverwebtoonBase, GalleryExtractor):
|
|||||||
extr('"painters":[', ']'), '"name":"', '"')]
|
extr('"painters":[', ']'), '"name":"', '"')]
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
def images(self, page):
|
||||||
def images(page):
|
|
||||||
view_area = text.extr(page, 'id="comic_view_area"', '</div>')
|
view_area = text.extr(page, 'id="comic_view_area"', '</div>')
|
||||||
return [
|
return [
|
||||||
(url, None)
|
(url, None)
|
||||||
|
|||||||
@@ -260,8 +260,7 @@ class NewgroundsExtractor(Extractor):
|
|||||||
else:
|
else:
|
||||||
yield {"image": url}
|
yield {"image": url}
|
||||||
|
|
||||||
@staticmethod
|
def _extract_audio_data(self, extr, url):
|
||||||
def _extract_audio_data(extr, url):
|
|
||||||
index = url.split("/")[5]
|
index = url.split("/")[5]
|
||||||
return {
|
return {
|
||||||
"title" : text.unescape(extr('"og:title" content="', '"')),
|
"title" : text.unescape(extr('"og:title" content="', '"')),
|
||||||
@@ -529,8 +528,7 @@ class NewgroundsFollowingExtractor(NewgroundsFavoriteExtractor):
|
|||||||
for url in self._pagination_favorites(kind, pnum):
|
for url in self._pagination_favorites(kind, pnum):
|
||||||
yield Message.Queue, url, data
|
yield Message.Queue, url, data
|
||||||
|
|
||||||
@staticmethod
|
def _extract_favorites(self, page):
|
||||||
def _extract_favorites(page):
|
|
||||||
return [
|
return [
|
||||||
text.ensure_http_scheme(user.rpartition('"')[2])
|
text.ensure_http_scheme(user.rpartition('"')[2])
|
||||||
for user in text.extract_iter(page, 'class="item-user', '"><img')
|
for user in text.extract_iter(page, 'class="item-user', '"><img')
|
||||||
|
|||||||
@@ -73,8 +73,7 @@ class NijieExtractor(AsynchronousMixin, BaseExtractor):
|
|||||||
def image_ids(self):
|
def image_ids(self):
|
||||||
"""Collect all relevant image-ids"""
|
"""Collect all relevant image-ids"""
|
||||||
|
|
||||||
@staticmethod
|
def _extract_data(self, page):
|
||||||
def _extract_data(page):
|
|
||||||
"""Extract image metadata from 'page'"""
|
"""Extract image metadata from 'page'"""
|
||||||
extr = text.extract_from(page)
|
extr = text.extract_from(page)
|
||||||
keywords = text.unescape(extr(
|
keywords = text.unescape(extr(
|
||||||
@@ -90,8 +89,7 @@ class NijieExtractor(AsynchronousMixin, BaseExtractor):
|
|||||||
"tags" : keywords[2:-1],
|
"tags" : keywords[2:-1],
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
def _extract_data_horne(self, page):
|
||||||
def _extract_data_horne(page):
|
|
||||||
"""Extract image metadata from 'page'"""
|
"""Extract image metadata from 'page'"""
|
||||||
extr = text.extract_from(page)
|
extr = text.extract_from(page)
|
||||||
keywords = text.unescape(extr(
|
keywords = text.unescape(extr(
|
||||||
@@ -124,8 +122,7 @@ class NijieExtractor(AsynchronousMixin, BaseExtractor):
|
|||||||
# do NOT use text.extr() here, as it doesn't support a pos argument
|
# do NOT use text.extr() here, as it doesn't support a pos argument
|
||||||
return (text.extract(page, 'itemprop="image" src="', '"', pos)[0],)
|
return (text.extract(page, 'itemprop="image" src="', '"', pos)[0],)
|
||||||
|
|
||||||
@staticmethod
|
def _extract_user_name(self, page):
|
||||||
def _extract_user_name(page):
|
|
||||||
return text.unescape(text.extr(page, "<br />", "<"))
|
return text.unescape(text.extr(page, "<br />", "<"))
|
||||||
|
|
||||||
def login(self):
|
def login(self):
|
||||||
@@ -248,8 +245,7 @@ class NijieNuitaExtractor(NijieExtractor):
|
|||||||
data["user_name"] = self.user_name
|
data["user_name"] = self.user_name
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@staticmethod
|
def _extract_user_name(self, page):
|
||||||
def _extract_user_name(page):
|
|
||||||
return text.unescape(text.extr(page, "<title>", "さんの抜いた"))
|
return text.unescape(text.extr(page, "<title>", "さんの抜いた"))
|
||||||
|
|
||||||
|
|
||||||
@@ -262,8 +258,7 @@ class NijieFeedExtractor(NijieExtractor):
|
|||||||
def image_ids(self):
|
def image_ids(self):
|
||||||
return self._pagination("like_user_view")
|
return self._pagination("like_user_view")
|
||||||
|
|
||||||
@staticmethod
|
def _extract_user_name(self, page):
|
||||||
def _extract_user_name(page):
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -98,8 +98,7 @@ class NozomiExtractor(Extractor):
|
|||||||
def metadata(self):
|
def metadata(self):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
@staticmethod
|
def _list(self, src):
|
||||||
def _list(src):
|
|
||||||
return [x["tagname_display"] for x in src] if src else ()
|
return [x["tagname_display"] for x in src] if src else ()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -70,13 +70,11 @@ class NsfwalbumAlbumExtractor(GalleryExtractor):
|
|||||||
self.root, image_id, spirit),),
|
self.root, image_id, spirit),),
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
def _validate_response(self, response):
|
||||||
def _validate_response(response):
|
|
||||||
return not response.url.endswith(
|
return not response.url.endswith(
|
||||||
("/no_image.jpg", "/placeholder.png", "/error.jpg"))
|
("/no_image.jpg", "/placeholder.png", "/error.jpg"))
|
||||||
|
|
||||||
@staticmethod
|
def _annihilate(self, value, base=6):
|
||||||
def _annihilate(value, base=6):
|
|
||||||
return "".join(
|
return "".join(
|
||||||
chr(ord(char) ^ base)
|
chr(ord(char) ^ base)
|
||||||
for char in value
|
for char in value
|
||||||
|
|||||||
@@ -108,8 +108,7 @@ class PahealTagExtractor(PahealExtractor):
|
|||||||
return
|
return
|
||||||
pnum += 1
|
pnum += 1
|
||||||
|
|
||||||
@staticmethod
|
def _extract_data(self, post):
|
||||||
def _extract_data(post):
|
|
||||||
pid , pos = text.extract(post, "", "'")
|
pid , pos = text.extract(post, "", "'")
|
||||||
data, pos = text.extract(post, "title='", "'", pos)
|
data, pos = text.extract(post, "title='", "'", pos)
|
||||||
md5 , pos = text.extract(post, "/_thumbs/", "/", pos)
|
md5 , pos = text.extract(post, "/_thumbs/", "/", pos)
|
||||||
|
|||||||
@@ -188,16 +188,14 @@ class PatreonExtractor(Extractor):
|
|||||||
|
|
||||||
return attr
|
return attr
|
||||||
|
|
||||||
@staticmethod
|
def _transform(self, included):
|
||||||
def _transform(included):
|
|
||||||
"""Transform 'included' into an easier to handle format"""
|
"""Transform 'included' into an easier to handle format"""
|
||||||
result = collections.defaultdict(dict)
|
result = collections.defaultdict(dict)
|
||||||
for inc in included:
|
for inc in included:
|
||||||
result[inc["type"]][inc["id"]] = inc["attributes"]
|
result[inc["type"]][inc["id"]] = inc["attributes"]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@staticmethod
|
def _files(self, post, included, key):
|
||||||
def _files(post, included, key):
|
|
||||||
"""Build a list of files"""
|
"""Build a list of files"""
|
||||||
files = post["relationships"].get(key)
|
files = post["relationships"].get(key)
|
||||||
if files and files.get("data"):
|
if files and files.get("data"):
|
||||||
@@ -226,8 +224,7 @@ class PatreonExtractor(Extractor):
|
|||||||
cd = response.headers.get("Content-Disposition")
|
cd = response.headers.get("Content-Disposition")
|
||||||
return text.extr(cd, 'filename="', '"')
|
return text.extr(cd, 'filename="', '"')
|
||||||
|
|
||||||
@staticmethod
|
def _filehash(self, url):
|
||||||
def _filehash(url):
|
|
||||||
"""Extract MD5 hash from a download URL"""
|
"""Extract MD5 hash from a download URL"""
|
||||||
parts = url.partition("?")[0].split("/")
|
parts = url.partition("?")[0].split("/")
|
||||||
parts.reverse()
|
parts.reverse()
|
||||||
@@ -237,8 +234,7 @@ class PatreonExtractor(Extractor):
|
|||||||
return part
|
return part
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@staticmethod
|
def _build_url(self, endpoint, query):
|
||||||
def _build_url(endpoint, query):
|
|
||||||
return (
|
return (
|
||||||
"https://www.patreon.com/api/" + endpoint +
|
"https://www.patreon.com/api/" + endpoint +
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,7 @@ class PhilomenaExtractor(BooruExtractor):
|
|||||||
return url.rpartition(".")[0] + ".svg"
|
return url.rpartition(".")[0] + ".svg"
|
||||||
return url
|
return url
|
||||||
|
|
||||||
@staticmethod
|
def _prepare(self, post):
|
||||||
def _prepare(post):
|
|
||||||
post["date"] = text.parse_datetime(
|
post["date"] = text.parse_datetime(
|
||||||
post["created_at"][:19], "%Y-%m-%dT%H:%M:%S")
|
post["created_at"][:19], "%Y-%m-%dT%H:%M:%S")
|
||||||
|
|
||||||
|
|||||||
@@ -336,8 +336,7 @@ class PixivExtractor(Extractor):
|
|||||||
if fmt in urls:
|
if fmt in urls:
|
||||||
yield urls[fmt]
|
yield urls[fmt]
|
||||||
|
|
||||||
@staticmethod
|
def _date_from_url(self, url, offset=timedelta(hours=9)):
|
||||||
def _date_from_url(url, offset=timedelta(hours=9)):
|
|
||||||
try:
|
try:
|
||||||
_, _, _, _, _, y, m, d, H, M, S, _ = url.split("/")
|
_, _, _, _, _, y, m, d, H, M, S, _ = url.split("/")
|
||||||
return datetime(
|
return datetime(
|
||||||
@@ -345,8 +344,7 @@ class PixivExtractor(Extractor):
|
|||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@staticmethod
|
def _make_work(self, kind, url, user):
|
||||||
def _make_work(kind, url, user):
|
|
||||||
p = url.split("/")
|
p = url.split("/")
|
||||||
return {
|
return {
|
||||||
"create_date" : "{}-{}-{}T{}:{}:{}+09:00".format(
|
"create_date" : "{}-{}-{}T{}:{}:{}+09:00".format(
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ class PlurkExtractor(Extractor):
|
|||||||
def plurks(self):
|
def plurks(self):
|
||||||
"""Return an iterable with all relevant 'plurk' objects"""
|
"""Return an iterable with all relevant 'plurk' objects"""
|
||||||
|
|
||||||
@staticmethod
|
def _urls(self, obj):
|
||||||
def _urls(obj):
|
|
||||||
"""Extract URLs from a 'plurk' object"""
|
"""Extract URLs from a 'plurk' object"""
|
||||||
return text.extract_iter(obj["content"], ' href="', '"')
|
return text.extract_iter(obj["content"], ' href="', '"')
|
||||||
|
|
||||||
@@ -59,8 +58,7 @@ class PlurkExtractor(Extractor):
|
|||||||
del data["count"]
|
del data["count"]
|
||||||
data["from_response_id"] = info["responses"][-1]["id"] + 1
|
data["from_response_id"] = info["responses"][-1]["id"] + 1
|
||||||
|
|
||||||
@staticmethod
|
def _load(self, data):
|
||||||
def _load(data):
|
|
||||||
if not data:
|
if not data:
|
||||||
raise exception.NotFoundError("user")
|
raise exception.NotFoundError("user")
|
||||||
return util.json_loads(
|
return util.json_loads(
|
||||||
|
|||||||
@@ -573,8 +573,7 @@ class RedditAPI():
|
|||||||
sid = self.extractor.config(key)
|
sid = self.extractor.config(key)
|
||||||
return self._decode(sid.rpartition("_")[2].lower()) if sid else default
|
return self._decode(sid.rpartition("_")[2].lower()) if sid else default
|
||||||
|
|
||||||
@staticmethod
|
def _decode(self, sid):
|
||||||
def _decode(sid):
|
|
||||||
return util.bdecode(sid, "0123456789abcdefghijklmnopqrstuvwxyz")
|
return util.bdecode(sid, "0123456789abcdefghijklmnopqrstuvwxyz")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -63,20 +63,17 @@ class SankakucomplexArticleExtractor(SankakucomplexExtractor):
|
|||||||
file.update(data)
|
file.update(data)
|
||||||
yield Message.Url, url, file
|
yield Message.Url, url, file
|
||||||
|
|
||||||
@staticmethod
|
def _extract_images(self, content):
|
||||||
def _extract_images(content):
|
|
||||||
orig_sub = util.re(r"-\d+x\d+\.").sub
|
orig_sub = util.re(r"-\d+x\d+\.").sub
|
||||||
return [
|
return [
|
||||||
orig_sub(".", url) for url in
|
orig_sub(".", url) for url in
|
||||||
util.unique(text.extract_iter(content, 'data-lazy-src="', '"'))
|
util.unique(text.extract_iter(content, 'data-lazy-src="', '"'))
|
||||||
]
|
]
|
||||||
|
|
||||||
@staticmethod
|
def _extract_videos(self, content):
|
||||||
def _extract_videos(content):
|
|
||||||
return util.re(r"<source [^>]*src=[\"']([^\"']+)").findall(content)
|
return util.re(r"<source [^>]*src=[\"']([^\"']+)").findall(content)
|
||||||
|
|
||||||
@staticmethod
|
def _extract_embeds(self, content):
|
||||||
def _extract_embeds(content):
|
|
||||||
return [
|
return [
|
||||||
"ytdl:" + url for url in
|
"ytdl:" + url for url in
|
||||||
util.re(r"<iframe [^>]*src=[\"']([^\"']+)").findall(content)
|
util.re(r"<iframe [^>]*src=[\"']([^\"']+)").findall(content)
|
||||||
|
|||||||
@@ -234,14 +234,12 @@ class SmugmugAPI(oauth.OAuth1API):
|
|||||||
return
|
return
|
||||||
params["start"] += params["count"]
|
params["start"] += params["count"]
|
||||||
|
|
||||||
@staticmethod
|
def _extend(self, endpoint, expands):
|
||||||
def _extend(endpoint, expands):
|
|
||||||
if expands:
|
if expands:
|
||||||
endpoint += "?_expand=" + expands
|
endpoint += "?_expand=" + expands
|
||||||
return endpoint
|
return endpoint
|
||||||
|
|
||||||
@staticmethod
|
def _apply_expansions(self, data, expands):
|
||||||
def _apply_expansions(data, expands):
|
|
||||||
|
|
||||||
def unwrap(response):
|
def unwrap(response):
|
||||||
locator = response["Locator"]
|
locator = response["Locator"]
|
||||||
|
|||||||
@@ -58,8 +58,7 @@ class SzurubooruExtractor(booru.BooruExtractor):
|
|||||||
url = self.root + "/" + url
|
url = self.root + "/" + url
|
||||||
return url
|
return url
|
||||||
|
|
||||||
@staticmethod
|
def _prepare(self, post):
|
||||||
def _prepare(post):
|
|
||||||
post["date"] = text.parse_datetime(
|
post["date"] = text.parse_datetime(
|
||||||
post["creationTime"], "%Y-%m-%dT%H:%M:%S.%fZ")
|
post["creationTime"], "%Y-%m-%dT%H:%M:%S.%fZ")
|
||||||
|
|
||||||
|
|||||||
@@ -158,8 +158,7 @@ class TsuminoSearchExtractor(TsuminoBase, Extractor):
|
|||||||
raise exception.StopExtraction(
|
raise exception.StopExtraction(
|
||||||
"Invalid search query '%s' (%s)", query, exc)
|
"Invalid search query '%s' (%s)", query, exc)
|
||||||
|
|
||||||
@staticmethod
|
def _parse_simple(self, query):
|
||||||
def _parse_simple(query):
|
|
||||||
"""Parse search query with format '?<key>=value>'"""
|
"""Parse search query with format '?<key>=value>'"""
|
||||||
key, _, value = query.partition("=")
|
key, _, value = query.partition("=")
|
||||||
tag_types = {
|
tag_types = {
|
||||||
@@ -179,8 +178,7 @@ class TsuminoSearchExtractor(TsuminoBase, Extractor):
|
|||||||
"Tags[0][Exclude]": "false",
|
"Tags[0][Exclude]": "false",
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
def _parse_jsurl(self, data):
|
||||||
def _parse_jsurl(data):
|
|
||||||
"""Parse search query in JSURL format
|
"""Parse search query in JSURL format
|
||||||
|
|
||||||
Nested lists and dicts are handled in a special way to deal
|
Nested lists and dicts are handled in a special way to deal
|
||||||
|
|||||||
@@ -198,14 +198,12 @@ class TumblrExtractor(Extractor):
|
|||||||
"', '".join(sorted(invalid)))
|
"', '".join(sorted(invalid)))
|
||||||
return types
|
return types
|
||||||
|
|
||||||
@staticmethod
|
def _prepare(self, url, post):
|
||||||
def _prepare(url, post):
|
|
||||||
text.nameext_from_url(url, post)
|
text.nameext_from_url(url, post)
|
||||||
post["hash"] = post["filename"].partition("_")[2]
|
post["hash"] = post["filename"].partition("_")[2]
|
||||||
return Message.Url, url, post
|
return Message.Url, url, post
|
||||||
|
|
||||||
@staticmethod
|
def _prepare_image(self, url, post):
|
||||||
def _prepare_image(url, post):
|
|
||||||
text.nameext_from_url(url, post)
|
text.nameext_from_url(url, post)
|
||||||
|
|
||||||
# try ".gifv" (#3095)
|
# try ".gifv" (#3095)
|
||||||
@@ -226,8 +224,7 @@ class TumblrExtractor(Extractor):
|
|||||||
|
|
||||||
return Message.Url, url, post
|
return Message.Url, url, post
|
||||||
|
|
||||||
@staticmethod
|
def _prepare_avatar(self, url, post, blog):
|
||||||
def _prepare_avatar(url, post, blog):
|
|
||||||
text.nameext_from_url(url, post)
|
text.nameext_from_url(url, post)
|
||||||
post["num"] = post["count"] = 1
|
post["num"] = post["count"] = 1
|
||||||
post["blog"] = blog
|
post["blog"] = blog
|
||||||
@@ -298,8 +295,7 @@ class TumblrPostExtractor(TumblrExtractor):
|
|||||||
def posts(self):
|
def posts(self):
|
||||||
return self.api.posts(self.blog, {"id": self.post_id})
|
return self.api.posts(self.blog, {"id": self.post_id})
|
||||||
|
|
||||||
@staticmethod
|
def _setup_posttypes(self):
|
||||||
def _setup_posttypes():
|
|
||||||
return POST_TYPES
|
return POST_TYPES
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,13 +20,11 @@ class TumblrgalleryExtractor(GalleryExtractor):
|
|||||||
root = "https://tumblrgallery.xyz"
|
root = "https://tumblrgallery.xyz"
|
||||||
referer = False
|
referer = False
|
||||||
|
|
||||||
@staticmethod
|
def _urls_from_page(self, page):
|
||||||
def _urls_from_page(page):
|
|
||||||
return text.extract_iter(
|
return text.extract_iter(
|
||||||
page, '<div class="report"> <a class="xx-co-me" href="', '"')
|
page, '<div class="report"> <a class="xx-co-me" href="', '"')
|
||||||
|
|
||||||
@staticmethod
|
def _data_from_url(self, url):
|
||||||
def _data_from_url(url):
|
|
||||||
filename = text.nameext_from_url(url)["filename"]
|
filename = text.nameext_from_url(url)["filename"]
|
||||||
parts = filename.split("_")
|
parts = filename.split("_")
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -36,8 +36,7 @@ class TwibooruExtractor(BooruExtractor):
|
|||||||
return post["view_url"].rpartition(".")[0] + ".svg"
|
return post["view_url"].rpartition(".")[0] + ".svg"
|
||||||
return post["view_url"]
|
return post["view_url"]
|
||||||
|
|
||||||
@staticmethod
|
def _prepare(self, post):
|
||||||
def _prepare(post):
|
|
||||||
post["date"] = text.parse_datetime(
|
post["date"] = text.parse_datetime(
|
||||||
post["created_at"], "%Y-%m-%dT%H:%M:%S.%fZ")
|
post["created_at"], "%Y-%m-%dT%H:%M:%S.%fZ")
|
||||||
|
|
||||||
|
|||||||
@@ -48,8 +48,7 @@ class UnsplashExtractor(Extractor):
|
|||||||
yield Message.Directory, photo
|
yield Message.Directory, photo
|
||||||
yield Message.Url, url, photo
|
yield Message.Url, url, photo
|
||||||
|
|
||||||
@staticmethod
|
def metadata(self):
|
||||||
def metadata():
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def skip(self, num):
|
def skip(self, num):
|
||||||
|
|||||||
@@ -73,8 +73,7 @@ class VichanThreadExtractor(VichanExtractor):
|
|||||||
self.root, post["board"], post["tim"], post["ext"])
|
self.root, post["board"], post["tim"], post["ext"])
|
||||||
return Message.Url, post["url"], post
|
return Message.Url, post["url"], post
|
||||||
|
|
||||||
@staticmethod
|
def _process_8kun(self, post, data):
|
||||||
def _process_8kun(post, data):
|
|
||||||
post.update(data)
|
post.update(data)
|
||||||
post["extension"] = post["ext"][1:]
|
post["extension"] = post["ext"][1:]
|
||||||
|
|
||||||
|
|||||||
@@ -109,8 +109,7 @@ class VscoExtractor(Extractor):
|
|||||||
yield from medias
|
yield from medias
|
||||||
params["page"] += 1
|
params["page"] += 1
|
||||||
|
|
||||||
@staticmethod
|
def _transform_media(self, media):
|
||||||
def _transform_media(media):
|
|
||||||
if "responsiveUrl" not in media:
|
if "responsiveUrl" not in media:
|
||||||
return None
|
return None
|
||||||
media["_id"] = media["id"]
|
media["_id"] = media["id"]
|
||||||
@@ -122,8 +121,7 @@ class VscoExtractor(Extractor):
|
|||||||
media["image_meta"] = media.get("imageMeta")
|
media["image_meta"] = media.get("imageMeta")
|
||||||
return media
|
return media
|
||||||
|
|
||||||
@staticmethod
|
def _transform_video(self, media):
|
||||||
def _transform_video(media):
|
|
||||||
media["is_video"] = True
|
media["is_video"] = True
|
||||||
media["grid_name"] = ""
|
media["grid_name"] = ""
|
||||||
media["video_url"] = media["playback_url"]
|
media["video_url"] = media["playback_url"]
|
||||||
|
|||||||
@@ -39,8 +39,7 @@ class WallhavenExtractor(Extractor):
|
|||||||
"""Return general metadata"""
|
"""Return general metadata"""
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
@staticmethod
|
def _transform(self, wp):
|
||||||
def _transform(wp):
|
|
||||||
wp["url"] = wp.pop("path")
|
wp["url"] = wp.pop("path")
|
||||||
if "tags" in wp:
|
if "tags" in wp:
|
||||||
wp["tags"] = [t["name"] for t in wp["tags"]]
|
wp["tags"] = [t["name"] for t in wp["tags"]]
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ class WeasylExtractor(Extractor):
|
|||||||
root = "https://www.weasyl.com"
|
root = "https://www.weasyl.com"
|
||||||
useragent = util.USERAGENT
|
useragent = util.USERAGENT
|
||||||
|
|
||||||
@staticmethod
|
def populate_submission(self, data):
|
||||||
def populate_submission(data):
|
|
||||||
# Some submissions don't have content and can be skipped
|
# Some submissions don't have content and can be skipped
|
||||||
if "submission" in data["media"]:
|
if "submission" in data["media"]:
|
||||||
data["url"] = data["media"]["submission"][0]["url"]
|
data["url"] = data["media"]["submission"][0]["url"]
|
||||||
|
|||||||
@@ -52,8 +52,7 @@ class WikimediaExtractor(BaseExtractor):
|
|||||||
return url
|
return url
|
||||||
raise exception.StopExtraction("Unable to find API endpoint")
|
raise exception.StopExtraction("Unable to find API endpoint")
|
||||||
|
|
||||||
@staticmethod
|
def prepare(self, image):
|
||||||
def prepare(image):
|
|
||||||
"""Adjust the content of an image object"""
|
"""Adjust the content of an image object"""
|
||||||
image["metadata"] = {
|
image["metadata"] = {
|
||||||
m["name"]: m["value"]
|
m["name"]: m["value"]
|
||||||
|
|||||||
@@ -463,8 +463,7 @@ class Literal():
|
|||||||
# __getattr__, __getattribute__, and __class_getitem__
|
# __getattr__, __getattribute__, and __class_getitem__
|
||||||
# are all slower than regular __getitem__
|
# are all slower than regular __getitem__
|
||||||
|
|
||||||
@staticmethod
|
def __getitem__(self, key):
|
||||||
def __getitem__(key):
|
|
||||||
return key
|
return key
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -682,8 +682,7 @@ class DownloadJob(Job):
|
|||||||
for hook, callback in hooks.items():
|
for hook, callback in hooks.items():
|
||||||
self.hooks[hook].append(callback)
|
self.hooks[hook].append(callback)
|
||||||
|
|
||||||
@staticmethod
|
def _call_hook(self, callback, condition, pathfmt):
|
||||||
def _call_hook(callback, condition, pathfmt):
|
|
||||||
if condition(pathfmt.kwdict):
|
if condition(pathfmt.kwdict):
|
||||||
callback(pathfmt)
|
callback(pathfmt)
|
||||||
|
|
||||||
@@ -818,12 +817,10 @@ class UrlJob(Job):
|
|||||||
if depth >= self.maxdepth:
|
if depth >= self.maxdepth:
|
||||||
self.handle_queue = self.handle_url
|
self.handle_queue = self.handle_url
|
||||||
|
|
||||||
@staticmethod
|
def handle_url(self, url, _):
|
||||||
def handle_url(url, _):
|
|
||||||
stdout_write(url + "\n")
|
stdout_write(url + "\n")
|
||||||
|
|
||||||
@staticmethod
|
def handle_url_fallback(self, url, kwdict):
|
||||||
def handle_url_fallback(url, kwdict):
|
|
||||||
stdout_write(url + "\n")
|
stdout_write(url + "\n")
|
||||||
if "_fallback" in kwdict:
|
if "_fallback" in kwdict:
|
||||||
for url in kwdict["_fallback"]:
|
for url in kwdict["_fallback"]:
|
||||||
|
|||||||
@@ -483,8 +483,7 @@ class CustomOutput():
|
|||||||
self._fmt_progress_total = (options.get("progress-total") or
|
self._fmt_progress_total = (options.get("progress-total") or
|
||||||
"\r{3:>3}% {0:>7}B {1:>7}B/s ").format
|
"\r{3:>3}% {0:>7}B {1:>7}B/s ").format
|
||||||
|
|
||||||
@staticmethod
|
def _make_func(self, shorten, format_string, limit):
|
||||||
def _make_func(shorten, format_string, limit):
|
|
||||||
fmt = format_string.format
|
fmt = format_string.format
|
||||||
return lambda txt: fmt(shorten(txt, limit, CHAR_ELLIPSIES))
|
return lambda txt: fmt(shorten(txt, limit, CHAR_ELLIPSIES))
|
||||||
|
|
||||||
|
|||||||
@@ -183,8 +183,7 @@ class PathFormat():
|
|||||||
return self.check_file()
|
return self.check_file()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
def check_file(self):
|
||||||
def check_file():
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _enum_file(self):
|
def _enum_file(self):
|
||||||
|
|||||||
@@ -62,12 +62,10 @@ class ComparePP(PostProcessor):
|
|||||||
def _compare(self, f1, f2):
|
def _compare(self, f1, f2):
|
||||||
return self._compare_size(f1, f2) and self._compare_content(f1, f2)
|
return self._compare_size(f1, f2) and self._compare_content(f1, f2)
|
||||||
|
|
||||||
@staticmethod
|
def _compare_size(self, f1, f2):
|
||||||
def _compare_size(f1, f2):
|
|
||||||
return os.stat(f1).st_size == os.stat(f2).st_size
|
return os.stat(f1).st_size == os.stat(f2).st_size
|
||||||
|
|
||||||
@staticmethod
|
def _compare_content(self, f1, f2):
|
||||||
def _compare_content(f1, f2):
|
|
||||||
size = 16384
|
size = 16384
|
||||||
with open(f1, "rb") as fp1, open(f2, "rb") as fp2:
|
with open(f1, "rb") as fp1, open(f2, "rb") as fp2:
|
||||||
while True:
|
while True:
|
||||||
|
|||||||
@@ -268,8 +268,7 @@ class MetadataPP(PostProcessor):
|
|||||||
if not private:
|
if not private:
|
||||||
return util.filter_dict
|
return util.filter_dict
|
||||||
|
|
||||||
@staticmethod
|
def _make_encoder(self, options, indent=None):
|
||||||
def _make_encoder(options, indent=None):
|
|
||||||
return json.JSONEncoder(
|
return json.JSONEncoder(
|
||||||
ensure_ascii=options.get("ascii", False),
|
ensure_ascii=options.get("ascii", False),
|
||||||
sort_keys=options.get("sort", False),
|
sort_keys=options.get("sort", False),
|
||||||
|
|||||||
@@ -425,15 +425,13 @@ class UgoiraPP(PostProcessor):
|
|||||||
|
|
||||||
return (None, None)
|
return (None, None)
|
||||||
|
|
||||||
@staticmethod
|
def _delay_gcd(self, frames):
|
||||||
def _delay_gcd(frames):
|
|
||||||
result = frames[0]["delay"]
|
result = frames[0]["delay"]
|
||||||
for f in frames:
|
for f in frames:
|
||||||
result = gcd(result, f["delay"])
|
result = gcd(result, f["delay"])
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@staticmethod
|
def _delay_is_uniform(self, frames):
|
||||||
def _delay_is_uniform(frames):
|
|
||||||
delay = frames[0]["delay"]
|
delay = frames[0]["delay"]
|
||||||
for f in frames:
|
for f in frames:
|
||||||
if f["delay"] != delay:
|
if f["delay"] != delay:
|
||||||
|
|||||||
@@ -684,8 +684,7 @@ class CustomNone():
|
|||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@staticmethod
|
def __next__(self):
|
||||||
def __next__():
|
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
@@ -733,20 +732,17 @@ class CustomNone():
|
|||||||
__abs__ = identity
|
__abs__ = identity
|
||||||
__invert__ = identity
|
__invert__ = identity
|
||||||
|
|
||||||
@staticmethod
|
def __len__(self):
|
||||||
def __len__():
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
__int__ = __len__
|
__int__ = __len__
|
||||||
__hash__ = __len__
|
__hash__ = __len__
|
||||||
__index__ = __len__
|
__index__ = __len__
|
||||||
|
|
||||||
@staticmethod
|
def __format__(self, _):
|
||||||
def __format__(_):
|
|
||||||
return "None"
|
return "None"
|
||||||
|
|
||||||
@staticmethod
|
def __str__(self):
|
||||||
def __str__():
|
|
||||||
return "None"
|
return "None"
|
||||||
|
|
||||||
__repr__ = __str__
|
__repr__ = __str__
|
||||||
@@ -1052,8 +1048,7 @@ class RangePredicate():
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
def _parse(self, rangespec):
|
||||||
def _parse(rangespec):
|
|
||||||
"""Parse an integer range string and return the resulting ranges
|
"""Parse an integer range string and return the resulting ranges
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|||||||
@@ -223,8 +223,7 @@ class TestConfigFiles(unittest.TestCase):
|
|||||||
self.assertIsInstance(cfg, dict)
|
self.assertIsInstance(cfg, dict)
|
||||||
self.assertTrue(cfg)
|
self.assertTrue(cfg)
|
||||||
|
|
||||||
@staticmethod
|
def _load(self, name):
|
||||||
def _load(name):
|
|
||||||
path = os.path.join(ROOTDIR, "docs", name)
|
path = os.path.join(ROOTDIR, "docs", name)
|
||||||
try:
|
try:
|
||||||
with open(path) as fp:
|
with open(path) as fp:
|
||||||
|
|||||||
@@ -296,8 +296,7 @@ class TestExtractorWait(unittest.TestCase):
|
|||||||
u = self._isotime_to_seconds(until.time().isoformat()[:8])
|
u = self._isotime_to_seconds(until.time().isoformat()[:8])
|
||||||
self.assertLessEqual(o-u, 1.0)
|
self.assertLessEqual(o-u, 1.0)
|
||||||
|
|
||||||
@staticmethod
|
def _isotime_to_seconds(self, isotime):
|
||||||
def _isotime_to_seconds(isotime):
|
|
||||||
parts = isotime.split(":")
|
parts = isotime.split(":")
|
||||||
return int(parts[0]) * 3600 + int(parts[1]) * 60 + int(parts[2])
|
return int(parts[0]) * 3600 + int(parts[1]) * 60 + int(parts[2])
|
||||||
|
|
||||||
|
|||||||
@@ -713,8 +713,7 @@ class MetadataTest(BasePostprocessorTest):
|
|||||||
}
|
}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
@staticmethod
|
def _output(self, mock):
|
||||||
def _output(mock):
|
|
||||||
return "".join(
|
return "".join(
|
||||||
call[1][0]
|
call[1][0]
|
||||||
for call in mock.mock_calls
|
for call in mock.mock_calls
|
||||||
|
|||||||
@@ -28,11 +28,18 @@ from gallery_dl import util, text, exception # noqa E402
|
|||||||
|
|
||||||
class TestRange(unittest.TestCase):
|
class TestRange(unittest.TestCase):
|
||||||
|
|
||||||
def test_parse_empty(self, f=util.RangePredicate._parse):
|
def setUp(self):
|
||||||
|
self.predicate = util.RangePredicate("")
|
||||||
|
|
||||||
|
def test_parse_empty(self):
|
||||||
|
f = self.predicate._parse
|
||||||
|
|
||||||
self.assertEqual(f(""), [])
|
self.assertEqual(f(""), [])
|
||||||
self.assertEqual(f([]), [])
|
self.assertEqual(f([]), [])
|
||||||
|
|
||||||
def test_parse_digit(self, f=util.RangePredicate._parse):
|
def test_parse_digit(self):
|
||||||
|
f = self.predicate._parse
|
||||||
|
|
||||||
self.assertEqual(f("2"), [range(2, 3)])
|
self.assertEqual(f("2"), [range(2, 3)])
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -42,7 +49,9 @@ class TestRange(unittest.TestCase):
|
|||||||
range(4, 5)],
|
range(4, 5)],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_parse_range(self, f=util.RangePredicate._parse):
|
def test_parse_range(self):
|
||||||
|
f = self.predicate._parse
|
||||||
|
|
||||||
self.assertEqual(f("1-2"), [range(1, 3)])
|
self.assertEqual(f("1-2"), [range(1, 3)])
|
||||||
self.assertEqual(f("2-"), [range(2, sys.maxsize)])
|
self.assertEqual(f("2-"), [range(2, sys.maxsize)])
|
||||||
self.assertEqual(f("-3"), [range(1, 4)])
|
self.assertEqual(f("-3"), [range(1, 4)])
|
||||||
@@ -62,7 +71,9 @@ class TestRange(unittest.TestCase):
|
|||||||
range(2, 7)],
|
range(2, 7)],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_parse_slice(self, f=util.RangePredicate._parse):
|
def test_parse_slice(self):
|
||||||
|
f = self.predicate._parse
|
||||||
|
|
||||||
self.assertEqual(f("2:4") , [range(2, 4)])
|
self.assertEqual(f("2:4") , [range(2, 4)])
|
||||||
self.assertEqual(f("3::") , [range(3, sys.maxsize)])
|
self.assertEqual(f("3::") , [range(3, sys.maxsize)])
|
||||||
self.assertEqual(f(":4:") , [range(1, 4)])
|
self.assertEqual(f(":4:") , [range(1, 4)])
|
||||||
|
|||||||
Reference in New Issue
Block a user