def parse(self, file=None, url=None): """Return metadata for the given file or raise an error. :type file: :class:`cgi.FieldStorage` or None :param file: A freshly uploaded file object. :type url: unicode or None :param url: A remote URL string. :rtype: dict :returns: Any extracted metadata. :raises UnsuitableEngineError: If file information cannot be parsed. """ if file is None: raise UnsuitableEngineError filename = os.path.basename(file.filename) name, ext = os.path.splitext(filename) ext = ext.lstrip('.').lower() container = guess_container_format(ext) return { 'type': guess_media_type(container), 'container': container, 'display_name': u'%s.%s' % (name, container or ext), 'size': get_file_size(file.file), }
def _add_new_media_file(media, original_filename, file): # FIXME: I think this will raise a KeyError if the uploaded # file doesn't have an extension. file_ext = os.path.splitext(original_filename)[1].lower()[1:] # set the file paths depending on the file type media_file = MediaFile() media_file.display_name = original_filename media_file.container = guess_container_format(file_ext) media_file.type = guess_media_type(media_file.container) # Small files are stored in memory and do not have a tmp file w/ fileno if hasattr(file, 'fileno'): media_file.size = os.fstat(file.fileno())[6] else: # The file may contain multi-byte characters, so we must seek instead of count chars file.seek(0, os.SEEK_END) media_file.size = file.tell() file.seek(0) # update media relations media.files.append(media_file) # add the media file (and its media, if new) to the database to get IDs DBSession.add(media_file) DBSession.flush() # copy the file to its permanent location file_name = '%d_%d_%s.%s' % (media.id, media_file.id, media.slug, file_ext) file_url = _store_media_file(file, file_name) media_file.file_name = file_name return media_file
def parse(self, file=None, url=None): """Return metadata for the given file or raise an error. :type file: :class:`cgi.FieldStorage` or None :param file: A freshly uploaded file object. :type url: unicode or None :param url: A remote URL string. :rtype: dict :returns: Any extracted metadata. :raises UnsuitableEngineError: If file information cannot be parsed. """ if url is None: raise UnsuitableEngineError if url.startswith('rtmp://'): known_server_uris = self._data.setdefault(RTMP_SERVER_URIS, ()) if RTMP_URI_DIVIDER in url: # Allow the user to explicitly mark the server/file separation parts = url.split(RTMP_URI_DIVIDER) server_uri = parts[0].rstrip('/') file_uri = ''.join(parts[1:]).lstrip('/') if server_uri not in known_server_uris: known_server_uris.append(server_uri) else: # Get the rtmp server from our list of known servers or fail for server_uri in known_server_uris: if url.startswith(server_uri): file_uri = url[len(server_uri.rstrip('/') + '/'):] break else: raise UserStorageError( _('This RTMP server has not been configured. Add it ' 'by going to Settings > Storage Engines > ' 'Remote URLs.')) unique_id = ''.join((server_uri, RTMP_URI_DIVIDER, file_uri)) else: unique_id = url filename = os.path.basename(url) name, ext = os.path.splitext(filename) ext = ext.lstrip('.').lower() container = guess_container_format(ext) # FIXME: Replace guess_container_format with something that takes # into consideration the supported formats of all the custom # players that may be installed. # if not container or container == 'unknown': # raise UnsuitableEngineError return { 'type': guess_media_type(ext), 'container': container, 'display_name': u'%s.%s' % (name, container or ext), 'unique_id': unique_id, }
def parse(self, file=None, url=None): """Return metadata for the given file or raise an error. :type file: :class:`cgi.FieldStorage` or None :param file: A freshly uploaded file object. :type url: unicode or None :param url: A remote URL string. :rtype: dict :returns: Any extracted metadata. :raises UnsuitableEngineError: If file information cannot be parsed. """ if url is None: raise UnsuitableEngineError if url.startswith('rtmp://'): known_server_uris = self._data.setdefault(RTMP_SERVER_URIS, ()) if RTMP_URI_DIVIDER in url: # Allow the user to explicitly mark the server/file separation parts = url.split(RTMP_URI_DIVIDER) server_uri = parts[0].rstrip('/') file_uri = ''.join(parts[1:]).lstrip('/') if server_uri not in known_server_uris: known_server_uris.append(server_uri) else: # Get the rtmp server from our list of known servers or fail for server_uri in known_server_uris: if url.startswith(server_uri): file_uri = url[len(server_uri.rstrip('/') + '/'):] break else: raise UserStorageError( _('This RTMP server has not been configured. Add it ' 'by going to Settings > Storage Engines > ' 'Remote URLs.')) unique_id = ''.join((server_uri, RTMP_URI_DIVIDER, file_uri)) else: unique_id = url filename = os.path.basename(url) name, ext = os.path.splitext(filename) ext = unicode(ext).lstrip('.').lower() container = guess_container_format(ext) # FIXME: Replace guess_container_format with something that takes # into consideration the supported formats of all the custom # players that may be installed. # if not container or container == 'unknown': # raise UnsuitableEngineError return { 'type': guess_media_type(ext), 'container': container, 'display_name': u'%s.%s' % (name, container or ext), 'unique_id': unique_id, }
def base_ext_container_from_uri(uri): """Returns a 3-tuple of strings: - Base of the filename (without extension) - Normalized file extension (without preceding dot) - Best-guess container format. Raises a formencode.Invalid exception if a useful container isn't found. """ name, file_ext = os.path.splitext(uri) ext = file_ext[1:].lower() container = guess_container_format(ext) if container is None: error_msg = _('File extension "%s" is not supported.') % file_ext raise formencode.Invalid(error_msg, None, None) return name, ext, container
def _to_python(self, value, state): if value == '': return value embed = parse_embed_url(value) if embed: return value ext = os.path.splitext(value)[1].lower()[1:] container = guess_container_format(ext) if container in accepted_extensions(): return value raise formencode.Invalid( "This isn't a valid YouTube, Google Video, Vimeo or direct link.", value, state )
def _save_media_obj(self, name, email, title, description, tags, file, url): # create our media object as a status-less placeholder initially media_obj = Media() media_obj.author = Author(name, email) media_obj.title = title media_obj.slug = get_available_slug(Media, title) media_obj.description = description media_obj.notes = fetch_setting('wording_additional_notes') media_obj.set_tags(tags) # Create a media object, add it to the media_obj, and store the file permanently. if file is not None: media_file = _add_new_media_file(media_obj, file.filename, file.file) else: media_file = MediaFile() url = unicode(url) embed = parse_embed_url(url) if embed: media_file.type = embed['type'] media_file.container = embed['container'] media_file.embed = embed['id'] media_file.display_name = '%s ID: %s' % \ (embed['container'].capitalize(), media_file.embed) else: # Check for types we can play ourselves ext = os.path.splitext(url)[1].lower()[1:] container = guess_container_format(ext) if container in accepted_extensions(): media_file.type = guess_media_type(container) media_file.container = container media_file.url = url media_file.display_name = os.path.basename(url) else: # Trigger a validation error on the whole form. raise formencode.Invalid('Please specify a URL or upload a file below.', None, None) media_obj.files.append(media_file) # Add the final changes. media_obj.update_status() DBSession.add(media_obj) DBSession.flush() create_default_thumbs_for(media_obj) return media_obj
def parse(self, file=None, url=None): """Return metadata for the given file or raise an error. :type file: :class:`cgi.FieldStorage` or None :param file: A freshly uploaded file object. :type url: unicode or None :param url: A remote URL string. :rtype: dict :returns: Any extracted metadata. :raises UnsuitableEngineError: If file information cannot be parsed. """ if not url or not url.startswith(PANDA_URL_PREFIX): raise UnsuitableEngineError() offset = len(PANDA_URL_PREFIX) # 'd' is the dict representing a Panda encoding or video # with an extra key: 'display_name' d = simplejson.loads(url[offset:]) # MediaCore uses extensions without prepended . ext = d['extname'].lstrip('.').lower() # XXX: Panda doesn't actually populate these fields yet. ba = d.get('audio_bitrate', None) or 0 bv = d.get('video_bitrate', None) or 0 bitrate = (ba + bv) or None return { 'unique_id': d['id'] + d['extname'], 'container': guess_container_format(ext), 'display_name': d['display_name'], 'type': VIDEO, # only video files get panda encoded, so it's video Q.E.D. 'height': d['height'], 'width': d['width'], 'size': d['file_size'], 'bitrate': bitrate, 'duration': d['duration'] / 1000.0, 'thumbnail_url': "%s%s_1.jpg" % (self.base_urls[0][1], d['id']), }
def add_file(self, id, file=None, url=None, **kwargs): """Save action for the :class:`~mediacore.forms.admin.media.AddFileForm`. Creates a new :class:`~mediacore.model.media.MediaFile` from the uploaded file or the local or remote URL. :param id: Media ID. If ``"new"`` a new Media stub is created with :func:`~mediacore.model.media.create_media_stub`. :type id: :class:`int` or ``"new"`` :param file: The uploaded file :type file: :class:`cgi.FieldStorage` or ``None`` :param url: A URL to a recognizable audio or video file :type url: :class:`unicode` or ``None`` :rtype: JSON dict :returns: success bool message Error message, if unsuccessful media_id The :attr:`~mediacore.model.media.Media.id` which is important if new media has just been created. file_id The :attr:`~mediacore.model.media.MediaFile.id` for the newly created file. edit_form The rendered XHTML :class:`~mediacore.forms.admin.media.EditFileForm` for this file. status_form The rendered XHTML :class:`~mediacore.forms.admin.media.UpdateStatusForm` """ if id == 'new': media = create_media_stub() else: media = fetch_row(Media, id) data = dict(success=False) if file is not None: # Create a media object, add it to the video, and store the file permanently. media_file = _add_new_media_file(media, file.filename, file.file) data['success'] = True elif url: media_file = MediaFile() # Parse the URL checking for known embeddables like YouTube for type, info in external_embedded_containers.iteritems(): match = info['pattern'].match(url) if match: media_file.type = guess_media_type(type) media_file.container = type media_file.embed = match.group('id') media_file.display_name = type.capitalize() + ' ID: ' + media_file.embed data['success'] = True break else: # Check for types we can play ourselves try: ext = os.path.splitext(url)[1].lower()[1:] container = guess_container_format(ext) except KeyError: container = None for conts in playable_containers.itervalues(): if container in conts: media_file.type = guess_media_type(container) media_file.container = container media_file.url = url media_file.display_name = os.path.basename(url) data['success'] = True break else: data['message'] = 'Unsupported URL' else: data['message'] = 'No action to perform.' if data['success']: media.files.append(media_file) media.update_type() media.update_status() DBSession.add(media) DBSession.flush() if id == 'new': helpers.create_default_thumbs_for(media) # Render some widgets so the XHTML can be injected into the page edit_form_xhtml = unicode(edit_file_form.display( action=url_for(action='edit_file', id=media.id), file=media_file)) status_form_xhtml = unicode(update_status_form.display( action=url_for(action='update_status', id=media.id), media=media)) data.update(dict( media_id = media.id, file_id = media_file.id, file_type = media_file.type, edit_form = edit_form_xhtml, status_form = status_form_xhtml, )) return data