From 963db7f44832ed022766979b5152448a768b31e5 Mon Sep 17 00:00:00 2001 From: Tobias Gruetzmacher Date: Thu, 26 Dec 2019 22:03:18 +0100 Subject: [PATCH] Adopt SmackJeeves to new site design (fixes #144) Some things got lost on the way: - Since there is no comprehensive comic directory anymore, removed automatic update script. New comics need to be added manually. - Some authors used the opportunity to move from SmackJeeves somewhere else - some of those got new modules (either standalone or ComicFury) - Abunch of comics just disappeared... --- dosagelib/plugins/comicfury.py | 1 + dosagelib/plugins/d.py | 8 +- dosagelib/plugins/f.py | 4 + dosagelib/plugins/old.py | 40 +- dosagelib/plugins/r.py | 8 +- dosagelib/plugins/s.py | 4 + dosagelib/plugins/smackjeeves.py | 1345 ++++++++++++++---------------- scripts/comicfury.py | 8 +- scripts/generate_json.sh | 2 +- scripts/smackjeeves.py | 172 ---- scripts/update_plugins.sh | 2 +- 11 files changed, 696 insertions(+), 898 deletions(-) delete mode 100755 scripts/smackjeeves.py diff --git a/dosagelib/plugins/comicfury.py b/dosagelib/plugins/comicfury.py index c173291a0..0485a01ca 100644 --- a/dosagelib/plugins/comicfury.py +++ b/dosagelib/plugins/comicfury.py @@ -634,6 +634,7 @@ class ComicFury(_ParserScraper): cls('MadGirl', 'madgirl'), cls('MagicElDesencuentro', 'magiceldesencuentro', 'es'), cls('MagicTheScattering', 'magicthescattering'), + cls('Magience', 'magience'), cls('MAGISAPARASAYOupdatesMonFri', 'mag-isa'), cls('MagnaComica', 'magnacomica'), cls('Maluk', 'maluk'), diff --git a/dosagelib/plugins/d.py b/dosagelib/plugins/d.py index 7df10c548..0ffd35a8e 100644 --- a/dosagelib/plugins/d.py +++ b/dosagelib/plugins/d.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs # Copyright (C) 2012-2014 Bastian Kleineidam -# Copyright (C) 2015-2018 Tobias Gruetzmacher +# Copyright (C) 2015-2019 Tobias Gruetzmacher from __future__ import absolute_import, division, print_function @@ -214,6 +214,12 @@ class DorkTower(_ParserScraper): prevSearch = '//a[%s][text()="Previous"]' % xpath_class('btn') +class DoomsdayMyDear(_ParserScraper): + url = 'http://doomsdaymydear.com/' + imageSearch = '//img[{}]'.format(xpath_class('attachment-full')) + prevSearch = '//a[{}]'.format(xpath_class('previous-webcomic-link')) + + class Dracula(_BasicScraper): url = 'http://draculacomic.net/' stripUrl = url + 'comic.php?comicID=%s' diff --git a/dosagelib/plugins/f.py b/dosagelib/plugins/f.py index c11b0def1..7f774c859 100644 --- a/dosagelib/plugins/f.py +++ b/dosagelib/plugins/f.py @@ -109,6 +109,10 @@ class FonFlatter(_ParserScraper): ) +class ForestHill(_WordPressScraper): + url = 'https://www.foresthillcomic.org/' + + class ForLackOfABetterComic(_BasicScraper): url = 'http://forlackofabettercomic.com/' rurl = r'http://(?:www\.)?forlackofabettercomic\.com/' diff --git a/dosagelib/plugins/old.py b/dosagelib/plugins/old.py index 677ade572..d8287dab1 100644 --- a/dosagelib/plugins/old.py +++ b/dosagelib/plugins/old.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs # Copyright (C) 2012-2014 Bastian Kleineidam -# Copyright (C) 2015-2017 Tobias Gruetzmacher +# Copyright (C) 2015-2019 Tobias Gruetzmacher from __future__ import absolute_import, division, print_function @@ -411,21 +411,27 @@ class Removed(Scraper): cls('SmackJeeves/AchievementStuck'), cls('SmackJeeves/AGirlAndHerShadow'), cls('SmackJeeves/Allthatglitters'), + cls('SmackJeeves/AloversRule'), cls('SmackJeeves/Anathemacomics'), cls('SmackJeeves/AngelBeast'), cls('SmackJeeves/ArchportCityChronicles'), cls('SmackJeeves/AwesomeSauce'), + cls('SmackJeeves/BetweenLightandDark'), cls('SmackJeeves/BetweenWorlds'), cls('SmackJeeves/BeyondTemptation'), + cls('SmackJeeves/BLDShortComics'), cls('SmackJeeves/Bloodyfairytale'), cls('SmackJeeves/BLOT'), cls('SmackJeeves/BlueWell'), + cls('SmackJeeves/BreakfastonaCliff'), cls('SmackJeeves/CafeAmargo'), cls('SmackJeeves/Captor'), cls('SmackJeeves/ChaosTheory2005'), + cls('SmackJeeves/CleanCure'), cls('SmackJeeves/DaddysGirl'), cls('SmackJeeves/Debtsettlement'), cls('SmackJeeves/DebtSettlement2OperationExtinction'), + cls('SmackJeeves/DefyingGravityTheFourGreatGuardians'), cls('SmackJeeves/Destinationunknown'), cls('SmackJeeves/DevilTrainee'), cls('SmackJeeves/DevilTraineeSpanish'), @@ -436,7 +442,9 @@ class Removed(Scraper): cls('SmackJeeves/EternalKnights'), cls('SmackJeeves/EvD'), cls('SmackJeeves/FeathersPI'), + cls('SmackJeeves/FemmeSchism'), cls('SmackJeeves/FireWire'), + cls('SmackJeeves/FrenzyRedux'), cls('SmackJeeves/FrogKing'), cls('SmackJeeves/FuckMyLife'), cls('SmackJeeves/FurtherDowntheRabbitHole'), @@ -445,21 +453,33 @@ class Removed(Scraper): cls('SmackJeeves/GraveImpressions'), cls('SmackJeeves/GreenKirbyandabunchofotherpeopledoinstuff'), cls('SmackJeeves/Harfang'), + cls('SmackJeeves/HIPS'), cls('SmackJeeves/HotChocolate'), + cls('SmackJeeves/Hybristorific'), cls('SmackJeeves/Ianua'), cls('SmackJeeves/ImminentMoose'), cls('SmackJeeves/InthePride'), cls('SmackJeeves/Intoxicated'), + cls('SmackJeeves/Jantarpol'), cls('SmackJeeves/Knife'), cls('SmackJeeves/Kranburn'), + cls('SmackJeeves/KuroNeko'), + cls('SmackJeeves/LastLivingSouls'), cls('SmackJeeves/LatchkeyKingdom'), + cls('SmackJeeves/LegendsofMobiusBookOne'), + cls('SmackJeeves/LiliBleu'), cls('SmackJeeves/LoveTwister'), + cls('SmackJeeves/MagicalGirlAlice'), + cls('SmackJeeves/MasqueradeWTTM'), + cls('SmackJeeves/MegaManBattleNetwork7'), cls('SmackJeeves/MegaManiacs'), cls('SmackJeeves/MerirosvotSeikkailumerella'), cls('SmackJeeves/MewsDynasty'), + cls('SmackJeeves/MixupofallMixups'), cls('SmackJeeves/MomthegamestorerippedusoffAGAIN'), cls('SmackJeeves/MoonlitDawnAMythicalTale'), cls('SmackJeeves/MyBoyfriendisaMobBoss'), + cls('SmackJeeves/MyTrollLife'), cls('SmackJeeves/NihilWandasJourney'), cls('SmackJeeves/OddContact'), cls('SmackJeeves/OneFrameGags'), @@ -472,24 +492,37 @@ class Removed(Scraper): cls('SmackJeeves/PumpkinFlower'), cls('SmackJeeves/Razor'), cls('SmackJeeves/SAKANA'), + cls('SmackJeeves/SenoireDelirium'), cls('SmackJeeves/SerendipityAnEquestrianTale'), cls('SmackJeeves/ShacklesInstallment02'), + cls('SmackJeeves/SimonSues'), + cls('SmackJeeves/SonicUniverseAsk'), cls('SmackJeeves/SoulGuardian'), + cls('SmackJeeves/Spidersilk', 'mov'), + cls('SmackJeeves/Symbios'), cls('SmackJeeves/TechnicolorLondon'), cls('SmackJeeves/TeKscloset'), cls('SmackJeeves/TheAttackoftheRecoloursSeason1'), + cls('SmackJeeves/TheCurtandTonyShow'), + cls('SmackJeeves/TheDarkAgeofMobius'), + cls('SmackJeeves/TheHobbitbic'), cls('SmackJeeves/ThehumanBEing'), + cls('SmackJeeves/TheKeyToReality'), + cls('SmackJeeves/TheLostland'), cls('SmackJeeves/TheMewExperiment'), cls('SmackJeeves/TheRandomObscureFairyTaleNoOnesEverReallyHeardOf'), cls('SmackJeeves/TheSomewhereOther'), cls('SmackJeeves/TheWastelands', 'mis'), + cls('SmackJeeves/ThinkBeforeYouThink', 'mov'), cls('SmackJeeves/ThroughTheWonkyEye'), cls('SmackJeeves/TitleUnrelated'), cls('SmackJeeves/TotalPokemonIsland'), cls('SmackJeeves/TrillyAndSilly'), + cls('SmackJeeves/TRIPP'), cls('SmackJeeves/VampireFetish'), cls('SmackJeeves/WolfWolf'), cls('SmackJeeves/WonderTheatre'), + cls('SmackJeeves/YouAreTheReasonForTheEndOfTheWorld'), cls('SnowFlakes'), cls('StrawberryDeathCake'), cls('Stubble'), @@ -629,6 +662,11 @@ class Renamed(Scraper): cls('PetiteSymphony/Djandora', 'ComicsBreak/Djandora'), cls('PetiteSymphony/Generation17', 'ComicsBreak/Generation17'), cls('SmackJeeves/CityFolk', 'ComicFury/CityFolk'), + cls('SmackJeeves/DoomsdayMyDear', 'DoomsdayMyDear'), + cls('SmackJeeves/ForestHill', 'ForestHill'), + cls('SmackJeeves/Magience', 'ComicFury/Magience'), + cls('SmackJeeves/RiversideExtras', 'RiversideExtras'), + cls('SmackJeeves/StarTrip', 'StarTrip'), cls('TracyAndTristan', 'ComicFury/TracyAndTristan'), cls('Wulffmorgenthaler', 'WuMo'), cls('ZebraGirl', 'ComicFury/ZebraGirl'), diff --git a/dosagelib/plugins/r.py b/dosagelib/plugins/r.py index 56149f8e0..8c0b95bd0 100644 --- a/dosagelib/plugins/r.py +++ b/dosagelib/plugins/r.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs # Copyright (C) 2012-2014 Bastian Kleineidam -# Copyright (C) 2015-2017 Tobias Gruetzmacher +# Copyright (C) 2015-2019 Tobias Gruetzmacher from __future__ import absolute_import, division, print_function @@ -108,6 +108,12 @@ class Replay(_ParserScraper): return name +class RiversideExtras(_ParserScraper): + url = 'https://riversidecomics.com/' + imageSearch = '//div[{}]//img'.format(xpath_class('webcomic-image')) + prevSearch = '//a[{}]'.format(xpath_class('previous-webcomic-link')) + + class RomanticallyApocalyptic(_ParserScraper): url = 'http://romanticallyapocalyptic.com/' stripUrl = url + '%s' diff --git a/dosagelib/plugins/s.py b/dosagelib/plugins/s.py index 0e9239ba7..a537c268f 100644 --- a/dosagelib/plugins/s.py +++ b/dosagelib/plugins/s.py @@ -507,6 +507,10 @@ class StarfireAgency(_WordPressScraper): return chapter + '_' + filename +class StarTrip(_ComicControlScraper): + url = 'https://www.startripcomic.com/' + + class StationV3(_ParserScraper): url = 'http://www.stationv3.com/' stripUrl = url + 'd3/%s.html' diff --git a/dosagelib/plugins/smackjeeves.py b/dosagelib/plugins/smackjeeves.py index 21619eb7b..ea91cbd08 100644 --- a/dosagelib/plugins/smackjeeves.py +++ b/dosagelib/plugins/smackjeeves.py @@ -1,740 +1,651 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs -# Copyright (C) 2012-2014 Bastian Kleineidam # Copyright (C) 2015-2019 Tobias Gruetzmacher from __future__ import absolute_import, division, print_function -from six.moves.urllib.parse import urlsplit +import re -from ..util import quote +from ..helpers import xpath_class from ..scraper import _ParserScraper -from ..output import out - -# SmackJeeves is a crawlers nightmare - users are allowed to edit HTML -# directly. Additionally, users use unescaped < characters sometimes, which -# breaks the parse tree on libxml2 before 2.9.3... class SmackJeeves(_ParserScraper): - ONLY_COMICS = '[contains(@href, "/comics/")]' + baseUrl = 'https://www.smackjeeves.com/discover/' + apiBase = 'https://www.smackjeeves.com/api/discover/' + prevSearch = '//a[i[{}]]'.format(xpath_class('i-arrow-double-left-black')) + imageSearch = re.compile("comicData:[^']*'([^']*)'", re.DOTALL) + help = 'Index format: n' - prevSearch = ( - '//a[@class="nav-prev"]' + ONLY_COMICS, - '//a[img[@id="sj_nav_prev_img"]]' + ONLY_COMICS, - '//a[img[re:test(@alt, "prev", "i") and not(@id="comic_image")]]' + ONLY_COMICS, - '//a[img[re:test(@src, "/(prev|back|Yun2lVQ)")]]' + ONLY_COMICS, - '//a[re:test(@title, "previous", "i")]' + ONLY_COMICS, - '//a[re:test(text(), "prev|back|atras", "i")]' + ONLY_COMICS, - '//a[div[@class="prev"]]' + ONLY_COMICS, - '//select[@class="jumpbox"]/preceding::a[1]' + ONLY_COMICS, - '//form[@name="jumpbox"]/preceding::a[1]' + ONLY_COMICS, - ) - - nextSearch = ( - '//a[@class="nav-next"]' + ONLY_COMICS, - '//a[img[@id="sj_nav_next_img"]]' + ONLY_COMICS, - '//a[img[re:test(@alt, "next", "i") and not(@id="comic_image")]]' + ONLY_COMICS, - '//a[img[re:test(@src, "/(next|wJkQA07)", "i")]]' + ONLY_COMICS, - '//a[re:test(@title, "next", "i")]' + ONLY_COMICS, - '//a[re:test(text(), "next|siguiente", "i")]' + ONLY_COMICS, - '//a[div[@class="next"]]' + ONLY_COMICS, - '//select[@class="jumpbox"]/following::a[1]' + ONLY_COMICS, - '//form[@name="jumpbox"]/following::a[1]' + ONLY_COMICS, - ) - - imageSearch = ( - '//img[@id="comic_image"]', - '//div[@id="comic-image"]//img', - '//img[@id="comic"]', - '//div[@id="comicset"]/object/param[@name="movie"]/@value', - ) - - broken_html_bugfix = True - - def __init__(self, name, host=None, sub=None, adult=False, endOfLife=False): + def __init__(self, name, id, adult=False, endOfLife=False): super(SmackJeeves, self).__init__('SmackJeeves/' + name) - if host: - self.url = 'http://%s/comics/' % host - else: - self.url = 'http://%s.smackjeeves.com/comics/' % sub + self._comicid = id + self.url = self.baseUrl + 'articleList?titleNo={}'.format(id) + self.stripUrl = self.baseUrl + 'detail?titleNo={}&articleNo=%s'.format(id) + self.firstStripUrl = self.stripUrl % 1 self.adult = adult self.endOfLife = endOfLife def starter(self): - """Get start URL.""" - start = self.url - if self.adult: - host = urlsplit(self.url).hostname - start = 'http://%s/mature.php?ref=%s' % (host, quote(start)) - data = self.getPage(start) - startimg = None - if not self.shouldSkipUrl(start, data): - startimg = self.fetchUrl(start, data, self.imageSearch) - prevurl = self.fetchUrl(start, data, self.prevSearch) - data = self.getPage(prevurl) - previmg = None - if not self.shouldSkipUrl(prevurl, data): - previmg = self.fetchUrl(prevurl, data, self.imageSearch) - if startimg and previmg and startimg == previmg: - out.debug("Matching! %s %s" % (prevurl, self.name)) - return prevurl - else: - return self.fetchUrl(prevurl, data, self.nextSearch) + response = self.session.post(self.apiBase + 'articleList', + params={'titleNo': self._comicid}) + response.raise_for_status() + return response.json()['result']['list'][-1]['articleUrl'] + + def fetchUrls(self, url, data, urlsearch): + if urlsearch != self.imageSearch: + return super(SmackJeeves, self).fetchUrls(url, data, urlsearch) + + # Find image URL in JavaScript + datatag = data.xpath('//script[contains(text(), "comicData")]') + if not datatag: + return () + datamatch = self.imageSearch.search(datatag[0].text) + if not datamatch: + return () + return (datamatch.group(1),) + + def link_modifier(self, fromurl, tourl): + # All links redirect to /discover/ - so fix it to save a request + return tourl.replace('com/detail', 'com/discover/detail') def namer(self, image_url, page_url): - parts = page_url.split('/') - name = parts[-2] - num = parts[-3] - return "%s_%s" % (name, num) - - def shouldSkipUrl(self, url, data): - return (data.xpath('//img[contains(@src, "/images/image_na.gif")]') or - '/851756/175-final-story-15-paradise' in url or - '/2422158/hedgehog-piece-grand-voyage' in url) + articleNo = int(page_url.rsplit('=', 1)[1]) + return '{:04}'.format(articleNo) @classmethod def getmodules(cls): return ( - # these would be generated by scripts/smackjeeves.py, but the sheer - # amount of comics on SmackJeeves makes that idea rather - # unattractive. If you add new comics, try to copy them from the - # output of that script... - # START AUTOUPDATE - cls('20TimesKirby', sub='20xkirby'), - cls('2Kingdoms', sub='2kingdoms', endOfLife=True), - cls('355Days', sub='355days'), - cls('_A_', sub='a-the-stalker', endOfLife=True), - cls('AB', sub='alistairandboggart', adult=True), - cls('AceOfHearts', sub='aceof-hearts'), - cls('AcidMonday', sub='acidmonday', adult=True), - cls('Adalsysla', sub='adalsysla', endOfLife=True), - cls('AddictiveScience', sub='addictivescience'), - cls('ADoodleADay', sub='adoodleaday'), - cls('AdventuresOfLumAndFriends', sub='aolaf'), - cls('AdventuresoftheWeird', sub='adventuresoftheweird'), - cls('AetherTheories', sub='aethertheories'), - cls('AgeOfTheGray', sub='ageofthegray'), - cls('AGirlOnTheServer', sub='girlontheserver'), - cls('AKirbyKomic', sub='akirbykomic'), - cls('ALaMode', sub='alamode'), - cls('AllInLOVE', sub='allinlove'), - cls('AllStarHeroes', sub='allstarheroes'), - cls('AlmostTouching', sub='almosttouching', adult=True), - cls('AloversRule', sub='aloversrule', adult=True), - cls('AlwaysDamnedWebcomic', sub='alwaysdamned', adult=True), - cls('AlwaysRainingHere', sub='alwaysraininghere'), - cls('Amaravati', sub='amaravati'), - cls('AmorVincitOmnia', sub='avo', adult=True), - cls('AmsdenEstate', sub='monsterous'), - cls('AngelGuardian', sub='angel-guardian'), - cls('ANGELOU', sub='angelou-esp'), - cls('AnimalAdventures', sub='animaladventures'), - cls('Animayhem', sub='animayhem'), - cls('AnythingAboutNothing', host='www.anythingcomic.com'), - cls('APTComic', sub='aptcomic'), - cls('AQuestionOfCharacter', sub='aqoc'), - cls('Area9', sub='area-9'), - cls('AroundTheBlock', sub='aroundtheblock'), - cls('ArtOfAFantasy', sub='artofafantasy', adult=True), - cls('ASongforElise', sub='asongforelise', adult=True), - cls('AtArmsLength', host='www.atarmslength.net'), - cls('Atlaswebcomic', sub='atlaswebcomic'), - cls('Autophobia', sub='autophobia'), - cls('Aware', sub='aware'), - cls('AyaTakeo', sub='ayatakeo'), - cls('AYuriCollab', sub='ayuricollabbitches', adult=True), - cls('BabysittingFourDemons', sub='babysitting4demons'), - cls('Babywhatsyoursign', sub='babywhatsyoursign'), - cls('BadassRiz', sub='badassriz'), - cls('BallandChain', sub='ballandchain'), - cls('Bard', sub='barred'), - cls('BassComicAdventures', sub='basscomicadventures'), - cls('BattleSequence', sub='battlesequence'), - cls('Bearhoney', sub='bear-honey'), - cls('BearlyAbel', sub='bearlyabel'), - cls('BeautifulLies', sub='beautiful-lies'), - cls('BehindTheGlassCurtain', sub='g1ass', endOfLife=True), - cls('BehindTheObsidianMirror', sub='obsidian-mirror', adult=True), - cls('BeretCatComics', sub='beretcatcomics'), - cls('Bestbrosforever', sub='bestbrosforever'), - cls('Betovering', sub='betovering', adult=True), - cls('BettencourtHotel', sub='bettencourt', endOfLife=True), - cls('BetweenLightAndDark', sub='bld'), - cls('BeTwin', sub='be-twin', endOfLife=True), - cls('BeyondTheOrdinary', sub='bto'), - cls('BioRevelation', sub='biorevelation'), - cls('Bl3', sub='bl3', endOfLife=True), - cls('BlackAndBlue', sub='black-and-blue', endOfLife=True), - cls('Blackdemon', sub='blackdemoncomics'), - cls('BlackDragon', sub='blackdragon'), - cls('BlackFridayRule', sub='blackfridayrule'), - cls('BlackTapestries', sub='blacktapestries', adult=True), - cls('BlackSheepcomic', sub='black-sheep'), - cls('BLDShortComics', sub='bldshortcomics'), - cls('BleachRedux', sub='bleachredux'), - cls('BlindandBlue', sub='blindandblue'), - cls('BloodhuntersBirthOfAVampire', sub='bloodhunters', endOfLife=True), - cls('BloomAPokemonConquestComic', sub='bloomconquest'), - cls('BlueHair', sub='bluehair'), - cls('BoilingPointofBrain', sub='bpob'), - cls('BoogeyDancingMonkeyPot', sub='monkeypot'), - cls('BreachOfAgency', sub='breachofagency', endOfLife=True), - cls('BreakfastOnACliff', sub='boac'), - cls('Burn', sub='burn'), - cls('ByTheBook', sub='bythebook', adult=True), - cls('CafeSuada', sub='cafesuada'), - cls('Cambion', sub='cambion', adult=True), - cls('CaptiveSoul', sub='captive-soul'), - cls('Captured', sub='captured', adult=True), - cls('CaravanaTaleofGodsandMen', sub='caravantale'), - cls('Cataclysm', sub='cataclysm', adult=True), - cls('Catnip', sub='catnipmanga', adult=True), - cls('Cerintha', sub='cerintha'), - cls('ChampionofChampions', sub='championofchampions'), - cls('ChampionsAndHeroesAgeOfDragons', sub='championsandheroes'), - cls('ChannelDDDNews', sub='dddnews'), - cls('ChaosAdventuresII', sub='chaosadventuresii'), - cls('ChaoticNation', sub='chaoticnation', adult=True), - cls('Charaktermaske', sub='charaktermaske'), - cls('Chatuplines', sub='chatuplines'), - cls('CheneysGotaGun', sub='cheney'), - cls('ChickenScratches', sub='chickenscratches'), - cls('ChildrenOfTheNight', sub='cotn'), - cls('ChimiMouryou', sub='cmmr'), - cls('ChocolatewithPepper', sub='chocolate-with-pepper'), - cls('ClairetheFlare', sub='clairetheflare'), - cls('CleanCure', sub='cleanpluscure'), - cls('ClockworkAtrium', host='www.clockwork-atrium.com'), - cls('CloeRemembrance', sub='cloe', endOfLife=True), - cls('CockroachTheater', sub='cockroachtheater'), - cls('Cogs', sub='cogs'), - cls('ColorBlind', sub='cbcomic'), - cls('ConventionalWisdom', sub='conventionalwisdom'), - cls('CosmicDash', sub='cosmicdash'), - cls('Cramberries', sub='cramberries'), - cls('CrimsonWings', sub='crimson-wings'), - cls('CrocodileTears', sub='crocodile-tears', adult=True), - cls('CupOfOlea', sub='cupofolea'), - cls('CurseLineage', sub='curselineage'), - cls('DanielleDark', sub='danielledark'), - cls('Dasien', sub='dasien', adult=True), - cls('DavidDoesntGetIt', sub='daviddoesntgetit'), - cls('DBON', sub='dbondoujin'), - cls('DeadtoDay', sub='deadtoday'), - cls('DeathNoteIridescent', sub='dn-iridescent'), - cls('DefyingGravityTheFourGreatGuardians', sub='defyinggravitycomic'), - cls('DEGAF', sub='degaf'), - cls('DEMENTED', sub='demented', adult=True), - cls('DemonBattles', sub='demonbattles'), - cls('DemonCat', sub='demoncat'), - cls('DemonEater', sub='demoneater', adult=True), - cls('DenizensAttention', sub='denizensattention'), - cls('DevilsCake', sub='devilscake'), - cls('DevotoMusicinHell', sub='devoto', adult=True), - cls('Diaz', sub='diaz'), - cls('DigimonSaviors', sub='digimonsaviors'), - cls('DigimonTamersMiraiProject', sub='digimontamersmiraiproject'), - cls('DigisRandomSpriteshack', sub='digisspriteshack'), - cls('DigitalInsanity', sub='digitalinsanity'), - cls('DoItYourself', sub='diy'), - cls('DontDie', sub='dontdie'), - cls('DoodleBeans', sub='beans', adult=True), - cls('DoodlingAround', sub='doodlingcomic'), - cls('DoomsdayMyDear', host='www.doomsdaymydear.com'), - cls('Dragonet', sub='dragonet'), - cls('DragonKid', sub='dragonkid'), - cls('DreamCatcher', host='www.dreamcatchercomic.com'), - cls('DumpofManyPeople', sub='dumpofmanypeople'), - cls('DungeonHordes', sub='dungeonhordes'), - cls('EATATAU', sub='eatatau'), - cls('EDepthAngel', sub='edepth'), - cls('EidolonWhispersOfEternity', sub='whispersofeternity'), - cls('ElementalSpirits', sub='elementalspirits'), - cls('EnkeltenKentta', sub='enkeltenkentta', adult=True), - cls('Enthrall', sub='enthrall', adult=True), - cls('EntreEuxDeux', sub='entreuxdeux', endOfLife=True), - cls('Entuthrie', sub='entuthrie', adult=True), - cls('Eorah', sub='eorah', adult=True), - cls('Equsopia', sub='equsopia'), - cls('ERAConvergence', sub='convergence', endOfLife=True), - cls('ERAIbuki', sub='eraibuki', endOfLife=True), - cls('ERRORERROR', sub='errorerror'), - cls('EuphemisticEephus', sub='eephus'), - cls('EvilPlan', host='evilplan.thewebcomic.com'), - cls('ExperimentalMegaman', sub='ex90081'), - cls('EyesOfADigimon', sub='eoad'), - cls('FailureConfetti', sub='failureconfetti'), - cls('FairyTaleRejects', sub='fairytalerejects', adult=True), - cls('FaithlessDigitals', sub='faithlessdigitals'), - cls('FalconersDailyStrips', sub='falcdaily'), - cls('FallenAngelslove', sub='fallen-angels-love'), - cls('FarOutMantic', sub='meteorflo'), - cls('FarOutThere', sub='faroutthere'), - cls('FatetheAnthologyofKaienandhisfuckingmagicfriends', sub='fatehoho'), - cls('FemmeSchism', sub='femmeschism'), - cls('FeralGentry', sub='feralgentry'), - cls('FinalArcanum', sub='finalarcanum'), - cls('FireredLisasReise', sub='lisasreise'), - cls('FlyorFail', sub='flyorfail'), - cls('ForcedSeduction', sub='forced-seduction'), - cls('ForestHill', host='www.foresthillcomic.org'), - cls('ForgetTheDistance', sub='forgetthedistance', adult=True), - cls('Fortheloveofabrokenstring', sub='fortheloveofabrokenstring'), - cls('FramebyFrame', sub='frame-by-frame', adult=True), - cls('FrenzyRedux', sub='theadventuresoffrenzy'), - cls('FrobertTheDemon', sub='frobby'), - cls('FromnowonImagirl', sub='fromnowonimagirl'), - cls('FruitloopAndMrDownbeat', sub='fruitbeat'), - cls('FullSpectrumTherapy', sub='fst'), - cls('FurryExperience', sub='furryexperience'), - cls('GamerCafe', sub='gamercafe'), - cls('GamesPeoplePlayUpdatedWeekly', sub='gamespeopleplay'), - cls('GardenofHearts', sub='gardenofhearts'), - cls('GayBacon', sub='gaybacon'), - cls('GayTimesWithRyanAndJay', sub='gtwraj'), - cls('GetUpAndGo', sub='getupandgo', adult=True), - cls('GigisNuzlockeRuns', sub='giginuzlocke'), - cls('Gloomverse', sub='gloomverse'), - cls('Gnoph', sub='gnoph', endOfLife=True), - cls('GoldenSunGenerationsAftermathVolume1', sub='gsgbtsyearone'), - cls('GoldenSunGenerationsColossoVolume6', sub='gsgbtsyearthree'), - cls('GoodGame', sub='goodgame', endOfLife=True), - cls('GoodnightMrsGoose', sub='goose'), - cls('Grayscale', sub='grayscale', adult=True), - cls('GuardianGhost', sub='guardianghost'), - cls('GuardiansoftheGalaxialSpaceways', sub='ggs'), - cls('Habibahssong', sub='habibahsong'), - cls('HarvestMoonParadiseFound', sub='paradisefound', endOfLife=True), - cls('HateThePlayer', host='hatetheplayer.thewebcomic.com'), - cls('HatShop', sub='hatshop'), - cls('Helix', host='www.helixcomic.com'), - cls('HeltonShelton', sub='heltonshelton'), - cls('HendrixAndJulian', sub='hendrixandjulian', adult=True), - cls('Hephaestus', host='hephaestus.thewebcomic.com'), - cls('HereBeVoodoo', sub='herebevoodoo', adult=True), - cls('HiddenStrengthAWhiteNuzlocke', sub='hsnuzlocke'), - cls('Hinata', sub='hinata'), - cls('HIPS', sub='hips', adult=True), - cls('HitandMiss', sub='hitandmiss'), - cls('Holocrash', sub='holocrash', endOfLife=True), - cls('HolyBlasphemy', sub='holyblasphemy'), - cls('HolyCrap', sub='holycrap'), - cls('HopeForABreeze', sub='h4ab'), - cls('HouseOfCraziness', sub='craziness'), - cls('HurrocksFardel', sub='hurrocksfardel'), - cls('Hybristorific', sub='hybristorific', adult=True), - cls('IciVontLesMorts', sub='icivontlesmorts', adult=True), - cls('Inchoatica', sub='inchoatica'), - cls('Ingloriousbasterds', sub='ingloriousbasterds'), - cls('InHouseHumor', sub='inhousehumor'), - cls('Inhuman', sub='inhumancomic'), - cls('InsideOuTAYuriTale', sub='insideout-a-yuri-tale'), - cls('InspiredByADream', sub='inspiredbyadream'), - cls('ItsAn8BitWorldBlankWorld', sub='8bitblankworld'), - cls('IWishIggysWish', sub='i-wish-comic'), - cls('JackiesStory', sub='jackiestory'), - cls('Jantarpol', sub='jantar-pl'), - cls('Jantar', sub='jantar'), - cls('Jason', sub='jasoncomic'), - cls('JoeysAdventure', sub='joeysadventure'), - cls('JourneyMan', sub='journeyman'), - cls('JoyToTheWorld', sub='joytotheworld'), - cls('June', sub='june'), - cls('JustAnotherLife', sub='justanotherlife'), - cls('JustCrazy', sub='justcrazy'), - cls('Justmyluck', sub='justmyluck'), - cls('KaitoShuno', sub='kaitoshuno', adult=True), - cls('KasaKeira', sub='kasakeira'), - cls('Katran', sub='katran'), - cls('KazanatoFuneralPlanningService', sub='kazanato'), - cls('KCNO', sub='kcno', endOfLife=True), - cls('KezroChroniclesPhantomOps', sub='phantomops'), - cls('Kirbandfriendsshowcase', sub='kas'), - cls('KirbiesoftheAlternateDimension', sub='kirbyaltdimension'), - cls('KirbyAdventure', sub='kirbysadventure'), - cls('KirbyDreamTeam', sub='kirbysdreamteam'), - cls('KirbyFunfestTheOriginals', sub='kirbyfunfestold'), - cls('KirbysDreamAdventure', sub='kirbyda'), - cls('KirbysDreamlandAdventures', sub='kirbysdreamlandadventures'), - cls('KirbyTheDeeArmy', sub='kirbyandthedeearmy', endOfLife=True), - cls('KissmeSnow', sub='kissmesnow'), - cls('KissoftheDevil', sub='kissofthedevil'), - cls('Knightface', sub='knightface', adult=True), - cls('KnightsRequiem', sub='knightsrequiem'), - cls('KojiX5', sub='kojix5', endOfLife=True), - cls('Kreetor', sub='kreetor'), - cls('Kruptos', sub='kruptos', endOfLife=True), - cls('KuronaFlutterandLylaSpamTime', sub='icantflyaplane'), - cls('KuroNeko', sub='kuro-neko'), - cls('LastBlockStanding', sub='lastblockstanding'), - cls('LastLivingSouls', host='lastlivingsouls.thewebcomic.com'), - cls('LavenderLegend', sub='lavenderlegend'), - cls('LeCirquedObscure', sub='cirquedobscure'), - cls('LedbyaMadMan', sub='ledbyamadman'), - cls('LegendOfZeldaAHerosStory', sub='aherosstory'), - cls('LegendOfZeldaStaffOfPower', sub='loz-sop'), - cls('LegendOfZeldaTheEdgeAndTheLight', sub='legendofzelda', endOfLife=True), - cls('LegendOfZeldaTheWindWaker', sub='zeldawindwaker'), - cls('LegendsofMobiusBookOne', sub='legendsofmobius-bookone'), - cls('Lemongrass', sub='lemongrass'), - cls('LesCendresdelHiver', sub='cendres'), - cls('LethalDose', sub='lethaldosecomic', adult=True), - cls('LetLoveRule', sub='letloverule'), - cls('LetsBreakitforReals', sub='breaktehmentality'), - cls('LicensedHeroes', sub='licensedheroes'), - cls('LifeAsACutOut', host='lifeasacutout.thewebcomic.com'), - cls('LifeAsItWas', sub='lifeasitwas'), - cls('LifeLessOrdinary', sub='lifelessordinary', adult=True), - cls('Lifeonpaper', sub='lifeonpaper'), - cls('LightLovers', sub='lightlovers', adult=True), - cls('LightwithinShadow', sub='lightwithinshadow'), - cls('LiliBleu', sub='lilibleu'), - cls('LilLevi', sub='lillevi'), - cls('LOGOS', sub='logoscomic', adult=True), - cls('LOKI', sub='loki'), - cls('LondonUnderworld', sub='lunderworld'), - cls('LostNova', sub='lostnova'), - cls('LoveandIcecream', sub='lovexandxicecream'), - cls('LoveHarbor', sub='shipcentral'), - cls('LoveMeLoveMyTeddyBear', sub='teddybear'), - cls('LoveroftheSunandMoon', sub='loverofthesunandmoon'), - cls('LsEmpire', sub='l-empire'), - cls('LuffinpuffandEric', sub='luffinpuff'), - cls('LumasParadise', sub='luma'), - cls('MagicalGirlAlice', sub='magicalgirlalice'), - cls('MagicalMisfits', sub='magicalmisfits'), - cls('Magience', host='www.magience.co'), - cls('Magipunk', sub='magipunk'), - cls('Manifestedpart1', sub='manifested'), - cls('MarioandLuigiMisadventures', sub='mandladventures'), - cls('MariosDayJob', sub='mariosjob'), - cls('MarioVsSonicVsMegaMan', sub='mvsvmm', endOfLife=True), - cls('MarsMind', sub='marsmind'), - cls('MarXistemTWC', sub='marxistem'), - cls('Mascara', sub='mascara'), - cls('MasqueradeWTTM', sub='masqueradewttm'), - cls('MatildasSweetCakeCafe', sub='mscc', adult=True), - cls('MayTheRainCome', sub='maytheraincome', endOfLife=True), - cls('Mazscara', sub='mazscara'), - cls('MegaManBattleNetwork7', sub='mmbn7-twt'), - cls('MegaManTales', sub='megamantales'), - cls('MegaPain', sub='megapain'), - cls('MelodyAndMacabre', sub='melodyandmacabre'), - cls('Merceneiress', host='www.merceneiress.com'), - cls('MetroJack', sub='metro-jack', adult=True), - cls('MidnightPrince', sub='midnightprince', adult=True), - cls('MineS', sub='mines'), - cls('Minibot', sub='minibot'), - cls('MinorActsOfHeroism', host='www.minoractsofheroism.com'), - cls('Missing', sub='missing'), - cls('Missingversionfrancaise', sub='missingfr'), - cls('MixupofallMixups', sub='mixupofmixups'), - cls('MobianChaos', sub='mobianchaos'), - cls('Mokepon', sub='mokepon'), - cls('Monstar', host='monstar.thewebcomic.com'), - cls('MoonValley', sub='moonvalley'), - cls('MorphE', sub='morphe'), - cls('Mortifer', sub='mortifer'), - cls('MrFactory', sub='mrfactory'), - cls('MUTE', sub='muterobot', endOfLife=True), - cls('MyFakeHeart', sub='myfakeheart'), - cls('MySisterTheDragon', sub='sisterdragon', endOfLife=True), - cls('MySparklingPrincesama', sub='kiraouji'), - cls('MyStereoBot', sub='mystereobot'), - cls('MysticanDreams', sub='mysticandreams'), - cls('MythsOfUnovaAWhiteNuzlockeRunHardMode', sub='mythsofunova'), - cls('MYth', sub='myth'), - cls('MyTrollLife', sub='mytrolllife'), - cls('MyTwoCentsPlusTax', sub='mtcpt'), - cls('Nah', sub='thecomicformerlyknownasgenlab'), - cls('Negligence', sub='negligence'), - cls('NeoCrystalAdventures', sub='neocrystaladventures'), - cls('NeonGlow', sub='neonglow'), - cls('NeverTheHero', sub='neverthehero'), - cls('Nexus', sub='nexus'), - cls('NiceKitty', sub='nicekitty'), - cls('NighHeavenandHell', sub='oldnighheavenandhell', adult=True), - cls('NightSpace', sub='nightspace'), - cls('NIK', sub='nik'), - cls('NissiesDragonPrincess', sub='drgnprincess'), - cls('NixsFireRedNuzlocke', sub='nixnuzlocke'), - cls('NobleHeartsHiruandMerroug', sub='hiruandmerroug', adult=True), - cls('NoEnd', sub='no-end'), - cls('NormalcyisforWimps', sub='normalcyisforwimps'), - cls('NotyoursamI', sub='notyoursami', adult=True), - cls('ObnoxiousHerokun', sub='hero-kun', adult=True), - cls('ObsidianHeart', sub='obsidianheart'), - cls('October20th', sub='october20th'), - cls('OddPlaceOddTime', sub='oddplaceoddtime'), - cls('Ohman', sub='ohman'), - cls('OldElastikid', sub='oldelastikid'), - cls('OneRainyDay', sub='one-rainy-day', adult=True), - cls('Onlyonelovesong', sub='onlyonelovesong'), - cls('OperationTheater', sub='operation-theater'), - cls('OriginBook1Codearth', sub='theoriginbooks'), - cls('OurTimeInEden', sub='ourtimeineden'), - cls('Outbreak', sub='xoutbreak'), - cls('OutofKey', sub='outofkey'), - cls('OverSync', sub='oversync'), - cls('Pahantekija', sub='pahantekija'), - cls('Panacea', sub='panacea', adult=True), - cls('PantsParty', sub='partypants'), - cls('PanzerDragonandEnigmaCompleteEdition', sub='panzerdragonandenigma'), - cls('Paradox', sub='paradoxcomic', adult=True), - cls('Pause', sub='pause'), - cls('PencilviewUpdatesMondayscough', sub='pencilview'), - cls('PerplexingMagnoliaDisruption', sub='smgpmd'), - cls('PeterPan', sub='peterpan'), - cls('Phantomland', sub='phantomland'), - cls('PhotoShootNarusasuDoujinshi', sub='photoshootnarusasu', adult=True), - cls('PlasticKings', sub='plastickings'), - cls('PlayTime', sub='dollysplaytime'), - cls('PleaseBeMyBoytoy', sub='pleasebemyboytoy'), - cls('PMDExplorersOfHeart', sub='pmd-explorers-of-heart'), - cls('PMDTeamFirefox', sub='pmdteamfirefox'), - cls('PMDVictoryFire', sub='victoryfire'), - cls('PokemonBeta', sub='pokemonbeta', endOfLife=True), - cls('PokemonCrystalDoubleNuzlockeChallenge', sub='miinuzlocke', endOfLife=True), - cls('PokemonLANDSKY', sub='landsky'), - cls('PokemonMysteryDungeonTeamCrystal', sub='crystalmysterydungeon'), - cls('PokemonNoRakuen', sub='pokemon-no-rakuen'), - cls('PokemonParallel', sub='pokemon-parallel'), - cls('PokemonSAKOHJU', sub='sakohju'), - cls('Pokeventurous', sub='pokeventuras'), - cls('Ponzi', sub='ponzi'), - cls('PrettyMouth', sub='prettymouth'), - cls('PrincessChroma', sub='princesschroma'), - cls('ProfessorDolphinpresentsPokemon', sub='pdpp'), - cls('ProjectCAPLimit', sub='imagecap'), - cls('PTO', sub='pto', adult=True), - cls('Puck', sub='puck'), - cls('PullingYouUnder', sub='pullingyouunder', adult=True), - cls('PulseandBolt', sub='pulse-bolt'), - cls('PurpureaNoxa', sub='purpureanoxa', adult=True), - cls('QueerQueen', sub='queerqueen'), - cls('RainbowMansion', host='rainbow-mansion.thewebcomic.com', adult=True), - cls('RainLGBT', sub='rainlgbt'), - cls('RainxSasori', sub='rainxsasori', adult=True, endOfLife=True), - cls('RANDOM', sub='randomthecomic'), - cls('RareCandyTreatment', sub='rarecandytreatment'), - cls('RavenWolf', sub='ravenwolf'), - cls('RedVelvetRequiem', sub='rvr'), - cls('Regina', sub='regina'), - cls('ReidyAndFriendsShowcase', sub='reidynfriends'), - cls('RemoteAngel', sub='remoteangel'), - cls('Replica', sub='replica', adult=True, endOfLife=True), - cls('Respectable', sub='respectable', adult=True, endOfLife=True), - cls('ReturntoEden', sub='rte'), - cls('RiversideExtras', host='www.riversidecomics.co'), - cls('ROSIER', sub='rosier'), - cls('RottenApple', sub='rottenapple'), - cls('RoyalIcing', sub='royalicing'), - cls('RubyNation', sub='therubynation'), - cls('RuderiQuest', sub='ruderi'), - cls('RuneSpark', sub='runespark'), - cls('RUScrewed', sub='ru-screwed'), - cls('RyuManwebcomicVersion', sub='ryuman-web', endOfLife=True), - cls('SabishiiGhost', sub='sabishiighost'), - cls('SaintforRent', sub='saint-for-rent'), - cls('SakuraDAY', sub='sakuraday4s'), - cls('SakuraMishzo', sub='sakurazo', adult=True), - cls('SalemUncommons', sub='salemuncommons'), - cls('SallySprocketAndPistonPete', sub='ssnpp'), - cls('SaltyKiss', sub='saltykiss'), - cls('SayWhatYouMean', sub='saywhatyoumean'), - cls('SChIzO', sub='schizophrenic'), - cls('SchoolOfRejectsSoRe', sub='sore'), - cls('ScionsoftheSeraph', sub='scions', adult=True), - cls('ScrappedProject', sub='scrappedproject'), - cls('SecretPowerbk1', sub='secretpower1'), - cls('SecretPowerbk2', sub='secretpower2'), - cls('Seki', sub='se-ki', adult=True), - cls('SenoireDelirium', sub='senoiredelirium', endOfLife=True), - cls('SeriousTimes', sub='serioustimes'), - cls('SFCBlackjackBay', sub='blackjackbay'), - cls('SFCForestofDreams', sub='sfcforestofdreams'), - cls('ShamelessAdvertisements', sub='advertiseat'), - cls('Shameless', sub='shamelesscomic'), - cls('ShotoutofCanon', sub='akumathfs'), - cls('ShroudofLight', sub='shroudoflight'), - cls('Signifikat', sub='signifikat', adult=True), - cls('SimonSues', sub='simonsues', adult=True), - cls('SimpleBear', sub='simplebear'), - cls('SimplySarah', sub='simplysarah'), - cls('Sire', host='sire.thewebcomic.com'), - cls('Skeptical', host='www.skepticalthewebcomic.com'), - cls('Slackmatic', sub='slackmatic'), - cls('SLightlyAbOVeAvErage', sub='slightlyaboveaverage', adult=True), - cls('SlipstreamSingularity', sub='slipstreamsingularity'), - cls('SmallPressAdventures', sub='smallpressadventures'), - cls('SocksMittensandScarfs', sub='socksmitsscarfs'), - cls('SomebodyShootMe', sub='somebodyshootme'), - cls('SomethingLikeaPhenomenon', sub='somethinglikeaphenomenon', adult=True), - cls('SonicAuthorAdventII', sub='saa2'), - cls('SonicBoom', sub='sonic-boom'), - cls('SonicClub', sub='sonicclub'), - cls('SonicDashly', sub='sonicdashly'), - cls('SonicFuture', sub='sonicfuture'), - cls('SonicSchoolRedo', sub='sonicschoolredo'), - cls('SonicUniverseAsk', sub='sonicuniverseask'), - cls('SOSRadio', sub='sosradio'), - cls('SouthernCross', host='southerncross.thewebcomic.com'), - cls('SovereignTheMostAmazingComicEver', sub='mostamazingcomicever'), - cls('SpaghettiAndMeatballs', sub='spaghettiandmeatballs', adult=True), - cls('SparElricsExtras', sub='sparextras'), - cls('SparkStory', sub='sparkstory'), - cls('Spellcross', sub='spellcross'), - cls('Spidersilk', sub='spidersilk'), - cls('SpiderWings', sub='spiderwings'), - cls('SplitScreen', sub='splitscreencomic', adult=True, endOfLife=True), - cls('SPRITEDHeroesofDobalia', sub='spritedhod'), - cls('Spriterschaos', sub='spriterschaos'), - cls('Sprytts', sub='sprytts'), - cls('SpursAndStripes', host='www.spursandstripescomic.com', adult=True), - cls('StarTrip', sub='startrip'), - cls('Stay', sub='stay-comic', adult=True), - cls('StellaInChrome', sub='stellainchrome'), - cls('Stereophonic', host='stereophonic.thewebcomic.com'), - cls('Storyofadamnedlove', sub='storyofadamnedlove'), - cls('StrangersandFriends', sub='hemu'), - cls('Striped', sub='striped', adult=True), - cls('StuntRayWalterswish', sub='stuntray'), - cls('SubjecttoChangeCollegeWoes', sub='subject-to-change'), - cls('Sunfall', host='sunfall.thewebcomic.com'), - cls('SunmeetsMoon', sub='sunmeetsmoon'), - cls('SUNRISESTORY', sub='sunrisestory'), - cls('SuperDimensionAfterTheHero', sub='afterthehero'), - cls('SuperMarioBros3', sub='smb3', endOfLife=True), - cls('SuperMarjoBros', sub='marjobros'), - cls('SupermassiveBlackHoleA', sub='smbhax'), - cls('SurvivorFanCharacters', sub='sfc'), - cls('SweetestPoison', sub='sweetestpoison'), - cls('SwitchMechanism', sub='switchmechanism', endOfLife=True), - cls('Symbios', sub='symbios', adult=True), - cls('TaikiTheWebcomic', sub='taiki'), - cls('TailsAdventureThroughTimeandOtherWorlds', sub='tailsadventure'), - cls('TakingPicturesofStrangers', sub='darrenandkale', adult=True), - cls('TalesFromAaronsWings', sub='tfaw', endOfLife=True), - cls('TEN', sub='ten'), - cls('ThatWasntThereYesterday', sub='twty'), - cls('The13thWorld', sub='the13thworld'), - cls('TheAdventuresOfBanjoZ', sub='abz-fancomic', adult=True, endOfLife=True), - cls('TheAntihero', sub='antihero'), - cls('TheArchipelago', sub='thearchipelago'), - cls('Theatrics', sub='theatrics'), - cls('TheAvianStories', sub='theavianstories'), - cls('TheBattleInTheSky', sub='thebattleinthesky'), - cls('TheBookOfNosferatu', host='www.thebookofnosferatu.com'), - cls('TheBrideoftheShark', sub='sameyome', adult=True), - cls('TheBucket', sub='thebucket'), - cls('TheCafedAlizee', sub='alizee'), - cls('TheCavernOfSecrets', sub='cavern'), - cls('TheColony', sub='thecolony', adult=True), - cls('TheContract', sub='the-contract'), - cls('TheCrawl', sub='thecrawl'), - cls('TheCurtAndTonyShow', sub='thecurtandtonyshow', endOfLife=True), - cls('TheDarkAgeofMobius', sub='thedarkageofmobius'), - cls('TheDarkLegacy', sub='tdlcomic'), - cls('TheDemonicAdventuresOfAngelWitchPita', sub='angelwitchpita', adult=True), - cls('TheDestroyer', sub='heartless-destroyer', adult=True), - cls('TheDragonAndTheLemur', sub='dal', adult=True), - cls('TheDreaming', sub='thedreaming', endOfLife=True), - cls('TheDrifter', sub='thedrifter', adult=True), - cls('TheElectricRose', host='www.electricrosecomic.com'), - cls('TheForestofWhispers', sub='theforestofwhispers'), - cls('TheGhostWithTheMost', sub='theghostwiththemost'), - cls('TheGoldRiderofPern', sub='goldrider'), - cls('TheGrayZone', sub='thegrayzone'), - cls('TheHeadhunters', sub='headhunters'), - cls('TheHeartofEarth', sub='heart-of-earth'), - cls('TheHobbitbic', sub='hobbit'), - cls('TheiaMania', sub='theia-mania'), - cls('TheJosephComics', sub='josephcomics', endOfLife=True), - cls('TheKeyHotelEnding', sub='tekeyhotel', endOfLife=True), - cls('TheKeyToReality', sub='keytoreality'), - cls('TheKwiddexProtocol', sub='kwiddexprotocol'), - cls('TheLastBloodCafe', sub='lastbloodcafe'), - cls('ThelaughingDeath', sub='thelaughingdeath'), - cls('TheLegendaryQueen', sub='legendaryqueen', adult=True), - cls('TheLifeofMagFlamequill', sub='lifeofmag'), - cls('TheLoneSwordsman', sub='theloneswordsman'), - cls('TheLostland', sub='thelostlandcomic'), - cls('TheMadMan', sub='themadman'), - cls('TheMegaManandSonicSpriteShowcase', sub='megamanshowcase'), - cls('TheMoistTouch', sub='themoisttouch'), - cls('TheNightSurfers', sub='thenightsurfers'), - cls('TheNocheComicSeries', sub='nochecomicseries', adult=True), - cls('TheNOMEDSEGA', sub='nomed'), - cls('ThePirateBalthasar', sub='thepiratebalthasar'), - cls('ThePremise', sub='thepremise'), - cls('ThePrincessAndTheGiant', sub='princess', endOfLife=True), - cls('ThePropertyofHate', sub='tpoh'), - cls('TheRealmOfKaerwyn', sub='kaerwyn'), - cls('TheReborn', sub='reborn'), - cls('TheSearchForHenryJekyll', sub='thesearchforhenryjekyll'), - cls('TheSilverLeague', sub='thesilverleague'), - cls('TheSummerofBlakeSinclair', sub='blake-sinclair'), - cls('Theswordsmanandtheamnesiac', sub='tsata', adult=True), - cls('TheTimeDog', sub='timedog'), - cls('TheTytonNuzlockeChallengeEmeraldEdition', sub='tytonnuzlockeemerald'), - cls('TheWhiteTower', sub='thewhitetower', endOfLife=True), - cls('TheWinterCampaign', sub='winterc'), - cls('TheYoshiHerd', sub='theyoshiherd'), - cls('ThiefCatcherRingTail', sub='tcringtail'), - cls('ThinkBeforeYouThink', sub='thinkbeforeyouthink'), - cls('ThornsComic', sub='thornscomic'), - cls('ThornTopia', sub='tnt100'), - cls('TLAAOK', sub='tlaaok', adult=True), - cls('TosiHuonoYaoiSarjis', sub='tosihuonoyaoisarjis', adult=True), - cls('TotallyCrossover', sub='totallycrossover'), - cls('TPTruePower', sub='truepower'), - cls('TrainerWantsToFight', sub='twtf'), - cls('Transfusions', sub='transfusions', adult=True), - cls('TransUMan', sub='transuman', adult=True, endOfLife=True), - cls('TRIPP', sub='tripp'), - cls('TroubleNextDoor', sub='troublenextdoor', endOfLife=True), - cls('UglyBoysLove', sub='shounenai'), - cls('Uglygame', sub='uglygame'), - cls('UnderTheDeadSkies', host='www.underthedeadskies.com'), - cls('UnicampaLapis', sub='ual'), - cls('UpDown', sub='updown', adult=True), - cls('UshalaatWorldsEnd', sub='ushala', adult=True), - cls('Vacan7', sub='vacan7', adult=True), - cls('VACANT', sub='vacant'), - cls('VerloreGeleentheid', host='verlore.thewebcomic.com'), - cls('VoidMisadventures', sub='voidmisadventures'), - cls('VoidTheGuideToAHealthyRelationship', sub='vtgtahr', adult=True), - cls('VoyageoftheBrokenPromise', sub='voyageofthebrokenpromise', adult=True), - cls('WakeEcho', sub='echo'), - cls('Wander', sub='wander'), - cls('WantedDeadorDead', sub='wanteddeadordead'), - cls('Wayfar', sub='wayfar'), - cls('Waysoftheheart', sub='wayoftheheart'), - cls('WeAreGolden', sub='wearegolden', adult=True), - cls('WelcomeToFreakshow', sub='welcometofreakshow'), - cls('WelcomeToThePCA', sub='welcometothepca', endOfLife=True), - cls('WhatAboutLove', sub='whataboutlove', adult=True), - cls('WHATAboutSHADOWS', sub='was', endOfLife=True), - cls('WhatIsDeepInOnesHeart', sub='ones-mindt'), - cls('WhenSheWasBad', sub='whenshewasbad'), - cls('Whenweweresilent', sub='silence'), - cls('WhereaboutsOfTime', sub='wot'), - cls('WhiteHeart', sub='whiteheart', adult=True), - cls('WhiteNoise', sub='white-noise'), - cls('WhOLE', sub='whole', adult=True), - cls('Wildflowers', host='www.wildflowerslgbt.ca'), - cls('WildWingBoysKoathArc', sub='wwbka'), - cls('WildWingBoys', sub='wwb'), - cls('WingsOverEthereal', sub='wings-over-ethereal'), - cls('WingsTurnedtoDust', sub='wingsturnedtodust'), - cls('Wootlabs', host='wootlabs.thewebcomic.com'), - cls('XXMoralityXx', sub='xxmoralityxx'), - cls('YadotCakeShop', sub='yadotcakeshop', adult=True), - cls('YamanaokiHighSchool', sub='yamanaokihs'), - cls('YouAreTheReasonForTheEndOfTheWorld', sub='thereasonfortheendoftheworld'), - cls('YoungCannibals', host='www.youngcannibals.net'), - cls('ZaenWell', sub='zaenwell'), - cls('ZeldaTheNewAdventureofLinkIIMajorasMask', sub='newlink'), - # END AUTOUPDATE + cls('20TimesKirby', 91583), + cls('2Kingdoms', 112096, endOfLife=True), + cls('355Days', 114138), + cls('_A_', 130892, endOfLife=True), + cls('AB', 110961, adult=True), + cls('AceOfHearts', 155154), + cls('AcidMonday', 30447, adult=True), + cls('Adalsysla', 96496, endOfLife=True), + cls('AddictiveScience', 130684), + cls('ADoodleADay', 141301), + cls('AdventuresOfLumAndFriends', 122193), + cls('AdventuresoftheWeird', 4430), + cls('AetherTheories', 116164), + cls('AgeOfTheGray', 132378), + cls('AGirlOnTheServer', 44252), + cls('AKirbyKomic', 25724), + cls('ALaMode', 35776), + cls('AllInLOVE', 6639), + cls('AllStarHeroes', 127874), + cls('AlmostTouching', 140881, adult=True), + cls('AlwaysDamnedWebcomic', 21652, adult=True), + cls('AlwaysRainingHere', 96902), + cls('Amaravati', 49250), + cls('AmorVincitOmnia', 66370, adult=True), + cls('AmsdenEstate', 105458), + cls('AngelGuardian', 72720), + cls('ANGELOU', 21129), + cls('AnimalAdventures', 125930), + cls('Animayhem', 53122), + cls('AnythingAboutNothing', 50399), + cls('APTComic', 71310), + cls('AQuestionOfCharacter', 70161), + cls('Area9', 108861), + cls('AroundTheBlock', 125385), + cls('ArtOfAFantasy', 92258, adult=True), + cls('ASongforElise', 45895, adult=True), + cls('AtArmsLength', 39242), + cls('Atlaswebcomic', 140920), + cls('Autophobia', 82522), + cls('Aware', 132405), + cls('AyaTakeo', 60325), + cls('AYuriCollab', 126727, adult=True), + cls('BabysittingFourDemons', 5992), + cls('Babywhatsyoursign', 123587), + cls('BadassRiz', 130263), + cls('BallandChain', 99503), + cls('Bard', 51147), + cls('BassComicAdventures', 131900), + cls('BattleSequence', 132075), + cls('Bearhoney', 111843), + cls('BearlyAbel', 41761), + cls('BeautifulLies', 130068), + cls('BehindTheGlassCurtain', 54480, endOfLife=True), + cls('BehindTheObsidianMirror', 94375, adult=True), + cls('BeretCatComics', 136026), + cls('Bestbrosforever', 132559), + cls('Betovering', 127694, adult=True), + cls('BettencourtHotel', 98760, endOfLife=True), + cls('BeTwin', 97886, endOfLife=True), + cls('BeyondTheOrdinary', 129233), + cls('BioRevelation', 121142), + cls('Bl3', 131849, endOfLife=True), + cls('BlackAndBlue', 63275, endOfLife=True), + cls('Blackdemon', 117183), + cls('BlackDragon', 131654), + cls('BlackFridayRule', 94517), + cls('BlackTapestries', 171490, adult=True), + cls('BlackSheepcomic', 91663), + cls('BleachRedux', 94169), + cls('BlindandBlue', 110850), + cls('BloodhuntersBirthOfAVampire', 92969, endOfLife=True), + cls('BloomAPokemonConquestComic', 122439), + cls('BlueHair', 119037), + cls('BoilingPointofBrain', 122291), + cls('BoogeyDancingMonkeyPot', 128196), + cls('BreachOfAgency', 82923, endOfLife=True), + cls('Burn', 93761), + cls('ByTheBook', 98401, adult=True), + cls('CafeSuada', 80707), + cls('Cambion', 112560, adult=True), + cls('CaptiveSoul', 115786), + cls('Captured', 135452, adult=True), + cls('CaravanaTaleofGodsandMen', 129824), + cls('Cataclysm', 98815, adult=True), + cls('Catnip', 108592, adult=True), + cls('Cerintha', 117941), + cls('ChampionofChampions', 103159), + cls('ChampionsAndHeroesAgeOfDragons', 98261), + cls('ChannelDDDNews', 120506), + cls('ChaosAdventuresII', 64827), + cls('ChaoticNation', 108410, adult=True), + cls('Charaktermaske', 118975), + cls('Chatuplines', 84863), + cls('CheneysGotaGun', 75737), + cls('ChickenScratches', 90898), + cls('ChildrenOfTheNight', 52560), + cls('ChimiMouryou', 108675), + cls('ChocolatewithPepper', 132832), + cls('ClairetheFlare', 121081), + cls('ClockworkAtrium', 3048), + cls('CloeRemembrance', 9150, endOfLife=True), + cls('CockroachTheater', 138343), + cls('Cogs', 130634), + cls('ColorBlind', 118617), + cls('ConventionalWisdom', 89324), + cls('CosmicDash', 4584), + cls('Cramberries', 82134), + cls('CrimsonWings', 113469), + cls('CrocodileTears', 85055, adult=True), + cls('CupOfOlea', 130678), + cls('CurseLineage', 86745), + cls('DanielleDark', 9257), + cls('Dasien', 1779, adult=True), + cls('DavidDoesntGetIt', 115176), + cls('DBON', 76205), + cls('DeadtoDay', 137063), + cls('DeathNoteIridescent', 87149), + cls('DEGAF', 120316), + cls('DEMENTED', 104334, adult=True), + cls('DemonBattles', 145936), + cls('DemonCat', 105404), + cls('DemonEater', 125937, adult=True), + cls('DenizensAttention', 56481), + cls('DevilsCake', 26927), + cls('DevotoMusicinHell', 114862, adult=True), + cls('Diaz', 129935), + cls('DigimonSaviors', 43521), + cls('DigimonTamersMiraiProject', 119257), + cls('DigisRandomSpriteshack', 47936), + cls('DigitalInsanity', 144866), + cls('DoItYourself', 103195), + cls('DontDie', 140541), + cls('DoodleBeans', 17473, adult=True), + cls('DoodlingAround', 117225), + cls('Dragonet', 119508), + cls('DragonKid', 96550), + cls('DreamCatcher', 23687), + cls('DumpofManyPeople', 138063), + cls('DungeonHordes', 94210), + cls('EATATAU', 64889), + cls('EDepthAngel', 98932), + cls('EidolonWhispersOfEternity', 136262), + cls('ElementalSpirits', 18192), + cls('EnkeltenKentta', 78834, adult=True), + cls('Enthrall', 113047, adult=True), + cls('EntreEuxDeux', 97894, endOfLife=True), + cls('Entuthrie', 114564, adult=True), + cls('Eorah', 135499, adult=True), + cls('Equsopia', 127680), + cls('ERAConvergence', 63750, endOfLife=True), + cls('ERAIbuki', 129506, endOfLife=True), + cls('ERRORERROR', 113481), + cls('EuphemisticEephus', 127121), + cls('EvilPlan', 19063), + cls('ExperimentalMegaman', 75706), + cls('EyesOfADigimon', 97117), + cls('FailureConfetti', 69275), + cls('FairyTaleRejects', 99139, adult=True), + cls('FaithlessDigitals', 137288), + cls('FalconersDailyStrips', 124329), + cls('FallenAngelslove', 113208), + cls('FarOutMantic', 48658), + cls('FarOutThere', 89199), + cls('FatetheAnthologyofKaienandhisfuckingmagicfriends', 140771), + cls('FeralGentry', 119912), + cls('FinalArcanum', 51191), + cls('FireredLisasReise', 109151), + cls('FlyorFail', 104604), + cls('ForcedSeduction', 61407), + cls('ForgetTheDistance', 80429, adult=True), + cls('Fortheloveofabrokenstring', 116411), + cls('FramebyFrame', 71042, adult=True), + cls('FrobertTheDemon', 26586), + cls('FromnowonImagirl', 99018), + cls('FruitloopAndMrDownbeat', 82798), + cls('FullSpectrumTherapy', 156285), + cls('FurryExperience', 62354), + cls('GamerCafe', 138841), + cls('GamesPeoplePlayUpdatedWeekly', 72207), + cls('GardenofHearts', 106504), + cls('GayBacon', 104466), + cls('GayTimesWithRyanAndJay', 121095), + cls('GetUpAndGo', 42180, adult=True), + cls('GigisNuzlockeRuns', 157589), + cls('Gloomverse', 75498), + cls('Gnoph', 138286, endOfLife=True), + cls('GoldenSunGenerationsAftermathVolume1', 17885), + cls('GoldenSunGenerationsColossoVolume6', 17945), + cls('GoodGame', 48048, endOfLife=True), + cls('GoodnightMrsGoose', 73655), + cls('Grayscale', 100295, adult=True), + cls('GuardianGhost', 118429), + cls('GuardiansoftheGalaxialSpaceways', 70286), + cls('Habibahssong', 137453), + cls('HarvestMoonParadiseFound', 105422, endOfLife=True), + cls('HateThePlayer', 118599), + cls('HatShop', 71816), + cls('Helix', 121066), + cls('HeltonShelton', 124804), + cls('HendrixAndJulian', 155252, adult=True), + cls('Hephaestus', 79909), + cls('HereBeVoodoo', 133691, adult=True), + cls('HiddenStrengthAWhiteNuzlocke', 116170), + cls('Hinata', 134703), + cls('HitandMiss', 82248), + cls('Holocrash', 64113, endOfLife=True), + cls('HolyBlasphemy', 91250), + cls('HolyCrap', 13235), + cls('HopeForABreeze', 40188), + cls('HouseOfCraziness', 171040), + cls('HurrocksFardel', 1488), + cls('IciVontLesMorts', 133719, adult=True), + cls('Inchoatica', 138342), + cls('Ingloriousbasterds', 139586), + cls('InHouseHumor', 108681), + cls('Inhuman', 108969), + cls('InsideOuTAYuriTale', 50590), + cls('InspiredByADream', 48419), + cls('ItsAn8BitWorldBlankWorld', 88082), + cls('IWishIggysWish', 107290), + cls('JackiesStory', 108822), + cls('Jantar', 134338), + cls('Jason', 139878), + cls('JoeysAdventure', 142807), + cls('JourneyMan', 129303), + cls('JoyToTheWorld', 129685), + cls('June', 90624), + cls('JustAnotherLife', 128013), + cls('JustCrazy', 84007), + cls('Justmyluck', 169106), + cls('KaitoShuno', 100498, adult=True), + cls('KasaKeira', 78059), + cls('Katran', 79778), + cls('KazanatoFuneralPlanningService', 24026), + cls('KCNO', 103010, endOfLife=True), + cls('KezroChroniclesPhantomOps', 104447), + cls('Kirbandfriendsshowcase', 85495), + cls('KirbiesoftheAlternateDimension', 108771), + cls('KirbyAdventure', 77366), + cls('KirbyDreamTeam', 112273), + cls('KirbyFunfestTheOriginals', 90652), + cls('KirbysDreamAdventure', 69796), + cls('KirbysDreamlandAdventures', 46154), + cls('KirbyTheDeeArmy', 115693, endOfLife=True), + cls('KissmeSnow', 125812), + cls('KissoftheDevil', 64006), + cls('Knightface', 97596, adult=True), + cls('KnightsRequiem', 68098), + cls('KojiX5', 108937, endOfLife=True), + cls('Kreetor', 80871), + cls('Kruptos', 99200, endOfLife=True), + cls('KuronaFlutterandLylaSpamTime', 124636), + cls('LastBlockStanding', 125034), + cls('LavenderLegend', 107018), + cls('LeCirquedObscure', 103647), + cls('LedbyaMadMan', 111999), + cls('LegendOfZeldaAHerosStory', 118155), + cls('LegendOfZeldaStaffOfPower', 112732), + cls('LegendOfZeldaTheEdgeAndTheLight', 126345, endOfLife=True), + cls('LegendOfZeldaTheWindWaker', 49542), + cls('Lemongrass', 131786), + cls('LesCendresdelHiver', 131767), + cls('LethalDose', 115067, adult=True), + cls('LetLoveRule', 177216), + cls('LetsBreakitforReals', 127909), + cls('LicensedHeroes', 123974), + cls('LifeAsACutOut', 86222), + cls('LifeAsItWas', 117747), + cls('LifeLessOrdinary', 63169, adult=True), + cls('Lifeonpaper', 126099), + cls('LightLovers', 135581, adult=True), + cls('LightwithinShadow', 47016), + cls('LilLevi', 134946), + cls('LOGOS', 93415, adult=True), + cls('LOKI', 93990), + cls('LondonUnderworld', 45699), + cls('LostNova', 84173), + cls('LoveandIcecream', 112872), + cls('LoveHarbor', 130349), + cls('LoveMeLoveMyTeddyBear', 50359), + cls('LoveroftheSunandMoon', 121615), + cls('LsEmpire', 33751), + cls('LuffinpuffandEric', 83450), + cls('LumasParadise', 46770), + cls('MagicalMisfits', 138166), + cls('Magipunk', 131204), + cls('Manifestedpart1', 140208), + cls('MarioandLuigiMisadventures', 4806), + cls('MariosDayJob', 2330), + cls('MarioVsSonicVsMegaMan', 14122, endOfLife=True), + cls('MarsMind', 129347), + cls('MarXistemTWC', 100651), + cls('Mascara', 59912), + cls('MatildasSweetCakeCafe', 115251, adult=True), + cls('MayTheRainCome', 119715, endOfLife=True), + cls('Mazscara', 12456), + cls('MegaManTales', 6516), + cls('MegaPain', 88178), + cls('MelodyAndMacabre', 28408), + cls('MetroJack', 61376, adult=True), + cls('MidnightPrince', 106681, adult=True), + cls('MineS', 139112), + cls('Minibot', 18129), + cls('MinorActsOfHeroism', 78356), + cls('Missing', 118871), + cls('Missingversionfrancaise', 126329), + cls('MobianChaos', 49021), + cls('Mokepon', 42705), + cls('Monstar', 141569), + cls('MoonValley', 157462), + cls('MorphE', 122406), + cls('Mortifer', 17271), + cls('MrFactory', 119931), + cls('MUTE', 32960, endOfLife=True), + cls('MyFakeHeart', 19105), + cls('MySisterTheDragon', 9612, endOfLife=True), + cls('MySparklingPrincesama', 105626), + cls('MyStereoBot', 133633), + cls('MysticanDreams', 130154), + cls('MythsOfUnovaAWhiteNuzlockeRunHardMode', 101385), + cls('MYth', 36430), + cls('MyTwoCentsPlusTax', 38595), + cls('Nah', 88350), + cls('Negligence', 66718), + cls('NeoCrystalAdventures', 2060), + cls('NeonGlow', 63747), + cls('NeverTheHero', 132200), + cls('Nexus', 115357), + cls('NiceKitty', 75854), + cls('NighHeavenandHell', 72209, adult=True), + cls('NightSpace', 142396), + cls('NIK', 83716), + cls('NissiesDragonPrincess', 112655), + cls('NixsFireRedNuzlocke', 127939), + cls('NobleHeartsHiruandMerroug', 138690, adult=True), + cls('NoEnd', 138812), + cls('NormalcyisforWimps', 23862), + cls('NotyoursamI', 63700, adult=True), + cls('ObnoxiousHerokun', 146954, adult=True), + cls('ObsidianHeart', 130610), + cls('October20th', 122344), + cls('OddPlaceOddTime', 60037), + cls('Ohman', 143967), + cls('OldElastikid', 97110), + cls('OneRainyDay', 111352, adult=True), + cls('Onlyonelovesong', 86555), + cls('OperationTheater', 97500), + cls('OriginBook1Codearth', 124751), + cls('OurTimeInEden', 27011), + cls('Outbreak', 134869), + cls('OutofKey', 123152), + cls('OverSync', 114781), + cls('Pahantekija', 139286), + cls('Panacea', 79601, adult=True), + cls('PantsParty', 70630), + cls('PanzerDragonandEnigmaCompleteEdition', 20039), + cls('Paradox', 29667, adult=True), + cls('Pause', 135615), + cls('PencilviewUpdatesMondayscough', 33041), + cls('PerplexingMagnoliaDisruption', 104698), + cls('PeterPan', 119991), + cls('Phantomland', 106943), + cls('PhotoShootNarusasuDoujinshi', 110984, adult=True), + cls('PlasticKings', 132377), + cls('PlayTime', 68440), + cls('PleaseBeMyBoytoy', 26922), + cls('PMDExplorersOfHeart', 121563), + cls('PMDTeamFirefox', 103870), + cls('PMDVictoryFire', 116780), + cls('PokemonBeta', 76962, endOfLife=True), + cls('PokemonCrystalDoubleNuzlockeChallenge', 102420, endOfLife=True), + cls('PokemonLANDSKY', 120046), + cls('PokemonMysteryDungeonTeamCrystal', 122892), + cls('PokemonNoRakuen', 22822), + cls('PokemonParallel', 86143), + cls('PokemonSAKOHJU', 120395), + cls('Pokeventurous', 98420), + cls('Ponzi', 85187), + cls('PrettyMouth', 131442), + cls('PrincessChroma', 106726), + cls('ProfessorDolphinpresentsPokemon', 81880), + cls('ProjectCAPLimit', 137000), + cls('PTO', 43363, adult=True), + cls('Puck', 100566), + cls('PullingYouUnder', 155504, adult=True), + cls('PulseandBolt', 86022), + cls('PurpureaNoxa', 103522, adult=True), + cls('QueerQueen', 130802), + cls('RainbowMansion', 140231, adult=True), + cls('RainLGBT', 90588), + cls('RainxSasori', 108131, adult=True, endOfLife=True), + cls('RANDOM', 99296), + cls('RareCandyTreatment', 83853), + cls('RavenWolf', 97826), + cls('RedVelvetRequiem', 127363), + cls('Regina', 129902), + cls('ReidyAndFriendsShowcase', 45097), + cls('RemoteAngel', 46191), + cls('Replica', 123116, adult=True, endOfLife=True), + cls('Respectable', 128996, adult=True, endOfLife=True), + cls('ReturntoEden', 15691), + cls('ROSIER', 54232), + cls('RottenApple', 133069), + cls('RoyalIcing', 81321), + cls('RubyNation', 107039), + cls('RuderiQuest', 111648), + cls('RuneSpark', 140886), + cls('RUScrewed', 144524), + cls('RyuManwebcomicVersion', 135497, endOfLife=True), + cls('SabishiiGhost', 136824), + cls('SaintforRent', 123862), + cls('SakuraDAY', 135342), + cls('SakuraMishzo', 58018, adult=True), + cls('SalemUncommons', 70211), + cls('SallySprocketAndPistonPete', 58930), + cls('SaltyKiss', 104227), + cls('SayWhatYouMean', 82290), + cls('SChIzO', 94872), + cls('SchoolOfRejectsSoRe', 37768), + cls('ScionsoftheSeraph', 43320, adult=True), + cls('ScrappedProject', 73142), + cls('SecretPowerbk1', 117146), + cls('SecretPowerbk2', 117458), + cls('Seki', 123118, adult=True), + cls('SeriousTimes', 73090), + cls('SFCBlackjackBay', 123799), + cls('SFCForestofDreams', 88943), + cls('ShamelessAdvertisements', 51975), + cls('Shameless', 130592), + cls('ShotoutofCanon', 18876), + cls('ShroudofLight', 121119), + cls('Signifikat', 12217, adult=True), + cls('SimpleBear', 120596), + cls('SimplySarah', 33343), + cls('Sire', 58167), + cls('Skeptical', 108904), + cls('Slackmatic', 144286), + cls('SLightlyAbOVeAvErage', 117203, adult=True), + cls('SlipstreamSingularity', 66132), + cls('SmallPressAdventures', 70273), + cls('SocksMittensandScarfs', 132813), + cls('SomebodyShootMe', 121562), + cls('SomethingLikeaPhenomenon', 176182, adult=True), + cls('SonicAuthorAdventII', 5867), + cls('SonicBoom', 111375), + cls('SonicClub', 5638), + cls('SonicDashly', 87024), + cls('SonicFuture', 30809), + cls('SonicSchoolRedo', 110100), + cls('SOSRadio', 107498), + cls('SouthernCross', 94541), + cls('SovereignTheMostAmazingComicEver', 129062), + cls('SpaghettiAndMeatballs', 130401, adult=True), + cls('SparElricsExtras', 125431), + cls('SparkStory', 131006), + cls('Spellcross', 125055), + cls('SpiderWings', 36314), + cls('SplitScreen', 125293, adult=True, endOfLife=True), + cls('SPRITEDHeroesofDobalia', 109013), + cls('Spriterschaos', 11126), + cls('Sprytts', 70422), + cls('Stay', 102560, adult=True), + cls('StellaInChrome', 70107), + cls('Stereophonic', 129406), + cls('Storyofadamnedlove', 107702), + cls('StrangersandFriends', 94050), + cls('Striped', 79896, adult=True), + cls('StuntRayWalterswish', 73075), + cls('SubjecttoChangeCollegeWoes', 48759), + cls('Sunfall', 133465), + cls('SunmeetsMoon', 62545), + cls('SUNRISESTORY', 127611), + cls('SuperDimensionAfterTheHero', 98885), + cls('SuperMarioBros3', 18739, endOfLife=True), + cls('SuperMarjoBros', 136454), + cls('SupermassiveBlackHoleA', 59625), + cls('SurvivorFanCharacters', 24928), + cls('SweetestPoison', 142001), + cls('SwitchMechanism', 121604, endOfLife=True), + cls('TaikiTheWebcomic', 87240), + cls('TailsAdventureThroughTimeandOtherWorlds', 116964), + cls('TakingPicturesofStrangers', 71337, adult=True), + cls('TalesFromAaronsWings', 142272, endOfLife=True), + cls('TEN', 96475), + cls('ThatWasntThereYesterday', 85420), + cls('The13thWorld', 108420), + cls('TheAdventuresOfBanjoZ', 136763, adult=True, endOfLife=True), + cls('TheAntihero', 64167), + cls('TheArchipelago', 142266), + cls('Theatrics', 93578), + cls('TheAvianStories', 145492), + cls('TheBattleInTheSky', 143006), + cls('TheBookOfNosferatu', 97421), + cls('TheBrideoftheShark', 61393, adult=True), + cls('TheBucket', 124197), + cls('TheCafedAlizee', 80009), + cls('TheCavernOfSecrets', 126366), + cls('TheColony', 70272, adult=True), + cls('TheContract', 121955), + cls('TheCrawl', 124962), + cls('TheDarkLegacy', 83199), + cls('TheDemonicAdventuresOfAngelWitchPita', 105060, adult=True), + cls('TheDestroyer', 79216, adult=True), + cls('TheDragonAndTheLemur', 91259, adult=True), + cls('TheDreaming', 142053, endOfLife=True), + cls('TheDrifter', 137597, adult=True), + cls('TheElectricRose', 133024), + cls('TheForestofWhispers', 123645), + cls('TheGhostWithTheMost', 125332), + cls('TheGoldRiderofPern', 30008), + cls('TheGrayZone', 116458), + cls('TheHeadhunters', 105336), + cls('TheHeartofEarth', 113048), + cls('TheiaMania', 115095), + cls('TheJosephComics', 19785, endOfLife=True), + cls('TheKeyHotelEnding', 106307, endOfLife=True), + cls('TheKwiddexProtocol', 70268), + cls('TheLastBloodCafe', 136484), + cls('ThelaughingDeath', 129212), + cls('TheLegendaryQueen', 17122, adult=True), + cls('TheLifeofMagFlamequill', 51697), + cls('TheLoneSwordsman', 18218), + cls('TheMadMan', 83928), + cls('TheMegaManandSonicSpriteShowcase', 75689), + cls('TheMoistTouch', 135862), + cls('TheNightSurfers', 120705), + cls('TheNocheComicSeries', 133439, adult=True), + cls('TheNOMEDSEGA', 127642), + cls('ThePirateBalthasar', 73113), + cls('ThePremise', 118125), + cls('ThePrincessAndTheGiant', 59629, endOfLife=True), + cls('ThePropertyofHate', 117970), + cls('TheRealmOfKaerwyn', 156193), + cls('TheReborn', 1898), + cls('TheSearchForHenryJekyll', 139257), + cls('TheSilverLeague', 110008), + cls('TheSummerofBlakeSinclair', 95648), + cls('Theswordsmanandtheamnesiac', 74220, adult=True), + cls('TheTimeDog', 97194), + cls('TheTytonNuzlockeChallengeEmeraldEdition', 115517), + cls('TheWhiteTower', 123161, endOfLife=True), + cls('TheWinterCampaign', 80021), + cls('TheYoshiHerd', 5814), + cls('ThiefCatcherRingTail', 112115), + cls('ThornsComic', 131578), + cls('ThornTopia', 54482), + cls('TLAAOK', 92316, adult=True), + cls('TosiHuonoYaoiSarjis', 141725, adult=True), + cls('TotallyCrossover', 73445), + cls('TPTruePower', 13199), + cls('TrainerWantsToFight', 134083), + cls('Transfusions', 77588, adult=True), + cls('TransUMan', 107514, adult=True, endOfLife=True), + cls('TroubleNextDoor', 114482, endOfLife=True), + cls('UglyBoysLove', 102165), + cls('Uglygame', 61960), + cls('UnderTheDeadSkies', 114107), + cls('UnicampaLapis', 111371), + cls('UpDown', 140374, adult=True), + cls('UshalaatWorldsEnd', 130596, adult=True), + cls('Vacan7', 63460, adult=True), + cls('VACANT', 127276), + cls('VerloreGeleentheid', 80604, endOfLife=True), + cls('VoidMisadventures', 129134), + cls('VoyageoftheBrokenPromise', 137418, adult=True), + cls('WakeEcho', 70945), + cls('Wander', 118109), + cls('WantedDeadorDead', 68540), + cls('Wayfar', 95839), + cls('Waysoftheheart', 91122), + cls('WeAreGolden', 72590, adult=True), + cls('WelcomeToFreakshow', 72225), + cls('WelcomeToThePCA', 127811, endOfLife=True), + cls('WhatAboutLove', 74057, adult=True), + cls('WHATAboutSHADOWS', 109321, endOfLife=True), + cls('WhatIsDeepInOnesHeart', 130798), + cls('WhenSheWasBad', 12859), + cls('Whenweweresilent', 156839), + cls('WhereaboutsOfTime', 133530), + cls('WhiteHeart', 124545, adult=True), + cls('WhiteNoise', 63110), + cls('Wildflowers', 125360), + cls('WildWingBoysKoathArc', 50240), + cls('WildWingBoys', 203574), + cls('WingsOverEthereal', 37417), + cls('WingsTurnedtoDust', 113033), + cls('Wootlabs', 101636), + cls('XXMoralityXx', 132016), + cls('YadotCakeShop', 106995, adult=True), + cls('YamanaokiHighSchool', 82468), + cls('YoungCannibals', 8027), + cls('ZaenWell', 111081), + cls('ZeldaTheNewAdventureofLinkIIMajorasMask', 43724), ) diff --git a/scripts/comicfury.py b/scripts/comicfury.py index 08702089e..fd506ad81 100755 --- a/scripts/comicfury.py +++ b/scripts/comicfury.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs # Copyright (C) 2012-2014 Bastian Kleineidam -# Copyright (C) 2015-2017 Tobias Gruetzmacher +# Copyright (C) 2015-2019 Tobias Gruetzmacher """ Script to get ComicFury comics and save the info in a JSON file for further processing. @@ -20,7 +20,7 @@ class ComicFuryUpdater(ComicListUpdater): MIN_COMICS = 90 dup_templates = ('ComicSherpa/%s', 'Creators/%s', 'GoComics/%s', - 'KeenSpot/%s', 'SmackJeeves/%s', 'Arcamax/%s') + 'KeenSpot/%s', 'Arcamax/%s') langmap = { 'german': 'de', @@ -158,8 +158,8 @@ class ComicFuryUpdater(ComicListUpdater): def collect_results(self): """Parse all search result pages.""" # Sort by page count, so we can abort when we get under some threshold. - baseUrl = ('http://comicfury.com/search.php?search=1&webcomics=1&' + - 'query=&worder=1&asc=0&incvi=1&incse=1&incnu=1&incla=1&' + + baseUrl = ('https://comicfury.com/search.php?search=1&webcomics=1&' + + 'query=&worder=1&asc=0&incvi=2&incnu=2&incla=2&incse=2&' + 'all_ge=1&all_st=1&all_la=1&page=%d') last_count = 999 page = 1 diff --git a/scripts/generate_json.sh b/scripts/generate_json.sh index 71e043dfa..4eb210dbc 100755 --- a/scripts/generate_json.sh +++ b/scripts/generate_json.sh @@ -8,7 +8,7 @@ d=$(dirname $0) if [ $# -ge 1 ]; then list="$*" else - list="arcamax comicfury comicgenesis creators gocomics keenspot smackjeeves webcomicfactory comicskingdom" + list="arcamax comicfury comicgenesis creators gocomics keenspot webcomicfactory comicskingdom" fi for script in $list; do echo "Executing ${script}.py" diff --git a/scripts/smackjeeves.py b/scripts/smackjeeves.py deleted file mode 100755 index bbbf91d3a..000000000 --- a/scripts/smackjeeves.py +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs -# Copyright (C) 2012-2014 Bastian Kleineidam -# Copyright (C) 2015-2017 Tobias Gruetzmacher -""" -Script to get a list of smackjeeves.com comics and save the info in a JSON file -for further processing. -""" -from __future__ import absolute_import, division, print_function - -import sys -from six.moves.urllib.parse import urlsplit - -from scriptutil import ComicListUpdater - - -class SmackJeevesUpdater(ComicListUpdater): - # Absolute minumum number of pages a comic may have (restrict search space) - MIN_COMICS = 90 - - # names of comics to exclude - excluded_comics = ( - # comic moved/we have a better module - "Amya", - "Footloose", - "TitleUnrelated", - - # does not follow standard layout - "300DaysOfSyao", - "ADifferentPerspective", - "Captor", - "ClubLove", - "Comatose", - "DeSTRESS", - "DreamCatcher", - "Fumiko", - "GART", - "GarytheAlchemist", - "ItoshiisCrazyNuzlockeAdventures", - "JennyHaniver", - "KiLAiLO", - "LoudEra", - "LunarHill", - "Mafiagame", - "MylifewithFel", - "MyLifewithFelENESPANOL", - "NegativeZen", - "Nemutionpobae", - "NightShot", - "NormalIsBoring", - "OpticalDisarray", - "PicturesofYou", - "Pornjunkiesstrip", - "PrettyUgly", - "Project217", - "RemmyzRandomz", - "Ribon", - "RubysWorld", - "ShinkaTheLastEevee", - "SimplePixel", - "SladesMansionofawesomeness", - "SpaceSchool", - "SushiGummy", - "TC2KsPokemobians", - "TheAfterSubtract", - "ThePokemonArtBox", - "THEVOIDWEBCOMIC", - "ToDefeatThemAll", - "TwoKeys", - "Vbcomics", - "WerewolfRichard", - - # has no previous comic link - "ThreadCrashers", - "AchievementStuck", - - # images are 403 forbidden - "AngelJunkPileFelix", - "AntavioussGenLab", - "Harfang", - "Okamirai", - - # missing images - "AGirlAndHerShadow", - "Carciphona", - "CatboyattheCon", - "ContraandtheSpamDump", - "Darkkyosshorts", - "DollarStoreCaviar", - "EdgeofDecember", - "EvD", - "HAndJ", - "HEARD", - "IwillbenapoSpamDump", - "KirbysoftheAlternateDimension", - "Letsreviewshallwe", - "MegaManSpriteExpo", - "OmnisSpriteShowcase", - "PiecesofBrokenGlass", - "PlatonicManagementDilemma", - "SecretSanta2011", - "SerendipityAnEquestrianTale", - "SJArtCollab", - "SlightlyDifferent", - "TheAttackoftheRecoloursSeason1", - "ThroughTheWonkyEye", - "TotallyKotor", - "WinterMelody", - "ZonowTheHedgehog", - - # missing previous link - "BambooArmonicKnightsGuild", - - # broken host name - "Razor", - ) - - def __init__(self, name): - super(SmackJeevesUpdater, self).__init__(name) - self.sleep = 1.5 - - def handle_url(self, url): - """Parse one search result page.""" - data = self.get_url(url) - - num = 999 - for comictag in data.cssselect('a.card'): - page_url = comictag.attrib['href'] - name = comictag.cssselect('div.title')[0].text - # search for url in extra page - data2 = self.get_url(page_url) - - # find out how many images this comic has - mo = data2.cssselect('div.num-pages div.value') - num = int(mo[0].text.strip().replace(',', '')) - - mo = data2.cssselect('div.buttons a:last-child') - comic_url = mo[0].attrib['href'] - # search for adult flag - adult = data2.cssselect('div.mature') - updates = data2.cssselect('div.updates div.value')[0].text_content() - self.add_comic(name, (comic_url, len(adult) > 0, updates), num) - - next_url = data.cssselect("a.next")[0].attrib['href'] - return (next_url, num) - - def collect_results(self): - """Parse all search result pages.""" - # Sort by number of comics, so we can abort when we get under some - # threshold. - next_url = "http://www.smackjeeves.com/search.php?last_update=6&sort_by=5" - last_count = 999 - while last_count >= self.MIN_COMICS: - print(last_count, file=sys.stderr) - next_url, last_count = self.handle_url(next_url) - - def get_entry(self, name, data): - sub, top = urlsplit(data[0]).hostname.split('.', 1) - if top.lower() == "smackjeeves.com": - opt = "sub='%s'" % sub - else: - opt = "host='%s.%s'" % (sub, top) - if data[1]: - opt += ", adult=True" - if data[2] == 'Completed': - opt += ", endOfLife=True" - return u"cls('%s', %s)," % (name, opt) - - -if __name__ == '__main__': - SmackJeevesUpdater(__file__).run() diff --git a/scripts/update_plugins.sh b/scripts/update_plugins.sh index 42a8ab334..ef57272ef 100755 --- a/scripts/update_plugins.sh +++ b/scripts/update_plugins.sh @@ -10,7 +10,7 @@ d=$(dirname $0) if [ $# -ge 1 ]; then list="$*" else - list="arcamax comicfury comicgenesis creators gocomics keenspot smackjeeves webcomicfactory comicskingdom" + list="arcamax comicfury comicgenesis creators gocomics keenspot webcomicfactory comicskingdom" fi for script in $list; do target="${d}/../dosagelib/plugins/${script}.py"