diff --git a/dosagelib/plugins/a.py b/dosagelib/plugins/a.py index 7cff9fc8f..283c48858 100644 --- a/dosagelib/plugins/a.py +++ b/dosagelib/plugins/a.py @@ -6,7 +6,7 @@ from re import compile, escape, MULTILINE from ..util import tagre -from ..scraper import BasicScraper, _BasicScraper, _ParserScraper +from ..scraper import BasicScraper, ParserScraper, _BasicScraper, _ParserScraper from ..helpers import regexNamer, bounceStarter, indirectStarter from .common import WordPressScraper, WordPressNavi, WordPressWebcomic @@ -166,18 +166,18 @@ class AllTheGrowingThings(WordPressScraper): endOfLife = True -class AlphaLuna(_ParserScraper): - url = 'https://alphaluna.net/' +class AlphaLuna(ParserScraper): + url = 'https://alphalunacomic.net/' stripUrl = url + 'comic/%s/' firstStripUrl = stripUrl % 'issue-1-cover' imageSearch = '//main[@id="comic"]//img' prevSearch = '//a[@rel="prev"]' -class AlphaLunaSpanish(_ParserScraper): +class AlphaLunaSpanish(ParserScraper): name = 'AlphaLuna/Spanish' lang = 'es' - url = 'https://alphaluna.net/spanish/' + url = 'https://alphalunacomic.net/spanish/' stripUrl = url + 'comic/%s/' firstStripUrl = stripUrl % 'issue-1-cover' imageSearch = '//main[@id="comic"]//img' diff --git a/dosagelib/plugins/c.py b/dosagelib/plugins/c.py index fa95e48ad..c731f375c 100644 --- a/dosagelib/plugins/c.py +++ b/dosagelib/plugins/c.py @@ -117,13 +117,6 @@ class CatAndGirl(_ParserScraper): prevSearch = '//a[d:class("pager--prev")]' -class CatenaCafe(WordPressScraper): - name = 'CatenaManor/CatenaCafe' - url = 'https://catenamanor.com/' - stripUrl = url + 'comic/%s/' - firstStripUrl = stripUrl % 'reboot-book1cover-small' - - class CatenaManor(_ParserScraper): baseUrl = ('https://web.archive.org/web/20141027141116/' 'http://catenamanor.com/') diff --git a/dosagelib/plugins/comicfury.py b/dosagelib/plugins/comicfury.py index 43808ddca..0a7a9c108 100644 --- a/dosagelib/plugins/comicfury.py +++ b/dosagelib/plugins/comicfury.py @@ -73,10 +73,16 @@ class ComicFury(ParserScraper): '//img[d:class("comicsegmentimage")]', ) - def namer(self, image_url, page_url): - parts = page_url.split('/') - path, ext = os.path.splitext(image_url) + def namer(self, imageUrl, pageUrl): + parts = pageUrl.split('/') + path, ext = os.path.splitext(imageUrl) num = parts[-1] + if self.multipleImagesPerStrip: + page = self.getPage(pageUrl) + images = page.xpath('//img[@class="comicsegmentimage"]/@src') + if len(images) > 1: + imageIndex = images.index(imageUrl) + 1 + return "%s_%s-%d%s" % (self.prefix, num, imageIndex, ext) return "%s_%s%s" % (self.prefix, num, ext) def shouldSkipUrl(self, url, data): @@ -136,7 +142,7 @@ class ComicFury(ParserScraper): cls('AgentBishop', 'agentbishop'), cls('AHappierKindOfSad', 'ahappierkindofsad'), cls('AlbinoBrothers', 'albinobros'), - cls('Alderwood', 'alderwood'), + cls('Alderwood', 'alderwood', segmented=True), cls('AlexanderAndLucasRebooted', 'alexanderandlucas'), cls('AliaTerra', 'alia-terra'), cls('AlienIrony', 'alien-irony'), @@ -785,6 +791,7 @@ class ComicFury(ParserScraper): cls('Pulse', 'pulse'), cls('PureHavoc', 'pure-havoc'), cls('Queenie', 'queenie'), + cls('QueenieAdventure', 'queenieadventure', adult=True, segmented=True), cls('QuestCorporeal', 'questcorporeal'), cls('Rain', 'rain'), cls('RandomlyAssembled', 'randomlyassembled'), diff --git a/dosagelib/plugins/f.py b/dosagelib/plugins/f.py index fa259e5f2..2bef57265 100644 --- a/dosagelib/plugins/f.py +++ b/dosagelib/plugins/f.py @@ -6,7 +6,7 @@ from re import compile, escape from ..util import tagre -from ..scraper import _BasicScraper, _ParserScraper +from ..scraper import ParserScraper, _BasicScraper, _ParserScraper from ..helpers import indirectStarter, joinPathPartsNamer from .common import ComicControlScraper, WordPressNaviIn, WordPressScraper @@ -20,24 +20,6 @@ class FalconTwin(_BasicScraper): help = 'Index format: nnn' -class FalseStart(_ParserScraper): - baseUrl = 'https://boneitisindustries.com/' - url = baseUrl + 'comics/false-start/' - stripUrl = baseUrl + 'comic/%s/' - firstStripUrl = stripUrl % 'false-start-chapter-zero-page-1' - imageSearch = '//div[@id="content"]//img[d:class("size-full")]' - prevSearch = '//a[./span[d:class("ticon-chevron-left")]]' - adult = True - - def starter(self): - archivePage = self.getPage(self.url) - self.archive = archivePage.xpath('//div[contains(@class, "vcex-portfolio-grid")]//a/@href') - return self.archive[-1] - - def getPrevUrl(self, url, data): - return self.archive[self.archive.index(url) - 1] - - class Faneurysm(WordPressNaviIn): url = 'http://hijinksensue.com/comic/think-only-tree/' firstStripUrl = 'http://hijinksensue.com/comic/captains-prerogative/' @@ -149,18 +131,19 @@ class ForLackOfABetterComic(_ParserScraper): endOfLife = True -class FoxDad(_ParserScraper): +class FoxDad(ParserScraper): url = 'https://foxdad.com/' stripUrl = url + 'post/%s' firstStripUrl = stripUrl % '149683014997/some-people-are-just-different-support-the-comic' - imageSearch = ('//figure[@class="photo-hires-item"]//img', '//figure[@class="tmblr-full"]//img') + imageSearch = '//figure[@class="photo-hires-item"]//img' prevSearch = '//a[@class="previous-button"]' def namer(self, imageUrl, pageUrl): page = self.getPage(pageUrl) - post = page.xpath('//link[@type="application/json+oembed"]')[0].get('href') - post = post.replace('https://www.tumblr.com/oembed/1.0?url=https://foxdad.com/post', '') - post = post.replace('-support-me-on-patreon', '') + post = page.xpath('//li[@class="timestamp"]/a/@href')[0] + post = post.replace('https://foxdad.com/post/', '') + if '-consider-support' in post: + post = post.split('-consider-support')[0] return post.replace('/', '-') diff --git a/dosagelib/plugins/g.py b/dosagelib/plugins/g.py index aa2726144..4c266f339 100644 --- a/dosagelib/plugins/g.py +++ b/dosagelib/plugins/g.py @@ -59,16 +59,6 @@ class GeeksNextDoor(_ParserScraper): help = 'Index format: yyyy-mm-dd' -class Ginpu(WordPressNavi): - url = 'https://www.ginpu.us/' - stripUrl = url + 'comic/%s/' - firstStripUrl = stripUrl % 'filler-2' - - def namer(self, imageUrl, pageUrl): - filename = imageUrl.rsplit('/', 3) - return '%s-%s_%s' % (filename[1], filename[2], filename[3]) - - class GirlGenius(_BasicScraper): baseUrl = 'http://www.girlgeniusonline.com/' rurl = escape(baseUrl) diff --git a/dosagelib/plugins/h.py b/dosagelib/plugins/h.py index 4ed5f75bf..0c45d77c0 100644 --- a/dosagelib/plugins/h.py +++ b/dosagelib/plugins/h.py @@ -68,6 +68,20 @@ class HeadlessBliss(ComicControlScraper): url = 'http://headlessbliss.com/' +class Hellkats(ParserScraper): + url = 'https://poecatcomix.com/hellkatscomic/' + stripUrl = url + '%s/' + firstStripUrl = stripUrl % 'hellkats-issue-1-cover' + imageSearch = '//img[@class="scale-with-grid wp-post-image"]' + prevSearch = '//a[d:class("fixed-nav-prev")]' + latestSearch = '//div[@class="post-title"]//a' + starter = indirectStarter + adult = True + + def namer(self, imageUrl, pageUrl): + return pageUrl.rsplit('/', 2)[1] + '.' + imageUrl.rsplit('.', 1)[-1] + + class HeyFox(WordPressScraper): url = 'http://www.steamclaw.com/heyfox/' stripUrl = url + 'archives/comic/%s' diff --git a/dosagelib/plugins/i.py b/dosagelib/plugins/i.py index 460bc49af..c11027e20 100644 --- a/dosagelib/plugins/i.py +++ b/dosagelib/plugins/i.py @@ -41,6 +41,16 @@ class InternetWebcomic(WordPressNavi): help = 'Index format: n' +class Inverloch(ParserScraper): + stripUrl = 'https://www.seraph-inn.com/view.php?story=inverloch&page=%s' + url = stripUrl % '763' + firstStripUrl = stripUrl % '2' + imageSearch = '//img[@class="page"]' + prevSearch = '//p[@class="comic-nav"]/a[text()=" Previous"]' + multipleImagesPerStrip = True + endOfLife = True + + class IrregularWebcomic(BasicScraper): url = 'http://www.irregularwebcomic.net/' stripUrl = url + '%s.html' diff --git a/dosagelib/plugins/kemonocafe.py b/dosagelib/plugins/kemonocafe.py index 119303816..788ab1eaf 100644 --- a/dosagelib/plugins/kemonocafe.py +++ b/dosagelib/plugins/kemonocafe.py @@ -37,11 +37,17 @@ class KemonoCafe(ParserScraper): filename = filename.replace('89', '90') elif 'rascals' in pageUrl and '133-2' in pageUrl: filename = filename.replace('133', '134') + elif 'caughtinorbit' in pageUrl and '26gs' in filename: + filename = filename.replace('026gs', '021') + elif 'caughtinorbit' in pageUrl and '27gs' in filename: + filename = filename.replace('027gs', '022') # Fix unordered filenames if 'addictivescience' in pageUrl: page = self.getPage(pageUrl) num = int(page.xpath('//div[@id="comic-wrap"]/@class')[0].replace('comic-id-', '')) filename = '%04d_%s' % (num, filename) + elif 'CaughtInOrbit' in filename: + filename = filename.replace('CaughtInOrbit', 'CIO') return filename @classmethod @@ -50,13 +56,13 @@ class KemonoCafe(ParserScraper): cls('AddictiveScience', 'addictivescience', 'page0001'), cls('Bethellium', 'bethellium', 'c01p00'), cls('CaribbeanBlue', 'cb', 'page000', last='page325'), + cls('CaughtInOrbit', 'caughtinorbit', 'comic-cover'), cls('IMew', 'imew', 'imew00', last='imew50'), cls('Knighthood', 'knighthood', 'kh0001'), cls('KnuckleUp', 'knuckle-up', 'page001', adult=True), cls('LasLindas', 'laslindas', 'll0001', adult=True), cls('Paprika', 'paprika', 'page000'), cls('PracticeMakesPerfect', 'pmp', 'title-001'), - cls('PrincessBunny', 'princessbunny', 'pg001'), cls('Rascals', 'rascals', 'rascals-pg-0', adult=True), cls('TheEyeOfRamalach', 'theeye', 'theeye-page01'), cls('TinaOfTheSouth', 'tots', 'tos-01-01'), diff --git a/dosagelib/plugins/l.py b/dosagelib/plugins/l.py index 1e9e4e36a..f28bccc93 100644 --- a/dosagelib/plugins/l.py +++ b/dosagelib/plugins/l.py @@ -11,11 +11,11 @@ from ..util import tagre from .common import ComicControlScraper, WordPressScraper, WordPressNaviIn -class Lackadaisy(_ParserScraper): +class Lackadaisy(ParserScraper): url = 'https://www.lackadaisy.com/comic.php' stripUrl = url + '?comicid=%s' firstStripUrl = stripUrl % '1' - imageSearch = '//div[@id="content"]/img' + imageSearch = '//div[@id="exhibit"]/img[contains(@src, "comic/")]' prevSearch = '//div[@class="prev"]/a' nextSearch = '//div[@class="next"]/a' help = 'Index format: n' @@ -28,6 +28,12 @@ class Lackadaisy(_ParserScraper): return 'lackadaisy_%s.%s' % (num, ext) +class Lancer(WordPressScraper): + url = 'https://lancercomic.com/' + stripUrl = url + 'comic/%s/' + firstStripUrl = stripUrl % 'chapter-1-cover' + + class LastResort(WordPressScraper): url = 'http://www.lastres0rt.com/' stripUrl = url + 'comic/%s/' diff --git a/dosagelib/plugins/mangadex.py b/dosagelib/plugins/mangadex.py index dd5d1cf91..1bd6e9ea9 100644 --- a/dosagelib/plugins/mangadex.py +++ b/dosagelib/plugins/mangadex.py @@ -95,6 +95,8 @@ class MangaDex(ParserScraper): @classmethod def getmodules(cls): return ( + cls('AniTomo', '920c22e7-49c9-4bb4-b394-0c964b6037fc'), + cls('ArcaneSniper', 'cbf53f02-9594-42e7-9dbf-8ae1c783466f'), cls('AttackOnTitan', '304ceac3-8cdb-4fe7-acf7-2b6ff7a60613'), cls('Beastars', 'f5e3baad-3cd4-427c-a2ec-ad7d776b370d'), cls('BokuNoKokoroNoYabaiYatsu', '3df1a9a3-a1be-47a3-9e90-9b3e55b1d0ac'), @@ -104,6 +106,7 @@ class MangaDex(ParserScraper): cls('DragonDrive', '5c06ae70-b5cf-431a-bcd5-262a411de527'), cls('FuguushokuKajishiDakedoSaikyouDesu', '17b3b648-fd89-4a69-9a42-6068ffbfa7a7'), cls('GanbareDoukiChan', '190616bc-7da6-45fd-abd4-dd2ca656c183'), + cls('GijiHarem', 'd8f9afe2-aa44-4bc6-9145-eebb1f282372'), cls('HangingOutWithAGamerGirl', 'de9e3b62-eac5-4c0a-917d-ffccad694381'), cls('HoriMiya', 'a25e46ec-30f7-4db6-89df-cacbc1d9a900'), cls('HowToOpenATriangularRiceball', '6ebd90ce-d5e8-49c0-a4bc-e02e0f8ecb93'), @@ -113,17 +116,23 @@ class MangaDex(ParserScraper): cls('JahySamaWaKujikenai', '2f4e5f5b-d930-4266-8c8a-c4cf9a81e51f'), cls('JingaiNoYomeToIchaIchaSuru', '809d2493-df3c-4e72-a57e-3e0026cae9fb'), cls('KaetteKudasaiAkutsuSan', '737a846b-2e67-4d63-9f7e-f54b3beebac4'), + cls('KaikoSaretaAnkokuHeishi30DaiNoSlowNaSecondLife', 'cbcf5051-74a0-4b93-b99c-1a6975f1bef9'), cls('KawaiiJoushiWoKomarasetai', '23b7cc7a-df89-4049-af28-1fa78f88713e'), cls('KanojoOkarishimasu', '32fdfe9b-6e11-4a13-9e36-dcd8ea77b4e4'), cls('KoiToUtatane', 'f7d40a27-e289-45b3-9c68-d1cb251897e6'), + cls('KonoKaishaNiSukiNaHitoGaImasu', '3e8cf40f-ba17-480a-b60b-a675db032ee2'), + cls('LonelyGirlNiSakaraenai', 'd7576e72-0301-4ed3-9137-722ed768bfda'), cls('Lv2KaraCheatDattaMotoYuushaKouhoNoMattariIsekaiLife', '58bc83a0-1808-484e-88b9-17e167469e23'), cls('MaouNoOreGaDoreiElfWoYomeNiShitandaGaDouMederebaIi', '55ace2fb-e157-4d76-9e72-67c6bd762a39'), cls('ModernMoGal', 'b1953f80-36f7-492c-b0f8-e9dd0ad01752'), + cls('MousouTelepathy', '3d25d7da-893f-400e-9aeb-6163773c671a'), cls('MyTinySenpaiFromWork', '28ed63af-61f8-43af-bac3-762030c72963'), + cls('MyWifeIsFromAThousandYearsAgo', '17a56d33-9443-433a-9e0d-70459893ed8f'), cls('OMaidensinYourSavageSeason', 'c4613b7d-7a6e-48f9-82f0-bce3dd33383a'), cls('OokamiShounenWaKyouMoUsoOKasaneru', '5e77d9e2-2e44-431a-a995-5fefd411e55e'), cls('OokamiToKoshinryou', 'de900fd3-c94c-4148-bbcb-ca56eaeb57a4'), cls('OtomeYoukaiZakuro', 'c1fa97be-0f1f-4686-84bc-806881c97d53'), + cls('Overgeared', '3fc308c9-4b00-4dc3-943e-1f39242bc708'), cls('OversimplifiedSCP', 'e911fe33-a9b3-43dc-9eb7-f5ee081a6dc8'), cls('PashiriNaBokuToKoisuruBanchouSan', '838e5b3a-51c8-44cf-b6e2-68193416f6fe'), cls('PleaseDontBullyMeNagatoro', 'd86cf65b-5f6c-437d-a0af-19a31f94ec55'), @@ -141,12 +150,14 @@ class MangaDex(ParserScraper): cls('SwordArtOnlineProgressive', '22ea3f54-11e4-4932-a527-89d63d3a62d9'), cls('TadokoroSan', '8ffbfa2f-23fa-4490-848e-942581a4d873'), cls('TamenDeGushi', '3f1453fb-9dac-4aca-a2ea-69613856c952'), + cls('TamingMaster', '534c1b5b-aff6-44fd-bf68-7294e6526fb3'), cls('TenseiShitaraSlimeDattaKen', 'e78a489b-6632-4d61-b00b-5206f5b8b22b'), cls('TheNewGate', 'b41bef1e-7df9-4255-bd82-ecf570fec566'), cls('TheWolfAndRedRidingHood', 'a7d1283b-ed38-4659-b8bc-47bfca5ccb8a'), cls('TomoChanWaOnnanoko', '76ee7069-23b4-493c-bc44-34ccbf3051a8'), cls('TonikakuKawaii', '30f3ac69-21b6-45ad-a110-d011b7aaadaa'), cls('UramikoiKoiUramikoi', '009b6788-48f3-4e78-975c-097f54def7ab'), + cls('UzakiChanWaAsobitai', '5a90308a-8b12-4a4d-9c6d-2487028fe319'), cls('YotsubaAnd', '58be6aa6-06cb-4ca5-bd20-f1392ce451fb'), cls('YuYuHakusho', '44a5cbe1-0204-4cc7-a1ff-0fda2ac004b6'), ) diff --git a/dosagelib/plugins/n.py b/dosagelib/plugins/n.py index 8387bccf2..21a66d588 100644 --- a/dosagelib/plugins/n.py +++ b/dosagelib/plugins/n.py @@ -5,7 +5,7 @@ # Copyright (C) 2019-2020 Daniel Ring from re import compile, escape -from ..scraper import _BasicScraper, _ParserScraper +from ..scraper import ParserScraper, _BasicScraper, _ParserScraper from ..helpers import indirectStarter, bounceStarter from ..util import tagre from .common import ComicControlScraper, WordPressScraper, WordPressNavi, WordPressWebcomic @@ -113,29 +113,18 @@ class Nicky510(WordPressNavi): endOfLife = True -class Nightshift(WordPressWebcomic): - url = 'https://poecatcomix.com/nightshift-static/' - stripUrl = 'https://poecatcomix.com/nightshift/%s/' - firstStripUrl = stripUrl % 'ns-cover' - imageSearch = '//div[contains(@class, "webcomic-media")]//img' +class Nightshift(ParserScraper): + url = 'https://poecatcomix.com/nightshiftcomic/' + stripUrl = url + '%s/' + firstStripUrl = stripUrl % 'ns-issue-1-cover' + imageSearch = '//img[@class="scale-with-grid wp-post-image"]' + prevSearch = '//a[d:class("fixed-nav-prev")]' + latestSearch = '//div[@class="post-title"]//a' + starter = indirectStarter adult = True - def starter(self): - # Build list of chapters for naming - indexPage = self.getPage(self.url) - self.chapters = indexPage.xpath('//a[./img[contains(@class, "attachment-large")]]/@href') - latestPage = self.chapters[0] - self.chapters = self.chapters[1:] - self.currentChapter = len(self.chapters) - return latestPage - def namer(self, imageUrl, pageUrl): - page = pageUrl.rstrip('/').rsplit('/', 1)[-1] - page = page.replace('blood-brothers', 'bloodbrothers').replace('bb-2', 'bb2').replace('ns7-', 'page-') - filename = 'ns%d-%s.%s' % (self.currentChapter, page, imageUrl.rsplit('.', 1)[-1]) - if pageUrl in self.chapters: - self.currentChapter = self.currentChapter - 1 - return filename + return pageUrl.rsplit('/', 2)[1] + '.' + imageUrl.rsplit('.', 1)[-1] class Nimona(_ParserScraper): @@ -176,13 +165,13 @@ class NoNeedForBushido(_ParserScraper): help = 'Index format: nnn' -class NonPlayerCharacter(_ParserScraper): +class NonPlayerCharacter(ParserScraper): url = 'https://www.lfg.co/' - stripUrl = url + 'npc/tale/%s/' + stripUrl = url + 'npc/comic/%s/' firstStripUrl = stripUrl % '1-1' imageSearch = '//div[@id="comic-img"]//img' prevSearch = '//a[@class="comic-nav-prev"]' - latestSearch = '//div[@id="feature-npc-footer"]/a[contains(@href, "npc/tale/")]' + latestSearch = '//div[@id="feature-npc-footer"]/a[contains(@href, "npc/comic/")]' starter = indirectStarter def namer(self, imageUrl, pageUrl): diff --git a/dosagelib/plugins/o.py b/dosagelib/plugins/o.py index 284623353..954d5d69b 100644 --- a/dosagelib/plugins/o.py +++ b/dosagelib/plugins/o.py @@ -75,6 +75,7 @@ class OhJoySexToy(WordPressNavi): url = 'http://www.ohjoysextoy.com/' firstStripUrl = url + 'introduction/' textSearch = '//div[@id="comic"]//img/@alt' + multipleImagesPerStrip = True adult = True diff --git a/dosagelib/plugins/old.py b/dosagelib/plugins/old.py index 9f06968c2..b5989665b 100644 --- a/dosagelib/plugins/old.py +++ b/dosagelib/plugins/old.py @@ -604,6 +604,7 @@ class Removed(Scraper): cls('WotNow'), # Removed in 3.0 + cls('CatenaManor/CatenaCafe'), cls('ComicFury/AdventuresOftheGreatCaptainMaggieandCrew'), cls('ComicFury/AWAKENING'), cls('ComicFury/Beebleville'), @@ -832,6 +833,8 @@ class Removed(Scraper): cls('ComicsKingdom/Redeye'), cls('ComicsKingdom/RedeyeSundays'), cls('CrapIDrewOnMyLunchBreak'), + cls('FalseStart'), + cls('Ginpu'), cls('GoComics/060'), cls('GoComics/2CowsAndAChicken'), cls('GoComics/ABitSketch'), @@ -992,9 +995,11 @@ class Removed(Scraper): cls('GoComics/Wrobbertcartoons'), cls('GoComics/Zootopia'), cls('JustAnotherEscape'), + cls('KemonoCafe/PrincessBunny'), cls('Laiyu', 'brk'), cls('MangaDex/DrStone', 'legal'), cls('MangaDex/HeavensDesignTeam', 'legal'), + cls('MangaDex/ImTheMaxLevelNewbie', 'legal'), cls('MangaDex/SPYxFAMILY', 'legal'), cls('Ryugou'), cls('SeelPeel'), @@ -1568,16 +1573,21 @@ class Removed(Scraper): cls('SnafuComics/Tin'), cls('SnafuComics/Titan'), cls('StudioKhimera/Eorah', 'mov'), + cls('StudioKhimera/Mousechevious'), cls('StuffNoOneToldMe'), cls('TaleOfTenThousand'), + cls('TalesAndTactics'), cls('TheCyantianChronicles/CookieCaper'), cls('TheCyantianChronicles/Pawprints'), + cls('VampireHunterBoyfriends'), cls('VGCats/Adventure'), cls('VGCats/Super'), cls('VictimsOfTheSystem'), cls('WebDesignerCOTW'), cls('WebToons/Adamsville'), cls('WebToons/CrapIDrewOnMyLunchBreak'), + cls('WebToons/CrystalVirus'), + cls('WebToons/OVERPOWERED'), cls('WintersLight'), ) @@ -1679,6 +1689,7 @@ class Renamed(Scraper): cls('SmackJeeves/TheRealmOfKaerwyn', 'ComicFury/TheRealmOfKaerwyn'), cls('SoloLeveling', 'MangaDex/SoloLeveling'), cls('StudioKhimera/Draconia', 'Draconia'), + cls('StudioKhimera/UberQuest', 'UberQuest'), cls('TracesOfThePast', 'RickGriffinStudios/TracesOfThePast'), cls('TracesOfThePast/NSFW', 'RickGriffinStudios/TracesOfThePastNSFW'), diff --git a/dosagelib/plugins/p.py b/dosagelib/plugins/p.py index 33089f463..41aad4a30 100644 --- a/dosagelib/plugins/p.py +++ b/dosagelib/plugins/p.py @@ -210,12 +210,12 @@ class PlanescapeSurvival(_BasicScraper): help = 'Index format: nnn' -class PlushAndBlood(_ParserScraper): +class PlushAndBlood(ParserScraper): url = 'http://www.plushandblood.com/Comic.php' stripUrl = url + '?strip_id=%s' firstStripUrl = stripUrl % '1' imageSearch = '//img[contains(@src, "comics/")]' - prevSearch = '//a[./img[contains(@src, "Nav/Prev")]]' + prevSearch = '//a[contains(text(), "PREV")]' class PokeyThePenguin(_ParserScraper): @@ -334,8 +334,10 @@ class PS238(_ParserScraper): class PvPOnline(ParserScraper): baseUrl = 'https://www.toonhoundstudios.com/' url = baseUrl + 'pvp/' - stripUrl = baseUrl + 'comic/%s/?sid=372' + stripUrl = baseUrl + 'comic/%s/' firstStripUrl = stripUrl % '19980504' imageSearch = '//div[@id="spliced-comic"]//img/@data-src-img' - prevSearch = '//div[d:class("comic-nav")]//a[d:class("prev")]' - help = 'Older pages need a Patreon subscription' + prevSearch = '//a[d:class("prev")]' + + def namer(self, imageUrl, pageUrl): + return 'pvp' + imageUrl.rsplit('/', 1)[-1] diff --git a/dosagelib/plugins/projectfuture.py b/dosagelib/plugins/projectfuture.py index ac7c6ed33..eb385adc6 100644 --- a/dosagelib/plugins/projectfuture.py +++ b/dosagelib/plugins/projectfuture.py @@ -30,10 +30,11 @@ class ProjectFuture(ParserScraper): cls('BookOfTenets', 'tenets', '01', last='45'), cls('CriticalMass', 'criticalmass', 'cover', last='26'), cls('DarkLordRising', 'darklord', '01-00', last='10-10'), - cls('Emily', 'emily', '01-00'), - cls('FishingTrip', 'fishing', '01-00'), + cls('Emily', 'emily', '01-00', last='07-10'), + cls('FishingTrip', 'fishing', '01-00', last='03-12'), cls('HeadsYouLose', 'heads', '00-01', last='07-12'), - cls('IPanther', 'panther', '00'), + cls('InnocenceGuiltAndChange', 'ernst', '01-00'), + cls('IPanther', 'panther', '00', last='20'), cls('NiallsStory', 'niall', '00'), cls('ProjectFuture', 'strip', '0', last='664'), cls('RedValentine', 'redvalentine', '1', last='6'), @@ -42,10 +43,12 @@ class ProjectFuture(ParserScraper): cls('TheAxemanCometh', 'axeman', '01-01', last='02-18'), cls('ToCatchADemon', 'daxxon', '01-00', last='03-14'), cls('TheDarkAngel', 'darkangel', 'cover', last='54'), + cls('TheBountyProject', 'bounty', '00-00'), cls('TheEpsilonProject', 'epsilon', '00-01'), - cls('TheHarvest', 'harvest', '01-00'), + cls('TheHarvest', 'harvest', '01-00', last='08-26'), cls('TheSierraChronicles', 'sierra', '0', last='29'), cls('TheTuppenyMan', 'tuppenny', '00', last='16'), cls('TurningANewPage', 'azrael', '1', last='54'), cls('Xerian', 'xerian', '01-00'), + cls('ZetaTakesATrip', 'zeta', '0-00'), ) diff --git a/dosagelib/plugins/r.py b/dosagelib/plugins/r.py index 035fef337..5a10455cc 100644 --- a/dosagelib/plugins/r.py +++ b/dosagelib/plugins/r.py @@ -7,11 +7,19 @@ from re import compile from urllib.parse import urljoin from ..helpers import bounceStarter -from ..scraper import _BasicScraper, _ParserScraper +from ..scraper import ParserScraper, _BasicScraper, _ParserScraper from ..util import tagre from .common import WordPressScraper, WordPressNavi, WordPressWebcomic +class Rainburn(ParserScraper): + url = 'https://rainburn.virmir.com/' + stripUrl = url + 'comic.php?page=%s' + firstStripUrl = stripUrl % '1' + imageSearch = '//div[@class="comic"]//img' + prevSearch = '//a[contains(@class, "prev")]' + + class RalfTheDestroyer(WordPressScraper): url = 'http://ralfthedestroyer.com/' diff --git a/dosagelib/plugins/s.py b/dosagelib/plugins/s.py index bfddc68c5..131873281 100644 --- a/dosagelib/plugins/s.py +++ b/dosagelib/plugins/s.py @@ -209,10 +209,65 @@ class Sheldon(_BasicScraper): help = 'Index format: yymmdd' -class Shifters(WordPressNavi): - url = 'http://shiftersonline.com/' - stripUrl = url + '%s/' - firstStripUrl = stripUrl % 'shifters-redux-promo' +class Shifters(ParserScraper): + baseUrl = 'https://shiftersonline.com/' + url = baseUrl + 'series/shifters-redux/' + stripUrl = baseUrl + 'comic/%s/' + firstStripUrl = stripUrl % 'chapter-1-pg-1' + imageSearch = '//div[@id="spliced-comic"]//span[@class="default-lang"]//img' + prevSearch = '//a[@class="previous-comic"]' + latestSearch = '//div[@id="comic-archive-list"]//a' + starter = indirectStarter + + def namer(self, imageUrl, pageUrl): + return pageUrl.rsplit('/', 2)[1] + '.' + imageUrl.rsplit('.', 1)[-1] + + +class ShiftersOnGossamerWings(Shifters): + name = 'Shifters/OnGossamerWings' + baseUrl = 'https://shiftersonline.com/' + url = baseUrl + 'series/shifters-on-gossamer-wings/' + stripUrl = baseUrl + 'comic/%s/' + firstStripUrl = stripUrl % 'on-gossamer-wings-cover' + + +class ShiftersTheBeastWithin(Shifters): + name = 'Shifters/TheBeastWithin' + baseUrl = 'https://shiftersonline.com/' + url = baseUrl + 'series/shifters-the-beast-within/' + stripUrl = baseUrl + 'comic/%s/' + firstStripUrl = stripUrl % 'awakenings-pg-1' + endOfLife = True + + def namer(self, imageUrl, pageUrl): + filename = pageUrl.rsplit('/', 2)[1] + '.' + imageUrl.rsplit('.', 1)[-1] + if filename.startswith('the-company-of-dragons'): + filename = 'in-' + filename + # Prepend chapter number to filename + chapters = [ + 'awakenings', + 'lifting-the-veil', + 'tears-of-blood', + 'on-the-lam', + 'shades-of-intrigue', + 'catfight', + 'out-of-control', + 'damage-control', + 'wolfs-clothing', + 'strange-dreams', + 'blood-bonds', + 'the-other-team', + 'get-ferrah', + 'the-price-of-power', + 'dogfight', + 'surfacing', + 'in-the-company-of-dragons', + 'filler', + ] + for chapter in chapters: + if filename.startswith(chapter): + filename = 'chapter-' + str(chapters.index(chapter) + 1) + '-' + filename + return filename class ShipInABottle(WordPressScraper): @@ -527,30 +582,18 @@ class StarCrossdDestiny(_ParserScraper): return directory + '-' + filename -class StarfireAgency(WordPressWebcomic): - url = 'https://poecatcomix.com/starfire-agency-static/' - stripUrl = 'https://poecatcomix.com/starfire-agency/%s/' - firstStripUrl = stripUrl % '2005-09-201' - imageSearch = '//div[contains(@class, "webcomic-media")]//img' - - def starter(self): - # Build list of chapters for naming - indexPage = self.getPage(self.url) - self.chapters = indexPage.xpath('//a[./img[contains(@class, "attachment-large")]]/@href') - latestPage = self.chapters[0] - self.chapters = self.chapters[1:] - self.currentChapter = len(self.chapters) - return latestPage +class StarfireAgency(ParserScraper): + url = 'https://poecatcomix.com/starfirecomic/' + stripUrl = url + '%s/' + firstStripUrl = stripUrl % 'sfa-issue-1-cover' + imageSearch = '//img[@class="scale-with-grid wp-post-image"]' + prevSearch = '//a[d:class("fixed-nav-prev")]' + latestSearch = '//div[@class="post-title"]//a' + starter = indirectStarter + adult = True def namer(self, imageUrl, pageUrl): - page = pageUrl.rstrip('/').rsplit('/', 1)[-1] - page = page.replace('3page00', 'cover3').replace('6429', 'cover7').replace('sfa-6-5-cover', 'cover6') - page = page.replace('sfa01', 'page01').replace('sfa03', 'page03').replace('sfa04', 'page04') - page = page.replace('sfa24', 'page24').replace('sfa07', 'page') - filename = 'sfa%d-%s.%s' % (self.currentChapter, page, imageUrl.rsplit('.', 1)[-1]) - if pageUrl in self.chapters: - self.currentChapter = self.currentChapter - 1 - return filename + return pageUrl.rsplit('/', 2)[1] + '.' + imageUrl.rsplit('.', 1)[-1] class StarTrip(ComicControlScraper): diff --git a/dosagelib/plugins/studiokhimera.py b/dosagelib/plugins/studiokhimera.py deleted file mode 100644 index 8a129157f..000000000 --- a/dosagelib/plugins/studiokhimera.py +++ /dev/null @@ -1,65 +0,0 @@ -# SPDX-License-Identifier: MIT -# Copyright (C) 2019-2022 Tobias Gruetzmacher -# Copyright (C) 2019-2020 Daniel Ring -from ..scraper import ParserScraper -from .common import WordPressScraper - - -class StudioKhimera(ParserScraper): - imageSearch = '//figure[@class="gallery-item"]//img/@data-src' - prevSearch = '//a[@rel="prev"]' - - def __init__(self, name, sub, last=None, adult=False, fixNames=False): - super().__init__('StudioKhimera/' + name) - - self.baseUrl = 'https://%s.studiokhimera.com/' % sub - self.stripUrl = self.baseUrl + '%s/' - self.url = self.baseUrl + 'category/comicChapter/?latest' - - self.multipleImagesPerStrip = True - - if last: - self.last = True - self.url = self.stripUrl % last - self.endOfLife = True - - if adult: - self.adult = True - - def starter(self): - # Retrieve list of chapter links - chapterPage = self.getPage(self.baseUrl + 'archive/') - self.chapters = chapterPage.xpath('//main//a/@href') - self.firstStripUrl = self.chapters[0] - return self.chapters[-1] - - def getPrevUrl(self, url, data): - # Select previous chapter from list - index = [i for i, ch in enumerate(self.chapters) if ch == url][0] - if index == 0: - return None - return self.chapters[index - 1] - - @classmethod - def getmodules(cls): - return ( - cls('Mousechievous', 'mousechievous'), - ) - - -class UberQuest(WordPressScraper): - name = 'StudioKhimera/UberQuest' - stripUrl = 'https://uberquest.studiokhimera.com/comic/page/%s/' - url = stripUrl % 'latest' - firstStripUrl = stripUrl % 'cover' - imageSearch = '//div[@class="prj--comic-image"]/img' - prevSearch = '//uq-image-button[d:class("prj--comic-control-prev")]' - - def namer(self, imageUrl, pageUrl): - # Fix inconsistent filenames - filename = imageUrl.rsplit('/', 1)[-1] - filename = filename.replace('Page', 'UberQuest') - filename = filename.replace('UberQuest01.', 'UberQuest001.') - filename = filename.replace('UberQuest98.', 'UberQuest098.') - filename = filename.replace('UberQuest99.', 'UberQuest099.') - return filename diff --git a/dosagelib/plugins/t.py b/dosagelib/plugins/t.py index ba41db60a..c9c1596dd 100644 --- a/dosagelib/plugins/t.py +++ b/dosagelib/plugins/t.py @@ -16,14 +16,6 @@ from .common import (ComicControlScraper, WordPressScraper, WordPressSpliced, WordPressNavi, WordPressWebcomic) -class TailsAndTactics(_ParserScraper): - url = 'http://tailsandtactics.com/comic/' - stripUrl = url + '%s/' - firstStripUrl = stripUrl % '1' - imageSearch = '//div[@class="comic-image"]/img' - prevSearch = '//a[text()=" Back"]' - - class TekMage(WordPressNavi): url = 'https://tekmagecomic.com/' stripUrl = url + 'comic/%s/' diff --git a/dosagelib/plugins/tapas.py b/dosagelib/plugins/tapas.py index 81765c66e..a1db5bdb0 100644 --- a/dosagelib/plugins/tapas.py +++ b/dosagelib/plugins/tapas.py @@ -66,6 +66,7 @@ class Tapas(ParserScraper): cls('AmpleTime', 'Ample-Time'), cls('FANGS', 'fangscomic'), cls('FishNuggets', 'Fish-Nuggets'), + cls('Ginpu', 'Ginpu-Studios-Comics'), cls('HoneyAndTheMoon', 'Honey-and-the-Moon'), cls('InsignificantOtters', 'IOtters'), cls('MagicalBoy', 'magicalboy'), diff --git a/dosagelib/plugins/u.py b/dosagelib/plugins/u.py index 01ec06e23..12eeb0bbd 100644 --- a/dosagelib/plugins/u.py +++ b/dosagelib/plugins/u.py @@ -3,6 +3,7 @@ # Copyright (C) 2012-2014 Bastian Kleineidam # Copyright (C) 2015-2020 Tobias Gruetzmacher # Copyright (C) 2019-2020 Daniel Ring +import json from re import compile from urllib.parse import urljoin from lxml import etree @@ -13,6 +14,28 @@ from ..util import tagre from .common import ComicControlScraper, WordPressScraper, WordPressNavi +class UberQuest(ParserScraper): + baseUrl = 'https://uberquest.studiokhimera.com/' + url = baseUrl + 'wp-json/keeros_comics/v1/chapters' + stripUrl = baseUrl + 'wp-json/wp/v2/cfx_comic_page?page_number=%s' + firstStripUrl = stripUrl % 'cover' + + def starter(self): + # Retrieve comic metadata from API + data = self.session.get(self.url) + data.raise_for_status() + return self.stripUrl % data.json()[-1]['pages'][-1]['page_number'] + + def getPrevUrl(self, url, data): + return self.stripUrl % json.loads(data.text_content())[0]['prev_id'] + + def fetchUrls(self, url, data, urlSearch): + return [json.loads(data.text_content())[0]['attachment']] + + def namer(self, imageUrl, pageUrl): + return 'UberQuest-' + pageUrl.rsplit('=', 1)[-1] + + class Underling(WordPressNavi): url = ('https://web.archive.org/web/20190806120425/' 'http://underlingcomic.com/') diff --git a/dosagelib/plugins/v.py b/dosagelib/plugins/v.py index e807882e8..cc0e1777b 100644 --- a/dosagelib/plugins/v.py +++ b/dosagelib/plugins/v.py @@ -3,28 +3,10 @@ # Copyright (C) 2012-2014 Bastian Kleineidam # Copyright (C) 2015-2020 Tobias Gruetzmacher # Copyright (C) 2019-2020 Daniel Ring -from ..scraper import _ParserScraper +from ..scraper import ParserScraper, _ParserScraper from ..helpers import bounceStarter, indirectStarter -class VampireHunterBoyfriends(_ParserScraper): - baseUrl = 'https://boneitisindustries.com/' - url = baseUrl + 'comics/vampire-hunter-boyfriends/' - stripUrl = baseUrl + 'comic/%s/' - firstStripUrl = stripUrl % 'vampire-hunter-boyfriends-chapter-1-cover' - imageSearch = '//div[@id="content"]//img[d:class("size-full")]' - prevSearch = '//a[./span[d:class("ticon-chevron-left")]]' - adult = True - - def starter(self): - archivePage = self.getPage(self.url) - self.archive = archivePage.xpath('//div[contains(@class, "vcex-portfolio-grid")]//a/@href') - return self.archive[-1] - - def getPrevUrl(self, url, data): - return self.archive[self.archive.index(url) - 1] - - class Vexxarr(_ParserScraper): baseUrl = 'http://www.vexxarr.com/' url = baseUrl + 'Index.php' @@ -82,3 +64,11 @@ class VirmirWorld(_ParserScraper): def getIndexStripUrl(self, index): index = index.split('-') return self.stripUrl % (index[0], index[1]) + + +class Vreakerz(ParserScraper): + url = 'http://vreakerz.angrykitten.nl/' + stripUrl = url + 'stories/read/%s' + firstStripUrl = stripUrl % '1' + imageSearch = '//img[contains(@src, "storypages")]' + prevSearch = '//a[@class="btn-prior"]' diff --git a/dosagelib/plugins/w.py b/dosagelib/plugins/w.py index 94c8e3008..0af93415b 100644 --- a/dosagelib/plugins/w.py +++ b/dosagelib/plugins/w.py @@ -5,7 +5,7 @@ # Copyright (C) 2019-2020 Daniel Ring from re import compile, escape, IGNORECASE -from ..scraper import _BasicScraper, _ParserScraper +from ..scraper import ParserScraper, _BasicScraper, _ParserScraper from ..util import tagre from ..helpers import bounceStarter from .common import ComicControlScraper, WordPressScraper, WordPressNaviIn, WordPressWebcomic @@ -36,13 +36,12 @@ class WebcomicName(_ParserScraper): multipleImagesPerStrip = True -class Weregeek(_ParserScraper): +class Weregeek(ParserScraper): url = 'http://www.weregeek.com/' - stripUrl = url + '%s/' - firstStripUrl = stripUrl % '2006/11/27' - imageSearch = '//div[@id="comic"]/img' - prevSearch = '//a[./img[@alt="Previous"]]' - help = 'Index format: yyyy/mm/dd' + stripUrl = url + 'comic/%s/' + firstStripUrl = stripUrl % 'comic-1' + imageSearch = '//div[d:class("webcomic-media")]//img' + prevSearch = '//a[d:class("previous-webcomic-link")]' class WereIWolf(_ParserScraper): diff --git a/dosagelib/plugins/webtoons.py b/dosagelib/plugins/webtoons.py index a77ff18c3..ecd3f47c2 100644 --- a/dosagelib/plugins/webtoons.py +++ b/dosagelib/plugins/webtoons.py @@ -87,6 +87,7 @@ class WebToons(ParserScraper): cls('BehindTheGIFs', 'comedy/behind-the-gifs', 658), cls('BigJo', 'romance/big-jo', 854), cls('BiteMe', 'thriller/bite-me', 1019), + cls('BitterSweetCoffee', 'challenge/bitter-sweet-coffee', 797203), cls('Blackened', 'challenge/blackened', 363805), cls('BladesOfFurry', 'romance/blades-of-furry', 2383), cls('Blessed', 'drama/blessed', 1193), @@ -105,6 +106,7 @@ class WebToons(ParserScraper): cls('CARL', 'slice-of-life/carl', 1216), cls('Caster', 'action/caster', 1461), cls('CastleSwimmer', 'fantasy/castle-swimmer', 1499), + cls('CatchMeIfYouCan', 'challenge/catch-me-if-you-can-', 434808), cls('Catharsis', 'fantasy/catharsis', 396), cls('CatLoafAdventures', 'slice-of-life/cat-loaf-adventures', 1381), cls('CChansACatgirl', 'challenge/c-chans-a-catgirl', 263430), @@ -120,7 +122,7 @@ class WebToons(ParserScraper): cls('CodeAdam', 'action/code-adam', 1657), cls('CookingComically', 'tiptoon/cooking-comically', 622), cls('Crumbs', 'romance/crumbs', 1648), - cls('CrystalVirus', 'challenge/crystal-virus', 347038), + cls('CrystalVirusOtherStory', 'challenge/crystal-virus-other-story', 837028), cls('CupidsArrows', 'romance/cupids-arrows', 1538), cls('CursedPrincessClub', 'comedy/cursed-princess-club', 1537), cls('Cyberbunk', 'sf/cyberbunk', 466), @@ -273,6 +275,7 @@ class WebToons(ParserScraper): cls('MidnightRain', 'drama/midnight-rain', 1797), cls('MidnightRhapsody', 'slice-of-life/midnight-rhapsody', 116), cls('MidnightRhapsodySeason2', 'slice-of-life/midnight-rhapsody-season2', 365), + cls('Miez', 'sf/miez', 2719), cls('MissAbbottAndTheDoctor', 'romance/miss-abbott-and-the-doctor', 707), cls('MonsterIsle', 'challenge/monster-isle', 531999), cls('MOONBEARD', 'comedy/moon-beard', 471), @@ -301,12 +304,12 @@ class WebToons(ParserScraper): cls('NoScope', 'sports/no-scope', 1572), cls('NotEvenBones', 'thriller/not-even-bones', 1756), cls('NothingSpecial', 'fantasy/nothing-special', 1188), + cls('NotSoLucky', 'challenge/not-so-lucky', 673387), cls('OddGirlOut', 'drama/odd-girl-out', 1420), cls('OhHoly', 'romance/oh-holy', 809), cls('OmniscientReader', 'action/omniscient-reader', 2154), cls('ORANGEMARMALADE', 'romance/orange-marmalade', 97), cls('Outrage', 'super-hero/outrage', 1450), - cls('OVERPOWERED', 'challenge/overpowered', 85292), cls('PacificRimAmara', 'sf/pacific-rim-amara', 1327), cls('PandorasBlogs', 'challenge/pandoras-blogs', 532007), cls('PaperRoses', 'challenge/paper-roses', 39736), @@ -401,6 +404,7 @@ class WebToons(ParserScraper): cls('TheRoomies', 'challenge/the-roomies-archive', 513669), cls('TheShadowProphet', 'drama/the-shadow-prophet', 1881), cls('TheSoundOfYourHeart', 'comedy/the-sound-of-your-heart', 269), + cls('TheSpectrumOfUs', 'challenge/the-spectrum-of-us', 334525), cls('TheSteamDragonExpress', 'fantasy/steam-dragon-express', 1270), cls('TheStoriesOfThoseAroundMe', 'romance/the-stories-of-those-around-me', 96), cls('TheStrangeTalesOfOscarZahn', 'fantasy/the-strange-tales-of-oscar-zahn', 685), @@ -453,6 +457,7 @@ class WebToons(ParserScraper): cls('WitchCreekRoad', 'horror/witch-creek-road', 1453), cls('WitchHunt', 'supernatural/witch-hunt', 363), cls('Wolfsbane', 'horror/wolfsbane', 1826), + cls('WorldsStrongestTroll', 'fantasy/worlds-strongest-troll', 5315), cls('XINK3R', 'super-hero/xinker', 541), cls('YourAdventure', 'comedy/your-adventure', 506), cls('YourLetter', 'drama/your-letter', 1540),