Improve post/storyitem-metadata-txt behavior

If an expression evaluates to None, an empty string is yielded, rather
than 'None'.

Blanks (and newlines) are strip()ed from the formatted strings, which
also avoids creation of whitespace-only textfiles.

save_captions parameter to Instaloader constructor has been removed, as
it is equivalent to setting both {post,storyitem}_metadata_txt_pattern
to '' (empty string).

Instaloader.save_caption() now prints the '[{old}] updated [{new}]' if
the caption was updated, rather than printing the new caption twice,
which was confusing.
This commit is contained in:
Alexander Graf 2018-04-29 10:55:29 +02:00
parent b2dd395a86
commit 8a8ea2913c
2 changed files with 32 additions and 24 deletions

View File

@ -302,10 +302,18 @@ def main():
post_metadata_txt_pattern = '\n'.join(args.post_metadata_txt) if args.post_metadata_txt else None post_metadata_txt_pattern = '\n'.join(args.post_metadata_txt) if args.post_metadata_txt else None
storyitem_metadata_txt_pattern = '\n'.join(args.storyitem_metadata_txt) if args.storyitem_metadata_txt else None storyitem_metadata_txt_pattern = '\n'.join(args.storyitem_metadata_txt) if args.storyitem_metadata_txt else None
if args.no_captions:
if not (post_metadata_txt_pattern or storyitem_metadata_txt_pattern):
post_metadata_txt_pattern = ''
storyitem_metadata_txt_pattern = ''
else:
raise SystemExit("--no-captions and --post-metadata-txt or --storyitem-metadata-txt given; "
"That contradicts.")
loader = Instaloader(sleep=not args.no_sleep, quiet=args.quiet, user_agent=args.user_agent, loader = Instaloader(sleep=not args.no_sleep, quiet=args.quiet, user_agent=args.user_agent,
dirname_pattern=args.dirname_pattern, filename_pattern=args.filename_pattern, dirname_pattern=args.dirname_pattern, filename_pattern=args.filename_pattern,
download_videos=not args.no_videos, download_video_thumbnails=not args.no_video_thumbnails, download_videos=not args.no_videos, download_video_thumbnails=not args.no_video_thumbnails,
download_geotags=args.geotags, save_captions=not args.no_captions, download_geotags=args.geotags,
download_comments=args.comments, save_metadata=not args.no_metadata_json, download_comments=args.comments, save_metadata=not args.no_metadata_json,
compress_json=not args.no_compress_json, compress_json=not args.no_compress_json,
post_metadata_txt_pattern=post_metadata_txt_pattern, post_metadata_txt_pattern=post_metadata_txt_pattern,

View File

@ -57,9 +57,12 @@ class _ArbitraryItemFormatter(string.Formatter):
def format_field(self, value, format_spec): def format_field(self, value, format_spec):
"""Override :meth:`string.Formatter.format_field` to have our """Override :meth:`string.Formatter.format_field` to have our
default format_spec for :class:`datetime.Datetime` objects.""" default format_spec for :class:`datetime.Datetime` objects, and to
let None yield an empty string rather than ``None``."""
if isinstance(value, datetime) and not format_spec: if isinstance(value, datetime) and not format_spec:
return super().format_field(value, '%Y-%m-%d_%H-%M-%S') return super().format_field(value, '%Y-%m-%d_%H-%M-%S')
if value is None:
return ''
return super().format_field(value, format_spec) return super().format_field(value, format_spec)
@ -80,11 +83,12 @@ class Instaloader:
:param download_videos: not :option:`--no-videos` :param download_videos: not :option:`--no-videos`
:param download_video_thumbnails: not :option:`--no-video-thumbnails` :param download_video_thumbnails: not :option:`--no-video-thumbnails`
:param download_geotags: :option:`--geotags` :param download_geotags: :option:`--geotags`
:param save_captions: not :option:`--no-captions`
:param download_comments: :option:`--comments` :param download_comments: :option:`--comments`
:param save_metadata: not :option:`--no-metadata-json` :param save_metadata: not :option:`--no-metadata-json`
:param compress_json: not :option:`--no-compress-json` :param compress_json: not :option:`--no-compress-json`
:param post_metadata_txt_pattern: :option:`--post-metadata-txt`, default is ``{caption}`` :param post_metadata_txt_pattern:
:option:`--post-metadata-txt`, default is ``{caption}``. Set to empty string to avoid creation of post metadata
txt file.
:param storyitem_metadata_txt_pattern: :option:`--storyitem-metadata-txt`, default is empty (=none) :param storyitem_metadata_txt_pattern: :option:`--storyitem-metadata-txt`, default is empty (=none)
:param max_connection_attempts: :option:`--max-connection-attempts` :param max_connection_attempts: :option:`--max-connection-attempts`
""" """
@ -97,7 +101,6 @@ class Instaloader:
download_videos: bool = True, download_videos: bool = True,
download_video_thumbnails: bool = True, download_video_thumbnails: bool = True,
download_geotags: bool = True, download_geotags: bool = True,
save_captions: bool = True,
download_comments: bool = True, download_comments: bool = True,
save_metadata: bool = True, save_metadata: bool = True,
compress_json: bool = True, compress_json: bool = True,
@ -113,19 +116,20 @@ class Instaloader:
self.download_videos = download_videos self.download_videos = download_videos
self.download_video_thumbnails = download_video_thumbnails self.download_video_thumbnails = download_video_thumbnails
self.download_geotags = download_geotags self.download_geotags = download_geotags
self.save_captions = save_captions
self.download_comments = download_comments self.download_comments = download_comments
self.save_metadata = save_metadata self.save_metadata = save_metadata
self.compress_json = compress_json self.compress_json = compress_json
self.post_metadata_txt_pattern = post_metadata_txt_pattern or '{caption}' self.post_metadata_txt_pattern = '{caption}' if post_metadata_txt_pattern is None \
self.storyitem_metadata_txt_pattern = storyitem_metadata_txt_pattern or '' else post_metadata_txt_pattern
self.storyitem_metadata_txt_pattern = '' if storyitem_metadata_txt_pattern is None \
else storyitem_metadata_txt_pattern
@contextmanager @contextmanager
def anonymous_copy(self): def anonymous_copy(self):
"""Yield an anonymous, otherwise equally-configured copy of an Instaloader instance; Then copy its error log.""" """Yield an anonymous, otherwise equally-configured copy of an Instaloader instance; Then copy its error log."""
new_loader = Instaloader(self.context.sleep, self.context.quiet, self.context.user_agent, self.dirname_pattern, new_loader = Instaloader(self.context.sleep, self.context.quiet, self.context.user_agent, self.dirname_pattern,
self.filename_pattern, self.download_videos, self.download_video_thumbnails, self.filename_pattern, self.download_videos, self.download_video_thumbnails,
self.download_geotags, self.save_captions, self.download_comments, self.save_metadata, self.download_geotags, self.download_comments, self.save_metadata,
self.compress_json, self.post_metadata_txt_pattern, self.compress_json, self.post_metadata_txt_pattern,
self.storyitem_metadata_txt_pattern, self.context.max_connection_attempts) self.storyitem_metadata_txt_pattern, self.context.max_connection_attempts)
new_loader.context.query_timestamps = self.context.query_timestamps new_loader.context.query_timestamps = self.context.query_timestamps
@ -200,11 +204,13 @@ class Instaloader:
def save_caption(self, filename: str, mtime: datetime, caption: str) -> None: def save_caption(self, filename: str, mtime: datetime, caption: str) -> None:
"""Updates picture caption / Post metadata info""" """Updates picture caption / Post metadata info"""
def _elliptify(caption):
pcaption = caption.replace('\n', ' ').strip()
return '[' + ((pcaption[:29] + u"\u2026") if len(pcaption) > 31 else pcaption) + ']'
filename += '.txt' filename += '.txt'
caption += '\n' caption += '\n'
pcaption = caption.replace('\n', ' ').strip() pcaption = _elliptify(caption)
caption = caption.encode("UTF-8") caption = caption.encode("UTF-8")
pcaption = '[' + ((pcaption[:29] + u"\u2026") if len(pcaption) > 31 else pcaption) + ']'
with suppress(FileNotFoundError): with suppress(FileNotFoundError):
with open(filename, 'rb') as file: with open(filename, 'rb') as file:
file_caption = file.read() file_caption = file.read()
@ -225,7 +231,7 @@ class Instaloader:
for index in range(i, 0, -1): for index in range(i, 0, -1):
os.rename(get_filename(index - 1), get_filename(index)) os.rename(get_filename(index - 1), get_filename(index))
try: try:
self.context.log(pcaption + ' updated', end=' ', flush=True) self.context.log(_elliptify(file_caption.decode("UTF-8")) + ' updated', end=' ', flush=True)
except UnicodeEncodeError: except UnicodeEncodeError:
self.context.log('txt updated', end=' ', flush=True) self.context.log('txt updated', end=' ', flush=True)
try: try:
@ -346,12 +352,9 @@ class Instaloader:
self.context.error("Warning: {0} has unknown typename: {1}".format(post, post.typename)) self.context.error("Warning: {0} has unknown typename: {1}".format(post, post.typename))
# Save caption if desired # Save caption if desired
if self.save_captions is not False: metadata_string = _ArbitraryItemFormatter(post).format(self.post_metadata_txt_pattern).strip()
metadata_string = _ArbitraryItemFormatter(post).format(self.post_metadata_txt_pattern) if metadata_string:
if metadata_string: self.save_caption(filename=filename, mtime=post.date_local, caption=metadata_string)
self.save_caption(filename=filename, mtime=post.date_local, caption=metadata_string)
else:
self.context.log("<no txt>", end=' ', flush=True)
# Download video if desired # Download video if desired
if post.is_video and self.download_videos is True: if post.is_video and self.download_videos is True:
@ -448,12 +451,9 @@ class Instaloader:
if item.is_video and self.download_videos is True: if item.is_video and self.download_videos is True:
downloaded |= self.download_pic(filename=filename, url=item.video_url, mtime=date_local) downloaded |= self.download_pic(filename=filename, url=item.video_url, mtime=date_local)
# Save caption if desired # Save caption if desired
if self.save_captions is not False: metadata_string = _ArbitraryItemFormatter(item).format(self.storyitem_metadata_txt_pattern).strip()
metadata_string = _ArbitraryItemFormatter(item).format(self.storyitem_metadata_txt_pattern) if metadata_string:
if metadata_string: self.save_caption(filename=filename, mtime=item.date_local, caption=metadata_string)
self.save_caption(filename=filename, mtime=item.date_local, caption=metadata_string)
else:
self.context.log("<no txt>", end=' ', flush=True)
# Save metadata as JSON if desired. # Save metadata as JSON if desired.
if self.save_metadata is not False: if self.save_metadata is not False:
self.save_metadata_json(filename, item) self.save_metadata_json(filename, item)