diff --git a/docs/supportedsites.md b/docs/supportedsites.md
index dafd0f27..6d4fd9c0 100644
--- a/docs/supportedsites.md
+++ b/docs/supportedsites.md
@@ -427,12 +427,6 @@ Consider all sites to be NSFW unless otherwise known.
Games |
|
-
- | JPG Fish |
- https://jpg1.su/ |
- Albums, individual Images, User Profiles |
- |
-
| Keenspot |
http://www.keenspot.com/ |
@@ -998,6 +992,22 @@ Consider all sites to be NSFW unless otherwise known.
|
+
+ | Chevereto Instances |
+
+
+ | JPG Fish |
+ https://jpg2.su/ |
+ Albums, individual Images, User Profiles |
+ |
+
+
+ | Pixl |
+ https://pixl.li/ |
+ Albums, individual Images, User Profiles |
+ |
+
+
| Danbooru Instances |
diff --git a/gallery_dl/extractor/__init__.py b/gallery_dl/extractor/__init__.py
index 3abe74b6..1c1473a0 100644
--- a/gallery_dl/extractor/__init__.py
+++ b/gallery_dl/extractor/__init__.py
@@ -28,6 +28,7 @@ modules = [
"blogger",
"bunkr",
"catbox",
+ "chevereto",
"comicvine",
"cyberdrop",
"danbooru",
@@ -73,7 +74,6 @@ modules = [
"issuu",
"itaku",
"itchio",
- "jpgfish",
"jschan",
"kabeuchi",
"keenspot",
diff --git a/gallery_dl/extractor/chevereto.py b/gallery_dl/extractor/chevereto.py
new file mode 100644
index 00000000..f7824e2f
--- /dev/null
+++ b/gallery_dl/extractor/chevereto.py
@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2023 Mike Fährmann
+#
+# 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
+# published by the Free Software Foundation.
+
+"""Extractors for Chevereto galleries"""
+
+from .common import BaseExtractor, Message
+from .. import text
+
+
+class CheveretoExtractor(BaseExtractor):
+ """Base class for chevereto extractors"""
+ basecategory = "chevereto"
+ directory_fmt = ("{category}", "{user}", "{album}",)
+ archive_fmt = "{id}"
+
+ def __init__(self, match):
+ BaseExtractor.__init__(self, match)
+ self.path = match.group(match.lastindex)
+
+ def _pagination(self, url):
+ while url:
+ page = self.request(url).text
+
+ for item in text.extract_iter(
+ page, '<')
+
+
+BASE_PATTERN = CheveretoExtractor.update({
+ "jpgfish": {
+ "root": "https://jpg2.su",
+ "pattern": r"jpe?g\d?\.(?:su|pet|fish(?:ing)?|church)",
+ },
+ "pixl": {
+ "root": "https://pixl.li",
+ "pattern": r"pixl\.(?:li|is)",
+ },
+})
+
+
+class CheveretoImageExtractor(CheveretoExtractor):
+ """Extractor for chevereto Images"""
+ subcategory = "image"
+ pattern = BASE_PATTERN + r"(/im(?:g|age)/[^/?#]+)"
+ example = "https://jpg2.su/img/TITLE.ID"
+
+ def items(self):
+ url = self.root + self.path
+ extr = text.extract_from(self.request(url).text)
+
+ image = {
+ "id" : self.path.rpartition(".")[2],
+ "url" : extr('"), ">", "<"),
+ "user" : extr('username: "', '"'),
+ }
+
+ text.nameext_from_url(image["url"], image)
+ yield Message.Directory, image
+ yield Message.Url, image["url"], image
+
+
+class CheveretoAlbumExtractor(CheveretoExtractor):
+ """Extractor for chevereto Albums"""
+ subcategory = "album"
+ pattern = BASE_PATTERN + r"(/a(?:lbum)?/[^/?#]+(?:/sub)?)"
+ example = "https://jpg2.su/album/TITLE.ID"
+
+ def items(self):
+ url = self.root + self.path
+ data = {"_extractor": CheveretoImageExtractor}
+
+ if self.path.endswith("/sub"):
+ albums = self._pagination(url)
+ else:
+ albums = (url,)
+
+ for album in albums:
+ for image in self._pagination(album):
+ yield Message.Queue, image, data
+
+
+class CheveretoUserExtractor(CheveretoExtractor):
+ """Extractor for chevereto Users"""
+ subcategory = "user"
+ pattern = BASE_PATTERN + r"(/(?!img|image|a(?:lbum)?)[^/?#]+(?:/albums)?)"
+ example = "https://jpg2.su/USER"
+
+ def items(self):
+ url = self.root + self.path
+
+ if self.path.endswith("/albums"):
+ data = {"_extractor": CheveretoAlbumExtractor}
+ else:
+ data = {"_extractor": CheveretoImageExtractor}
+
+ for url in self._pagination(url):
+ yield Message.Queue, url, data
diff --git a/gallery_dl/extractor/jpgfish.py b/gallery_dl/extractor/jpgfish.py
deleted file mode 100644
index 8862a7b7..00000000
--- a/gallery_dl/extractor/jpgfish.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# 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
-# published by the Free Software Foundation.
-
-"""Extractors for https://jpg1.su/"""
-
-from .common import Extractor, Message
-from .. import text
-
-BASE_PATTERN = r"(?:https?://)?jpe?g\d?\.(?:su|pet|fish(?:ing)?|church)"
-
-
-class JpgfishExtractor(Extractor):
- """Base class for jpgfish extractors"""
- category = "jpgfish"
- root = "https://jpg1.su"
- directory_fmt = ("{category}", "{user}", "{album}",)
- archive_fmt = "{id}"
-
- def _pagination(self, url):
- while url:
- page = self.request(url).text
-
- for item in text.extract_iter(
- page, '