remove '&' from URL patterns

'/?&#' -> '/?#' and '?&#' -> '?#'

According to https://www.ietf.org/rfc/rfc3986.txt, URLs are
"organized hierarchically" by using "the slash ("/"), question
mark ("?"), and number sign ("#") characters to delimit components"
This commit is contained in:
Mike Fährmann
2020-10-22 23:12:59 +02:00
parent 1686dc1757
commit 968d3e8465
74 changed files with 158 additions and 158 deletions

View File

@@ -101,7 +101,7 @@ class _35photoUserExtractor(_35photoExtractor):
"""Extractor for all images of a user on 35photo.pro""" """Extractor for all images of a user on 35photo.pro"""
subcategory = "user" subcategory = "user"
pattern = (r"(?:https?://)?(?:[a-z]+\.)?35photo\.pro" pattern = (r"(?:https?://)?(?:[a-z]+\.)?35photo\.pro"
r"/(?!photo_|genre_|tags/|rating/)([^/?&#]+)") r"/(?!photo_|genre_|tags/|rating/)([^/?#]+)")
test = ( test = (
("https://35photo.pro/liya", { ("https://35photo.pro/liya", {
"pattern": r"https://m\d+.35photo.pro/photos_(main|series)/.*.jpg", "pattern": r"https://m\d+.35photo.pro/photos_(main|series)/.*.jpg",
@@ -142,7 +142,7 @@ class _35photoTagExtractor(_35photoExtractor):
subcategory = "tag" subcategory = "tag"
directory_fmt = ("{category}", "Tags", "{search_tag}") directory_fmt = ("{category}", "Tags", "{search_tag}")
archive_fmt = "t{search_tag}_{id}_{num}" archive_fmt = "t{search_tag}_{id}_{num}"
pattern = r"(?:https?://)?(?:[a-z]+\.)?35photo\.pro/tags/([^/?&#]+)" pattern = r"(?:https?://)?(?:[a-z]+\.)?35photo\.pro/tags/([^/?#]+)"
test = ("https://35photo.pro/tags/landscape/", { test = ("https://35photo.pro/tags/landscape/", {
"range": "1-25", "range": "1-25",
"count": 25, "count": 25,

View File

@@ -65,7 +65,7 @@ class _4chanBoardExtractor(Extractor):
"""Extractor for 4chan boards""" """Extractor for 4chan boards"""
category = "4chan" category = "4chan"
subcategory = "board" subcategory = "board"
pattern = r"(?:https?://)?boards\.4chan(?:nel)?\.org/([^/?&#]+)/\d*$" pattern = r"(?:https?://)?boards\.4chan(?:nel)?\.org/([^/?#]+)/\d*$"
test = ("https://boards.4channel.org/po/", { test = ("https://boards.4channel.org/po/", {
"pattern": _4chanThreadExtractor.pattern, "pattern": _4chanThreadExtractor.pattern,
"count": ">= 100", "count": ">= 100",

View File

@@ -90,7 +90,7 @@ class _500pxExtractor(Extractor):
class _500pxUserExtractor(_500pxExtractor): class _500pxUserExtractor(_500pxExtractor):
"""Extractor for photos from a user's photostream on 500px.com""" """Extractor for photos from a user's photostream on 500px.com"""
subcategory = "user" subcategory = "user"
pattern = BASE_PATTERN + r"/(?!photo/)(?:p/)?([^/?&#]+)/?(?:$|\?|#)" pattern = BASE_PATTERN + r"/(?!photo/)(?:p/)?([^/?#]+)/?(?:$|[?#])"
test = ( test = (
("https://500px.com/p/light_expression_photography", { ("https://500px.com/p/light_expression_photography", {
"pattern": r"https?://drscdn.500px.org/photo/\d+/m%3D4096/v2", "pattern": r"https?://drscdn.500px.org/photo/\d+/m%3D4096/v2",
@@ -132,7 +132,7 @@ class _500pxGalleryExtractor(_500pxExtractor):
subcategory = "gallery" subcategory = "gallery"
directory_fmt = ("{category}", "{user[username]}", "{gallery[name]}") directory_fmt = ("{category}", "{user[username]}", "{gallery[name]}")
pattern = (BASE_PATTERN + r"/(?!photo/)(?:p/)?" pattern = (BASE_PATTERN + r"/(?!photo/)(?:p/)?"
r"([^/?&#]+)/galleries/([^/?&#]+)") r"([^/?#]+)/galleries/([^/?#]+)")
test = ( test = (
("https://500px.com/p/fashvamp/galleries/lera", { ("https://500px.com/p/fashvamp/galleries/lera", {
"url": "002dc81dee5b4a655f0e31ad8349e8903b296df6", "url": "002dc81dee5b4a655f0e31ad8349e8903b296df6",

View File

@@ -64,7 +64,7 @@ class _8kunBoardExtractor(Extractor):
"""Extractor for 8kun boards""" """Extractor for 8kun boards"""
category = "8kun" category = "8kun"
subcategory = "board" subcategory = "board"
pattern = r"(?:https?://)?8kun\.top/([^/?&#]+)/(?:index|\d+)\.html" pattern = r"(?:https?://)?8kun\.top/([^/?#]+)/(?:index|\d+)\.html"
test = ( test = (
("https://8kun.top/v/index.html", { ("https://8kun.top/v/index.html", {
"pattern": _8kunThreadExtractor.pattern, "pattern": _8kunThreadExtractor.pattern,

View File

@@ -22,7 +22,7 @@ class _8musesAlbumExtractor(Extractor):
archive_fmt = "{hash}" archive_fmt = "{hash}"
root = "https://comics.8muses.com" root = "https://comics.8muses.com"
pattern = (r"(?:https?://)?(?:comics\.|www\.)?8muses\.com" pattern = (r"(?:https?://)?(?:comics\.|www\.)?8muses\.com"
r"(/comics/album/[^?&#]+)(\?[^#]+)?") r"(/comics/album/[^?#]+)(\?[^#]+)?")
test = ( test = (
("https://comics.8muses.com/comics/album/Fakku-Comics/mogg/Liar", { ("https://comics.8muses.com/comics/album/Fakku-Comics/mogg/Liar", {
"url": "6286ac33087c236c5a7e51f8a9d4e4d5548212d4", "url": "6286ac33087c236c5a7e51f8a9d4e4d5548212d4",

View File

@@ -131,7 +131,7 @@ class ArtstationUserExtractor(ArtstationExtractor):
"""Extractor for all projects of an artstation user""" """Extractor for all projects of an artstation user"""
subcategory = "user" subcategory = "user"
pattern = (r"(?:https?://)?(?:(?:www\.)?artstation\.com" pattern = (r"(?:https?://)?(?:(?:www\.)?artstation\.com"
r"/(?!artwork|projects|search)([^/?&#]+)(?:/albums/all)?" r"/(?!artwork|projects|search)([^/?#]+)(?:/albums/all)?"
r"|((?!www)\w+)\.artstation\.com(?:/projects)?)/?$") r"|((?!www)\w+)\.artstation\.com(?:/projects)?)/?$")
test = ( test = (
("https://www.artstation.com/gaerikim/", { ("https://www.artstation.com/gaerikim/", {
@@ -156,7 +156,7 @@ class ArtstationAlbumExtractor(ArtstationExtractor):
"{album[id]} - {album[title]}") "{album[id]} - {album[title]}")
archive_fmt = "a_{album[id]}_{asset[id]}" archive_fmt = "a_{album[id]}_{asset[id]}"
pattern = (r"(?:https?://)?(?:(?:www\.)?artstation\.com" pattern = (r"(?:https?://)?(?:(?:www\.)?artstation\.com"
r"/(?!artwork|projects|search)([^/?&#]+)" r"/(?!artwork|projects|search)([^/?#]+)"
r"|((?!www)\w+)\.artstation\.com)/albums/(\d+)") r"|((?!www)\w+)\.artstation\.com)/albums/(\d+)")
test = ( test = (
("https://www.artstation.com/huimeiye/albums/770899", { ("https://www.artstation.com/huimeiye/albums/770899", {
@@ -199,7 +199,7 @@ class ArtstationLikesExtractor(ArtstationExtractor):
directory_fmt = ("{category}", "{userinfo[username]}", "Likes") directory_fmt = ("{category}", "{userinfo[username]}", "Likes")
archive_fmt = "f_{userinfo[id]}_{asset[id]}" archive_fmt = "f_{userinfo[id]}_{asset[id]}"
pattern = (r"(?:https?://)?(?:www\.)?artstation\.com" pattern = (r"(?:https?://)?(?:www\.)?artstation\.com"
r"/(?!artwork|projects|search)([^/?&#]+)/likes/?") r"/(?!artwork|projects|search)([^/?#]+)/likes/?")
test = ( test = (
("https://www.artstation.com/mikf/likes", { ("https://www.artstation.com/mikf/likes", {
"pattern": r"https://\w+\.artstation\.com/p/assets" "pattern": r"https://\w+\.artstation\.com/p/assets"
@@ -225,7 +225,7 @@ class ArtstationChallengeExtractor(ArtstationExtractor):
"{challenge[id]} - {challenge[title]}") "{challenge[id]} - {challenge[title]}")
archive_fmt = "c_{challenge[id]}_{asset_id}" archive_fmt = "c_{challenge[id]}_{asset_id}"
pattern = (r"(?:https?://)?(?:www\.)?artstation\.com" pattern = (r"(?:https?://)?(?:www\.)?artstation\.com"
r"/contests/[^/?&#]+/challenges/(\d+)" r"/contests/[^/?#]+/challenges/(\d+)"
r"/?(?:\?sorting=([a-z]+))?") r"/?(?:\?sorting=([a-z]+))?")
test = ( test = (
("https://www.artstation.com/contests/thu-2017/challenges/20"), ("https://www.artstation.com/contests/thu-2017/challenges/20"),
@@ -386,7 +386,7 @@ class ArtstationFollowingExtractor(ArtstationExtractor):
"""Extractor for a user's followed users""" """Extractor for a user's followed users"""
subcategory = "following" subcategory = "following"
pattern = (r"(?:https?://)?(?:www\.)?artstation\.com" pattern = (r"(?:https?://)?(?:www\.)?artstation\.com"
r"/(?!artwork|projects|search)([^/?&#]+)/following") r"/(?!artwork|projects|search)([^/?#]+)/following")
test = ("https://www.artstation.com/gaerikim/following", { test = ("https://www.artstation.com/gaerikim/following", {
"pattern": ArtstationUserExtractor.pattern, "pattern": ArtstationUserExtractor.pattern,
"count": ">= 50", "count": ">= 50",

View File

@@ -153,7 +153,7 @@ class AryionGalleryExtractor(AryionExtractor):
"""Extractor for a user's gallery on eka's portal""" """Extractor for a user's gallery on eka's portal"""
subcategory = "gallery" subcategory = "gallery"
categorytransfer = True categorytransfer = True
pattern = BASE_PATTERN + r"/(?:gallery/|user/|latest.php\?name=)([^/?&#]+)" pattern = BASE_PATTERN + r"/(?:gallery/|user/|latest.php\?name=)([^/?#]+)"
test = ( test = (
("https://aryion.com/g4/gallery/jameshoward", { ("https://aryion.com/g4/gallery/jameshoward", {
"options": (("recursive", False),), "options": (("recursive", False),),

View File

@@ -151,7 +151,7 @@ class BehanceUserExtractor(BehanceExtractor):
"""Extractor for a user's galleries from www.behance.net""" """Extractor for a user's galleries from www.behance.net"""
subcategory = "user" subcategory = "user"
categorytransfer = True categorytransfer = True
pattern = r"(?:https?://)?(?:www\.)?behance\.net/([^/?&#]+)/?$" pattern = r"(?:https?://)?(?:www\.)?behance\.net/([^/?#]+)/?$"
test = ("https://www.behance.net/alexstrohl", { test = ("https://www.behance.net/alexstrohl", {
"count": ">= 8", "count": ">= 8",
"pattern": BehanceGalleryExtractor.pattern, "pattern": BehanceGalleryExtractor.pattern,

View File

@@ -92,7 +92,7 @@ class BloggerExtractor(Extractor):
class BloggerPostExtractor(BloggerExtractor): class BloggerPostExtractor(BloggerExtractor):
"""Extractor for a single blog post""" """Extractor for a single blog post"""
subcategory = "post" subcategory = "post"
pattern = BASE_PATTERN + r"(/\d{4}/\d\d/[^/?&#]+\.html)" pattern = BASE_PATTERN + r"(/\d{4}/\d\d/[^/?#]+\.html)"
test = ( test = (
("https://julianbphotography.blogspot.com/2010/12/moon-rise.html", { ("https://julianbphotography.blogspot.com/2010/12/moon-rise.html", {
"url": "9928429fb62f712eb4de80f53625eccecc614aae", "url": "9928429fb62f712eb4de80f53625eccecc614aae",
@@ -171,7 +171,7 @@ class BloggerBlogExtractor(BloggerExtractor):
class BloggerSearchExtractor(BloggerExtractor): class BloggerSearchExtractor(BloggerExtractor):
"""Extractor for search resuls and labels""" """Extractor for search resuls and labels"""
subcategory = "search" subcategory = "search"
pattern = BASE_PATTERN + r"/search(?:/?\?q=([^/?&#]+)|/label/([^/?&#]+))" pattern = BASE_PATTERN + r"/search(?:/?\?q=([^/?#]+)|/label/([^/?#]+))"
test = ( test = (
("https://julianbphotography.blogspot.com/search?q=400mm", { ("https://julianbphotography.blogspot.com/search?q=400mm", {
"count": "< 10" "count": "< 10"

View File

@@ -460,7 +460,7 @@ class DeviantartFolderExtractor(DeviantartExtractor):
subcategory = "folder" subcategory = "folder"
directory_fmt = ("{category}", "{username}", "{folder[title]}") directory_fmt = ("{category}", "{username}", "{folder[title]}")
archive_fmt = "F_{folder[uuid]}_{index}.{extension}" archive_fmt = "F_{folder[uuid]}_{index}.{extension}"
pattern = BASE_PATTERN + r"/gallery/(\d+)/([^/?&#]+)" pattern = BASE_PATTERN + r"/gallery/(\d+)/([^/?#]+)"
test = ( test = (
# user # user
("https://www.deviantart.com/shimoda7/gallery/722019/Miscellaneous", { ("https://www.deviantart.com/shimoda7/gallery/722019/Miscellaneous", {
@@ -601,7 +601,7 @@ class DeviantartCollectionExtractor(DeviantartExtractor):
directory_fmt = ("{category}", "{username}", "Favourites", directory_fmt = ("{category}", "{username}", "Favourites",
"{collection[title]}") "{collection[title]}")
archive_fmt = "C_{collection[uuid]}_{index}.{extension}" archive_fmt = "C_{collection[uuid]}_{index}.{extension}"
pattern = BASE_PATTERN + r"/favourites/(\d+)/([^/?&#]+)" pattern = BASE_PATTERN + r"/favourites/(\d+)/([^/?#]+)"
test = ( test = (
(("https://www.deviantart.com/pencilshadings" (("https://www.deviantart.com/pencilshadings"
"/favourites/70595441/3D-Favorites"), { "/favourites/70595441/3D-Favorites"), {
@@ -671,8 +671,8 @@ class DeviantartPopularExtractor(DeviantartExtractor):
archive_fmt = "P_{popular[range]}_{popular[search]}_{index}.{extension}" archive_fmt = "P_{popular[range]}_{popular[search]}_{index}.{extension}"
pattern = (r"(?:https?://)?www\.deviantart\.com/(?:" pattern = (r"(?:https?://)?www\.deviantart\.com/(?:"
r"search(?:/deviations)?" r"search(?:/deviations)?"
r"|(?:deviations/?)?\?order=(popular-[^/?&#]+)" r"|(?:deviations/?)?\?order=(popular-[^/?#]+)"
r"|((?:[\w-]+/)*)(popular-[^/?&#]+)" r"|((?:[\w-]+/)*)(popular-[^/?#]+)"
r")/?(?:\?([^#]*))?") r")/?(?:\?([^#]*))?")
test = ( test = (
("https://www.deviantart.com/?order=popular-all-time", { ("https://www.deviantart.com/?order=popular-all-time", {
@@ -730,7 +730,7 @@ class DeviantartDeviationExtractor(DeviantartExtractor):
"""Extractor for single deviations""" """Extractor for single deviations"""
subcategory = "deviation" subcategory = "deviation"
archive_fmt = "{index}.{extension}" archive_fmt = "{index}.{extension}"
pattern = BASE_PATTERN + r"/(art|journal)/(?:[^/?&#]+-)?(\d+)" pattern = BASE_PATTERN + r"/(art|journal)/(?:[^/?#]+-)?(\d+)"
test = ( test = (
(("https://www.deviantart.com/shimoda7/art/For-the-sake-10073852"), { (("https://www.deviantart.com/shimoda7/art/For-the-sake-10073852"), {
"options": (("original", 0),), "options": (("original", 0),),

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright 2017-2019 Mike Fährmann # Copyright 2017-2020 Mike Fährmann
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as # it under the terms of the GNU General Public License version 2 as
@@ -17,7 +17,7 @@ class DirectlinkExtractor(Extractor):
category = "directlink" category = "directlink"
filename_fmt = "{domain}/{path}/{filename}.{extension}" filename_fmt = "{domain}/{path}/{filename}.{extension}"
archive_fmt = filename_fmt archive_fmt = filename_fmt
pattern = (r"(?i)https?://(?P<domain>[^/?&#]+)/(?P<path>[^?&#]+\." pattern = (r"(?i)https?://(?P<domain>[^/?#]+)/(?P<path>[^?#]+\."
r"(?:jpe?g|jpe|png|gif|web[mp]|mp4|mkv|og[gmv]|opus))" r"(?:jpe?g|jpe|png|gif|web[mp]|mp4|mkv|og[gmv]|opus))"
r"(?:\?(?P<query>[^/?#]*))?(?:#(?P<fragment>.*))?$") r"(?:\?(?P<query>[^/?#]*))?(?:#(?P<fragment>.*))?$")
test = ( test = (

View File

@@ -44,7 +44,7 @@ class DynastyscansBase():
class DynastyscansChapterExtractor(DynastyscansBase, ChapterExtractor): class DynastyscansChapterExtractor(DynastyscansBase, ChapterExtractor):
"""Extractor for manga-chapters from dynasty-scans.com""" """Extractor for manga-chapters from dynasty-scans.com"""
pattern = BASE_PATTERN + r"(/chapters/[^/?&#]+)" pattern = BASE_PATTERN + r"(/chapters/[^/?#]+)"
test = ( test = (
(("http://dynasty-scans.com/chapters/" (("http://dynasty-scans.com/chapters/"
"hitoribocchi_no_oo_seikatsu_ch33"), { "hitoribocchi_no_oo_seikatsu_ch33"), {

View File

@@ -17,7 +17,7 @@ class FallenangelsChapterExtractor(ChapterExtractor):
"""Extractor for manga-chapters from fascans.com""" """Extractor for manga-chapters from fascans.com"""
category = "fallenangels" category = "fallenangels"
pattern = (r"(?:https?://)?(manga|truyen)\.fascans\.com" pattern = (r"(?:https?://)?(manga|truyen)\.fascans\.com"
r"/manga/([^/]+)/(\d+)(\.[^/?&#]+)?") r"/manga/([^/]+)/(\d+)(\.[^/?#]+)?")
test = ( test = (
("https://manga.fascans.com/manga/chronos-ruler/20/1", { ("https://manga.fascans.com/manga/chronos-ruler/20/1", {
"url": "4604a7914566cc2da0ff789aa178e2d1c8c241e3", "url": "4604a7914566cc2da0ff789aa178e2d1c8c241e3",

View File

@@ -45,7 +45,7 @@ class FoolslideChapterExtractor(FoolslideBase, ChapterExtractor):
"""Base class for chapter extractors for FoOlSlide based sites""" """Base class for chapter extractors for FoOlSlide based sites"""
directory_fmt = ("{category}", "{manga}", "{chapter_string}") directory_fmt = ("{category}", "{manga}", "{chapter_string}")
archive_fmt = "{id}" archive_fmt = "{id}"
pattern_fmt = r"(/read/[^/?&#]+/[a-z-]+/\d+/\d+(?:/\d+)?)" pattern_fmt = r"(/read/[^/?#]+/[a-z-]+/\d+/\d+(?:/\d+)?)"
decode = "default" decode = "default"
def items(self): def items(self):
@@ -86,7 +86,7 @@ class FoolslideChapterExtractor(FoolslideBase, ChapterExtractor):
class FoolslideMangaExtractor(FoolslideBase, MangaExtractor): class FoolslideMangaExtractor(FoolslideBase, MangaExtractor):
"""Base class for manga extractors for FoOlSlide based sites""" """Base class for manga extractors for FoOlSlide based sites"""
pattern_fmt = r"(/series/[^/?&#]+)" pattern_fmt = r"(/series/[^/?#]+)"
def chapters(self, page): def chapters(self, page):
extr = text.extract_from(page) extr = text.extract_from(page)

View File

@@ -177,7 +177,7 @@ class FuraffinityExtractor(Extractor):
class FuraffinityGalleryExtractor(FuraffinityExtractor): class FuraffinityGalleryExtractor(FuraffinityExtractor):
"""Extractor for a furaffinity user's gallery""" """Extractor for a furaffinity user's gallery"""
subcategory = "gallery" subcategory = "gallery"
pattern = BASE_PATTERN + r"/gallery/([^/?&#]+)" pattern = BASE_PATTERN + r"/gallery/([^/?#]+)"
test = ("https://www.furaffinity.net/gallery/mirlinthloth/", { test = ("https://www.furaffinity.net/gallery/mirlinthloth/", {
"pattern": r"https://d\d?.facdn.net/art/mirlinthloth/\d+/\d+.\w+\.\w+", "pattern": r"https://d\d?.facdn.net/art/mirlinthloth/\d+/\d+.\w+\.\w+",
"range": "45-50", "range": "45-50",
@@ -189,7 +189,7 @@ class FuraffinityScrapsExtractor(FuraffinityExtractor):
"""Extractor for a furaffinity user's scraps""" """Extractor for a furaffinity user's scraps"""
subcategory = "scraps" subcategory = "scraps"
directory_fmt = ("{category}", "{user!l}", "Scraps") directory_fmt = ("{category}", "{user!l}", "Scraps")
pattern = BASE_PATTERN + r"/scraps/([^/?&#]+)" pattern = BASE_PATTERN + r"/scraps/([^/?#]+)"
test = ("https://www.furaffinity.net/scraps/mirlinthloth/", { test = ("https://www.furaffinity.net/scraps/mirlinthloth/", {
"pattern": r"https://d\d?.facdn.net/art/[^/]+(/stories)?/\d+/\d+.\w+.", "pattern": r"https://d\d?.facdn.net/art/[^/]+(/stories)?/\d+/\d+.\w+.",
"count": ">= 3", "count": ">= 3",
@@ -200,7 +200,7 @@ class FuraffinityFavoriteExtractor(FuraffinityExtractor):
"""Extractor for a furaffinity user's favorites""" """Extractor for a furaffinity user's favorites"""
subcategory = "favorite" subcategory = "favorite"
directory_fmt = ("{category}", "{user!l}", "Favorites") directory_fmt = ("{category}", "{user!l}", "Favorites")
pattern = BASE_PATTERN + r"/favorites/([^/?&#]+)" pattern = BASE_PATTERN + r"/favorites/([^/?#]+)"
test = ("https://www.furaffinity.net/favorites/mirlinthloth/", { test = ("https://www.furaffinity.net/favorites/mirlinthloth/", {
"pattern": r"https://d\d?.facdn.net/art/[^/]+/\d+/\d+.\w+\.\w+", "pattern": r"https://d\d?.facdn.net/art/[^/]+/\d+/\d+.\w+\.\w+",
"range": "45-50", "range": "45-50",
@@ -278,7 +278,7 @@ class FuraffinityUserExtractor(FuraffinityExtractor):
"""Extractor for furaffinity user profiles""" """Extractor for furaffinity user profiles"""
subcategory = "user" subcategory = "user"
cookiedomain = None cookiedomain = None
pattern = BASE_PATTERN + r"/user/([^/?&#]+)" pattern = BASE_PATTERN + r"/user/([^/?#]+)"
test = ( test = (
("https://www.furaffinity.net/user/mirlinthloth/", { ("https://www.furaffinity.net/user/mirlinthloth/", {
"pattern": r"/gallery/mirlinthloth/$", "pattern": r"/gallery/mirlinthloth/$",
@@ -302,7 +302,7 @@ class FuraffinityUserExtractor(FuraffinityExtractor):
class FuraffinityFollowingExtractor(FuraffinityExtractor): class FuraffinityFollowingExtractor(FuraffinityExtractor):
"""Extractor for a furaffinity user's watched users""" """Extractor for a furaffinity user's watched users"""
subcategory = "following" subcategory = "following"
pattern = BASE_PATTERN + "/watchlist/by/([^/?&#]+)" pattern = BASE_PATTERN + "/watchlist/by/([^/?#]+)"
test = ("https://www.furaffinity.net/watchlist/by/mirlinthloth/", { test = ("https://www.furaffinity.net/watchlist/by/mirlinthloth/", {
"pattern": FuraffinityUserExtractor.pattern, "pattern": FuraffinityUserExtractor.pattern,
"range": "176-225", "range": "176-225",

View File

@@ -17,7 +17,7 @@ class FuskatorGalleryExtractor(GalleryExtractor):
"""Extractor for image galleries on fuskator.com""" """Extractor for image galleries on fuskator.com"""
category = "fuskator" category = "fuskator"
root = "https://fuskator.com" root = "https://fuskator.com"
pattern = r"(?:https?://)?fuskator\.com/(?:thumbs|expanded)/([^/?&#]+)" pattern = r"(?:https?://)?fuskator\.com/(?:thumbs|expanded)/([^/?#]+)"
test = ( test = (
("https://fuskator.com/thumbs/d0GnIzXrSKU/", { ("https://fuskator.com/thumbs/d0GnIzXrSKU/", {
"pattern": r"https://i\d+.fuskator.com/large/d0GnIzXrSKU/.+\.jpg", "pattern": r"https://i\d+.fuskator.com/large/d0GnIzXrSKU/.+\.jpg",

View File

@@ -56,7 +56,7 @@ class GfycatUserExtractor(GfycatExtractor):
"""Extractor for gfycat user profiles""" """Extractor for gfycat user profiles"""
subcategory = "user" subcategory = "user"
directory_fmt = ("{category}", "{userName}") directory_fmt = ("{category}", "{userName}")
pattern = r"(?:https?://)?gfycat\.com/@([^/?&#]+)" pattern = r"(?:https?://)?gfycat\.com/@([^/?#]+)"
test = ("https://gfycat.com/@gretta", { test = ("https://gfycat.com/@gretta", {
"pattern": r"https://giant\.gfycat\.com/[A-Za-z]+\.mp4", "pattern": r"https://giant\.gfycat\.com/[A-Za-z]+\.mp4",
"count": ">= 100", "count": ">= 100",
@@ -70,7 +70,7 @@ class GfycatSearchExtractor(GfycatExtractor):
"""Extractor for gfycat search results""" """Extractor for gfycat search results"""
subcategory = "search" subcategory = "search"
directory_fmt = ("{category}", "Search", "{search}") directory_fmt = ("{category}", "Search", "{search}")
pattern = r"(?:https?://)?gfycat\.com/gifs/search/([^/?&#]+)" pattern = r"(?:https?://)?gfycat\.com/gifs/search/([^/?#]+)"
test = ("https://gfycat.com/gifs/search/funny+animals", { test = ("https://gfycat.com/gifs/search/funny+animals", {
"pattern": r"https://\w+\.gfycat\.com/[A-Za-z]+\.mp4", "pattern": r"https://\w+\.gfycat\.com/[A-Za-z]+\.mp4",
"archive": False, "archive": False,

View File

@@ -23,7 +23,7 @@ class Hentai2readBase():
class Hentai2readChapterExtractor(Hentai2readBase, ChapterExtractor): class Hentai2readChapterExtractor(Hentai2readBase, ChapterExtractor):
"""Extractor for a single manga chapter from hentai2read.com""" """Extractor for a single manga chapter from hentai2read.com"""
archive_fmt = "{chapter_id}_{page}" archive_fmt = "{chapter_id}_{page}"
pattern = r"(?:https?://)?(?:www\.)?hentai2read\.com(/[^/?&#]+/(\d+))" pattern = r"(?:https?://)?(?:www\.)?hentai2read\.com(/[^/?#]+/(\d+))"
test = ("https://hentai2read.com/amazon_elixir/1/", { test = ("https://hentai2read.com/amazon_elixir/1/", {
"url": "964b942cf492b3a129d2fe2608abfc475bc99e71", "url": "964b942cf492b3a129d2fe2608abfc475bc99e71",
"keyword": "ff84b8f751f0e4ee37717efc4332ff1db71951d9", "keyword": "ff84b8f751f0e4ee37717efc4332ff1db71951d9",
@@ -63,7 +63,7 @@ class Hentai2readChapterExtractor(Hentai2readBase, ChapterExtractor):
class Hentai2readMangaExtractor(Hentai2readBase, MangaExtractor): class Hentai2readMangaExtractor(Hentai2readBase, MangaExtractor):
"""Extractor for hmanga from hentai2read.com""" """Extractor for hmanga from hentai2read.com"""
chapterclass = Hentai2readChapterExtractor chapterclass = Hentai2readChapterExtractor
pattern = r"(?:https?://)?(?:www\.)?hentai2read\.com(/[^/?&#]+)/?$" pattern = r"(?:https?://)?(?:www\.)?hentai2read\.com(/[^/?#]+)/?$"
test = ( test = (
("https://hentai2read.com/amazon_elixir/", { ("https://hentai2read.com/amazon_elixir/", {
"url": "273073752d418ec887d7f7211e42b832e8c403ba", "url": "273073752d418ec887d7f7211e42b832e8c403ba",

View File

@@ -20,7 +20,7 @@ class HentaicafeChapterExtractor(foolslide.FoolslideChapterExtractor):
category = "hentaicafe" category = "hentaicafe"
directory_fmt = ("{category}", "{manga}") directory_fmt = ("{category}", "{manga}")
pattern = (r"(?:https?://)?(?:www\.)?hentai\.cafe" pattern = (r"(?:https?://)?(?:www\.)?hentai\.cafe"
r"(/manga/read/[^/?&#]+/[a-z-]+/\d+/\d+(?:/\d+)?)") r"(/manga/read/[^/?#]+/[a-z-]+/\d+/\d+(?:/\d+)?)")
test = ("https://hentai.cafe/manga/read/saitom-box/en/0/1/", { test = ("https://hentai.cafe/manga/read/saitom-box/en/0/1/", {
"url": "8c6a8c56875ba3ed7ab0a74a64f9960077767fc2", "url": "8c6a8c56875ba3ed7ab0a74a64f9960077767fc2",
"keyword": "6913608267d883c82b887303b9ced13821188329", "keyword": "6913608267d883c82b887303b9ced13821188329",
@@ -45,7 +45,7 @@ class HentaicafeMangaExtractor(foolslide.FoolslideMangaExtractor):
"""Extractor for manga from hentai.cafe""" """Extractor for manga from hentai.cafe"""
category = "hentaicafe" category = "hentaicafe"
pattern = (r"(?:https?://)?" + r"(?:www\.)?hentai\.cafe" pattern = (r"(?:https?://)?" + r"(?:www\.)?hentai\.cafe"
r"(/hc\.fyi/\d+|(?:/manga/series)?/[^/?&#]+)/?$") r"(/hc\.fyi/\d+|(?:/manga/series)?/[^/?#]+)/?$")
test = ( test = (
# single chapter # single chapter
("https://hentai.cafe/hazuki-yuuto-summer-blues/", { ("https://hentai.cafe/hazuki-yuuto-summer-blues/", {

View File

@@ -156,7 +156,7 @@ class HentaifoundryExtractor(Extractor):
class HentaifoundryUserExtractor(HentaifoundryExtractor): class HentaifoundryUserExtractor(HentaifoundryExtractor):
"""Extractor for a hentaifoundry user profile""" """Extractor for a hentaifoundry user profile"""
subcategory = "user" subcategory = "user"
pattern = BASE_PATTERN + r"/user/([^/?&#]+)/profile" pattern = BASE_PATTERN + r"/user/([^/?#]+)/profile"
test = ("https://www.hentai-foundry.com/user/Tenpura/profile",) test = ("https://www.hentai-foundry.com/user/Tenpura/profile",)
def items(self): def items(self):
@@ -177,7 +177,7 @@ class HentaifoundryUserExtractor(HentaifoundryExtractor):
class HentaifoundryPicturesExtractor(HentaifoundryExtractor): class HentaifoundryPicturesExtractor(HentaifoundryExtractor):
"""Extractor for all pictures of a hentaifoundry user""" """Extractor for all pictures of a hentaifoundry user"""
subcategory = "pictures" subcategory = "pictures"
pattern = BASE_PATTERN + r"/pictures/user/([^/?&#]+)(?:/page/(\d+))?/?$" pattern = BASE_PATTERN + r"/pictures/user/([^/?#]+)(?:/page/(\d+))?/?$"
test = ( test = (
("https://www.hentai-foundry.com/pictures/user/Tenpura", { ("https://www.hentai-foundry.com/pictures/user/Tenpura", {
"url": "ebbc981a85073745e3ca64a0f2ab31fab967fc28", "url": "ebbc981a85073745e3ca64a0f2ab31fab967fc28",
@@ -194,7 +194,7 @@ class HentaifoundryScrapsExtractor(HentaifoundryExtractor):
"""Extractor for scraps of a hentaifoundry user""" """Extractor for scraps of a hentaifoundry user"""
subcategory = "scraps" subcategory = "scraps"
directory_fmt = ("{category}", "{user}", "Scraps") directory_fmt = ("{category}", "{user}", "Scraps")
pattern = BASE_PATTERN + r"/pictures/user/([^/?&#]+)/scraps" pattern = BASE_PATTERN + r"/pictures/user/([^/?#]+)/scraps"
test = ( test = (
("https://www.hentai-foundry.com/pictures/user/Evulchibi/scraps", { ("https://www.hentai-foundry.com/pictures/user/Evulchibi/scraps", {
"url": "7cd9c6ec6258c4ab8c44991f7731be82337492a7", "url": "7cd9c6ec6258c4ab8c44991f7731be82337492a7",
@@ -214,7 +214,7 @@ class HentaifoundryFavoriteExtractor(HentaifoundryExtractor):
subcategory = "favorite" subcategory = "favorite"
directory_fmt = ("{category}", "{user}", "Favorites") directory_fmt = ("{category}", "{user}", "Favorites")
archive_fmt = "f_{user}_{index}" archive_fmt = "f_{user}_{index}"
pattern = BASE_PATTERN + r"/user/([^/?&#]+)/faves/pictures" pattern = BASE_PATTERN + r"/user/([^/?#]+)/faves/pictures"
test = ( test = (
("https://www.hentai-foundry.com/user/Tenpura/faves/pictures", { ("https://www.hentai-foundry.com/user/Tenpura/faves/pictures", {
"url": "56f9ae2e89fe855e9fe1da9b81e5ec6212b0320b", "url": "56f9ae2e89fe855e9fe1da9b81e5ec6212b0320b",
@@ -236,7 +236,7 @@ class HentaifoundryRecentExtractor(HentaifoundryExtractor):
archive_fmt = "r_{index}" archive_fmt = "r_{index}"
pattern = BASE_PATTERN + r"/pictures/recent/(\d\d\d\d-\d\d-\d\d)" pattern = BASE_PATTERN + r"/pictures/recent/(\d\d\d\d-\d\d-\d\d)"
test = ("http://www.hentai-foundry.com/pictures/recent/2018-09-20", { test = ("http://www.hentai-foundry.com/pictures/recent/2018-09-20", {
"pattern": r"https://pictures.hentai-foundry.com/[^/]/[^/?&#]+/\d+/", "pattern": r"https://pictures.hentai-foundry.com/[^/]/[^/?#]+/\d+/",
"range": "20-30", "range": "20-30",
}) })
@@ -255,7 +255,7 @@ class HentaifoundryPopularExtractor(HentaifoundryExtractor):
archive_fmt = "p_{index}" archive_fmt = "p_{index}"
pattern = BASE_PATTERN + r"/pictures/popular()" pattern = BASE_PATTERN + r"/pictures/popular()"
test = ("http://www.hentai-foundry.com/pictures/popular", { test = ("http://www.hentai-foundry.com/pictures/popular", {
"pattern": r"https://pictures.hentai-foundry.com/[^/]/[^/?&#]+/\d+/", "pattern": r"https://pictures.hentai-foundry.com/[^/]/[^/?#]+/\d+/",
"range": "20-30", "range": "20-30",
}) })
@@ -268,7 +268,7 @@ class HentaifoundryImageExtractor(HentaifoundryExtractor):
"""Extractor for a single image from hentaifoundry.com""" """Extractor for a single image from hentaifoundry.com"""
subcategory = "image" subcategory = "image"
pattern = (r"(?:https?://)?(?:www\.|pictures\.)?hentai-foundry\.com" pattern = (r"(?:https?://)?(?:www\.|pictures\.)?hentai-foundry\.com"
r"/(?:pictures/user|[^/?&#])/([^/?&#]+)/(\d+)") r"/(?:pictures/user|[^/?#])/([^/?#]+)/(\d+)")
test = ( test = (
(("https://www.hentai-foundry.com" (("https://www.hentai-foundry.com"
"/pictures/user/Tenpura/407501/shimakaze"), { "/pictures/user/Tenpura/407501/shimakaze"), {
@@ -313,7 +313,7 @@ class HentaifoundryStoriesExtractor(HentaifoundryExtractor):
"""Extractor for stories of a hentaifoundry user""" """Extractor for stories of a hentaifoundry user"""
subcategory = "stories" subcategory = "stories"
archive_fmt = "s_{index}" archive_fmt = "s_{index}"
pattern = BASE_PATTERN + r"/stories/user/([^/?&#]+)(?:/page/(\d+))?/?$" pattern = BASE_PATTERN + r"/stories/user/([^/?#]+)(?:/page/(\d+))?/?$"
test = ("https://www.hentai-foundry.com/stories/user/SnowWolf35", { test = ("https://www.hentai-foundry.com/stories/user/SnowWolf35", {
"count": ">= 35", "count": ">= 35",
"keyword": { "keyword": {
@@ -349,7 +349,7 @@ class HentaifoundryStoryExtractor(HentaifoundryExtractor):
"""Extractor for a hentaifoundry story""" """Extractor for a hentaifoundry story"""
subcategory = "story" subcategory = "story"
archive_fmt = "s_{index}" archive_fmt = "s_{index}"
pattern = BASE_PATTERN + r"/stories/user/([^/?&#]+)/(\d+)" pattern = BASE_PATTERN + r"/stories/user/([^/?#]+)/(\d+)"
test = (("https://www.hentai-foundry.com/stories/user/SnowWolf35" test = (("https://www.hentai-foundry.com/stories/user/SnowWolf35"
"/26416/Overwatch-High-Chapter-Voting-Location"), { "/26416/Overwatch-High-Chapter-Voting-Location"), {
"url": "5a67cfa8c3bf7634c8af8485dd07c1ea74ee0ae8", "url": "5a67cfa8c3bf7634c8af8485dd07c1ea74ee0ae8",

View File

@@ -74,7 +74,7 @@ class HentaihandTagExtractor(Extractor):
root = "https://hentaihand.com" root = "https://hentaihand.com"
pattern = (r"(?i)(?:https?://)?(?:www\.)?hentaihand\.com" pattern = (r"(?i)(?:https?://)?(?:www\.)?hentaihand\.com"
r"/\w+/(parody|character|tag|artist|group|language" r"/\w+/(parody|character|tag|artist|group|language"
r"|category|relationship)/([^/?&#]+)") r"|category|relationship)/([^/?#]+)")
test = ( test = (
("https://hentaihand.com/en/artist/himuro", { ("https://hentaihand.com/en/artist/himuro", {
"pattern": HentaihandGalleryExtractor.pattern, "pattern": HentaihandGalleryExtractor.pattern,

View File

@@ -64,7 +64,7 @@ class HiperdexBase():
class HiperdexChapterExtractor(HiperdexBase, ChapterExtractor): class HiperdexChapterExtractor(HiperdexBase, ChapterExtractor):
"""Extractor for manga chapters from hiperdex.com""" """Extractor for manga chapters from hiperdex.com"""
pattern = BASE_PATTERN + r"(/manga/([^/?&#]+)/([^/?&#]+))" pattern = BASE_PATTERN + r"(/manga/([^/?#]+)/([^/?#]+))"
test = ( test = (
("https://hiperdex.com/manga/domestic-na-kanojo/154-5/", { ("https://hiperdex.com/manga/domestic-na-kanojo/154-5/", {
"pattern": r"https://hiperdex.(com|net|info)/wp-content/uploads" "pattern": r"https://hiperdex.(com|net|info)/wp-content/uploads"
@@ -105,7 +105,7 @@ class HiperdexChapterExtractor(HiperdexBase, ChapterExtractor):
class HiperdexMangaExtractor(HiperdexBase, MangaExtractor): class HiperdexMangaExtractor(HiperdexBase, MangaExtractor):
"""Extractor for manga from hiperdex.com""" """Extractor for manga from hiperdex.com"""
chapterclass = HiperdexChapterExtractor chapterclass = HiperdexChapterExtractor
pattern = BASE_PATTERN + r"(/manga/([^/?&#]+))/?$" pattern = BASE_PATTERN + r"(/manga/([^/?#]+))/?$"
test = ( test = (
("https://hiperdex.com/manga/youre-not-that-special/", { ("https://hiperdex.com/manga/youre-not-that-special/", {
"count": 51, "count": 51,
@@ -157,7 +157,7 @@ class HiperdexArtistExtractor(HiperdexBase, MangaExtractor):
categorytransfer = False categorytransfer = False
chapterclass = HiperdexMangaExtractor chapterclass = HiperdexMangaExtractor
reverse = False reverse = False
pattern = BASE_PATTERN + r"(/manga-a(?:rtist|uthor)/([^/?&#]+))" pattern = BASE_PATTERN + r"(/manga-a(?:rtist|uthor)/([^/?#]+))"
test = ( test = (
("https://hiperdex.com/manga-artist/beck-ho-an/"), ("https://hiperdex.com/manga-artist/beck-ho-an/"),
("https://hiperdex.net/manga-artist/beck-ho-an/"), ("https://hiperdex.net/manga-artist/beck-ho-an/"),

View File

@@ -158,7 +158,7 @@ class HitomiTagExtractor(Extractor):
subcategory = "tag" subcategory = "tag"
pattern = (r"(?:https?://)?hitomi\.la/" pattern = (r"(?:https?://)?hitomi\.la/"
r"(tag|artist|group|series|type|character)/" r"(tag|artist|group|series|type|character)/"
r"([^/?&#]+)\.html") r"([^/?#]+)\.html")
test = ( test = (
("https://hitomi.la/tag/screenshots-japanese.html", { ("https://hitomi.la/tag/screenshots-japanese.html", {
"pattern": HitomiGalleryExtractor.pattern, "pattern": HitomiGalleryExtractor.pattern,

View File

@@ -151,7 +151,7 @@ class ImagefapUserExtractor(ImagefapExtractor):
subcategory = "user" subcategory = "user"
categorytransfer = True categorytransfer = True
pattern = (BASE_PATTERN + pattern = (BASE_PATTERN +
r"/(?:profile(?:\.php\?user=|/)([^/?&#]+)" r"/(?:profile(?:\.php\?user=|/)([^/?#]+)"
r"|usergallery\.php\?userid=(\d+))") r"|usergallery\.php\?userid=(\d+))")
test = ( test = (
("https://www.imagefap.com/profile/LucyRae/galleries", { ("https://www.imagefap.com/profile/LucyRae/galleries", {

View File

@@ -176,7 +176,7 @@ class ImagetwistImageExtractor(ImagehostImageExtractor):
class ImgspiceImageExtractor(ImagehostImageExtractor): class ImgspiceImageExtractor(ImagehostImageExtractor):
"""Extractor for single images from imgspice.com""" """Extractor for single images from imgspice.com"""
category = "imgspice" category = "imgspice"
pattern = r"(?:https?://)?((?:www\.)?imgspice\.com/([^/?&#]+))" pattern = r"(?:https?://)?((?:www\.)?imgspice\.com/([^/?#]+))"
test = ("https://imgspice.com/nwfwtpyog50y/test.png.html", { test = ("https://imgspice.com/nwfwtpyog50y/test.png.html", {
"url": "b8c30a8f51ee1012959a4cfd46197fabf14de984", "url": "b8c30a8f51ee1012959a4cfd46197fabf14de984",
"keyword": "100e310a19a2fa22d87e1bbc427ecb9f6501e0c0", "keyword": "100e310a19a2fa22d87e1bbc427ecb9f6501e0c0",
@@ -198,7 +198,7 @@ class PixhostImageExtractor(ImagehostImageExtractor):
"""Extractor for single images from pixhost.to""" """Extractor for single images from pixhost.to"""
category = "pixhost" category = "pixhost"
pattern = (r"(?:https?://)?((?:www\.)?pixhost\.(?:to|org)" pattern = (r"(?:https?://)?((?:www\.)?pixhost\.(?:to|org)"
r"/show/\d+/(\d+)_[^/?&#]+)") r"/show/\d+/(\d+)_[^/?#]+)")
test = ("http://pixhost.to/show/190/130327671_test-.png", { test = ("http://pixhost.to/show/190/130327671_test-.png", {
"url": "4e5470dcf6513944773044d40d883221bbc46cff", "url": "4e5470dcf6513944773044d40d883221bbc46cff",
"keyword": "3bad6d59db42a5ebbd7842c2307e1c3ebd35e6b0", "keyword": "3bad6d59db42a5ebbd7842c2307e1c3ebd35e6b0",
@@ -218,7 +218,7 @@ class PostimgImageExtractor(ImagehostImageExtractor):
"""Extractor for single images from postimages.org""" """Extractor for single images from postimages.org"""
category = "postimg" category = "postimg"
pattern = (r"(?:https?://)?((?:www\.)?(?:postimg|pixxxels)\.(?:cc|org)" pattern = (r"(?:https?://)?((?:www\.)?(?:postimg|pixxxels)\.(?:cc|org)"
r"/(?:image/)?([^/?&#]+)/?)") r"/(?:image/)?([^/?#]+)/?)")
test = ("https://postimg.cc/Wtn2b3hC", { test = ("https://postimg.cc/Wtn2b3hC", {
"url": "0794cfda9b8951a8ac3aa692472484200254ab86", "url": "0794cfda9b8951a8ac3aa692472484200254ab86",
"keyword": "2d05808d04e4e83e33200db83521af06e3147a84", "keyword": "2d05808d04e4e83e33200db83521af06e3147a84",
@@ -237,7 +237,7 @@ class TurboimagehostImageExtractor(ImagehostImageExtractor):
"""Extractor for single images from www.turboimagehost.com""" """Extractor for single images from www.turboimagehost.com"""
category = "turboimagehost" category = "turboimagehost"
pattern = (r"(?:https?://)?((?:www\.)?turboimagehost\.com" pattern = (r"(?:https?://)?((?:www\.)?turboimagehost\.com"
r"/p/(\d+)/[^/?&#]+\.html)") r"/p/(\d+)/[^/?#]+\.html)")
test = ("https://www.turboimagehost.com/p/39078423/test--.png.html", { test = ("https://www.turboimagehost.com/p/39078423/test--.png.html", {
"url": "b94de43612318771ced924cb5085976f13b3b90e", "url": "b94de43612318771ced924cb5085976f13b3b90e",
"keyword": "704757ca8825f51cec516ec44c1e627c1f2058ca", "keyword": "704757ca8825f51cec516ec44c1e627c1f2058ca",

View File

@@ -115,7 +115,7 @@ class ImgbbAlbumExtractor(ImgbbExtractor):
"""Extractor for albums on imgbb.com""" """Extractor for albums on imgbb.com"""
subcategory = "album" subcategory = "album"
directory_fmt = ("{category}", "{user}", "{album_name} {album_id}") directory_fmt = ("{category}", "{user}", "{album_name} {album_id}")
pattern = r"(?:https?://)?ibb\.co/album/([^/?&#]+)/?(?:\?([^#]+))?" pattern = r"(?:https?://)?ibb\.co/album/([^/?#]+)/?(?:\?([^#]+))?"
test = ( test = (
("https://ibb.co/album/i5PggF", { ("https://ibb.co/album/i5PggF", {
"range": "1-80", "range": "1-80",
@@ -173,7 +173,7 @@ class ImgbbUserExtractor(ImgbbExtractor):
pattern = r"(?:https?://)?([^.]+)\.imgbb\.com/?(?:\?([^#]+))?$" pattern = r"(?:https?://)?([^.]+)\.imgbb\.com/?(?:\?([^#]+))?$"
test = ("https://folkie.imgbb.com", { test = ("https://folkie.imgbb.com", {
"range": "1-80", "range": "1-80",
"pattern": r"https?://i\.ibb\.co/\w+/[^/?&#]+", "pattern": r"https?://i\.ibb\.co/\w+/[^/?#]+",
}) })
def __init__(self, match): def __init__(self, match):
@@ -197,7 +197,7 @@ class ImgbbUserExtractor(ImgbbExtractor):
class ImgbbImageExtractor(ImgbbExtractor): class ImgbbImageExtractor(ImgbbExtractor):
subcategory = "image" subcategory = "image"
pattern = r"(?:https?://)?ibb\.co/(?!album/)([^/?&#]+)" pattern = r"(?:https?://)?ibb\.co/(?!album/)([^/?#]+)"
test = ("https://ibb.co/fUqh5b", { test = ("https://ibb.co/fUqh5b", {
"pattern": r"https://i\.ibb\.co/g3kvx80/Arundel-Ireeman-5\.jpg", "pattern": r"https://i\.ibb\.co/g3kvx80/Arundel-Ireeman-5\.jpg",
"content": "c5a0965178a8b357acd8aa39660092918c63795e", "content": "c5a0965178a8b357acd8aa39660092918c63795e",

View File

@@ -259,7 +259,7 @@ class ImgurGalleryExtractor(ImgurExtractor):
class ImgurUserExtractor(ImgurExtractor): class ImgurUserExtractor(ImgurExtractor):
"""Extractor for all images posted by a user""" """Extractor for all images posted by a user"""
subcategory = "user" subcategory = "user"
pattern = BASE_PATTERN + r"/user/([^/?&#]+)(?:/posts|/submitted)?/?$" pattern = BASE_PATTERN + r"/user/([^/?#]+)(?:/posts|/submitted)?/?$"
test = ( test = (
("https://imgur.com/user/Miguenzo", { ("https://imgur.com/user/Miguenzo", {
"range": "1-100", "range": "1-100",
@@ -277,7 +277,7 @@ class ImgurUserExtractor(ImgurExtractor):
class ImgurFavoriteExtractor(ImgurExtractor): class ImgurFavoriteExtractor(ImgurExtractor):
"""Extractor for a user's favorites""" """Extractor for a user's favorites"""
subcategory = "favorite" subcategory = "favorite"
pattern = BASE_PATTERN + r"/user/([^/?&#]+)/favorites" pattern = BASE_PATTERN + r"/user/([^/?#]+)/favorites"
test = ("https://imgur.com/user/Miguenzo/favorites", { test = ("https://imgur.com/user/Miguenzo/favorites", {
"range": "1-100", "range": "1-100",
"count": 100, "count": 100,
@@ -291,7 +291,7 @@ class ImgurFavoriteExtractor(ImgurExtractor):
class ImgurSubredditExtractor(ImgurExtractor): class ImgurSubredditExtractor(ImgurExtractor):
"""Extractor for a subreddits's imgur links""" """Extractor for a subreddits's imgur links"""
subcategory = "subreddit" subcategory = "subreddit"
pattern = BASE_PATTERN + r"/r/([^/?&#]+)" pattern = BASE_PATTERN + r"/r/([^/?#]+)"
test = ("https://imgur.com/r/pics", { test = ("https://imgur.com/r/pics", {
"range": "1-100", "range": "1-100",
"count": 100, "count": 100,
@@ -305,7 +305,7 @@ class ImgurSubredditExtractor(ImgurExtractor):
class ImgurTagExtractor(ImgurExtractor): class ImgurTagExtractor(ImgurExtractor):
"""Extractor for imgur tag searches""" """Extractor for imgur tag searches"""
subcategory = "tag" subcategory = "tag"
pattern = BASE_PATTERN + r"/t/([^/?&#]+)$" pattern = BASE_PATTERN + r"/t/([^/?#]+)$"
test = ("https://imgur.com/t/animals", { test = ("https://imgur.com/t/animals", {
"range": "1-100", "range": "1-100",
"count": 100, "count": 100,
@@ -319,7 +319,7 @@ class ImgurTagExtractor(ImgurExtractor):
class ImgurSearchExtractor(ImgurExtractor): class ImgurSearchExtractor(ImgurExtractor):
"""Extractor for imgur search results""" """Extractor for imgur search results"""
subcategory = "search" subcategory = "search"
pattern = BASE_PATTERN + r"/search(?:/[^?&#]+)?/?\?q=([^&#]+)" pattern = BASE_PATTERN + r"/search(?:/[^?#]+)?/?\?q=([^&#]+)"
test = ("https://imgur.com/search?q=cute+cat", { test = ("https://imgur.com/search?q=cute+cat", {
"range": "1-100", "range": "1-100",
"count": 100, "count": 100,

View File

@@ -60,7 +60,7 @@ class InkbunnyExtractor(Extractor):
class InkbunnyUserExtractor(InkbunnyExtractor): class InkbunnyUserExtractor(InkbunnyExtractor):
"""Extractor for inkbunny user profiles""" """Extractor for inkbunny user profiles"""
subcategory = "user" subcategory = "user"
pattern = BASE_PATTERN + r"/(?!s/)(gallery/|scraps/)?([^/?&#]+)" pattern = BASE_PATTERN + r"/(?!s/)(gallery/|scraps/)?([^/?#]+)"
test = ( test = (
("https://inkbunny.net/soina", { ("https://inkbunny.net/soina", {
"pattern": r"https://[\w.]+\.metapix\.net/files/full" "pattern": r"https://[\w.]+\.metapix\.net/files/full"

View File

@@ -343,7 +343,7 @@ class InstagramImageExtractor(InstagramExtractor):
"""Extractor for PostPage""" """Extractor for PostPage"""
subcategory = "image" subcategory = "image"
pattern = (r"(?:https?://)?(?:www\.)?instagram\.com" pattern = (r"(?:https?://)?(?:www\.)?instagram\.com"
r"/(?:p|tv|reel)/([^/?&#]+)") r"/(?:p|tv|reel)/([^/?#]+)")
test = ( test = (
# GraphImage # GraphImage
("https://www.instagram.com/p/BqvsDleB3lV/", { ("https://www.instagram.com/p/BqvsDleB3lV/", {
@@ -458,7 +458,7 @@ class InstagramStoriesExtractor(InstagramExtractor):
"""Extractor for StoriesPage""" """Extractor for StoriesPage"""
subcategory = "stories" subcategory = "stories"
pattern = (r"(?:https?://)?(?:www\.)?instagram\.com" pattern = (r"(?:https?://)?(?:www\.)?instagram\.com"
r"/stories/([^/?&#]+)(?:/(\d+))?") r"/stories/([^/?#]+)(?:/(\d+))?")
test = ( test = (
("https://www.instagram.com/stories/instagram/"), ("https://www.instagram.com/stories/instagram/"),
("https://www.instagram.com/stories/highlights/18042509488170095/"), ("https://www.instagram.com/stories/highlights/18042509488170095/"),
@@ -478,7 +478,7 @@ class InstagramSavedExtractor(InstagramExtractor):
subcategory = "saved" subcategory = "saved"
pattern = (r"(?:https?://)?(?:www\.)?instagram\.com" pattern = (r"(?:https?://)?(?:www\.)?instagram\.com"
r"/(?!p/|explore/|directory/|accounts/|stories/|tv/)" r"/(?!p/|explore/|directory/|accounts/|stories/|tv/)"
r"([^/?&#]+)/saved") r"([^/?#]+)/saved")
test = ("https://www.instagram.com/instagram/saved/",) test = ("https://www.instagram.com/instagram/saved/",)
def __init__(self, match): def __init__(self, match):
@@ -504,7 +504,7 @@ class InstagramUserExtractor(InstagramExtractor):
subcategory = "user" subcategory = "user"
pattern = (r"(?:https?://)?(?:www\.)?instagram\.com" pattern = (r"(?:https?://)?(?:www\.)?instagram\.com"
r"/(?!(?:p|explore|directory|accounts|stories|tv|reel)/)" r"/(?!(?:p|explore|directory|accounts|stories|tv|reel)/)"
r"([^/?&#]+)/?(?:$|[?#])") r"([^/?#]+)/?(?:$|[?#])")
test = ( test = (
("https://www.instagram.com/instagram/", { ("https://www.instagram.com/instagram/", {
"range": "1-16", "range": "1-16",
@@ -550,7 +550,7 @@ class InstagramChannelExtractor(InstagramExtractor):
subcategory = "channel" subcategory = "channel"
pattern = (r"(?:https?://)?(?:www\.)?instagram\.com" pattern = (r"(?:https?://)?(?:www\.)?instagram\.com"
r"/(?!p/|explore/|directory/|accounts/|stories/|tv/)" r"/(?!p/|explore/|directory/|accounts/|stories/|tv/)"
r"([^/?&#]+)/channel") r"([^/?#]+)/channel")
test = ("https://www.instagram.com/instagram/channel/", { test = ("https://www.instagram.com/instagram/channel/", {
"range": "1-16", "range": "1-16",
"count": ">= 16", "count": ">= 16",
@@ -579,7 +579,7 @@ class InstagramTagExtractor(InstagramExtractor):
subcategory = "tag" subcategory = "tag"
directory_fmt = ("{category}", "{subcategory}", "{tag}") directory_fmt = ("{category}", "{subcategory}", "{tag}")
pattern = (r"(?:https?://)?(?:www\.)?instagram\.com" pattern = (r"(?:https?://)?(?:www\.)?instagram\.com"
r"/explore/tags/([^/?&#]+)") r"/explore/tags/([^/?#]+)")
test = ("https://www.instagram.com/explore/tags/instagram/", { test = ("https://www.instagram.com/explore/tags/instagram/", {
"range": "1-16", "range": "1-16",
"count": ">= 16", "count": ">= 16",

View File

@@ -26,7 +26,7 @@ class IssuuPublicationExtractor(IssuuBase, GalleryExtractor):
"{document[originalPublishDate]} {document[title]}") "{document[originalPublishDate]} {document[title]}")
filename_fmt = "{num:>03}.{extension}" filename_fmt = "{num:>03}.{extension}"
archive_fmt = "{document[id]}_{num}" archive_fmt = "{document[id]}_{num}"
pattern = r"(?:https?://)?issuu\.com(/[^/?&#]+/docs/[^/?&#]+)" pattern = r"(?:https?://)?issuu\.com(/[^/?#]+/docs/[^/?#]+)"
test = ("https://issuu.com/issuu/docs/motions-1-2019/", { test = ("https://issuu.com/issuu/docs/motions-1-2019/", {
"pattern": r"https://image.isu.pub/190916155301-\w+/jpg/page_\d+.jpg", "pattern": r"https://image.isu.pub/190916155301-\w+/jpg/page_\d+.jpg",
"count" : 36, "count" : 36,
@@ -80,7 +80,7 @@ class IssuuPublicationExtractor(IssuuBase, GalleryExtractor):
class IssuuUserExtractor(IssuuBase, Extractor): class IssuuUserExtractor(IssuuBase, Extractor):
"""Extractor for all publications of a user/publisher""" """Extractor for all publications of a user/publisher"""
subcategory = "user" subcategory = "user"
pattern = r"(?:https?://)?issuu\.com/([^/?&#]+)/?$" pattern = r"(?:https?://)?issuu\.com/([^/?#]+)/?$"
test = ("https://issuu.com/issuu", { test = ("https://issuu.com/issuu", {
"pattern": IssuuPublicationExtractor.pattern, "pattern": IssuuPublicationExtractor.pattern,
"count" : "> 25", "count" : "> 25",

View File

@@ -19,7 +19,7 @@ class KhinsiderSoundtrackExtractor(AsynchronousMixin, Extractor):
directory_fmt = ("{category}", "{album[name]}") directory_fmt = ("{category}", "{album[name]}")
archive_fmt = "{filename}.{extension}" archive_fmt = "{filename}.{extension}"
pattern = (r"(?:https?://)?downloads\.khinsider\.com" pattern = (r"(?:https?://)?downloads\.khinsider\.com"
r"/game-soundtracks/album/([^/?&#]+)") r"/game-soundtracks/album/([^/?#]+)")
root = "https://downloads.khinsider.com" root = "https://downloads.khinsider.com"
test = (("https://downloads.khinsider.com" test = (("https://downloads.khinsider.com"
"/game-soundtracks/album/horizon-riders-wii"), { "/game-soundtracks/album/horizon-riders-wii"), {

View File

@@ -45,7 +45,7 @@ class KomikcastBase():
class KomikcastChapterExtractor(KomikcastBase, ChapterExtractor): class KomikcastChapterExtractor(KomikcastBase, ChapterExtractor):
"""Extractor for manga-chapters from komikcast.com""" """Extractor for manga-chapters from komikcast.com"""
pattern = r"(?:https?://)?(?:www\.)?komikcast\.com(/chapter/[^/?&#]+/)" pattern = r"(?:https?://)?(?:www\.)?komikcast\.com(/chapter/[^/?#]+/)"
test = ( test = (
(("https://komikcast.com/chapter/" (("https://komikcast.com/chapter/"
"apotheosis-chapter-02-2-bahasa-indonesia/"), { "apotheosis-chapter-02-2-bahasa-indonesia/"), {
@@ -81,7 +81,7 @@ class KomikcastMangaExtractor(KomikcastBase, MangaExtractor):
"""Extractor for manga from komikcast.com""" """Extractor for manga from komikcast.com"""
chapterclass = KomikcastChapterExtractor chapterclass = KomikcastChapterExtractor
pattern = (r"(?:https?://)?(?:www\.)?komikcast\.com" pattern = (r"(?:https?://)?(?:www\.)?komikcast\.com"
r"(/(?:komik/)?[^/?&#]+)/?$") r"(/(?:komik/)?[^/?#]+)/?$")
test = ( test = (
("https://komikcast.com/komik/090-eko-to-issho/", { ("https://komikcast.com/komik/090-eko-to-issho/", {
"url": "dc798d107697d1f2309b14ca24ca9dba30c6600f", "url": "dc798d107697d1f2309b14ca24ca9dba30c6600f",

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright 2019 Mike Fährmann # Copyright 2019-2020 Mike Fährmann
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as # it under the terms of the GNU General Public License version 2 as
@@ -42,7 +42,7 @@ class LineblogBase():
class LineblogBlogExtractor(LineblogBase, LivedoorBlogExtractor): class LineblogBlogExtractor(LineblogBase, LivedoorBlogExtractor):
"""Extractor for a user's blog on lineblog.me""" """Extractor for a user's blog on lineblog.me"""
pattern = r"(?:https?://)?lineblog\.me/(\w+)/?(?:$|[?&#])" pattern = r"(?:https?://)?lineblog\.me/(\w+)/?(?:$|[?#])"
test = ("https://lineblog.me/mamoru_miyano/", { test = ("https://lineblog.me/mamoru_miyano/", {
"range": "1-20", "range": "1-20",
"count": 20, "count": 20,

View File

@@ -84,7 +84,7 @@ class LivedoorExtractor(Extractor):
class LivedoorBlogExtractor(LivedoorExtractor): class LivedoorBlogExtractor(LivedoorExtractor):
"""Extractor for a user's blog on blog.livedoor.jp""" """Extractor for a user's blog on blog.livedoor.jp"""
subcategory = "blog" subcategory = "blog"
pattern = r"(?:https?://)?blog\.livedoor\.jp/(\w+)/?(?:$|[?&#])" pattern = r"(?:https?://)?blog\.livedoor\.jp/(\w+)/?(?:$|[?#])"
test = ( test = (
("http://blog.livedoor.jp/zatsu_ke/", { ("http://blog.livedoor.jp/zatsu_ke/", {
"range": "1-50", "range": "1-50",

View File

@@ -46,7 +46,7 @@ class LusciousAlbumExtractor(LusciousExtractor):
directory_fmt = ("{category}", "{album[id]} {album[title]}") directory_fmt = ("{category}", "{album[id]} {album[title]}")
archive_fmt = "{album[id]}_{id}" archive_fmt = "{album[id]}_{id}"
pattern = (r"(?:https?://)?(?:www\.|members\.)?luscious\.net" pattern = (r"(?:https?://)?(?:www\.|members\.)?luscious\.net"
r"/(?:albums|pictures/c/[^/?&#]+/album)/[^/?&#]+_(\d+)") r"/(?:albums|pictures/c/[^/?#]+/album)/[^/?#]+_(\d+)")
test = ( test = (
("https://luscious.net/albums/okinami-no-koigokoro_277031/", { ("https://luscious.net/albums/okinami-no-koigokoro_277031/", {
"url": "7e4984a271a1072ac6483e4228a045895aff86f3", "url": "7e4984a271a1072ac6483e4228a045895aff86f3",

View File

@@ -16,7 +16,7 @@ class MangafoxChapterExtractor(ChapterExtractor):
"""Extractor for manga-chapters from fanfox.net""" """Extractor for manga-chapters from fanfox.net"""
category = "mangafox" category = "mangafox"
pattern = (r"(?:https?://)?(?:www\.|m\.)?(?:mangafox\.me|fanfox\.net)" pattern = (r"(?:https?://)?(?:www\.|m\.)?(?:mangafox\.me|fanfox\.net)"
r"(/manga/[^/]+/((?:v(\d+)/)?c(\d+)([^/?&#]*)))") r"(/manga/[^/]+/((?:v(\d+)/)?c(\d+)([^/?#]*)))")
test = ( test = (
("http://fanfox.net/manga/kidou_keisatsu_patlabor/v05/c006.2/1.html", { ("http://fanfox.net/manga/kidou_keisatsu_patlabor/v05/c006.2/1.html", {
"keyword": "5661dab258d42d09d98f194f7172fb9851a49766", "keyword": "5661dab258d42d09d98f194f7172fb9851a49766",

View File

@@ -24,7 +24,7 @@ class MangahereBase():
class MangahereChapterExtractor(MangahereBase, ChapterExtractor): class MangahereChapterExtractor(MangahereBase, ChapterExtractor):
"""Extractor for manga-chapters from mangahere.cc""" """Extractor for manga-chapters from mangahere.cc"""
pattern = (r"(?:https?://)?(?:www\.|m\.)?mangahere\.c[co]/manga/" pattern = (r"(?:https?://)?(?:www\.|m\.)?mangahere\.c[co]/manga/"
r"([^/]+(?:/v0*(\d+))?/c([^/?&#]+))") r"([^/]+(?:/v0*(\d+))?/c([^/?#]+))")
test = ( test = (
("https://www.mangahere.cc/manga/dongguo_xiaojie/c004.2/", { ("https://www.mangahere.cc/manga/dongguo_xiaojie/c004.2/", {
"keyword": "7c98d7b50a47e6757b089aa875a53aa970cac66f", "keyword": "7c98d7b50a47e6757b089aa875a53aa970cac66f",

View File

@@ -32,7 +32,7 @@ class MangakakalotBase():
class MangakakalotChapterExtractor(MangakakalotBase, ChapterExtractor): class MangakakalotChapterExtractor(MangakakalotBase, ChapterExtractor):
"""Extractor for manga-chapters from mangakakalot.com""" """Extractor for manga-chapters from mangakakalot.com"""
pattern = (r"(?:https?://)?(?:www\.)?mangakakalot\.com" pattern = (r"(?:https?://)?(?:www\.)?mangakakalot\.com"
r"(/chapter/\w+/chapter_[^/?&#]+)") r"(/chapter/\w+/chapter_[^/?#]+)")
test = ( test = (
("https://mangakakalot.com/chapter/rx922077/chapter_6", { ("https://mangakakalot.com/chapter/rx922077/chapter_6", {
"pattern": r"https://s\d+\.\w+\.com/mangakakalot/r\d+/rx922077/" "pattern": r"https://s\d+\.\w+\.com/mangakakalot/r\d+/rx922077/"

View File

@@ -35,7 +35,7 @@ class MangapandaBase():
class MangapandaChapterExtractor(MangapandaBase, ChapterExtractor): class MangapandaChapterExtractor(MangapandaBase, ChapterExtractor):
"""Extractor for manga-chapters from mangapanda.com""" """Extractor for manga-chapters from mangapanda.com"""
archive_fmt = "{manga}_{chapter}_{page}" archive_fmt = "{manga}_{chapter}_{page}"
pattern = r"(?:https?://)?(?:www\.)?mangapanda\.com((/[^/?&#]+)/(\d+))" pattern = r"(?:https?://)?(?:www\.)?mangapanda\.com((/[^/?#]+)/(\d+))"
test = ("https://www.mangapanda.com/red-storm/2", { test = ("https://www.mangapanda.com/red-storm/2", {
"url": "1f633f776e950531ba9b1e81965316458e785261", "url": "1f633f776e950531ba9b1e81965316458e785261",
"keyword": "b24df4b9cc36383fb6a44e06d32a3884a4dcb5fb", "keyword": "b24df4b9cc36383fb6a44e06d32a3884a4dcb5fb",
@@ -96,7 +96,7 @@ class MangapandaMangaExtractor(MangapandaBase, MangaExtractor):
"""Extractor for manga from mangapanda.com""" """Extractor for manga from mangapanda.com"""
chapterclass = MangapandaChapterExtractor chapterclass = MangapandaChapterExtractor
reverse = False reverse = False
pattern = r"(?:https?://)?(?:www\.)?mangapanda\.com(/[^/?&#]+)/?$" pattern = r"(?:https?://)?(?:www\.)?mangapanda\.com(/[^/?#]+)/?$"
test = ("https://www.mangapanda.com/mushishi", { test = ("https://www.mangapanda.com/mushishi", {
"url": "357f965732371cac1990fee8b480f62e29141a42", "url": "357f965732371cac1990fee8b480f62e29141a42",
"keyword": "031b3ea085921c552de017ecbb9b906e462229c9", "keyword": "031b3ea085921c552de017ecbb9b906e462229c9",

View File

@@ -51,7 +51,7 @@ class MangaparkBase():
class MangaparkChapterExtractor(MangaparkBase, ChapterExtractor): class MangaparkChapterExtractor(MangaparkBase, ChapterExtractor):
"""Extractor for manga-chapters from mangapark.net""" """Extractor for manga-chapters from mangapark.net"""
pattern = (r"(?:https?://)?(?:www\.)?mangapark\.(me|net|com)" pattern = (r"(?:https?://)?(?:www\.)?mangapark\.(me|net|com)"
r"/manga/([^?&#]+/i\d+)") r"/manga/([^?#]+/i\d+)")
test = ( test = (
("https://mangapark.net/manga/gosu/i811653/c055/1", { ("https://mangapark.net/manga/gosu/i811653/c055/1", {
"count": 50, "count": 50,
@@ -117,7 +117,7 @@ class MangaparkMangaExtractor(MangaparkBase, MangaExtractor):
"""Extractor for manga from mangapark.net""" """Extractor for manga from mangapark.net"""
chapterclass = MangaparkChapterExtractor chapterclass = MangaparkChapterExtractor
pattern = (r"(?:https?://)?(?:www\.)?mangapark\.(me|net|com)" pattern = (r"(?:https?://)?(?:www\.)?mangapark\.(me|net|com)"
r"(/manga/[^/?&#]+)/?$") r"(/manga/[^/?#]+)/?$")
test = ( test = (
("https://mangapark.net/manga/aria", { ("https://mangapark.net/manga/aria", {
"url": "9b62883c25c8de471f8ab43651e1448536c4ce3f", "url": "9b62883c25c8de471f8ab43651e1448536c4ce3f",

View File

@@ -53,7 +53,7 @@ class MangareaderBase():
class MangareaderChapterExtractor(MangareaderBase, ChapterExtractor): class MangareaderChapterExtractor(MangareaderBase, ChapterExtractor):
"""Extractor for manga-chapters from mangareader.net""" """Extractor for manga-chapters from mangareader.net"""
archive_fmt = "{manga}_{chapter}_{page}" archive_fmt = "{manga}_{chapter}_{page}"
pattern = r"(?:https?://)?(?:www\.)?mangareader\.net((/[^/?&#]+)/(\d+))" pattern = r"(?:https?://)?(?:www\.)?mangareader\.net((/[^/?#]+)/(\d+))"
test = (("https://www.mangareader.net" test = (("https://www.mangareader.net"
"/karate-shoukoushi-kohinata-minoru/11"), { "/karate-shoukoushi-kohinata-minoru/11"), {
"url": "45ece5668d1e9f65cf2225237d78de58660b54e4", "url": "45ece5668d1e9f65cf2225237d78de58660b54e4",
@@ -84,7 +84,7 @@ class MangareaderMangaExtractor(MangareaderBase, MangaExtractor):
"""Extractor for manga from mangareader.net""" """Extractor for manga from mangareader.net"""
chapterclass = MangareaderChapterExtractor chapterclass = MangareaderChapterExtractor
reverse = False reverse = False
pattern = r"(?:https?://)?(?:www\.)?mangareader\.net(/[^/?&#]+)/?$" pattern = r"(?:https?://)?(?:www\.)?mangareader\.net(/[^/?#]+)/?$"
test = ("https://www.mangareader.net/mushishi", { test = ("https://www.mangareader.net/mushishi", {
"url": "bc203b858b4ad76e5d77e39118a7be0350e357da", "url": "bc203b858b4ad76e5d77e39118a7be0350e357da",
"keyword": "031b3ea085921c552de017ecbb9b906e462229c9", "keyword": "031b3ea085921c552de017ecbb9b906e462229c9",

View File

@@ -184,7 +184,7 @@ def generate_extractors():
Extr.category = category Extr.category = category
Extr.instance = instance Extr.instance = instance
Extr.pattern = (r"(?:https?://)?" + pattern + Extr.pattern = (r"(?:https?://)?" + pattern +
r"/@([^/?&#]+)(?:/media)?/?$") r"/@([^/?#]+)(?:/media)?/?$")
Extr.test = info.get("test-user") Extr.test = info.get("test-user")
Extr.root = root Extr.root = root
Extr.access_token = token Extr.access_token = token
@@ -197,7 +197,7 @@ def generate_extractors():
Extr.__doc__ = "Extractor for images from a status on " + instance Extr.__doc__ = "Extractor for images from a status on " + instance
Extr.category = category Extr.category = category
Extr.instance = instance Extr.instance = instance
Extr.pattern = r"(?:https?://)?" + pattern + r"/@[^/?&#]+/(\d+)" Extr.pattern = r"(?:https?://)?" + pattern + r"/@[^/?#]+/(\d+)"
Extr.test = info.get("test-status") Extr.test = info.get("test-status")
Extr.root = root Extr.root = root
Extr.access_token = token Extr.access_token = token

View File

@@ -21,14 +21,14 @@ class MyportfolioGalleryExtractor(Extractor):
archive_fmt = "{user}_{filename}" archive_fmt = "{user}_{filename}"
pattern = (r"(?:myportfolio:(?:https?://)?([^/]+)|" pattern = (r"(?:myportfolio:(?:https?://)?([^/]+)|"
r"(?:https?://)?([^.]+\.myportfolio\.com))" r"(?:https?://)?([^.]+\.myportfolio\.com))"
r"(/[^/?&#]+)?") r"(/[^/?#]+)?")
test = ( test = (
("https://andrewling.myportfolio.com/volvo-xc-90-hybrid", { ("https://andrewling.myportfolio.com/volvo-xc-90-hybrid", {
"url": "acea0690c76db0e5cf267648cefd86e921bc3499", "url": "acea0690c76db0e5cf267648cefd86e921bc3499",
"keyword": "6ac6befe2ee0af921d24cf1dd4a4ed71be06db6d", "keyword": "6ac6befe2ee0af921d24cf1dd4a4ed71be06db6d",
}), }),
("https://andrewling.myportfolio.com/", { ("https://andrewling.myportfolio.com/", {
"pattern": r"https://andrewling\.myportfolio\.com/[^/?&#+]+$", "pattern": r"https://andrewling\.myportfolio\.com/[^/?#+]+$",
"count": ">= 6", "count": ">= 6",
}), }),
("https://stevenilousphotography.myportfolio.com/society", { ("https://stevenilousphotography.myportfolio.com/society", {

View File

@@ -226,7 +226,7 @@ class NewgroundsImageExtractor(NewgroundsExtractor):
"""Extractor for a single image from newgrounds.com""" """Extractor for a single image from newgrounds.com"""
subcategory = "image" subcategory = "image"
pattern = (r"(?:https?://)?(?:" pattern = (r"(?:https?://)?(?:"
r"(?:www\.)?newgrounds\.com/art/view/([^/?&#]+)/[^/?&#]+" r"(?:www\.)?newgrounds\.com/art/view/([^/?#]+)/[^/?#]+"
r"|art\.ngfiles\.com/images/\d+/\d+_([^_]+)_([^.]+))") r"|art\.ngfiles\.com/images/\d+/\d+_([^_]+)_([^.]+))")
test = ( test = (
("https://www.newgrounds.com/art/view/tomfulp/ryu-is-hawt", { ("https://www.newgrounds.com/art/view/tomfulp/ryu-is-hawt", {

View File

@@ -18,7 +18,7 @@ class NgomikChapterExtractor(ChapterExtractor):
category = "ngomik" category = "ngomik"
root = "http://ngomik.in" root = "http://ngomik.in"
pattern = (r"(?:https?://)?(?:www\.)?ngomik\.in" pattern = (r"(?:https?://)?(?:www\.)?ngomik\.in"
r"(/[^/?&#]+-chapter-[^/?&#]+)") r"(/[^/?#]+-chapter-[^/?#]+)")
test = ( test = (
("https://www.ngomik.in/14-sai-no-koi-chapter-1-6/", { ("https://www.ngomik.in/14-sai-no-koi-chapter-1-6/", {
"url": "8e67fdf751bbc79bc6f4dead7675008ddb8e32a4", "url": "8e67fdf751bbc79bc6f4dead7675008ddb8e32a4",

View File

@@ -124,7 +124,7 @@ class NozomiTagExtractor(NozomiExtractor):
subcategory = "tag" subcategory = "tag"
directory_fmt = ("{category}", "{search_tags}") directory_fmt = ("{category}", "{search_tags}")
archive_fmt = "t_{search_tags}_{postid}" archive_fmt = "t_{search_tags}_{postid}"
pattern = r"(?:https?://)?nozomi\.la/tag/([^/?&#]+)-\d+\." pattern = r"(?:https?://)?nozomi\.la/tag/([^/?#]+)-\d+\."
test = ("https://nozomi.la/tag/3:1_aspect_ratio-1.html", { test = ("https://nozomi.la/tag/3:1_aspect_ratio-1.html", {
"pattern": r"^https://i.nozomi.la/\w/\w\w/\w+\.\w+$", "pattern": r"^https://i.nozomi.la/\w/\w\w/\w+\.\w+$",
"count": ">= 25", "count": ">= 25",

View File

@@ -315,7 +315,7 @@ class OAuthTumblr(OAuthBase):
class OAuthMastodon(OAuthBase): class OAuthMastodon(OAuthBase):
subcategory = "mastodon" subcategory = "mastodon"
pattern = "oauth:mastodon:(?:https?://)?([^/?&#]+)" pattern = "oauth:mastodon:(?:https?://)?([^/?#]+)"
def __init__(self, match): def __init__(self, match):
OAuthBase.__init__(self, match) OAuthBase.__init__(self, match)

View File

@@ -44,7 +44,7 @@ class PahealTagExtractor(PahealExtractor):
subcategory = "tag" subcategory = "tag"
directory_fmt = ("{category}", "{search_tags}") directory_fmt = ("{category}", "{search_tags}")
pattern = (r"(?:https?://)?(?:rule34|rule63|cosplay)\.paheal\.net" pattern = (r"(?:https?://)?(?:rule34|rule63|cosplay)\.paheal\.net"
r"/post/list/([^/?&#]+)") r"/post/list/([^/?#]+)")
test = ("https://rule34.paheal.net/post/list/Ayane_Suzuki/1", { test = ("https://rule34.paheal.net/post/list/Ayane_Suzuki/1", {
"pattern": r"https://[^.]+\.paheal\.net/_images/\w+/\d+%20-%20", "pattern": r"https://[^.]+\.paheal\.net/_images/\w+/\d+%20-%20",
"count": ">= 15" "count": ">= 15"

View File

@@ -202,8 +202,8 @@ class PatreonCreatorExtractor(PatreonExtractor):
"""Extractor for a creator's works""" """Extractor for a creator's works"""
subcategory = "creator" subcategory = "creator"
pattern = (r"(?:https?://)?(?:www\.)?patreon\.com" pattern = (r"(?:https?://)?(?:www\.)?patreon\.com"
r"/(?!(?:home|join|posts|login|signup)(?:$|[/?&#]))" r"/(?!(?:home|join|posts|login|signup)(?:$|[/?#]))"
r"([^/?&#]+)(?:/posts)?/?(?:\?([^#]+))?") r"([^/?#]+)(?:/posts)?/?(?:\?([^#]+))?")
test = ( test = (
("https://www.patreon.com/koveliana", { ("https://www.patreon.com/koveliana", {
"range": "1-25", "range": "1-25",
@@ -283,7 +283,7 @@ class PatreonUserExtractor(PatreonExtractor):
class PatreonPostExtractor(PatreonExtractor): class PatreonPostExtractor(PatreonExtractor):
"""Extractor for media from a single post""" """Extractor for media from a single post"""
subcategory = "post" subcategory = "post"
pattern = r"(?:https?://)?(?:www\.)?patreon\.com/posts/([^/?&#]+)" pattern = r"(?:https?://)?(?:www\.)?patreon\.com/posts/([^/?#]+)"
test = ( test = (
# postfile + attachments # postfile + attachments
("https://www.patreon.com/posts/precious-metal-23563293", { ("https://www.patreon.com/posts/precious-metal-23563293", {

View File

@@ -22,7 +22,7 @@ class PhotobucketAlbumExtractor(Extractor):
filename_fmt = "{offset:>03}{pictureId:?_//}_{titleOrFilename}.{extension}" filename_fmt = "{offset:>03}{pictureId:?_//}_{titleOrFilename}.{extension}"
archive_fmt = "{id}" archive_fmt = "{id}"
pattern = (r"(?:https?://)?((?:[^.]+\.)?photobucket\.com)" pattern = (r"(?:https?://)?((?:[^.]+\.)?photobucket\.com)"
r"/user/[^/?&#]+/library(?:/[^?&#]*)?") r"/user/[^/?#]+/library(?:/[^?#]*)?")
test = ( test = (
("https://s369.photobucket.com/user/CrpyLrkr/library", { ("https://s369.photobucket.com/user/CrpyLrkr/library", {
"pattern": r"https?://[oi]+\d+.photobucket.com/albums/oo139/", "pattern": r"https?://[oi]+\d+.photobucket.com/albums/oo139/",
@@ -111,8 +111,8 @@ class PhotobucketImageExtractor(Extractor):
filename_fmt = "{pictureId:?/_/}{titleOrFilename}.{extension}" filename_fmt = "{pictureId:?/_/}{titleOrFilename}.{extension}"
archive_fmt = "{username}_{id}" archive_fmt = "{username}_{id}"
pattern = (r"(?:https?://)?(?:[^.]+\.)?photobucket\.com" pattern = (r"(?:https?://)?(?:[^.]+\.)?photobucket\.com"
r"(?:/gallery/user/([^/?&#]+)/media/([^/?&#]+)" r"(?:/gallery/user/([^/?#]+)/media/([^/?#]+)"
r"|/user/([^/?&#]+)/media/[^?&#]+\.html)") r"|/user/([^/?#]+)/media/[^?#]+\.html)")
test = ( test = (
(("https://s271.photobucket.com/user/lakerfanryan" (("https://s271.photobucket.com/user/lakerfanryan"
"/media/Untitled-3-1.jpg.html"), { "/media/Untitled-3-1.jpg.html"), {

View File

@@ -67,7 +67,7 @@ class PiczelExtractor(Extractor):
class PiczelUserExtractor(PiczelExtractor): class PiczelUserExtractor(PiczelExtractor):
"""Extractor for all images from a user's gallery""" """Extractor for all images from a user's gallery"""
subcategory = "user" subcategory = "user"
pattern = r"(?:https?://)?(?:www\.)?piczel\.tv/gallery/([^/?&#]+)/?$" pattern = r"(?:https?://)?(?:www\.)?piczel\.tv/gallery/([^/?#]+)/?$"
test = ("https://piczel.tv/gallery/Bikupan", { test = ("https://piczel.tv/gallery/Bikupan", {
"range": "1-100", "range": "1-100",
"count": ">= 100", "count": ">= 100",
@@ -88,7 +88,7 @@ class PiczelFolderExtractor(PiczelExtractor):
directory_fmt = ("{category}", "{user[username]}", "{folder[name]}") directory_fmt = ("{category}", "{user[username]}", "{folder[name]}")
archive_fmt = "f{folder[id]}_{id}_{num}" archive_fmt = "f{folder[id]}_{id}_{num}"
pattern = (r"(?:https?://)?(?:www\.)?piczel\.tv" pattern = (r"(?:https?://)?(?:www\.)?piczel\.tv"
r"/gallery/(?!image)([^/?&#]+)/(\d+)") r"/gallery/(?!image)([^/?#]+)/(\d+)")
test = ("https://piczel.tv/gallery/Lulena/1114", { test = ("https://piczel.tv/gallery/Lulena/1114", {
"count": ">= 4", "count": ">= 4",
}) })

View File

@@ -86,7 +86,7 @@ class PixivUserExtractor(PixivExtractor):
subcategory = "user" subcategory = "user"
pattern = (r"(?:https?://)?(?:www\.|touch\.)?pixiv\.net/(?:" pattern = (r"(?:https?://)?(?:www\.|touch\.)?pixiv\.net/(?:"
r"(?:en/)?users/(\d+)(?:/(?:artworks|illustrations|manga)" r"(?:en/)?users/(\d+)(?:/(?:artworks|illustrations|manga)"
r"(?:/([^/?&#]+))?)?/?(?:$|[?#])" r"(?:/([^/?#]+))?)?/?(?:$|[?#])"
r"|member(?:_illust)?\.php\?id=(\d+)(?:&([^#]+))?" r"|member(?:_illust)?\.php\?id=(\d+)(?:&([^#]+))?"
r"|(?:u(?:ser)?/|(?:mypage\.php)?#id=)(\d+))") r"|(?:u(?:ser)?/|(?:mypage\.php)?#id=)(\d+))")
test = ( test = (
@@ -170,7 +170,7 @@ class PixivUserExtractor(PixivExtractor):
class PixivMeExtractor(PixivExtractor): class PixivMeExtractor(PixivExtractor):
"""Extractor for pixiv.me URLs""" """Extractor for pixiv.me URLs"""
subcategory = "me" subcategory = "me"
pattern = r"(?:https?://)?pixiv\.me/([^/?&#]+)" pattern = r"(?:https?://)?pixiv\.me/([^/?#]+)"
test = ( test = (
("https://pixiv.me/del_shannon", { ("https://pixiv.me/del_shannon", {
"url": "29c295ce75150177e6b0a09089a949804c708fbf", "url": "29c295ce75150177e6b0a09089a949804c708fbf",
@@ -243,7 +243,7 @@ class PixivFavoriteExtractor(PixivExtractor):
"{user_bookmark[id]} {user_bookmark[account]}") "{user_bookmark[id]} {user_bookmark[account]}")
archive_fmt = "f_{user_bookmark[id]}_{id}{num}.{extension}" archive_fmt = "f_{user_bookmark[id]}_{id}{num}.{extension}"
pattern = (r"(?:https?://)?(?:www\.|touch\.)?pixiv\.net/(?:(?:en/)?" pattern = (r"(?:https?://)?(?:www\.|touch\.)?pixiv\.net/(?:(?:en/)?"
r"users/(\d+)/(bookmarks/artworks(?:/([^/?&#]+))?|following)" r"users/(\d+)/(bookmarks/artworks(?:/([^/?#]+))?|following)"
r"|bookmark\.php(?:\?([^#]*))?)") r"|bookmark\.php(?:\?([^#]*))?)")
test = ( test = (
("https://www.pixiv.net/en/users/173530/bookmarks/artworks", { ("https://www.pixiv.net/en/users/173530/bookmarks/artworks", {
@@ -407,7 +407,7 @@ class PixivSearchExtractor(PixivExtractor):
archive_fmt = "s_{search[word]}_{id}{num}.{extension}" archive_fmt = "s_{search[word]}_{id}{num}.{extension}"
directory_fmt = ("{category}", "search", "{search[word]}") directory_fmt = ("{category}", "search", "{search[word]}")
pattern = (r"(?:https?://)?(?:www\.|touch\.)?pixiv\.net" pattern = (r"(?:https?://)?(?:www\.|touch\.)?pixiv\.net"
r"/(?:(?:en/)?tags/([^/?&#]+)(?:/[^/?&#]+)?/?" r"/(?:(?:en/)?tags/([^/?#]+)(?:/[^/?#]+)?/?"
r"|search\.php)(?:\?([^#]+))?") r"|search\.php)(?:\?([^#]+))?")
test = ( test = (
("https://www.pixiv.net/en/tags/Original", { ("https://www.pixiv.net/en/tags/Original", {

View File

@@ -169,7 +169,7 @@ class PixnetUserExtractor(PixnetExtractor):
"""Extractor for all sets and folders of a pixnet user""" """Extractor for all sets and folders of a pixnet user"""
subcategory = "user" subcategory = "user"
url_fmt = "{}{}/album/list" url_fmt = "{}{}/album/list"
pattern = BASE_PATTERN + r"()(?:/blog|/album(?:/list)?)?/?(?:$|[?&#])" pattern = BASE_PATTERN + r"()(?:/blog|/album(?:/list)?)?/?(?:$|[?#])"
test = ( test = (
("https://albertayu773.pixnet.net/"), ("https://albertayu773.pixnet.net/"),
("https://albertayu773.pixnet.net/blog"), ("https://albertayu773.pixnet.net/blog"),

View File

@@ -72,7 +72,7 @@ class PlurkExtractor(Extractor):
class PlurkTimelineExtractor(PlurkExtractor): class PlurkTimelineExtractor(PlurkExtractor):
"""Extractor for URLs from all posts in a Plurk timeline""" """Extractor for URLs from all posts in a Plurk timeline"""
subcategory = "timeline" subcategory = "timeline"
pattern = r"(?:https?://)?(?:www\.)?plurk\.com/(?!p/)(\w+)/?(?:$|[?&#])" pattern = r"(?:https?://)?(?:www\.)?plurk\.com/(?!p/)(\w+)/?(?:$|[?#])"
test = ("https://www.plurk.com/plurkapi", { test = ("https://www.plurk.com/plurkapi", {
"pattern": r"https?://.+", "pattern": r"https?://.+",
"count": ">= 23" "count": ">= 23"

View File

@@ -118,7 +118,7 @@ class PornhubGalleryExtractor(PornhubExtractor):
class PornhubUserExtractor(PornhubExtractor): class PornhubUserExtractor(PornhubExtractor):
"""Extractor for all galleries of a pornhub user""" """Extractor for all galleries of a pornhub user"""
subcategory = "user" subcategory = "user"
pattern = (BASE_PATTERN + r"/(users|model)/([^/?&#]+)" pattern = (BASE_PATTERN + r"/(users|model)/([^/?#]+)"
"(?:/photos(?:/(public|private|favorites))?)?/?$") "(?:/photos(?:/(public|private|favorites))?)?/?$")
test = ( test = (
("https://www.pornhub.com/users/flyings0l0/photos/public", { ("https://www.pornhub.com/users/flyings0l0/photos/public", {

View File

@@ -150,7 +150,7 @@ class ReactorTagExtractor(ReactorExtractor):
subcategory = "tag" subcategory = "tag"
directory_fmt = ("{category}", "{search_tags}") directory_fmt = ("{category}", "{search_tags}")
archive_fmt = "{search_tags}_{post_id}_{num}" archive_fmt = "{search_tags}_{post_id}_{num}"
pattern = BASE_PATTERN + r"/tag/([^/?&#]+)" pattern = BASE_PATTERN + r"/tag/([^/?#]+)"
test = ("http://anime.reactor.cc/tag/Anime+Art",) test = ("http://anime.reactor.cc/tag/Anime+Art",)
def __init__(self, match): def __init__(self, match):
@@ -166,7 +166,7 @@ class ReactorSearchExtractor(ReactorTagExtractor):
subcategory = "search" subcategory = "search"
directory_fmt = ("{category}", "search", "{search_tags}") directory_fmt = ("{category}", "search", "{search_tags}")
archive_fmt = "s_{search_tags}_{post_id}_{num}" archive_fmt = "s_{search_tags}_{post_id}_{num}"
pattern = BASE_PATTERN + r"/search(?:/|\?q=)([^/?&#]+)" pattern = BASE_PATTERN + r"/search(?:/|\?q=)([^/?#]+)"
test = ("http://anime.reactor.cc/search?q=Art",) test = ("http://anime.reactor.cc/search?q=Art",)
@@ -174,7 +174,7 @@ class ReactorUserExtractor(ReactorExtractor):
"""Extractor for all posts of a user on *reactor.cc sites""" """Extractor for all posts of a user on *reactor.cc sites"""
subcategory = "user" subcategory = "user"
directory_fmt = ("{category}", "user", "{user}") directory_fmt = ("{category}", "user", "{user}")
pattern = BASE_PATTERN + r"/user/([^/?&#]+)" pattern = BASE_PATTERN + r"/user/([^/?#]+)"
test = ("http://anime.reactor.cc/user/Shuster",) test = ("http://anime.reactor.cc/user/Shuster",)
def __init__(self, match): def __init__(self, match):
@@ -215,7 +215,7 @@ JR_BASE_PATTERN = r"(?:https?://)?(?:www\.)?(joyreactor\.c(?:c|om))"
class JoyreactorTagExtractor(ReactorTagExtractor): class JoyreactorTagExtractor(ReactorTagExtractor):
"""Extractor for tag searches on joyreactor.cc""" """Extractor for tag searches on joyreactor.cc"""
category = "joyreactor" category = "joyreactor"
pattern = JR_BASE_PATTERN + r"/tag/([^/?&#]+)" pattern = JR_BASE_PATTERN + r"/tag/([^/?#]+)"
test = ( test = (
("http://joyreactor.cc/tag/Advent+Cirno", { ("http://joyreactor.cc/tag/Advent+Cirno", {
"count": ">= 17", "count": ">= 17",
@@ -229,7 +229,7 @@ class JoyreactorTagExtractor(ReactorTagExtractor):
class JoyreactorSearchExtractor(ReactorSearchExtractor): class JoyreactorSearchExtractor(ReactorSearchExtractor):
"""Extractor for search results on joyreactor.cc""" """Extractor for search results on joyreactor.cc"""
category = "joyreactor" category = "joyreactor"
pattern = JR_BASE_PATTERN + r"/search(?:/|\?q=)([^/?&#]+)" pattern = JR_BASE_PATTERN + r"/search(?:/|\?q=)([^/?#]+)"
test = ( test = (
("http://joyreactor.cc/search/Cirno+Gifs", { ("http://joyreactor.cc/search/Cirno+Gifs", {
"range": "1-25", "range": "1-25",
@@ -244,7 +244,7 @@ class JoyreactorSearchExtractor(ReactorSearchExtractor):
class JoyreactorUserExtractor(ReactorUserExtractor): class JoyreactorUserExtractor(ReactorUserExtractor):
"""Extractor for all posts of a user on joyreactor.cc""" """Extractor for all posts of a user on joyreactor.cc"""
category = "joyreactor" category = "joyreactor"
pattern = JR_BASE_PATTERN + r"/user/([^/?&#]+)" pattern = JR_BASE_PATTERN + r"/user/([^/?#]+)"
test = ( test = (
("http://joyreactor.cc/user/hemantic"), ("http://joyreactor.cc/user/hemantic"),
("http://joyreactor.com/user/Tacoman123", { ("http://joyreactor.com/user/Tacoman123", {
@@ -289,7 +289,7 @@ PR_BASE_PATTERN = r"(?:https?://)?(?:www\.)?(pornreactor\.cc|fapreactor.com)"
class PornreactorTagExtractor(ReactorTagExtractor): class PornreactorTagExtractor(ReactorTagExtractor):
"""Extractor for tag searches on pornreactor.cc""" """Extractor for tag searches on pornreactor.cc"""
category = "pornreactor" category = "pornreactor"
pattern = PR_BASE_PATTERN + r"/tag/([^/?&#]+)" pattern = PR_BASE_PATTERN + r"/tag/([^/?#]+)"
test = ( test = (
("http://pornreactor.cc/tag/RiceGnat", { ("http://pornreactor.cc/tag/RiceGnat", {
"range": "1-25", "range": "1-25",
@@ -302,7 +302,7 @@ class PornreactorTagExtractor(ReactorTagExtractor):
class PornreactorSearchExtractor(ReactorSearchExtractor): class PornreactorSearchExtractor(ReactorSearchExtractor):
"""Extractor for search results on pornreactor.cc""" """Extractor for search results on pornreactor.cc"""
category = "pornreactor" category = "pornreactor"
pattern = PR_BASE_PATTERN + r"/search(?:/|\?q=)([^/?&#]+)" pattern = PR_BASE_PATTERN + r"/search(?:/|\?q=)([^/?#]+)"
test = ( test = (
("http://pornreactor.cc/search?q=ecchi+hentai", { ("http://pornreactor.cc/search?q=ecchi+hentai", {
"range": "1-25", "range": "1-25",
@@ -315,7 +315,7 @@ class PornreactorSearchExtractor(ReactorSearchExtractor):
class PornreactorUserExtractor(ReactorUserExtractor): class PornreactorUserExtractor(ReactorUserExtractor):
"""Extractor for all posts of a user on pornreactor.cc""" """Extractor for all posts of a user on pornreactor.cc"""
category = "pornreactor" category = "pornreactor"
pattern = PR_BASE_PATTERN + r"/user/([^/?&#]+)" pattern = PR_BASE_PATTERN + r"/user/([^/?#]+)"
test = ( test = (
("http://pornreactor.cc/user/Disillusion", { ("http://pornreactor.cc/user/Disillusion", {
"range": "1-25", "range": "1-25",

View File

@@ -45,7 +45,7 @@ class ReadcomiconlineIssueExtractor(ReadcomiconlineBase, ChapterExtractor):
"""Extractor for comic-issues from readcomiconline.to""" """Extractor for comic-issues from readcomiconline.to"""
subcategory = "issue" subcategory = "issue"
pattern = (r"(?i)(?:https?://)?(?:www\.)?readcomiconline\.to" pattern = (r"(?i)(?:https?://)?(?:www\.)?readcomiconline\.to"
r"(/Comic/[^/?&#]+/[^/?&#]+\?id=(\d+))") r"(/Comic/[^/?#]+/[^/?#]+\?id=(\d+))")
test = ("https://readcomiconline.to/Comic/W-i-t-c-h/Issue-130?id=22289", { test = ("https://readcomiconline.to/Comic/W-i-t-c-h/Issue-130?id=22289", {
"url": "2bbab6ec4fbc05d269cca420a82a9b5acda28682", "url": "2bbab6ec4fbc05d269cca420a82a9b5acda28682",
"keyword": "30fe110273e871305001f33c18634516a0a51421", "keyword": "30fe110273e871305001f33c18634516a0a51421",
@@ -81,7 +81,7 @@ class ReadcomiconlineComicExtractor(ReadcomiconlineBase, MangaExtractor):
chapterclass = ReadcomiconlineIssueExtractor chapterclass = ReadcomiconlineIssueExtractor
subcategory = "comic" subcategory = "comic"
pattern = (r"(?i)(?:https?://)?(?:www\.)?readcomiconline\.to" pattern = (r"(?i)(?:https?://)?(?:www\.)?readcomiconline\.to"
r"(/Comic/[^/?&#]+/?)$") r"(/Comic/[^/?#]+/?)$")
test = ( test = (
("https://readcomiconline.to/Comic/W-i-t-c-h", { ("https://readcomiconline.to/Comic/W-i-t-c-h", {
"url": "e231bc2a293edb465133c37a8e36a7e7d94cab14", "url": "e231bc2a293edb465133c37a8e36a7e7d94cab14",

View File

@@ -137,7 +137,7 @@ class RedditSubredditExtractor(RedditExtractor):
"""Extractor for URLs from subreddits on reddit.com""" """Extractor for URLs from subreddits on reddit.com"""
subcategory = "subreddit" subcategory = "subreddit"
pattern = (r"(?:https?://)?(?:\w+\.)?reddit\.com/r/" pattern = (r"(?:https?://)?(?:\w+\.)?reddit\.com/r/"
r"([^/?&#]+(?:/[a-z]+)?)/?(?:\?([^#]*))?(?:$|#)") r"([^/?#]+(?:/[a-z]+)?)/?(?:\?([^#]*))?(?:$|#)")
test = ( test = (
("https://www.reddit.com/r/lavaporn/", { ("https://www.reddit.com/r/lavaporn/", {
"range": "1-20", "range": "1-20",
@@ -162,7 +162,7 @@ class RedditUserExtractor(RedditExtractor):
"""Extractor for URLs from posts by a reddit user""" """Extractor for URLs from posts by a reddit user"""
subcategory = "user" subcategory = "user"
pattern = (r"(?:https?://)?(?:\w+\.)?reddit\.com/u(?:ser)?/" pattern = (r"(?:https?://)?(?:\w+\.)?reddit\.com/u(?:ser)?/"
r"([^/?&#]+(?:/[a-z]+)?)/?(?:\?([^#]*))?") r"([^/?#]+(?:/[a-z]+)?)/?(?:\?([^#]*))?")
test = ( test = (
("https://www.reddit.com/user/username/", { ("https://www.reddit.com/user/username/", {
"count": ">= 2", "count": ">= 2",
@@ -185,7 +185,7 @@ class RedditSubmissionExtractor(RedditExtractor):
"""Extractor for URLs from a submission on reddit.com""" """Extractor for URLs from a submission on reddit.com"""
subcategory = "submission" subcategory = "submission"
pattern = (r"(?:https?://)?(?:" pattern = (r"(?:https?://)?(?:"
r"(?:\w+\.)?reddit\.com/(?:r/[^/?&#]+/comments|gallery)" r"(?:\w+\.)?reddit\.com/(?:r/[^/?#]+/comments|gallery)"
r"|redd\.it)/([a-z0-9]+)") r"|redd\.it)/([a-z0-9]+)")
test = ( test = (
("https://www.reddit.com/r/lavaporn/comments/8cqhub/", { ("https://www.reddit.com/r/lavaporn/comments/8cqhub/", {
@@ -231,7 +231,7 @@ class RedditImageExtractor(Extractor):
subcategory = "image" subcategory = "image"
archive_fmt = "{filename}" archive_fmt = "{filename}"
pattern = (r"(?:https?://)?i\.redd(?:\.it|ituploads\.com)" pattern = (r"(?:https?://)?i\.redd(?:\.it|ituploads\.com)"
r"/[^/?&#]+(?:\?[^#]*)?") r"/[^/?#]+(?:\?[^#]*)?")
test = ( test = (
("https://i.redd.it/upjtjcx2npzz.jpg", { ("https://i.redd.it/upjtjcx2npzz.jpg", {
"url": "0de614900feef103e580b632190458c0b62b641a", "url": "0de614900feef103e580b632190458c0b62b641a",

View File

@@ -22,7 +22,7 @@ class RedgifsUserExtractor(RedgifsExtractor):
"""Extractor for redgifs user profiles""" """Extractor for redgifs user profiles"""
subcategory = "user" subcategory = "user"
directory_fmt = ("{category}", "{userName}") directory_fmt = ("{category}", "{userName}")
pattern = r"(?:https?://)?(?:www\.)?redgifs\.com/users/([^/?&#]+)" pattern = r"(?:https?://)?(?:www\.)?redgifs\.com/users/([^/?#]+)"
test = ("https://www.redgifs.com/users/Natalifiction", { test = ("https://www.redgifs.com/users/Natalifiction", {
"pattern": r"https://\w+\.(redgifs|gfycat)\.com/[A-Za-z]+\.mp4", "pattern": r"https://\w+\.(redgifs|gfycat)\.com/[A-Za-z]+\.mp4",
"count": ">= 100", "count": ">= 100",
@@ -36,7 +36,7 @@ class RedgifsSearchExtractor(RedgifsExtractor):
"""Extractor for redgifs search results""" """Extractor for redgifs search results"""
subcategory = "search" subcategory = "search"
directory_fmt = ("{category}", "Search", "{search}") directory_fmt = ("{category}", "Search", "{search}")
pattern = r"(?:https?://)?(?:www\.)?redgifs\.com/gifs/browse/([^/?&#]+)" pattern = r"(?:https?://)?(?:www\.)?redgifs\.com/gifs/browse/([^/?#]+)"
test = ("https://www.redgifs.com/gifs/browse/jav", { test = ("https://www.redgifs.com/gifs/browse/jav", {
"pattern": r"https://\w+\.(redgifs|gfycat)\.com/[A-Za-z]+\.mp4", "pattern": r"https://\w+\.(redgifs|gfycat)\.com/[A-Za-z]+\.mp4",
"range": "100-300", "range": "100-300",

View File

@@ -30,7 +30,7 @@ class SankakucomplexArticleExtractor(SankakucomplexExtractor):
filename_fmt = "{filename}.{extension}" filename_fmt = "{filename}.{extension}"
archive_fmt = "{date:%Y%m%d}_{filename}" archive_fmt = "{date:%Y%m%d}_{filename}"
pattern = (r"(?:https?://)?www\.sankakucomplex\.com" pattern = (r"(?:https?://)?www\.sankakucomplex\.com"
r"/(\d{4}/\d\d/\d\d/[^/?&#]+)") r"/(\d{4}/\d\d/\d\d/[^/?#]+)")
test = ( test = (
("https://www.sankakucomplex.com/2019/05/11/twitter-cosplayers", { ("https://www.sankakucomplex.com/2019/05/11/twitter-cosplayers", {
"url": "4a9ecc5ae917fbce469280da5b6a482510cae84d", "url": "4a9ecc5ae917fbce469280da5b6a482510cae84d",

View File

@@ -168,7 +168,7 @@ class SexcomBoardExtractor(SexcomExtractor):
subcategory = "board" subcategory = "board"
directory_fmt = ("{category}", "{user}", "{board}") directory_fmt = ("{category}", "{user}", "{board}")
pattern = (r"(?:https?://)?(?:www\.)?sex\.com/user" pattern = (r"(?:https?://)?(?:www\.)?sex\.com/user"
r"/([^/?&#]+)/(?!(?:following|pins|repins|likes)/)([^/?&#]+)") r"/([^/?#]+)/(?!(?:following|pins|repins|likes)/)([^/?#]+)")
test = ("https://www.sex.com/user/ronin17/exciting-hentai/", { test = ("https://www.sex.com/user/ronin17/exciting-hentai/", {
"count": ">= 15", "count": ">= 15",
}) })
@@ -193,7 +193,7 @@ class SexcomSearchExtractor(SexcomExtractor):
subcategory = "search" subcategory = "search"
directory_fmt = ("{category}", "search", "{search[query]}") directory_fmt = ("{category}", "search", "{search[query]}")
pattern = (r"(?:https?://)?(?:www\.)?sex\.com/((?:" pattern = (r"(?:https?://)?(?:www\.)?sex\.com/((?:"
r"(pic|gif|video)s/([^/?&#]+)|search/(pic|gif|video)s" r"(pic|gif|video)s/([^/?#]+)|search/(pic|gif|video)s"
r")/?(?:\?([^#]+))?)") r")/?(?:\?([^#]+))?)")
test = ( test = (
("https://www.sex.com/search/pics?query=ecchi", { ("https://www.sex.com/search/pics?query=ecchi", {

View File

@@ -18,7 +18,7 @@ class SimplyhentaiGalleryExtractor(GalleryExtractor):
archive_fmt = "{image_id}" archive_fmt = "{image_id}"
pattern = (r"(?:https?://)?(?!videos\.)([\w-]+\.simply-hentai\.com" pattern = (r"(?:https?://)?(?!videos\.)([\w-]+\.simply-hentai\.com"
r"(?!/(?:album|gifs?|images?|series)(?:/|$))" r"(?!/(?:album|gifs?|images?|series)(?:/|$))"
r"(?:/(?!(?:page|all-pages)(?:/|\.|$))[^/?&#]+)+)") r"(?:/(?!(?:page|all-pages)(?:/|\.|$))[^/?#]+)+)")
test = ( test = (
(("https://original-work.simply-hentai.com" (("https://original-work.simply-hentai.com"
"/amazon-no-hiyaku-amazon-elixir"), { "/amazon-no-hiyaku-amazon-elixir"), {
@@ -84,7 +84,7 @@ class SimplyhentaiImageExtractor(Extractor):
filename_fmt = "{category}_{token}{title:?_//}.{extension}" filename_fmt = "{category}_{token}{title:?_//}.{extension}"
archive_fmt = "{token}" archive_fmt = "{token}"
pattern = (r"(?:https?://)?(?:www\.)?(simply-hentai\.com" pattern = (r"(?:https?://)?(?:www\.)?(simply-hentai\.com"
r"/(image|gif)/[^/?&#]+)") r"/(image|gif)/[^/?#]+)")
test = ( test = (
(("https://www.simply-hentai.com/image" (("https://www.simply-hentai.com/image"
"/pheromomania-vol-1-kanzenban-isao-3949d8b3-400c-4b6"), { "/pheromomania-vol-1-kanzenban-isao-3949d8b3-400c-4b6"), {
@@ -138,7 +138,7 @@ class SimplyhentaiVideoExtractor(Extractor):
directory_fmt = ("{category}", "{type}s") directory_fmt = ("{category}", "{type}s")
filename_fmt = "{title}{episode:?_//>02}.{extension}" filename_fmt = "{title}{episode:?_//>02}.{extension}"
archive_fmt = "{title}_{episode}" archive_fmt = "{title}_{episode}"
pattern = r"(?:https?://)?(videos\.simply-hentai\.com/[^/?&#]+)" pattern = r"(?:https?://)?(videos\.simply-hentai\.com/[^/?#]+)"
test = ( test = (
("https://videos.simply-hentai.com/creamy-pie-episode-02", { ("https://videos.simply-hentai.com/creamy-pie-episode-02", {
"pattern": r"https://www\.googleapis\.com/drive/v3/files" "pattern": r"https://www\.googleapis\.com/drive/v3/files"

View File

@@ -33,7 +33,7 @@ class SlickpicAlbumExtractor(SlickpicExtractor):
"{album[id]} {album[title]}") "{album[id]} {album[title]}")
filename_fmt = "{num:>03}_{id}{title:?_//}.{extension}" filename_fmt = "{num:>03}_{id}{title:?_//}.{extension}"
archive_fmt = "{id}" archive_fmt = "{id}"
pattern = BASE_PATTERN + r"/albums/([^/?&#]+)" pattern = BASE_PATTERN + r"/albums/([^/?#]+)"
test = ( test = (
("https://mattcrandall.slickpic.com/albums/LamborghiniMurcielago/", { ("https://mattcrandall.slickpic.com/albums/LamborghiniMurcielago/", {
"url": "58bd94ebc80fd906e9879826970b408d54c6da07", "url": "58bd94ebc80fd906e9879826970b408d54c6da07",

View File

@@ -20,7 +20,7 @@ class SlidesharePresentationExtractor(Extractor):
filename_fmt = "{presentation}-{num:>02}.{extension}" filename_fmt = "{presentation}-{num:>02}.{extension}"
archive_fmt = "{presentation}_{num}" archive_fmt = "{presentation}_{num}"
pattern = (r"(?:https?://)?(?:www\.)?slideshare\.net" pattern = (r"(?:https?://)?(?:www\.)?slideshare\.net"
r"/(?:mobile/)?([^/?&#]+)/([^/?&#]+)") r"/(?:mobile/)?([^/?#]+)/([^/?#]+)")
test = ( test = (
(("https://www.slideshare.net" (("https://www.slideshare.net"
"/Slideshare/get-started-with-slide-share"), { "/Slideshare/get-started-with-slide-share"), {

View File

@@ -108,7 +108,7 @@ class SmugmugImageExtractor(SmugmugExtractor):
"""Extractor for individual smugmug images""" """Extractor for individual smugmug images"""
subcategory = "image" subcategory = "image"
archive_fmt = "{Image[ImageKey]}" archive_fmt = "{Image[ImageKey]}"
pattern = BASE_PATTERN + r"(?:/[^/?&#]+)+/i-([^/?&#-]+)" pattern = BASE_PATTERN + r"(?:/[^/?#]+)+/i-([^/?#-]+)"
test = ( test = (
("https://tdm.smugmug.com/Nature/Dove/i-kCsLJT6", { ("https://tdm.smugmug.com/Nature/Dove/i-kCsLJT6", {
"url": "f624ad7293afd6412a7d34e3950a118596c36c85", "url": "f624ad7293afd6412a7d34e3950a118596c36c85",
@@ -141,7 +141,7 @@ class SmugmugImageExtractor(SmugmugExtractor):
class SmugmugPathExtractor(SmugmugExtractor): class SmugmugPathExtractor(SmugmugExtractor):
"""Extractor for smugmug albums from URL paths and users""" """Extractor for smugmug albums from URL paths and users"""
subcategory = "path" subcategory = "path"
pattern = BASE_PATTERN + r"((?:/[^/?&#a-fh-mo-z][^/?&#]*)*)/?$" pattern = BASE_PATTERN + r"((?:/[^/?#a-fh-mo-z][^/?#]*)*)/?$"
test = ( test = (
("https://tdm.smugmug.com/Nature/Dove", { ("https://tdm.smugmug.com/Nature/Dove", {
"pattern": "smugmug:album:cr4C7f$", "pattern": "smugmug:album:cr4C7f$",

View File

@@ -20,7 +20,7 @@ class SpeakerdeckPresentationExtractor(Extractor):
filename_fmt = "{presentation}-{num:>02}.{extension}" filename_fmt = "{presentation}-{num:>02}.{extension}"
archive_fmt = "{presentation}_{num}" archive_fmt = "{presentation}_{num}"
pattern = (r"(?:https?://)?(?:www\.)?speakerdeck\.com" pattern = (r"(?:https?://)?(?:www\.)?speakerdeck\.com"
r"/([^/?&#]+)/([^/?&#]+)") r"/([^/?#]+)/([^/?#]+)")
test = ( test = (
(("https://speakerdeck.com/speakerdeck/introduction-to-speakerdeck"), { (("https://speakerdeck.com/speakerdeck/introduction-to-speakerdeck"), {
"pattern": r"https://files.speakerdeck.com/presentations/" "pattern": r"https://files.speakerdeck.com/presentations/"

View File

@@ -135,7 +135,7 @@ class SubscribestarExtractor(Extractor):
class SubscribestarUserExtractor(SubscribestarExtractor): class SubscribestarUserExtractor(SubscribestarExtractor):
"""Extractor for media from a subscribestar user""" """Extractor for media from a subscribestar user"""
subcategory = "user" subcategory = "user"
pattern = BASE_PATTERN + r"/(?!posts/)([^/?&#]+)" pattern = BASE_PATTERN + r"/(?!posts/)([^/?#]+)"
test = ( test = (
("https://www.subscribestar.com/subscribestar", { ("https://www.subscribestar.com/subscribestar", {
"count": ">= 20", "count": ">= 20",

View File

@@ -295,7 +295,7 @@ class TumblrPostExtractor(TumblrExtractor):
class TumblrTagExtractor(TumblrExtractor): class TumblrTagExtractor(TumblrExtractor):
"""Extractor for images from a tumblr-user by tag""" """Extractor for images from a tumblr-user by tag"""
subcategory = "tag" subcategory = "tag"
pattern = BASE_PATTERN + r"/tagged/([^/?&#]+)" pattern = BASE_PATTERN + r"/tagged/([^/?#]+)"
test = ("http://demo.tumblr.com/tagged/Times%20Square", { test = ("http://demo.tumblr.com/tagged/Times%20Square", {
"pattern": (r"https://\d+\.media\.tumblr\.com/tumblr_[^/_]+_1280.jpg"), "pattern": (r"https://\d+\.media\.tumblr\.com/tumblr_[^/_]+_1280.jpg"),
"count": 1, "count": 1,

View File

@@ -263,7 +263,7 @@ class TwitterTimelineExtractor(TwitterExtractor):
"""Extractor for all images from a user's timeline""" """Extractor for all images from a user's timeline"""
subcategory = "timeline" subcategory = "timeline"
pattern = BASE_PATTERN + \ pattern = BASE_PATTERN + \
r"/(?!search)(?:([^/?&#]+)/?(?:$|[?#])|intent/user\?user_id=(\d+))" r"/(?!search)(?:([^/?#]+)/?(?:$|[?#])|intent/user\?user_id=(\d+))"
test = ( test = (
("https://twitter.com/supernaturepics", { ("https://twitter.com/supernaturepics", {
"range": "1-40", "range": "1-40",
@@ -287,7 +287,7 @@ class TwitterTimelineExtractor(TwitterExtractor):
class TwitterMediaExtractor(TwitterExtractor): class TwitterMediaExtractor(TwitterExtractor):
"""Extractor for all images from a user's Media Tweets""" """Extractor for all images from a user's Media Tweets"""
subcategory = "media" subcategory = "media"
pattern = BASE_PATTERN + r"/(?!search)([^/?&#]+)/media(?!\w)" pattern = BASE_PATTERN + r"/(?!search)([^/?#]+)/media(?!\w)"
test = ( test = (
("https://twitter.com/supernaturepics/media", { ("https://twitter.com/supernaturepics/media", {
"range": "1-40", "range": "1-40",
@@ -304,7 +304,7 @@ class TwitterMediaExtractor(TwitterExtractor):
class TwitterLikesExtractor(TwitterExtractor): class TwitterLikesExtractor(TwitterExtractor):
"""Extractor for liked tweets""" """Extractor for liked tweets"""
subcategory = "likes" subcategory = "likes"
pattern = BASE_PATTERN + r"/(?!search)([^/?&#]+)/likes(?!\w)" pattern = BASE_PATTERN + r"/(?!search)([^/?#]+)/likes(?!\w)"
test = ("https://twitter.com/supernaturepics/likes",) test = ("https://twitter.com/supernaturepics/likes",)
def tweets(self): def tweets(self):
@@ -342,7 +342,7 @@ class TwitterSearchExtractor(TwitterExtractor):
class TwitterTweetExtractor(TwitterExtractor): class TwitterTweetExtractor(TwitterExtractor):
"""Extractor for images from individual tweets""" """Extractor for images from individual tweets"""
subcategory = "tweet" subcategory = "tweet"
pattern = BASE_PATTERN + r"/([^/?&#]+|i/web)/status/(\d+)" pattern = BASE_PATTERN + r"/([^/?#]+|i/web)/status/(\d+)"
test = ( test = (
("https://twitter.com/supernaturepics/status/604341487988576256", { ("https://twitter.com/supernaturepics/status/604341487988576256", {
"url": "0e801d2f98142dd87c3630ded9e4be4a4d63b580", "url": "0e801d2f98142dd87c3630ded9e4be4a4d63b580",

View File

@@ -29,7 +29,7 @@ class VanillarockPostExtractor(VanillarockExtractor):
filename_fmt = "{num:>02}.{extension}" filename_fmt = "{num:>02}.{extension}"
archive_fmt = "{filename}" archive_fmt = "{filename}"
pattern = (r"(?:https?://)?(?:www\.)?vanilla-rock\.com" pattern = (r"(?:https?://)?(?:www\.)?vanilla-rock\.com"
r"(/(?!category/|tag/)[^/?&#]+)/?$") r"(/(?!category/|tag/)[^/?#]+)/?$")
test = ("https://vanilla-rock.com/mizuhashi_parsee-5", { test = ("https://vanilla-rock.com/mizuhashi_parsee-5", {
"url": "7fb9a4d18d9fa22d7295fee8d94ab5a7a52265dd", "url": "7fb9a4d18d9fa22d7295fee8d94ab5a7a52265dd",
"keyword": "b91df99b714e1958d9636748b1c81a07c3ef52c9", "keyword": "b91df99b714e1958d9636748b1c81a07c3ef52c9",
@@ -66,7 +66,7 @@ class VanillarockTagExtractor(VanillarockExtractor):
"""Extractor for vanillarock blog posts by tag or category""" """Extractor for vanillarock blog posts by tag or category"""
subcategory = "tag" subcategory = "tag"
pattern = (r"(?:https?://)?(?:www\.)?vanilla-rock\.com" pattern = (r"(?:https?://)?(?:www\.)?vanilla-rock\.com"
r"(/(?:tag|category)/[^?&#]+)") r"(/(?:tag|category)/[^?#]+)")
test = ( test = (
("https://vanilla-rock.com/tag/%e5%b0%84%e5%91%bd%e4%b8%b8%e6%96%87", { ("https://vanilla-rock.com/tag/%e5%b0%84%e5%91%bd%e4%b8%b8%e6%96%87", {
"pattern": VanillarockPostExtractor.pattern, "pattern": VanillarockPostExtractor.pattern,

View File

@@ -34,7 +34,7 @@ class WebtoonsEpisodeExtractor(WebtoonsExtractor):
directory_fmt = ("{category}", "{comic}") directory_fmt = ("{category}", "{comic}")
filename_fmt = "{episode}-{num:>02}.{extension}" filename_fmt = "{episode}-{num:>02}.{extension}"
archive_fmt = "{title_no}_{episode}_{num}" archive_fmt = "{title_no}_{episode}_{num}"
pattern = (BASE_PATTERN + r"/([^/?&#]+)/([^/?&#]+)/(?:[^/?&#]+))" pattern = (BASE_PATTERN + r"/([^/?#]+)/([^/?#]+)/(?:[^/?#]+))"
r"/viewer(?:\?([^#'\"]+))") r"/viewer(?:\?([^#'\"]+))")
test = ( test = (
(("https://www.webtoons.com/en/comedy/safely-endangered" (("https://www.webtoons.com/en/comedy/safely-endangered"
@@ -97,7 +97,7 @@ class WebtoonsComicExtractor(WebtoonsExtractor):
"""Extractor for an entire comic on webtoons.com""" """Extractor for an entire comic on webtoons.com"""
subcategory = "comic" subcategory = "comic"
categorytransfer = True categorytransfer = True
pattern = (BASE_PATTERN + r"/([^/?&#]+)/([^/?&#]+))" pattern = (BASE_PATTERN + r"/([^/?#]+)/([^/?#]+))"
r"/list(?:\?([^#]+))") r"/list(?:\?([^#]+))")
test = ( test = (
# english # english

View File

@@ -33,7 +33,7 @@ class XhamsterGalleryExtractor(XhamsterExtractor):
"{gallery[id]} {gallery[title]}") "{gallery[id]} {gallery[title]}")
filename_fmt = "{num:>03}_{id}.{extension}" filename_fmt = "{num:>03}_{id}.{extension}"
archive_fmt = "{id}" archive_fmt = "{id}"
pattern = BASE_PATTERN + r"(/photos/gallery/[^/?&#]+)" pattern = BASE_PATTERN + r"(/photos/gallery/[^/?#]+)"
test = ( test = (
("https://xhamster.com/photos/gallery/11748968", { ("https://xhamster.com/photos/gallery/11748968", {
"pattern": r"https://thumb-p\d+.xhcdn.com/./[\w/-]+_1000.jpg$", "pattern": r"https://thumb-p\d+.xhcdn.com/./[\w/-]+_1000.jpg$",
@@ -152,7 +152,7 @@ class XhamsterGalleryExtractor(XhamsterExtractor):
class XhamsterUserExtractor(XhamsterExtractor): class XhamsterUserExtractor(XhamsterExtractor):
"""Extractor for all galleries of an xhamster user""" """Extractor for all galleries of an xhamster user"""
subcategory = "user" subcategory = "user"
pattern = BASE_PATTERN + r"/users/([^/?&#]+)(?:/photos)?/?(?:$|[?#])" pattern = BASE_PATTERN + r"/users/([^/?#]+)(?:/photos)?/?(?:$|[?#])"
test = ( test = (
("https://xhamster.com/users/goldenpalomino/photos", { ("https://xhamster.com/users/goldenpalomino/photos", {
"pattern": XhamsterGalleryExtractor.pattern, "pattern": XhamsterGalleryExtractor.pattern,

View File

@@ -28,7 +28,7 @@ class XvideosGalleryExtractor(XvideosBase, GalleryExtractor):
archive_fmt = "{gallery[id]}_{num}" archive_fmt = "{gallery[id]}_{num}"
pattern = (r"(?:https?://)?(?:www\.)?xvideos\.com" pattern = (r"(?:https?://)?(?:www\.)?xvideos\.com"
r"/(?:profiles|amateur-channels|model-channels)" r"/(?:profiles|amateur-channels|model-channels)"
r"/([^/?&#]+)/photos/(\d+)") r"/([^/?#]+)/photos/(\d+)")
test = ( test = (
("https://www.xvideos.com/profiles/pervertedcouple/photos/751031", { ("https://www.xvideos.com/profiles/pervertedcouple/photos/751031", {
"url": "cb4657a37eea5ab6b1d333491cee7eeb529b0645", "url": "cb4657a37eea5ab6b1d333491cee7eeb529b0645",
@@ -94,7 +94,7 @@ class XvideosUserExtractor(XvideosBase, Extractor):
subcategory = "user" subcategory = "user"
categorytransfer = True categorytransfer = True
pattern = (r"(?:https?://)?(?:www\.)?xvideos\.com" pattern = (r"(?:https?://)?(?:www\.)?xvideos\.com"
r"/profiles/([^/?&#]+)/?(?:#.*)?$") r"/profiles/([^/?#]+)/?(?:#.*)?$")
test = ( test = (
("https://www.xvideos.com/profiles/pervertedcouple", { ("https://www.xvideos.com/profiles/pervertedcouple", {
"url": "a413f3e60d6d3a2de79bd44fa3b7a9c03db4336e", "url": "a413f3e60d6d3a2de79bd44fa3b7a9c03db4336e",

View File

@@ -19,7 +19,7 @@ class YukiThreadExtractor(Extractor):
directory_fmt = ("{category}", "{board}", "{thread}{title:? - //}") directory_fmt = ("{category}", "{board}", "{thread}{title:? - //}")
filename_fmt = "{time}-{filename}.{extension}" filename_fmt = "{time}-{filename}.{extension}"
archive_fmt = "{board}_{thread}_{tim}" archive_fmt = "{board}_{thread}_{tim}"
pattern = r"(?:https?://)?yuki\.la/([^/?&#]+)/(\d+)" pattern = r"(?:https?://)?yuki\.la/([^/?#]+)/(\d+)"
test = ( test = (
("https://yuki.la/gd/309639", { ("https://yuki.la/gd/309639", {
"url": "289e86c5caf673a2515ec5f5f521ac0ae7e189e9", "url": "289e86c5caf673a2515ec5f5f521ac0ae7e189e9",