add .netrc support (#22)

Use the '--netrc' cmdline option or set the 'netrc' config option
to 'true' to enable the use of .netrc authentication data.

The 'machine' names for the .netrc info are the lowercase extractor
names (or categories): batoto, exhentai, nijie, pixiv, seiga.
This commit is contained in:
Mike Fährmann
2017-06-24 12:17:26 +02:00
parent fbe8c519e2
commit d3b04076f7
9 changed files with 42 additions and 11 deletions

View File

@@ -23,6 +23,15 @@ Description Directory path used as the base for all download destinations.
=========== ===== =========== =====
netrc
-----
=========== =====
Type ``bool``
Default ``false``
Description Enable the use of |.netrc|_ authentication data.
=========== =====
cache.file cache.file
---------- ----------
=========== ===== =========== =====
@@ -331,7 +340,7 @@ Description The value of the ``limit`` parameter when loading
extractor.reddit.morecomments extractor.reddit.morecomments
------------------------- -----------------------------
=========== ===== =========== =====
Type ``bool`` Type ``bool``
Default ``false`` Default ``false``
@@ -392,11 +401,13 @@ Description The ``refresh_token`` value you get from linking your Reddit account
=========== ===== =========== =====
.. |.netrc| replace:: ``.netrc``
.. |tempfile.gettempdir()| replace:: ``tempfile.gettempdir()`` .. |tempfile.gettempdir()| replace:: ``tempfile.gettempdir()``
.. |requests.get()| replace:: ``requests.get()`` .. |requests.get()| replace:: ``requests.get()``
.. |mature_content| replace:: ``mature_content`` .. |mature_content| replace:: ``mature_content``
.. |webbrowser.open()| replace:: ``webbrowser.open()`` .. |webbrowser.open()| replace:: ``webbrowser.open()``
.. _.netrc: https://stackoverflow.com/tags/.netrc/info
.. _tempfile.gettempdir(): https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir .. _tempfile.gettempdir(): https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir
.. _requests.get(): https://docs.python-requests.org/en/latest/user/advanced/#timeouts .. _requests.get(): https://docs.python-requests.org/en/latest/user/advanced/#timeouts
.. _format string: https://docs.python.org/3/library/string.html#formatstrings .. _format string: https://docs.python.org/3/library/string.html#formatstrings

View File

@@ -1,5 +1,6 @@
{ {
"base-directory": "/tmp/", "base-directory": "/tmp/",
"netrc": false,
"downloader": "downloader":
{ {
"http": "http":

View File

@@ -22,8 +22,7 @@ class BatotoExtractor():
def login(self): def login(self):
"""Login and set necessary cookies""" """Login and set necessary cookies"""
username = self.config("username") username, password = self.auth_info()
password = self.config("password")
if username: if username:
cookies = self._login_impl(username, password) cookies = self._login_impl(username, password)
for key, value in cookies.items(): for key, value in cookies.items():

View File

@@ -10,6 +10,7 @@
import os import os
import time import time
import netrc
import queue import queue
import logging import logging
import requests import requests
@@ -42,6 +43,24 @@ class Extractor():
return config.interpolate( return config.interpolate(
("extractor", self.category, self.subcategory, key), default) ("extractor", self.category, self.subcategory, key), default)
def auth_info(self):
"""Return authentication information as (username, password) tuple"""
username = self.config("username")
password = None
if username:
password = self.config("password")
elif config.get(("netrc",), False):
try:
info = netrc.netrc().authenticators(self.category)
username, _, password = info
except (OSError, netrc.NetrcParseError) as exc:
self.log.error("netrc: %s", exc)
except TypeError:
self.log.warning("netrc: No authentication info")
return username, password
def request(self, url, encoding=None, *args, **kwargs): def request(self, url, encoding=None, *args, **kwargs):
response = safe_request(self.session, url, *args, **kwargs) response = safe_request(self.session, url, *args, **kwargs)
if encoding: if encoding:

View File

@@ -182,13 +182,12 @@ class ExhentaiGalleryExtractor(Extractor):
def login(self): def login(self):
"""Login and set necessary cookies""" """Login and set necessary cookies"""
username = self.config("username") username, password = self.auth_info()
if not username: if not username:
self.log.info("no username given; using e-hentai.org") self.log.info("no username given; using e-hentai.org")
self.root = "https://e-hentai.org" self.root = "https://e-hentai.org"
self.original = False self.original = False
return return
password = self.config("password")
cookies = self._login_impl(username, password) cookies = self._login_impl(username, password)
for key, value in cookies.items(): for key, value in cookies.items():
self.session.cookies.set( self.session.cookies.set(

View File

@@ -62,8 +62,7 @@ class NijieExtractor(AsynchronousExtractor):
def login(self): def login(self):
"""Login and obtain session cookie""" """Login and obtain session cookie"""
username = self.config("username") username, password = self.auth_info()
password = self.config("password")
self.session.cookies = self._login_impl(username, password) self.session.cookies = self._login_impl(username, password)
@cache(maxage=30*24*60*60, keyarg=1) @cache(maxage=30*24*60*60, keyarg=1)

View File

@@ -233,8 +233,7 @@ class PixivAPI():
def __init__(self, extractor): def __init__(self, extractor):
self.session = extractor.session self.session = extractor.session
self.log = extractor.log self.log = extractor.log
self.username = extractor.config("username") self.username, self.password = extractor.auth_info()
self.password = extractor.config("password")
self.user_info = None self.user_info = None
self.session.headers.update({ self.session.headers.update({
"Referer": "https://www.pixiv.net/", "Referer": "https://www.pixiv.net/",

View File

@@ -47,8 +47,7 @@ class SeigaExtractor(Extractor):
def login(self): def login(self):
"""Login and set necessary cookies""" """Login and set necessary cookies"""
username = self.config("username") username, password = self.auth_info()
password = self.config("password")
self.session.cookies = self._login_impl(username, password) self.session.cookies = self._login_impl(username, password)
@cache(maxage=7*24*60*60, keyarg=1) @cache(maxage=7*24*60*60, keyarg=1)

View File

@@ -86,6 +86,11 @@ def build_parser():
"-p", "--password", "-p", "--password",
metavar="PASS", action=ConfigAction, dest="password", metavar="PASS", action=ConfigAction, dest="password",
) )
parser.add_argument(
"--netrc",
action=ConfigConstAction, nargs=0, dest="netrc", const=True,
help="Use .netrc authentication data",
)
parser.add_argument( parser.add_argument(
"-i", "--input-file", "-i", "--input-file",
metavar="FILE", dest="inputfile", metavar="FILE", dest="inputfile",