def handle(self, *args, **options): # Create the JWPlatform client self.client = jwplatform.get_jwplatform_client() # Fetch and cache the video resources if not options['skip_video_fetch'] and not options['skip_fetch']: self.stdout.write('Caching video resources...') models.set_resources(self.fetch_videos(), 'video') # Print out the total number of videos cached self.stdout.write(self.style.SUCCESS('Number of cached video resources: {}'.format( models.CachedResource.videos.count() ))) if not options['skip_channel_fetch'] and not options['skip_fetch']: self.stdout.write('Fetching channels...') models.set_resources(self.fetch_channels(), 'channel') # Print out the total number of channels cached self.stdout.write(self.style.SUCCESS('Number of cached channel resources: {}'.format( models.CachedResource.channels.count() ))) # Synchronise cached resources into main application state sync.update_related_models_from_cache(update_all_videos=options['sync_all']) # Print out the total number of media items self.stdout.write(self.style.SUCCESS('Number of media items: {}'.format( mediaplatform.models.MediaItem.objects.count() ))) # Print out the total number of channels self.stdout.write(self.style.SUCCESS('Number of channels: {}'.format( mediaplatform.models.Channel.objects.count() )))
def _perform_item_update(item): # Get a JWPlatform client jwp_client = jwp.get_jwplatform_client() video_resource = { 'title': item.title, # HACK: JWP does not allow a blank description(!) 'description': item.description if item.description != '' else ' ', # We need to populate the SMS fields so that jwpfetch does not overwrite this item 'custom': { 'sms_downloadable': 'downloadable:{}:'.format(item.downloadable), 'sms_language': 'language:{}:'.format(item.language), 'sms_copyright': 'copyright:{}:'.format(item.copyright), 'sms_keywords': 'keywords:{}:'.format('|'.join(item.tags)), }, } if item.published_at is not None: video_resource['date'] = int(item.published_at.timestamp()) # If there are any permissions, add them too if hasattr(item, 'view_permission'): video_resource['custom']['sms_acl'] = 'acl:{}:'.format( _permission_to_acl(item.view_permission)) # Convert the model updated_at field to a timestamp updated = int(item.updated_at.timestamp()) if hasattr(item, 'jwp'): # Get/create the corresponding cached JWP resource video_key = item.jwp.key # Update the video using the JWP management API response = jwp_client.videos.update(http_method='POST', video_key=video_key, **_flatten_dict(video_resource)) # Record the update item.jwp.updated = updated item.jwp.save() else: # Create the video using the JWP management API response = jwp_client.videos.create(http_method='POST', **_flatten_dict(video_resource)) # Get/create the corresponding cached JWP resource video_key = response.get('media', {}).get('key') if video_key is None: raise RuntimeError('Unexpected response from JWP: {}'.format( repr(response))) # Create a JWP video model models.Video.objects.create(key=video_key, updated=updated, item=item) # If there was an upload link in the response, record it. link_data = response.get('link') if link_data is not None: upload.record_link_response(link_data, item)
def synchronise(sync_all=False, skip_video_fetch=False, skip_channel_fetch=False): """ Synchronise the list of Cached JWP resources in the database with the actual list of resources using the JWP management API. For JWP videos which come from the SMS, media items are automatically created as videos apear. All JWP videos with corresponding media items have basic metadata such as title and description synchronised. If *sync_all* is True, all media items are re-synchronised from their corresponding cached JWP resource. If False, only those items whose JWP resources have changed are synchronised. If *skip_video_fetch* is True, the cached video resources are not re-fetched from JWP. If *skip_channel_fetch* is True, the cached channel resources are not re-fetched from JWP. """ # Create the JWPlatform client client = jwplatform.get_jwplatform_client() # Fetch and cache the video resources if not skip_video_fetch: LOG.info('Caching video resources...') models.set_resources(fetch_videos(client), 'video') # Print out the total number of videos cached LOG.info('Number of cached video resources: {}'.format( models.CachedResource.videos.count())) if not skip_channel_fetch: LOG.info('Fetching channels...') models.set_resources(fetch_channels(client), 'channel') # Print out the total number of channels cached LOG.info('Number of cached channel resources: {}'.format( models.CachedResource.channels.count())) # Synchronise cached resources into main application state sync.update_related_models_from_cache(update_all_videos=sync_all) # Print out the total number of media items LOG.info('Number of media items: {}'.format( mediaplatform.models.MediaItem.objects.count())) # Print out the total number of channels LOG.info('Number of channels: {}'.format( mediaplatform.models.Channel.objects.count()))
def create_upload_endpoint(item): """ Create an upload endpoint for a media item. Raises ValueError if the item does not have a corresponding JWP video """ if not hasattr(item, 'jwp'): raise ValueError('MediaItem has no associated JWP video') # Get a JWPlatform client jwp_client = jwp.get_jwplatform_client() response = jwp_client.videos.update(http_method='POST', video_key=item.jwp.key, update_file=True) upload.record_link_response(response['link'], item)
def _perform_item_update(item): # Get a JWPlatform client jwp_client = jwp.get_jwplatform_client() # Form a key for the current site replacing "."s with "_"s since JWP interprets "." specially. # NOTE: using get_current() here will use the SITE_ID setting so that must be set. current_site = Site.objects.get_current() safe_site_name = current_site.domain.replace('.', '_') video_resource = { 'title': item.title, # HACK: JWP does not allow a blank description(!) 'description': item.description if item.description != '' else ' ', 'custom': { # We need to populate the SMS fields so that jwpfetch does not overwrite this item 'sms_downloadable': 'downloadable:{}:'.format(item.downloadable), 'sms_language': 'language:{}:'.format(item.language), 'sms_copyright': 'copyright:{}:'.format(item.copyright), 'sms_keywords': 'keywords:{}:'.format('|'.join(item.tags)), # Add custom props to the video to specify which site it is available on and which # media id it corresponds to. 'site': { safe_site_name: { 'name': current_site.name, 'media_id': item.id, }, } }, } # Additional tags which should be set on the video. These tags are added in addition to any # existing tags. additional_tags = [f'sitedomain:{current_site.domain}'] # Note: only has an effect if the item is being created if item.initially_fetched_from_url != '': video_resource['download_url'] = item.initially_fetched_from_url if item.published_at is not None: video_resource['date'] = int(item.published_at.timestamp()) # If there are any permissions, add them too if hasattr(item, 'view_permission'): video_resource['custom']['sms_acl'] = 'acl:{}:'.format( _permission_to_acl(item.view_permission)) # Convert the model updated_at field to a timestamp updated = int(item.updated_at.timestamp()) if hasattr(item, 'jwp'): # Get/create the corresponding cached JWP resource video_key = item.jwp.key # Merge the tags in. JWP seems somewhat cavalier in whitespace surrounding tags and whether # the tags field comes back as null or "" so we have to be quite defensive. # See: RFC 1122 §1.2.2 and https://en.wikipedia.org/wiki/Robustness_principle existing_video = jwp_client.videos.show(video_key=video_key).get( 'video', {}) existing_tags = [ t.strip() for t in (existing_video.get('tags') or '').strip().split(',') ] for t in set(additional_tags) - set(existing_tags): existing_tags.append(t) video_resource['tags'] = ','.join(existing_tags) # Update the video using the JWP management API response = jwp_client.videos.update(http_method='POST', video_key=video_key, **_flatten_dict(video_resource)) # Record the update item.jwp.updated = updated item.jwp.save() else: # Create the video using the JWP management API video_resource['tags'] = ','.join(additional_tags) response = jwp_client.videos.create(http_method='POST', **_flatten_dict(video_resource)) # Get/create the corresponding cached JWP resource resource_data = response.get('media', {}) video_key = resource_data.get('key') # For reasons best known to JWP, the response is different if download_url is set(!) if video_key is None: video_key = response.get('video', {}).get('key') if video_key is not None: # We need to fetch the resource again if download_url is set(!) resource_data = jwp_client.videos.show( http_method='POST', video_key=video_key)['video'] if video_key is None: raise RuntimeError('Unexpected response from JWP: {}'.format( repr(response))) # Create a JWP video model and update/create the associated cached resource for it resource, _ = models.CachedResource.objects.get_or_create( key=video_key, defaults={'data': resource_data}) models.Video.objects.create(key=video_key, updated=updated, item=item, resource=resource) # If there was an upload link in the response, record it. link_data = response.get('link') if link_data is not None: upload.record_link_response(link_data, item)