def annotate_topic_tree(node, level=0, statusdict=None, remote_sizes=None, lang_code=None): # Not needed when on an api request (since translation.activate is already called), # but just to do things right / in an encapsulated way... # Though to be honest, this isn't quite right; we should be DE-activating translation # at the end. But with so many function exit-points... just a nightmare. if not lang_code: lang_code = settings.LANGUAGE_CODE if level == 0: translation.activate(lang_code) if not statusdict: statusdict = {} if node["kind"] == "Topic": if "Video" not in node["contains"]: return None children = [] unstarted = True complete = True for child_node in node["children"]: child = annotate_topic_tree(child_node, level=level + 1, statusdict=statusdict, lang_code=lang_code) if not child: continue elif child["addClass"] == "unstarted": complete = False elif child["addClass"] == "partial": complete = False unstarted = False elif child["addClass"] == "complete": unstarted = False children.append(child) if not children: # All children were eliminated; so eliminate self. return None return { "title": _(node["title"]), "tooltip": re.sub(r'<[^>]*?>', '', _(node.get("description")) or ""), "isFolder": True, "key": node["id"], "children": children, "addClass": complete and "complete" or unstarted and "unstarted" or "partial", "expand": level < 1, } elif node["kind"] == "Video": video_id = node.get("youtube_id", node.get("id")) youtube_id = get_youtube_id(video_id, lang_code=lang_code) if not youtube_id: # This video doesn't exist in this language, so remove from the topic tree. return None # statusdict contains an item for each video registered in the database # will be {} (empty dict) if there are no videos downloaded yet percent = statusdict.get(youtube_id, 0) vid_size = None status = None if not percent: status = "unstarted" vid_size = get_remote_video_size(youtube_id) / float(2 ** 20) # express in MB elif percent == 100: status = "complete" vid_size = get_local_video_size(youtube_id, 0) / float(2 ** 20) # express in MB else: status = "partial" return { "title": _(node["title"]), "tooltip": re.sub(r'<[^>]*?>', '', _(node.get("description")) or ""), "key": youtube_id, "addClass": status, "size": vid_size, } return None
def annotate_topic_tree(node, level=0, statusdict=None, remote_sizes=None, lang_code=settings.LANGUAGE_CODE): # Not needed when on an api request (since translation.activate is already called), # but just to do things right / in an encapsulated way... # Though to be honest, this isn't quite right; we should be DE-activating translation # at the end. But with so many function exit-points... just a nightmare. if level == 0: translation.activate(lang_code) if not statusdict: statusdict = {} if node["kind"] == "Topic": if "Video" not in node["contains"]: return None children = [] unstarted = True complete = True for child_node in node["children"]: child = annotate_topic_tree(child_node, level=level + 1, statusdict=statusdict, lang_code=lang_code) if not child: continue elif child["addClass"] == "unstarted": complete = False elif child["addClass"] == "partial": complete = False unstarted = False elif child["addClass"] == "complete": unstarted = False children.append(child) if not children: # All children were eliminated; so eliminate self. return None return { "title": _(node["title"]), "tooltip": re.sub(r'<[^>]*?>', '', _(node.get("description")) or ""), "isFolder": True, "key": node["id"], "children": children, "addClass": complete and "complete" or unstarted and "unstarted" or "partial", "expand": level < 1, } elif node["kind"] == "Video": video_id = node.get("youtube_id", node.get("id")) youtube_id = get_youtube_id(video_id, lang_code=lang_code) if not youtube_id: # This video doesn't exist in this language, so remove from the topic tree. return None # statusdict contains an item for each video registered in the database # will be {} (empty dict) if there are no videos downloaded yet percent = statusdict.get(youtube_id, 0) vid_size = None status = None if not percent: status = "unstarted" vid_size = get_remote_video_size(youtube_id) / float( 2**20) # express in MB elif percent == 100: status = "complete" vid_size = get_local_video_size(youtube_id, 0) / float( 2**20) # express in MB else: status = "partial" return { "title": _(node["title"]), "tooltip": re.sub(r'<[^>]*?>', '', _(node.get("description")) or ""), "key": youtube_id, "addClass": status, "size": vid_size, } return None
def stamp_availability_on_video(video, format="mp4", force=False, stamp_urls=True, videos_path=None): """ Stamp all relevant urls and availability onto a video object (if necessary), including: * whether the video is available (on disk or online) """ videos_path = videos_path or settings.CONTENT_ROOT def compute_video_availability(youtube_id, format, videos_path=videos_path): return {"on_disk": is_video_on_disk(youtube_id, format, videos_path=videos_path)} def compute_video_metadata(youtube_id, format): return {"stream_type": "video/%s" % format} def compute_video_urls(youtube_id, format, lang_code, on_disk=None, thumb_formats=["png", "jpg"], videos_path=videos_path): if on_disk is None: on_disk = is_video_on_disk(youtube_id, format, videos_path=videos_path) if on_disk: video_base_url = settings.CONTENT_URL + youtube_id stream_url = video_base_url + ".%s" % format thumbnail_url = None # default to None now, so we know when no thumbnail is available. for thumb_format in thumb_formats: # find the thumbnail on disk thumb_filename = '%s.%s' % (youtube_id, thumb_format) thumb_filepath = os.path.join(videos_path, thumb_filename) if os.path.exists(thumb_filepath): thumbnail_url = video_base_url + "." + thumb_format # default break elif settings.BACKUP_VIDEO_SOURCE and lang_code == "en": dict_vals = {"youtube_id": youtube_id, "video_format": format, "thumb_format": thumb_formats[0] } stream_url = settings.BACKUP_VIDEO_SOURCE % dict_vals thumbnail_url = settings.BACKUP_THUMBNAIL_SOURCE % dict_vals if settings.BACKUP_THUMBNAIL_SOURCE else None else: return {} # no URLs return {"stream": stream_url, "thumbnail": thumbnail_url} video_availability = video.get("availability", {}) if not force else {} en_youtube_id = get_youtube_id(video["id"], lang_code=None) # get base ID video_map = get_id2oklang_map(video["id"]) or {} if not "on_disk" in video_availability: for lang_code in video_map.keys(): youtube_id = video_map[lang_code].encode('utf-8') video_availability[lang_code] = compute_video_availability(youtube_id, format=format, videos_path=videos_path) video_availability["en"] = video_availability.get("en", {"on_disk": False}) # en should always be defined # Summarize status any_on_disk = any([lang_avail["on_disk"] for lang_avail in video_availability.values()]) any_available = any_on_disk or bool(settings.BACKUP_VIDEO_SOURCE) if stamp_urls: # Loop over all known dubbed videos for lang_code, youtube_id in video_map.iteritems(): urls = compute_video_urls(youtube_id, format, lang_code, on_disk=video_availability[lang_code]["on_disk"], videos_path=videos_path) if urls: # Only add properties if anything is available. video_availability[lang_code].update(urls) video_availability[lang_code].update(compute_video_metadata(youtube_id, format)) # Get the (english) subtitle urls subtitle_lang_codes = get_langs_with_subtitle(en_youtube_id) subtitles_tuple = [(lc, get_srt_url(en_youtube_id, lc)) for lc in subtitle_lang_codes if os.path.exists(get_srt_path(lc, en_youtube_id))] subtitles_urls = dict(subtitles_tuple) video_availability["en"]["subtitles"] = subtitles_urls # now scrub any values that don't actually exist for lang_code in video_availability.keys(): if not video_availability[lang_code]["on_disk"] and len(video_availability[lang_code]) == 1: del video_availability[lang_code] # Now summarize some availability onto the video itself video["availability"] = video_availability video["on_disk"] = any_on_disk video["available"] = any_available return video