mirror of
https://github.com/instaloader/instaloader.git
synced 2026-10-23 17:09:37 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ad9111753 | ||
|
|
327fcfd8e8 | ||
|
|
ae39ab9893 | ||
|
|
0372f7c8e8 | ||
|
|
94d599db61 | ||
|
|
a0e3e8db0d | ||
|
|
8c1129e556 | ||
|
|
c200031be6 | ||
|
|
a0d2ec95b9 |
+2
-1
@@ -1 +1,2 @@
|
|||||||
custom: "https://instaloader.github.io/contributing.html#donations"
|
github: [aandergr]
|
||||||
|
custom: "https://instaloader.github.io/sponsors.html"
|
||||||
|
|||||||
@@ -30,5 +30,5 @@ jobs:
|
|||||||
stale-pr-label: 'stale'
|
stale-pr-label: 'stale'
|
||||||
exempt-issue-label: 'leave open'
|
exempt-issue-label: 'leave open'
|
||||||
exempt-pr-label: 'leave open'
|
exempt-pr-label: 'leave open'
|
||||||
days-before-stale: 90
|
days-before-stale: 135
|
||||||
days-before-close: 14
|
days-before-close: 14
|
||||||
|
|||||||
+28
-18
@@ -104,6 +104,34 @@ already have a valid session cookie file.
|
|||||||
|
|
||||||
`Instaloader Documentation <https://instaloader.github.io/basic-usage.html>`__
|
`Instaloader Documentation <https://instaloader.github.io/basic-usage.html>`__
|
||||||
|
|
||||||
|
Contributing
|
||||||
|
------------
|
||||||
|
|
||||||
|
As an open source project, Instaloader heavily depends on the contributions from
|
||||||
|
its community. See
|
||||||
|
`contributing <https://instaloader.github.io/contributing.html>`__
|
||||||
|
for how you may help Instaloader to become an even greater tool.
|
||||||
|
|
||||||
|
Supporters
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. current-sponsors-start
|
||||||
|
|
||||||
|
See `Alex' GitHub Sponsors <https://github.com/sponsors/aandergr>`__ page for
|
||||||
|
how you can sponsor the development of Instaloader!
|
||||||
|
|
||||||
|
.. current-sponsors-end
|
||||||
|
|
||||||
|
It is a pleasure for us to share our Instaloader to the world, and we are proud
|
||||||
|
to have attracted such an active and motivating community, with so many users
|
||||||
|
who share their suggestions and ideas with us. Buying a community-sponsored beer
|
||||||
|
or coffee from time to time is very likely to further raise our passion for the
|
||||||
|
development of Instaloader.
|
||||||
|
|
||||||
|
| For Donations, we provide GitHub Sponsors page, a PayPal.Me link and a Bitcoin address.
|
||||||
|
| GitHub Sponsors: `Sponsor @aandergr on GitHub Sponsors <https://github.com/sponsors/aandergr>`__
|
||||||
|
| PayPal: `PayPal.me/aandergr <https://www.paypal.me/aandergr>`__
|
||||||
|
| BTC: 1Nst4LoadeYzrKjJ1DX9CpbLXBYE9RKLwY
|
||||||
|
|
||||||
Disclaimer
|
Disclaimer
|
||||||
----------
|
----------
|
||||||
@@ -116,21 +144,3 @@ subsidiaries. This is an independent and unofficial project. Use at your own ris
|
|||||||
Instaloader is licensed under an MIT license. Refer to ``LICENSE`` file for more information.
|
Instaloader is licensed under an MIT license. Refer to ``LICENSE`` file for more information.
|
||||||
|
|
||||||
.. disclaimer-end
|
.. disclaimer-end
|
||||||
|
|
||||||
Contributing
|
|
||||||
------------
|
|
||||||
|
|
||||||
As an open source project, Instaloader heavily depends on the contributions from
|
|
||||||
its community. See
|
|
||||||
`contributing <https://instaloader.github.io/contributing.html>`__
|
|
||||||
for how you may help Instaloader to become an even greater tool.
|
|
||||||
|
|
||||||
It is a pleasure for us to share our Instaloader to the world, and we are proud
|
|
||||||
to have attracted such an active and motivating community, with so many users
|
|
||||||
who share their suggestions and ideas with us. Buying a community-sponsored beer
|
|
||||||
or coffee from time to time is very likely to further raise our passion for the
|
|
||||||
development of Instaloader.
|
|
||||||
|
|
||||||
| For Donations, we provide a PayPal.Me link and a Bitcoin address.
|
|
||||||
| PayPal: `PayPal.me/aandergr <https://www.paypal.me/aandergr>`__
|
|
||||||
| BTC: 1Nst4LoadeYzrKjJ1DX9CpbLXBYE9RKLwY
|
|
||||||
|
|||||||
+5
-17
@@ -132,21 +132,9 @@ details. If you feel the need to do so, please create a "feature suggestion".
|
|||||||
be implemented and the underlying problem could be solved. Also **describe
|
be implemented and the underlying problem could be solved. Also **describe
|
||||||
alternatives** that you have considered.
|
alternatives** that you have considered.
|
||||||
|
|
||||||
Donations
|
Sponsoring
|
||||||
---------
|
----------
|
||||||
|
|
||||||
.. donations-start
|
.. include:: sponsors.rst
|
||||||
|
:start-after: donations-start
|
||||||
It is a pleasure for us to share our Instaloader to the world, and we are proud
|
:end-before: donations-end
|
||||||
to have attracted such an active and motivating community, with so many users
|
|
||||||
who share their suggestions and ideas with us. Buying a community-sponsored beer
|
|
||||||
or coffee from time to time is very likely to further raise our passion for the
|
|
||||||
development of Instaloader.
|
|
||||||
|
|
||||||
| For donations, we provide a PayPal.Me link and a Bitcoin address.
|
|
||||||
| `PayPal.me/aandergr <https://www.paypal.me/aandergr>`__
|
|
||||||
| BTC: 1Nst4LoadeYzrKjJ1DX9CpbLXBYE9RKLwY
|
|
||||||
|
|
||||||
.. donations-end
|
|
||||||
|
|
||||||
.. (Discussion in :issue:`130`)
|
|
||||||
|
|||||||
+11
-8
@@ -78,13 +78,6 @@ Useful Links
|
|||||||
- `Issue Tracker / Bug Tracker <https://github.com/instaloader/instaloader/issues>`__
|
- `Issue Tracker / Bug Tracker <https://github.com/instaloader/instaloader/issues>`__
|
||||||
- `Version History <https://github.com/instaloader/instaloader/releases>`__
|
- `Version History <https://github.com/instaloader/instaloader/releases>`__
|
||||||
|
|
||||||
Disclaimer
|
|
||||||
----------
|
|
||||||
|
|
||||||
.. include:: ../README.rst
|
|
||||||
:start-after: disclaimer-start
|
|
||||||
:end-before: disclaimer-end
|
|
||||||
|
|
||||||
Contributing
|
Contributing
|
||||||
------------
|
------------
|
||||||
|
|
||||||
@@ -92,10 +85,20 @@ As an open source project, Instaloader heavily depends on the contributions from
|
|||||||
its community. See :ref:`contributing` for how you may help Instaloader to
|
its community. See :ref:`contributing` for how you may help Instaloader to
|
||||||
become an even greater tool.
|
become an even greater tool.
|
||||||
|
|
||||||
.. include:: contributing.rst
|
Supporters
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. include:: sponsors.rst
|
||||||
:start-after: donations-start
|
:start-after: donations-start
|
||||||
:end-before: donations-end
|
:end-before: donations-end
|
||||||
|
|
||||||
|
Disclaimer
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. include:: ../README.rst
|
||||||
|
:start-after: disclaimer-start
|
||||||
|
:end-before: disclaimer-end
|
||||||
|
|
||||||
..
|
..
|
||||||
* :ref:`genindex`
|
* :ref:`genindex`
|
||||||
* :ref:`modindex`
|
* :ref:`modindex`
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
.. _sponsors:
|
||||||
|
|
||||||
|
Sponsoring the development of Instaloader
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
.. donations-start
|
||||||
|
|
||||||
|
.. include:: ../README.rst
|
||||||
|
:start-after: current-sponsors-start
|
||||||
|
:end-before: current-sponsors-end
|
||||||
|
|
||||||
|
It is a pleasure for us to share our Instaloader to the world, and we are proud
|
||||||
|
to have attracted such an active and motivating community, with so many users
|
||||||
|
who share their suggestions and ideas with us. Buying a community-sponsored beer
|
||||||
|
or coffee from time to time is very likely to further raise our passion for the
|
||||||
|
development of Instaloader.
|
||||||
|
|
||||||
|
| For Donations, we provide GitHub Sponsors page, a PayPal.Me link and a Bitcoin address.
|
||||||
|
| GitHub Sponsors: `Sponsor @aandergr on GitHub Sponsors <https://github.com/sponsors/aandergr>`__
|
||||||
|
| PayPal: `PayPal.me/aandergr <https://www.paypal.me/aandergr>`__
|
||||||
|
| BTC: 1Nst4LoadeYzrKjJ1DX9CpbLXBYE9RKLwY
|
||||||
|
|
||||||
|
.. donations-end
|
||||||
@@ -62,7 +62,8 @@ Two-Factor-Authentication. It also supports handling the *checkpoint challenge*,
|
|||||||
issued when Instagram suspects authentication activity on your account, by
|
issued when Instagram suspects authentication activity on your account, by
|
||||||
pointing the user to an URL to be opened in a browser.
|
pointing the user to an URL to be opened in a browser.
|
||||||
|
|
||||||
Nevertheless, in :issue:`92` and :issue:`615` users reported problems with
|
Nevertheless, in :issue:`92`, :issue:`615`, :issue:`1150` and :issue:`1217`,
|
||||||
|
users reported problems with
|
||||||
logging in. We recommend to always keep the session file which Instaloader
|
logging in. We recommend to always keep the session file which Instaloader
|
||||||
creates when using :option:`--login`. If a session file is present,
|
creates when using :option:`--login`. If a session file is present,
|
||||||
:option:`--login` does not make use of the failure-prone login procedure.
|
:option:`--login` does not make use of the failure-prone login procedure.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""Download pictures (or videos) along with their captions and other metadata from Instagram."""
|
"""Download pictures (or videos) along with their captions and other metadata from Instagram."""
|
||||||
|
|
||||||
|
|
||||||
__version__ = '4.7.3'
|
__version__ = '4.7.6'
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -152,7 +152,6 @@ class InstaloaderContext:
|
|||||||
if empty_session_only:
|
if empty_session_only:
|
||||||
del header['Host']
|
del header['Host']
|
||||||
del header['Origin']
|
del header['Origin']
|
||||||
del header['Referer']
|
|
||||||
del header['X-Instagram-AJAX']
|
del header['X-Instagram-AJAX']
|
||||||
del header['X-Requested-With']
|
del header['X-Requested-With']
|
||||||
return header
|
return header
|
||||||
@@ -528,6 +527,28 @@ class InstaloaderContext:
|
|||||||
:raises ConnectionException: When download repeatedly failed."""
|
:raises ConnectionException: When download repeatedly failed."""
|
||||||
self.write_raw(self.get_raw(url), filename)
|
self.write_raw(self.get_raw(url), filename)
|
||||||
|
|
||||||
|
def head(self, url: str, allow_redirects: bool = False) -> requests.Response:
|
||||||
|
"""HEAD a URL anonymously.
|
||||||
|
|
||||||
|
:raises QueryReturnedNotFoundException: When the server responds with a 404.
|
||||||
|
:raises QueryReturnedForbiddenException: When the server responds with a 403.
|
||||||
|
:raises ConnectionException: When request failed.
|
||||||
|
|
||||||
|
.. versionadded:: 4.7.6
|
||||||
|
"""
|
||||||
|
with self.get_anonymous_session() as anonymous_session:
|
||||||
|
resp = anonymous_session.head(url, allow_redirects=allow_redirects)
|
||||||
|
if resp.status_code == 200:
|
||||||
|
return resp
|
||||||
|
else:
|
||||||
|
if resp.status_code == 403:
|
||||||
|
# suspected invalid URL signature
|
||||||
|
raise QueryReturnedForbiddenException("403 when accessing {}.".format(url))
|
||||||
|
if resp.status_code == 404:
|
||||||
|
# 404 not worth retrying.
|
||||||
|
raise QueryReturnedNotFoundException("404 when accessing {}.".format(url))
|
||||||
|
raise ConnectionException("HTTP error code {}.".format(resp.status_code))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def root_rhx_gis(self) -> Optional[str]:
|
def root_rhx_gis(self) -> Optional[str]:
|
||||||
"""rhx_gis string returned in the / query."""
|
"""rhx_gis string returned in the / query."""
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import re
|
|||||||
from base64 import b64decode, b64encode
|
from base64 import b64decode, b64encode
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, Dict, Iterable, Iterator, List, Optional, Union
|
from typing import Any, Dict, Iterable, Iterator, List, Optional, Tuple, Union
|
||||||
|
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
@@ -374,13 +374,26 @@ class Post:
|
|||||||
def video_url(self) -> Optional[str]:
|
def video_url(self) -> Optional[str]:
|
||||||
"""URL of the video, or None."""
|
"""URL of the video, or None."""
|
||||||
if self.is_video:
|
if self.is_video:
|
||||||
|
version_urls = [self._field('video_url')]
|
||||||
if self._context.is_logged_in:
|
if self._context.is_logged_in:
|
||||||
|
version_urls.extend(version['url'] for version in self._iphone_struct['video_versions'])
|
||||||
|
url_candidates: List[Tuple[int, str]] = []
|
||||||
|
for idx, version_url in enumerate(version_urls):
|
||||||
|
if any(url_candidate[1] == version_url for url_candidate in url_candidates):
|
||||||
|
# Skip duplicates
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
url = self._iphone_struct['video_versions'][0]['url']
|
url_candidates.append((
|
||||||
return url
|
int(self._context.head(version_url, allow_redirects=True).headers.get('Content-Length', 0)),
|
||||||
|
version_url
|
||||||
|
))
|
||||||
except (InstaloaderException, KeyError, IndexError) as err:
|
except (InstaloaderException, KeyError, IndexError) as err:
|
||||||
self._context.error('{} Unable to fetch high quality video version of {}.'.format(err, self))
|
self._context.error(f"Video URL candidate {idx+1}/{len(version_urls)} for {self}: {err}")
|
||||||
return self._field('video_url')
|
if not url_candidates:
|
||||||
|
# All candidates fail: Fallback to default URL and handle errors later at the actual download attempt
|
||||||
|
return version_urls[0]
|
||||||
|
url_candidates.sort()
|
||||||
|
return url_candidates[-1][1]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -553,8 +566,8 @@ class Post:
|
|||||||
return None
|
return None
|
||||||
location_id = int(loc['id'])
|
location_id = int(loc['id'])
|
||||||
if any(k not in loc for k in ('name', 'slug', 'has_public_page', 'lat', 'lng')):
|
if any(k not in loc for k in ('name', 'slug', 'has_public_page', 'lat', 'lng')):
|
||||||
loc = self._context.get_json("explore/locations/{0}/".format(location_id),
|
loc.update(self._context.get_json("explore/locations/{0}/".format(location_id),
|
||||||
params={'__a': 1})['graphql']['location']
|
params={'__a': 1})['native_location_data']['location_info'])
|
||||||
self._location = PostLocation(location_id, loc['name'], loc['slug'], loc['has_public_page'],
|
self._location = PostLocation(location_id, loc['name'], loc['slug'], loc['has_public_page'],
|
||||||
loc['lat'], loc['lng'])
|
loc['lat'], loc['lng'])
|
||||||
return self._location
|
return self._location
|
||||||
@@ -1103,7 +1116,26 @@ class StoryItem:
|
|||||||
def video_url(self) -> Optional[str]:
|
def video_url(self) -> Optional[str]:
|
||||||
"""URL of the video, or None."""
|
"""URL of the video, or None."""
|
||||||
if self.is_video:
|
if self.is_video:
|
||||||
return self._node['video_resources'][-1]['src']
|
version_urls = [self._node['video_resources'][-1]['src']]
|
||||||
|
if self._context.is_logged_in:
|
||||||
|
version_urls.extend(version['url'] for version in self._iphone_struct['video_versions'])
|
||||||
|
url_candidates: List[Tuple[int, str]] = []
|
||||||
|
for idx, version_url in enumerate(version_urls):
|
||||||
|
if any(url_candidate[1] == version_url for url_candidate in url_candidates):
|
||||||
|
# Skip duplicates
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
url_candidates.append((
|
||||||
|
int(self._context.head(version_url, allow_redirects=True).headers.get('Content-Length', 0)),
|
||||||
|
version_url
|
||||||
|
))
|
||||||
|
except (InstaloaderException, KeyError, IndexError) as err:
|
||||||
|
self._context.error(f"Video URL candidate {idx+1}/{len(version_urls)} for {self}: {err}")
|
||||||
|
if not url_candidates:
|
||||||
|
# All candidates fail: Fallback to default URL and handle errors later at the actual download attempt
|
||||||
|
return version_urls[0]
|
||||||
|
url_candidates.sort()
|
||||||
|
return url_candidates[-1][1]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user