def save_content(user: Member, post: instaloader.Post) -> Feed or None: ig = Feed.objects.instagram_v2().filter(status_id=post.shortcode).first() if ig: return ig profile = post.owner_profile created_at = post.date.replace(tzinfo=timezone.utc) # handle caption caption = '' if post.caption is not None: caption = post.caption ig = Feed.objects.create(author=profile.username, created_at=created_at, title=caption, user=user, type='instagram_v2', status_id=post.shortcode, link=f'https://www.instagram.com/p/{post.shortcode}') # Only an image if post.typename == 'GraphImage': m = Media.objects.create(feed=ig, original_url=post.url) async_task(m.download_to_local) # Multi images elif post.typename == 'GraphSidecar': for image in post.get_sidecar_nodes(): m = Media.objects.create(feed=ig, original_url=image.display_url) async_task(m.download_to_local) elif post.typename == 'GraphVideo': ig.is_video = True ig.save(update_fields=['is_video']) m = Media.objects.create(feed=ig, original_url=post.url, ) logger.info(f'Instagram: {ig} saved') return ig
async def create_from_instaloader(self, post: instaloader.Post) -> Post: """Create a post from a instaloader post object. :param post: a instaloader post object """ # figure out post_type, items and download_tasks if post.typename == 'GraphImage': post_type = PostType.IMAGE items = [PostItem(index=0, type=PostItemType.IMAGE)] download_tasks = [DownloadTask(url=post.url)] elif post.typename == 'GraphVideo': post_type = PostType.VIDEO items = [ PostItem(index=0, type=PostItemType.VIDEO, duration=post.video_duration) ] download_tasks = [ DownloadTask(url=post.video_url, thumb_url=post.url) ] elif post.typename == 'GraphSidecar': post_type = PostType.SIDECAR items, download_tasks = [], [] for index, node in enumerate(post.get_sidecar_nodes()): post_item = PostItem(index=index, type=PostItemType.VIDEO if node.is_video else PostItemType.IMAGE) download_task = DownloadTask( url=node.video_url if node.is_video else node.display_url, thumb_url=node.display_url if node.is_video else None, ) items.append(post_item) download_tasks.append(download_task) else: post_type = None items, download_tasks = [], [] # convert instaloader post to Post object post = Post( shortcode=post.shortcode, username=post.owner_username, timestamp=post.date_utc, type=post_type, caption=post.caption, caption_hashtags=post.caption_hashtags, caption_mentions=post.caption_mentions, items=[], ) # create profile if not exist profile_service = ProfileService(self.database, self.http_session) if not await profile_service.exists(post.username): await profile_service.upsert(post.username) # download image and videos post_filename = f'{post.timestamp.strftime("%Y-%m-%dT%H-%M-%S")}_[{post.shortcode}]' for item, download_task in zip(items, download_tasks): filename = f'{post_filename}_{item.index}' if len( items) > 1 else post_filename file_path = await self._download( download_task.url, self.post_dir.joinpath(post.username), filename, post.timestamp) item.filename = file_path.name if download_task.thumb_url: file_path = await self._download( download_task.thumb_url, self.thumb_images_dir.joinpath(post.username), filename, post.timestamp, ) item.thumb_image_filename = file_path.name # upsert the post entity post.items = items await self._upsert(post) logger.info(f'Saved post {post.shortcode} of user {post.username} ' f'which contains {len(post.items)} item(s).') return post
def download_post_custom(self, post: Post, target: Union[str, Path]) -> bool: """ Download everything associated with one instagram post node, i.e. picture, caption and video. :param post: Post to download. :param target: Target name, i.e. profile name, #hashtag, :feed; for filename. :return: True if something was downloaded, False otherwise, i.e. file was already there """ # score = int(post.likes/post.video_view_count*20) + 1 if post.is_video else 0 # score_str = str(score) + '_' + str(int(post.likes/post.video_view_count*100)) score_str = 'score' dirname = instaloader._PostPathFormatter(post).format(self.dirname_pattern, target=target, score=score_str) filename = self.format_filename_custom(post, target=target, score=score_str) # insert post record db_manager.insert_post(post.mediaid, 'instagram', target, str(post.date), time.strftime('%Y-%m-%d %X'), filename) filename = dirname + '/' + filename os.makedirs(os.path.dirname(filename), exist_ok=True) # Download the image(s) / video thumbnail and videos within sidecars if desired downloaded = True # self._committed = self.check_if_committed(filename) if self.download_pictures: if post.typename == 'GraphSidecar': edge_number = 1 for sidecar_node in post.get_sidecar_nodes(): # Download picture or video thumbnail if not sidecar_node.is_video or self.download_video_thumbnails is True: downloaded &= self.download_pic( filename=filename, url=sidecar_node.display_url, mtime=post.date_local, filename_suffix=str(edge_number)) # Additionally download video if available and desired if sidecar_node.is_video and self.download_videos is True: downloaded &= self.download_pic( filename=filename, url=sidecar_node.video_url, mtime=post.date_local, filename_suffix=str(edge_number)) edge_number += 1 elif post.typename == 'GraphImage': downloaded = self.download_pic(filename=filename, url=post.url, mtime=post.date_local) elif post.typename == 'GraphVideo': if self.download_video_thumbnails is True: downloaded = self.download_pic(filename=filename, url=post.url, mtime=post.date_local) else: self.context.error("Warning: {0} has unknown typename: {1}".format( post, post.typename)) # Download video if desired if post.is_video and self.download_videos is True: downloaded &= self.download_pic(filename=filename, url=post.video_url, mtime=post.date_local) if downloaded: # Save caption if desired metadata_string = instaloader._ArbitraryItemFormatter(post).format( self.post_metadata_txt_pattern).strip() if metadata_string: self.save_caption(filename=filename, mtime=post.date_local, caption=metadata_string) # Download geotags if desired if self.download_geotags and post.location: self.save_location(filename, post.location, post.date_local) # Update comments if desired # if self.download_comments is True: # #self.update_comments(filename=filename, post=post) # self.save_metadata_json(filename, post) # with open(filename+'.json') as filename_json: # with open(filename+'.txt', 'a', encoding='utf-8') as filename_txt: # data = json.load(filename_json) # for comment_data in data['node']['edge_media_to_parent_comment']['edges']: # comment_text = comment_data['node']['text'] # filename_txt.write('\n'+comment_text+'\n') # os.remove(filename+'.json') # Save metadata as JSON if desired. if self.save_metadata is not False: self.save_metadata_json(filename, post) self.context.log() return downloaded