Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

steps:
- name: Checkout
Expand Down
8 changes: 1 addition & 7 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
def pys = [
[name: 'Python 3.13', docker: '3.13-bookworm', tox:'py313', main: true],
[name: 'Python 3.12', docker: '3.12-bookworm', tox:'py312', main: false],
[name: 'Python 3.8', docker: '3.8-bookworm', tox:'py38', main: false],
[name: 'Python 3.9', docker: '3.9-bookworm', tox:'py39', main: false],
]

properties([
Expand Down Expand Up @@ -76,12 +76,6 @@ parallel modern: {
windowsBuild('3.13', 'dosage.exe')
}
},
legacy: {
stage('Legacy Windows binary') {
// Still compatible with Windows 7
windowsBuild('3.8', 'dosage-legacy.exe')
}
},
report: {
stage('Allure report') {
processAllure()
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ are old enough to view them.
### Dependencies

Since dosage is written in [Python](http://www.python.org/), a Python
installation is required: Dosage needs at least Python 3.8. Dosage requires
installation is required: Dosage needs at least Python 3.9. Dosage requires
some Python modules from PyPI, so installation with `pip` is recommended.

### Optional dependencies
Expand Down
2 changes: 1 addition & 1 deletion dosagelib/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def display_version(verbose: bool) -> None:
attrs = {'version': version, 'app': AppName,
'url': url, 'currentversion': __version__}
print(text % attrs)
except (IOError, KeyError) as err:
except (OSError, KeyError) as err:
print(f'An error occured while checking for an update of {AppName}: {err!r}')


Expand Down
4 changes: 2 additions & 2 deletions dosagelib/comic.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import glob
import logging
import os
from collections.abc import Iterator
from datetime import datetime
from typing import Iterator

from rich import filesize

Expand Down Expand Up @@ -82,7 +82,7 @@ def connect(self, lastchange=None):
subtype = None
if maintype != 'image' and content_type not in (
'application/octet-stream', 'application/x-shockwave-flash'):
raise IOError('content type %r is not an image at %s' % (
raise OSError('content type {!r} is not an image at {}'.format(
content_type, self.url))
# Always use mime type for file extension if it is sane.
if maintype == 'image':
Expand Down
6 changes: 3 additions & 3 deletions dosagelib/director.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import os
import re
import threading
from collections.abc import Collection
from queue import Empty, Queue
from typing import Collection, Dict
from urllib.parse import urlparse

from . import events
Expand Down Expand Up @@ -45,7 +45,7 @@ def clear(self):


# ensure threads download only from one host at a time
host_locks: Dict[str, threading.Lock] = {}
host_locks: dict[str, threading.Lock] = {}


def get_hostname(url):
Expand All @@ -67,7 +67,7 @@ class ComicGetter(threading.Thread):

def __init__(self, options, jobs) -> None:
"""Store options."""
super(ComicGetter, self).__init__()
super().__init__()
self.options = options
self.jobs = jobs
self.origname = self.name
Expand Down
4 changes: 2 additions & 2 deletions dosagelib/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def check_robotstxt(url: str, session: Session) -> None:
roboturl = _get_roboturl(url)
rp = _get_robotstxt_parser(roboturl, session)
if not rp.can_fetch(configuration.App, str(url)):
raise IOError("%s is disallowed by %s" % (url, roboturl))
raise OSError(f"{url} is disallowed by {roboturl}")


def _get_roboturl(url: str) -> str:
Expand All @@ -101,7 +101,7 @@ def _get_roboturl(url: str) -> str:
return parse.urlunsplit((pu.scheme, pu.netloc, "/robots.txt", None, None))


@functools.lru_cache()
@functools.lru_cache
def _get_robotstxt_parser(url, session: Session) -> robotparser.RobotFileParser:
"""Get a RobotFileParser for the given robots.txt URL."""
rp = robotparser.RobotFileParser()
Expand Down
2 changes: 1 addition & 1 deletion dosagelib/plugins/a.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def getPrevUrl(self, url, data):
# Fix broken navigation links
if url == self.stripUrl % 'lg06':
return self.stripUrl % 'lg05'
return super(AdventuresOfFifne, self).getPrevUrl(url, data)
return super().getPrevUrl(url, data)


class AfterStrife(WordPressNavi):
Expand Down
2 changes: 1 addition & 1 deletion dosagelib/plugins/b.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def namer(self, imageUrl, pageUrl):
if filename == 'image.jpg':
[year, month] = imageUrl.rsplit('/', 3)[-3:-1]
pageNr = int(pageUrl.rsplit('/', 1)[-2].rsplit('-', 1)[-1])
filename = '{0}-{1}-Vol2-pg{2}.jpg'.format(year, month, pageNr)
filename = f'{year}-{month}-Vol2-pg{pageNr}.jpg'
elif filename == '27637.jpg':
filename = 'BB_Vol2_Cover.jpg'
return filename
Expand Down
3 changes: 1 addition & 2 deletions dosagelib/plugins/c.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# SPDX-FileCopyrightText: © 2015 Tobias Gruetzmacher
# SPDX-FileCopyrightText: © 2019 Daniel Ring
from re import compile, escape
from typing import List

from .. import util
from ..helpers import bounceStarter, indirectStarter, joinPathPartsNamer
Expand Down Expand Up @@ -137,7 +136,7 @@ class CatenaManor(ParserScraper):
imageSearch = '//img[d:class("comicthumbnail")]'
multipleImagesPerStrip = True
endOfLife = True
strips: List[str] = []
strips: list[str] = []

def starter(self):
# Retrieve archive links and select valid range
Expand Down
4 changes: 2 additions & 2 deletions dosagelib/plugins/comicfury.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class ComicFury(ParserScraper):
XPATH_LINK % ('comicnavlink', 'Previous'),
XPATH_IMG % ('Previous'),
# Art, ConsolersDLC, etc.
u'//nav//a[contains(text(), "\u2039")]',
'//nav//a[contains(text(), "\u2039")]',
# LatchkeyKingdom
'//a[d:class("navi") and img[contains(@src, "Previous")]]',
# KATRAN
Expand All @@ -43,7 +43,7 @@ class ComicFury(ParserScraper):
XPATH_LINK % ('comicnavlink', 'Next'),
XPATH_IMG % ('Next'),
# Art, ConsolersDLC, etc.
u'//nav//a[contains(text(), "\u203A")]',
'//nav//a[contains(text(), "\u203A")]',
# LatchkeyKingdom
'//a[d:class("navi") and img[contains(@src, "Next")]]',
# RedSpot, KATRAN
Expand Down
14 changes: 8 additions & 6 deletions dosagelib/plugins/common.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# SPDX-License-Identifier: MIT
# Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs
# Copyright (C) 2012-2014 Bastian Kleineidam
# Copyright (C) 2015-2022 Tobias Gruetzmacher
# Copyright (C) 2019-2020 Daniel Ring
from typing import Sequence, Union
# SPDX-FileCopyrightText: © 2004 Tristan Seligmann and Jonathan Jacobs
# SPDX-FileCopyrightText: © 2012 Bastian Kleineidam
# SPDX-FileCopyrightText: © 2015 Tobias Gruetzmacher
# SPDX-FileCopyrightText: © 2019 Daniel Ring
from __future__ import annotations

from collections.abc import Sequence

from ..scraper import ParserScraper

Expand All @@ -22,7 +24,7 @@


class ComicControlScraper(ParserScraper):
imageSearch: Union[Sequence[str], str] = '//img[@id="cc-comic"]'
imageSearch: Sequence[str] | str = '//img[@id="cc-comic"]'
prevSearch = '//a[@rel="prev"]'
nextSearch = '//a[@rel="next"]'
latestSearch = '//a[@rel="last"]'
Expand Down
10 changes: 5 additions & 5 deletions dosagelib/plugins/creators.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# SPDX-License-Identifier: MIT
# Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs
# Copyright (C) 2012-2014 Bastian Kleineidam
# Copyright (C) 2015-2022 Tobias Gruetzmacher
from ..scraper import ParserScraper
# SPDX-FileCopyrightText: © 2004 Tristan Seligmann and Jonathan Jacobs
# SPDX-FileCopyrightText: © 2012 Bastian Kleineidam
# SPDX-FileCopyrightText: © 2015 Tobias Gruetzmacher
from ..helpers import indirectStarter
from ..scraper import ParserScraper


class Creators(ParserScraper):
Expand All @@ -13,7 +13,7 @@ class Creators(ParserScraper):
starter = indirectStarter

def __init__(self, name, path, lang=None):
super(Creators, self).__init__('Creators/' + name)
super().__init__('Creators/' + name)
self.url = 'https://www.creators.com/features/' + path
if lang:
self.lang = lang
Expand Down
2 changes: 1 addition & 1 deletion dosagelib/plugins/d.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ class DerTodUndDasMaedchen(_ParserScraper):
stripUrl = url + '?bild=%s.jpg'
firstStripUrl = stripUrl % '00_01_01'
imageSearch = '//img[contains(@src, "images/tod/teil2")]'
prevSearch = u'//a[text()="zur\u00FCck"]'
prevSearch = '//a[text()="zur\u00FCck"]'
help = 'Index format: nn_nn_nn'
lang = 'de'

Expand Down
10 changes: 5 additions & 5 deletions dosagelib/plugins/dmfa.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: MIT
# Copyright (C) 2019-2022 Tobias Gruetzmacher
# Copyright (C) 2019-2020 Daniel Ring
# SPDX-FileCopyrightText: © 2019 Tobias Gruetzmacher
# SPDX-FileCopyrightText: © 2019 Daniel Ring
from ..helpers import bounceStarter
from ..scraper import ParserScraper

Expand All @@ -15,15 +15,15 @@ class DMFA(ParserScraper):

def __init__(self, name, first, last=None):
if name == 'DMFA':
super(DMFA, self).__init__(name)
super().__init__(name)
else:
super(DMFA, self).__init__('DMFA/' + name)
super().__init__('DMFA/' + name)

self.firstStripUrl = self.stripUrl % first

if last:
self.url = self.stripUrl % last
self.starter = super(DMFA, self).starter
self.starter = super().starter
self.endOfLife = True

@classmethod
Expand Down
10 changes: 5 additions & 5 deletions dosagelib/plugins/keenspot.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: MIT
# Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs
# Copyright (C) 2012-2014 Bastian Kleineidam
# Copyright (C) 2015-2022 Tobias Gruetzmacher
# Copyright (C) 2019-2020 Daniel Ring
# SPDX-FileCopyrightText: © 2004 Tristan Seligmann and Jonathan Jacobs
# SPDX-FileCopyrightText: © 2012 Bastian Kleineidam
# SPDX-FileCopyrightText: © 2015 Tobias Gruetzmacher
# SPDX-FileCopyrightText: © 2019 Daniel Ring
from ..scraper import ParserScraper


Expand Down Expand Up @@ -37,7 +37,7 @@ class KeenSpot(ParserScraper):
help = 'Index format: yyyymmdd'

def __init__(self, name, sub, last=None, adult=False, path='d/%s.html'):
super(KeenSpot, self).__init__('KeenSpot/' + name)
super().__init__('KeenSpot/' + name)
self.url = 'http://%s.keenspot.com/' % sub
self.stripUrl = self.url + path

Expand Down
2 changes: 1 addition & 1 deletion dosagelib/plugins/kemonocafe.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class KemonoCafe(ParserScraper):
prevSearch = '//a[contains(@class, "comic-nav-previous")]'

def __init__(self, name, sub, first, last=None, adult=False):
super(KemonoCafe, self).__init__('KemonoCafe/' + name)
super().__init__('KemonoCafe/' + name)

self.url = 'https://%s.kemono.cafe/' % sub
self.stripUrl = self.url + 'comic/%s/'
Expand Down
4 changes: 2 additions & 2 deletions dosagelib/plugins/krisstraub.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: MIT
# Copyright (C) 2021 Tobias Gruetzmacher
# SPDX-FileCopyrightText: © 2021 Tobias Gruetzmacher
from .common import WordPressScraper


Expand All @@ -10,7 +10,7 @@ class KrisStraub(WordPressScraper):

def __init__(self, name, firstDate):
super().__init__(name)
self.url = 'https://{}.krisstraub.com/'.format(name.lower())
self.url = f'https://{name.lower()}.krisstraub.com/'
self.stripUrl = self.url + '%s.shtml'
self.firstStripUrl = self.stripUrl % firstDate

Expand Down
6 changes: 3 additions & 3 deletions dosagelib/plugins/l.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,14 @@ def getPrevUrl(self, url, data):
page = url.rstrip('/').rsplit('/', 1)[-1]
if page in self.nav:
return self.stripUrl % self.nav[page]
return super(LifeAsRendered, self).getPrevUrl(url, data)
return super().getPrevUrl(url, data)

def fetchText(self, url, data, textSearch, optional):
# Save final summary text
if url == self.firstStripUrl:
url = self.stripUrl % 'the-end'
data = self.getPage(url)
return super(LifeAsRendered, self).fetchText(url, data, textSearch, optional)
return super().fetchText(url, data, textSearch, optional)
return None


Expand Down Expand Up @@ -165,7 +165,7 @@ def getPrevUrl(self, url, data):
page = url.rsplit('=', 1)[1]
if page in self.nav:
return self.stripUrl % self.nav[page]
return super(LittleTales, self).getPrevUrl(url, data)
return super().getPrevUrl(url, data)


class LoadingArtist(_ParserScraper):
Expand Down
10 changes: 5 additions & 5 deletions dosagelib/plugins/n.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: MIT
# Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs
# Copyright (C) 2012-2014 Bastian Kleineidam
# Copyright (C) 2015-2021 Tobias Gruetzmacher
# Copyright (C) 2019-2020 Daniel Ring
# SPDX-FileCopyrightText: © 2004 Tristan Seligmann and Jonathan Jacobs
# SPDX-FileCopyrightText: © 2012 Bastian Kleineidam
# SPDX-FileCopyrightText: © 2015 Tobias Gruetzmacher
# SPDX-FileCopyrightText: © 2019 Daniel Ring
from re import compile, escape

from ..helpers import bounceStarter, indirectStarter, joinPathPartsNamer
Expand Down Expand Up @@ -77,7 +77,7 @@ def getPrevUrl(self, url, data):
# Add navigation link between comic and graphic novel
if url == self.stripUrl % 'nh2/20070201':
return self.stripUrl % 'nh1/20061208'
return super(Newshounds, self).getPrevUrl(url, data)
return super().getPrevUrl(url, data)


class NewWorld(WordPressScraper):
Expand Down
4 changes: 2 additions & 2 deletions dosagelib/plugins/namirdeiter.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ class NamirDeiter(ParserScraper):

def __init__(self, name, baseUrl, first=None, last=None):
if name == 'NamirDeiter':
super(NamirDeiter, self).__init__(name)
super().__init__(name)
else:
super(NamirDeiter, self).__init__('NamirDeiter/' + name)
super().__init__('NamirDeiter/' + name)

self.url = 'https://' + baseUrl + '/'
self.stripUrl = self.url + 'comics/index.php?date=%s'
Expand Down
4 changes: 2 additions & 2 deletions dosagelib/plugins/old.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class Removed(Scraper):
}

def __init__(self, name, reason='del'):
super(Removed, self).__init__(name)
super().__init__(name)
self.reason = reason

def getDisabledReasons(self):
Expand Down Expand Up @@ -1697,7 +1697,7 @@ def counter(cls):
return cls.count

def __init__(self, name, newname):
super(Renamed, self).__init__(name)
super().__init__(name)
self.newname = newname
self.i = self.counter()

Expand Down
2 changes: 1 addition & 1 deletion dosagelib/plugins/p.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ class PHDComics(ParserScraper):
# Ugly hack :(
def _parse_page(self, data):
data = self.BROKEN_COMMENT_END.sub('-->', data)
return super(PHDComics, self)._parse_page(data)
return super()._parse_page(data)

def shouldSkipUrl(self, url, data):
"""Skip pages without images."""
Expand Down
Loading
Loading