def comment(self, slug, name="", email=None, body="", **kwargs): """Post a comment from :class:`~mediacore.forms.comments.PostCommentForm`. :param slug: The media :attr:`~mediacore.model.media.Media.slug` :returns: Redirect to :meth:`view` page for media. """ def result(success, message=None, comment=None): if request.is_xhr: result = dict(success=success, message=message) if comment: result["comment"] = render("comments/_list.html", {"comment_to_render": comment}, method="xhtml") return result elif success: return redirect(action="view") else: return self.view(slug, name=name, email=email, body=body, **kwargs) akismet_key = request.settings["akismet_key"] if akismet_key: akismet = Akismet(agent=USER_AGENT) akismet.key = akismet_key akismet.blog_url = request.settings["akismet_url"] or url_for("/", qualified=True) akismet.verify_key() data = { "comment_author": name.encode("utf-8"), "user_ip": request.environ.get("REMOTE_ADDR"), "user_agent": request.environ.get("HTTP_USER_AGENT", ""), "referrer": request.environ.get("HTTP_REFERER", "unknown"), "HTTP_ACCEPT": request.environ.get("HTTP_ACCEPT"), } if akismet.comment_check(body.encode("utf-8"), data): return result(False, _(u"Your comment has been rejected.")) media = fetch_row(Media, slug=slug) request.perm.assert_permission(u"view", media.resource) c = Comment() name = filter_vulgarity(name) c.author = AuthorWithIP(name, email, request.environ["REMOTE_ADDR"]) c.subject = "Re: %s" % media.title c.body = filter_vulgarity(body) require_review = request.settings["req_comment_approval"] if not require_review: c.reviewed = True c.publishable = True media.comments.append(c) DBSession.flush() send_comment_notification(media, c) if require_review: message = _("Thank you for your comment! We will post it just as " "soon as a moderator approves it.") return result(True, message=message) else: return result(True, comment=c)
def save_media_obj(self, name, email, title, description, tags, uploaded_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 if request.settings['wording_display_administrative_notes']: media_obj.notes = request.settings['wording_administrative_notes'] media_obj.set_tags(tags) # Give the Media object an ID. DBSession.add(media_obj) DBSession.flush() # Create a MediaFile object, add it to the media_obj, and store the file permanently. media_file = add_new_media_file(media_obj, file=uploaded_file, url=url) # The thumbs may have been created already by add_new_media_file if not has_thumbs(media_obj): create_default_thumbs_for(media_obj) media_obj.update_status() DBSession.flush() return media_obj
def save(self, id, email_address, display_name, login_details, delete=None, **kwargs): """Save changes or create a new :class:`~mediacore.model.auth.User` instance. :param id: User ID. If ``"new"`` a new user is created. :type id: ``int`` or ``"new"`` :returns: Redirect back to :meth:`index` after successful save. """ user = fetch_row(User, id) if delete: DBSession.delete(user) redirect(action="index", id=None) user.display_name = display_name user.email_address = email_address user.user_name = login_details["user_name"] password = login_details["password"] if password is not None and password != "": user.password = password if login_details["group"]: group = fetch_row(Group, login_details["group"]) user.groups = [group] else: user.groups = [] DBSession.add(user) DBSession.flush() redirect(action="index", id=None)
def _update_settings(self, values): """Modify the settings associated with the given dictionary.""" for name, value in values.iteritems(): if name in tmpl_context.settings: setting = tmpl_context.settings[name] else: setting = Setting(key=name, value=value) if value is None: value = u'' else: value = unicode(value) if setting.value != value: setting.value = value DBSession.add(setting) DBSession.flush() # Clear the settings cache unless there are multiple processes. # We have no way of notifying the other processes that they need # to clear their caches too, so we've just gotta let it play out # until all the caches expire. if not request.environ.get('wsgi.multiprocess', False): app_globals.settings_cache.clear() else: # uWSGI provides an automagically included module # that we can use to call a graceful restart of all # the uwsgi processes. # http://projects.unbit.it/uwsgi/wiki/uWSGIReload try: import uwsgi uwsgi.reload() except ImportError: pass
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.type = file_ext media_file.url = 'dummy_url' # model requires that url not NULL media_file.is_original = True media_file.enable_player = media_file.is_playable media_file.enable_feed = not media_file.is_embeddable media_file.size = os.fstat(file.fileno())[6] # 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.url = file_url return media_file
def save_media_obj(self, name, email, title, description, tags, uploaded_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 if request.settings['wording_display_administrative_notes']: media_obj.notes = request.settings['wording_administrative_notes'] media_obj.set_tags(tags) # Give the Media object an ID. DBSession.add(media_obj) DBSession.flush() # Create a MediaFile object, add it to the media_obj, and store the file permanently. media_file = add_new_media_file(media_obj, file=uploaded_file, url=url) # The thumbs may have been created already by add_new_media_file if not has_thumbs(media_obj): create_default_thumbs_for(media_obj) media_obj.update_status() DBSession.flush() return media_obj
def _create_user_without_groups(self): user = User() user.user_name = u'joe' user.email_address = u'*****@*****.**' user.display_name = u'Joe' user.groups = [] DBSession.add(user) DBSession.flush() return user
def test_can_restrict_query_if_user_does_not_have_the_required_permission(self): query = Media.query permission = u'view' perm = self.perm() view_permission = DBSession.query(Permission).filter(Permission.permission_name == permission).one() view_permission.groups = [] DBSession.flush() assert_none(self.policy.access_condition_for_query(query, permission, perm))
def _create_user_without_groups(self): user = User() user.user_name = u'joe' user.email_address = u'*****@*****.**' user.display_name = u'Joe' user.groups = [] DBSession.add(user) DBSession.flush() return user
def save_album_art(self, id, album_art, **kwargs): """Save album art uploaded with :class:`~mediacore.forms.media.AlbumArtForm`. :param id: Media ID. If ``"new"`` a new Media stub is created with :func:`~mediacore.model.media.create_media_stub`. :type id: ``int`` or ``"new"`` :param file: The uploaded file :type file: :class:`cgi.FieldStorage` or ``None`` :rtype: JSON dict :returns: success bool message Error message, if unsuccessful id The :attr:`~mediacore.model.media.Media.id` which is important if a new media has just been created. """ if id == 'new': media = create_media_stub() else: media = fetch_row(Media, id, incl_trash=True) im_path = os.path.join(config.image_dir, 'media/%s%s.%s') try: # Create thumbnails im = Image.open(album_art.file) if id == 'new': DBSession.add(media) DBSession.flush() # TODO: Allow other formats? for key, dimensions in config.album_art_sizes.iteritems(): file_path = im_path % (media.id, key, 'jpg') im.resize(dimensions, 1).save(file_path) # Backup the original image just for kicks orig_type = os.path.splitext(album_art.filename)[1].lower()[1:] backup_file = open(im_path % (media.id, 'orig', orig_type), 'w') copyfileobj(album_art.file, backup_file) album_art.file.close() backup_file.close() success = True message = None except IOError: success = False message = 'Unsupported image type' except Exception, e: success = False message = e.message
def test_can_restrict_query_if_user_does_not_have_the_required_permission( self): query = Media.query permission = u'view' perm = self.perm() view_permission = DBSession.query(Permission).filter( Permission.permission_name == permission).one() view_permission.groups = [] DBSession.flush() assert_none( self.policy.access_condition_for_query(query, permission, perm))
def fetch_and_create_tags(tag_names): tag_dict = dict() for t in tag_names: tag_dict[slugify(t)] = t existing_tags = DBSession.query(Tag).filter(Tag.slug.in_(tag_dict.keys())).all() existing_slugs = [t.slug for t in existing_tags] new_slugs = [s for s in tag_dict.keys() if s not in existing_slugs] new_tags = [{'name': tag_dict[s], 'slug': s} for s in new_slugs] if new_tags: DBSession.connection().execute(tags.insert(), new_tags) DBSession.flush() existing_tags += DBSession.query(Tag).filter(Tag.slug.in_(new_slugs)).all() return existing_tags
def delete(self, id, **kwargs): """Delete a PlayerPref. After deleting the PlayerPref, cleans up the players table, ensuring that each Player class is represented--if the deleted PlayerPref is the last example of that Player class, creates a new disabled PlayerPref for that Player class with the default settings. :param id: Player ID. :type id: ``int`` :returns: Redirect back to :meth:`index` after successful delete. """ player = fetch_row(PlayerPrefs, id) DBSession.delete(player) DBSession.flush() cleanup_players_table() redirect(action='index', id=None)
def delete(self, id, **kwargs): """Delete a PlayerPref. After deleting the PlayerPref, cleans up the players table, ensuring that each Player class is represented--if the deleted PlayerPref is the last example of that Player class, creates a new disabled PlayerPref for that Player class with the default settings. :param id: Player ID. :type id: ``int`` :returns: Redirect back to :meth:`index` after successful delete. """ player = fetch_row(PlayerPrefs, id) DBSession.delete(player) DBSession.flush() cleanup_players_table() redirect(action='index', id=None)
def rate(self, slug, up=None, down=None, **kwargs): """Say 'I like this' for the given media. :param slug: The media :attr:`~mediacore.model.media.Media.slug` :rtype: unicode :returns: The new number of likes """ # we have to check if current user is anonymous or authenticated userid = check_user_authentication(request) if not userid: log.warn('Anonymous user cannot rate media') raise HTTPUnauthorized().exception media = fetch_row(Media, slug=slug) # check if current user has already voted this media object votes = Vote.query.get_votes(media_id=media.id, user_name = userid) if votes.count(): # if true redirect to 'view' log.warn('User %s already voted this media') redirect(action='view') # create new vote object mapping current media and user vote = Vote() vote.media_id = media.id vote.user_name = userid # Give the Vote object an ID. DBSession.add(vote) DBSession.flush() if up: vote.increment_likes() media.increment_likes() elif down: vote.increment_dislikes() media.increment_dislikes() if request.is_xhr: return u'' else: redirect(action='view')
def rate(self, slug, up=None, down=None, **kwargs): """Say 'I like this' for the given media. :param slug: The media :attr:`~mediacore.model.media.Media.slug` :rtype: unicode :returns: The new number of likes """ # we have to check if current user is anonymous or authenticated userid = check_user_authentication(request) if not userid: log.warn('Anonymous user cannot rate media') raise HTTPUnauthorized().exception media = fetch_row(Media, slug=slug) # check if current user has already voted this media object votes = Vote.query.get_votes(media_id=media.id, user_name=userid) if votes.count(): # if true redirect to 'view' log.warn('User %s already voted this media') redirect(action='view') # create new vote object mapping current media and user vote = Vote() vote.media_id = media.id vote.user_name = userid # Give the Vote object an ID. DBSession.add(vote) DBSession.flush() if up: vote.increment_likes() media.increment_likes() elif down: vote.increment_dislikes() media.increment_dislikes() if request.is_xhr: return u'' else: redirect(action='view')
def reorder_file(self, id, file_id, budge_infront_id, **kwargs): """Change the position of the given file relative to the 2nd file. :param file_id: The file to move :type file_id: ``int`` :param budge_infront_id: The file whos position the first file takes. All files behind/after this file are bumped back as well. :type budge_infront_id: ``int`` or ``None`` :rtype: JSON dict :returns: success bool """ media = fetch_row(Media, id, incl_trash=True) media.reposition_file(file_id, budge_infront_id) DBSession.add(media) DBSession.flush() return dict(success=True)
def update_status(self, id, update_button=None, publish_on=None, **values): """Update the publish status for the given media. :param id: Media ID :type id: ``int`` :param update_status: The text of the submit button which indicates that the :attr:`~mediacore.model.media.Media.status` should change. :type update_status: ``unicode`` or ``None`` :param publish_on: A date to set to :attr:`~mediacore.model.media.Media.publish_on` :type publish_on: :class:`datetime.datetime` or ``None`` :rtype: JSON dict :returns: success bool message Error message, if unsuccessful status_form Rendered XHTML for the status form, updated to reflect the changes made. """ media = fetch_row(Media, id, incl_trash=True) # Make the requested change assuming it will be allowed if update_button == 'Review Complete': media.status.discard('unreviewed') elif update_button == 'Publish Now': media.status.discard('draft') media.status.add('publish') media.publish_on = publish_on or datetime.now() elif publish_on: media.publish_on = publish_on try: # Verify the change is valid by re-determining the status media.update_status() DBSession.add(media) DBSession.flush() data = dict(success=True) except Exception, e: data = dict(success=False, message=e.message)
def save(self, email, legal_wording, default_wording, **kwargs): """Save :class:`~mediacore.forms.settings.SettingsForm`. Redirects back to :meth:`edit` after successful editing. """ settings = self._fetch_keyed_settings() settings['email_media_uploaded'].value = email['media_uploaded'] settings['email_comment_posted'].value = email['comment_posted'] settings['email_support_requests'].value = email['support_requests'] settings['email_send_from'].value = email['send_from'] # settings['ftp_server'].value = ftp['server'] # settings['ftp_username'].value = ftp['username'] # if ftp['password'] is not None and ftp['password'] != '': # settings['ftp_password'].value = ftp['password'] # settings['ftp_upload_path'].value = ftp['upload_path'] # settings['ftp_download_url'].value = ftp['download_url'] settings['wording_user_uploads'].value = legal_wording['user_uploads'] settings['wording_additional_notes'].value = default_wording['additional_notes'] DBSession.add_all(settings.values()) DBSession.flush() redirect(action='edit')
def save(self, id, slug, title, author_name, author_email, description, notes, details, podcast, tags, topics, delete=None, **kwargs): """Save changes or create a new :class:`~mediacore.model.media.Media` instance. Form handler the :meth:`edit` action and the :class:`~mediacore.forms.media.MediaForm`. Redirects back to :meth:`edit` after successful editing and :meth:`index` after successful deletion. """ media = fetch_row(Media, id, incl_trash=True) if delete: media.status.add('trash') DBSession.add(media) DBSession.flush() redirect(action='index', id=None) if id == 'new': media.status = 'draft,unencoded,unreviewed' media.slug = get_available_slug(Media, slug, media) media.title = title media.author = Author(author_name, author_email) media.description = helpers.clean_admin_xhtml(description) media.notes = notes media.duration = helpers.duration_to_seconds(details['duration']) media.podcast_id = podcast media.set_tags(tags) media.set_topics(topics) media.update_status() DBSession.add(media) DBSession.flush() redirect(action='edit', id=media.id)
def add_new_media_file(media, file=None, url=None): """Create a MediaFile instance from the given file or URL. This function MAY modify the given media object. :type media: :class:`~mediacore.model.media.Media` instance :param media: The media object that this file or URL will belong to. :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: :class:`~mediacore.model.media.MediaFile` :returns: A newly created media file instance. :raises StorageError: If the input file or URL cannot be stored with any of the registered storage engines. """ sorted_engines = enabled_engines() for engine in sorted_engines: try: meta = engine.parse(file=file, url=url) log.debug('Engine %r returned meta %r', engine, meta) break except UnsuitableEngineError: log.debug('Engine %r unsuitable for %r/%r', engine, file, url) continue else: raise StorageError(_('Unusable file or URL provided.'), None, None) from mediacore.model import DBSession, MediaFile mf = MediaFile() mf.storage = engine mf.media = media mf.type = meta['type'] mf.display_name = meta.get('display_name', default_display_name(file, url)) mf.unique_id = meta.get('unique_id', None) mf.container = meta.get('container', None) mf.size = meta.get('size', None) mf.bitrate = meta.get('bitrate', None) mf.width = meta.get('width', None) mf.height = meta.get('height', None) media.files.append(mf) DBSession.flush() unique_id = engine.store(media_file=mf, file=file, url=url, meta=meta) if unique_id: mf.unique_id = unique_id elif not mf.unique_id: raise StorageError('Engine %r returned no unique ID.', engine) if not media.duration and meta.get('duration', 0): media.duration = meta['duration'] if not media.description and meta.get('description'): media.description = clean_xhtml(meta['description']) if not media.title: media.title = meta.get('title', None) or mf.display_name if media.type is None: media.type = mf.type if ('thumbnail_url' in meta or 'thumbnail_file' in meta) \ and (not has_thumbs(media) or has_default_thumbs(media)): thumb_file = meta.get('thumbnail_file', None) if thumb_file is not None: thumb_filename = thumb_file.filename else: thumb_url = meta['thumbnail_url'] thumb_filename = os.path.basename(thumb_url) # Download the image to a buffer and wrap it as a file-like object try: temp_img = urlopen(thumb_url) thumb_file = StringIO(temp_img.read()) temp_img.close() except URLError, e: log.exception(e) if thumb_file is not None: create_thumbs_for(media, thumb_file, thumb_filename) thumb_file.close()
thumb_url = meta['thumbnail_url'] thumb_filename = os.path.basename(thumb_url) # Download the image to a buffer and wrap it as a file-like object try: temp_img = urlopen(thumb_url) thumb_file = StringIO(temp_img.read()) temp_img.close() except URLError, e: log.exception(e) if thumb_file is not None: create_thumbs_for(media, thumb_file, thumb_filename) thumb_file.close() DBSession.flush() engine.postprocess(mf) # Try to transcode the file. for engine in sorted_engines: try: engine.transcode(mf) log.debug('Engine %r has agreed to transcode %r', engine, mf) break except CannotTranscode: log.debug('Engine %r unsuitable for transcoding %r', engine, mf) continue return mf
def edit_file(self, id, file_id, player_enabled, feed_enabled, toggle_feed, toggle_player, delete, **kwargs): """Save action for the :class:`~mediacore.forms.media.EditFileForm`. Changes or delets a :class:`~mediacore.model.media.MediaFile`. :param id: Media ID :type id: :class:`int` :rtype: JSON dict :returns: success bool message Error message, if unsuccessful status_form Rendered XHTML for the status form, updated to reflect the changes made. """ media = fetch_row(Media, id, incl_trash=True) data = {} # try: try: file = [file for file in media.files if file.id == file_id][0] except IndexError: raise Exception, 'File does not exist.' if toggle_player: data['field'] = 'player_enabled' file.enable_player = data['value'] = not player_enabled DBSession.add(file) elif toggle_feed: data['field'] = 'feed_enabled' file.enable_feed = data['value'] = not feed_enabled # Raises an exception if it is the only feed enabled file for # an already published podcast episode. DBSession.add(file) elif delete: data['field'] = 'delete' DBSession.delete(file) media.files.remove(file) else: raise Exception, 'No action to perform.' data['success'] = True media.update_type() media.update_status() DBSession.add(media) # except Exception, e: # data['success'] = False # data['message'] = e.message if request.is_xhr: # Return the rendered widget for injection status_form_xhtml = unicode(update_status_form.display( action=url_for(action='update_status'), media=media)) data['status_form'] = status_form_xhtml return data else: DBSession.flush() redirect(action='edit')
thumb_url = meta['thumbnail_url'] thumb_filename = os.path.basename(thumb_url) # Download the image to a buffer and wrap it as a file-like object try: temp_img = urlopen(thumb_url) thumb_file = StringIO(temp_img.read()) temp_img.close() except URLError, e: log.exception(e) if thumb_file is not None: create_thumbs_for(media, thumb_file, thumb_filename) thumb_file.close() DBSession.flush() engine.postprocess(mf) # Try to transcode the file. for engine in sorted_engines: try: engine.transcode(mf) log.debug('Engine %r has agreed to transcode %r', engine, mf) break except CannotTranscode: log.debug('Engine %r unsuitable for transcoding %r', engine, mf) continue return mf
def comment(self, slug, name='', email=None, body='', **kwargs): """Post a comment from :class:`~mediacore.forms.comments.PostCommentForm`. :param slug: The media :attr:`~mediacore.model.media.Media.slug` :returns: Redirect to :meth:`view` page for media. """ def result(success, message=None, comment=None): if request.is_xhr: result = dict(success=success, message=message) if comment: result['comment'] = render('comments/_list.html', {'comment_to_render': comment}, method='xhtml') return result elif success: return redirect(action='view') else: return self.view(slug, name=name, email=email, body=body, **kwargs) if request.settings['comments_engine'] != 'mediacore': abort(404) akismet_key = request.settings['akismet_key'] if akismet_key: akismet = Akismet(agent=USER_AGENT) akismet.key = akismet_key akismet.blog_url = request.settings['akismet_url'] or \ url_for('/', qualified=True) akismet.verify_key() data = { 'comment_author': name.encode('utf-8'), 'user_ip': request.environ.get('REMOTE_ADDR'), 'user_agent': request.environ.get('HTTP_USER_AGENT', ''), 'referrer': request.environ.get('HTTP_REFERER', 'unknown'), 'HTTP_ACCEPT': request.environ.get('HTTP_ACCEPT') } if akismet.comment_check(body.encode('utf-8'), data): return result(False, _(u'Your comment has been rejected.')) media = fetch_row(Media, slug=slug) request.perm.assert_permission(u'view', media.resource) c = Comment() name = filter_vulgarity(name) c.author = AuthorWithIP(name, email, request.environ['REMOTE_ADDR']) c.subject = 'Re: %s' % media.title c.body = filter_vulgarity(body) require_review = request.settings['req_comment_approval'] if not require_review: c.reviewed = True c.publishable = True media.comments.append(c) DBSession.flush() send_comment_notification(media, c) if require_review: message = _('Thank you for your comment! We will post it just as ' 'soon as a moderator approves it.') return result(True, message=message) else: return result(True, comment=c)
def test_sizeless_file_picking(self): """Test while file gets served to each browser, given that all files are the same filesize. """ media, media_files = self._get_media('unsized') for mf in media_files: media_files[mf].size = None DBSession.flush() pylons.app_globals.settings['html5_player'] = 'html5' pylons.app_globals.settings['flash_player'] = 'flowplayer' combinations = [ # Prefer flash, without embeds ('firefox', 2, 'flash', False, 'flv', 'flowplayer'), ('firefox', 3, 'flash', False, 'flv', 'flowplayer'), ('firefox', 3.5, 'flash', False, 'flv', 'flowplayer'), ('safari', 522, 'flash', False, 'flv', 'flowplayer'), ('opera', 10.5, 'flash', False, 'flv', 'flowplayer'), ('opera', 9, 'flash', False, 'flv', 'flowplayer'), ('chrome', 3.0, 'flash', False, 'flv', 'flowplayer'), ('android', 0, 'flash', False, 'flv', 'flowplayer'), ('itunes', 0, 'flash', False, 'm4v', 'html5'), ('iphone-ipod-ipad', 0, 'flash', False, 'm4v', 'html5'), ('unknown', 0, 'flash', False, 'flv', 'flowplayer'), # Prefer flash, including embeds ('firefox', 2, 'flash', True, 'youtube', 'youtube'), ('firefox', 3, 'flash', True, 'youtube', 'youtube'), ('firefox', 3.5, 'flash', True, 'youtube', 'youtube'), ('safari', 522, 'flash', True, 'youtube', 'youtube'), ('opera', 10.5, 'flash', True, 'youtube', 'youtube'), ('opera', 9, 'flash', True, 'youtube', 'youtube'), ('chrome', 3.0, 'flash', True, 'youtube', 'youtube'), ('android', 0, 'flash', True, 'youtube', 'youtube'), ('itunes', 0, 'flash', True, 'm4v', 'html5'), ('iphone-ipod-ipad', 0, 'flash', True, 'm4v', 'html5'), ('unknown', 0, 'flash', True, 'youtube', 'youtube'), # Prefer HTML5, without embeds ('firefox', 2, 'best', False, 'flv', 'flowplayer'), ('firefox', 3, 'best', False, 'flv', 'flowplayer'), ('firefox', 3.5, 'best', False, 'ogv', 'html5'), ('safari', 522, 'best', False, 'm4v', 'html5'), ('opera', 10.5, 'best', False, 'ogv', 'html5'), ('opera', 9, 'best', False, 'flv', 'flowplayer'), ('chrome', 3.0, 'best', False, 'm4v', 'html5'), ('android', 0, 'best', False, 'm4v', 'html5'), ('itunes', 0, 'best', False, 'm4v', 'html5'), ('iphone-ipod-ipad', 0, 'best', False, 'm4v', 'html5'), ('unknown', 0, 'best', False, 'flv', 'flowplayer'), # Prefer HTML5, including embeds ('firefox', 2, 'best', True, 'youtube', 'youtube'), ('firefox', 3, 'best', True, 'youtube', 'youtube'), ('firefox', 3.5, 'best', True, 'ogv', 'html5'), ('safari', 522, 'best', True, 'm4v', 'html5'), ('opera', 10.5, 'best', True, 'ogv', 'html5'), ('opera', 9, 'best', True, 'youtube', 'youtube'), ('chrome', 3.0, 'best', True, 'm4v', 'html5'), ('android', 0, 'best', True, 'm4v', 'html5'), ('itunes', 0, 'best', True, 'm4v', 'html5'), ('iphone-ipod-ipad', 0, 'best', True, 'm4v', 'html5'), ('unknown', 0, 'best', True, 'youtube', 'youtube'), # HTML5 only, without embeds ('firefox', 2, 'html5', False, None, None), ('firefox', 3, 'html5', False, None, None), ('firefox', 3.5, 'html5', False, 'ogv', 'html5'), ('safari', 522, 'html5', False, 'm4v', 'html5'), ('opera', 10.5, 'html5', False, 'ogv', 'html5'), ('opera', 9, 'html5', False, None, None), ('chrome', 3.0, 'html5', False, 'm4v', 'html5'), ('android', 0, 'html5', False, 'm4v', 'html5'), ('itunes', 0, 'html5', False, 'm4v', 'html5'), ('iphone-ipod-ipad', 0, 'html5', False, 'm4v', 'html5'), ('unknown', 0, 'html5', False, None, None), # HTML5 only, including embeds ('firefox', 2, 'html5', True, None, None), ('firefox', 3, 'html5', True, None, None), ('firefox', 3.5, 'html5', True, 'ogv', 'html5'), ('safari', 522, 'html5', True, 'm4v', 'html5'), ('opera', 10.5, 'html5', True, 'ogv', 'html5'), ('opera', 9, 'html5', True, None, None), ('chrome', 3.0, 'html5', True, 'm4v', 'html5'), ('android', 0, 'html5', True, 'm4v', 'html5'), ('itunes', 0, 'html5', True, 'm4v', 'html5'), ('iphone-ipod-ipad', 0, 'html5', True, 'm4v', 'html5'), ('unknown', 0, 'html5', True, None, None), ] from mediacore.lib.players import players players = dict(players) players[None] = None media_files[None] = None for browser, version, p_type, embedded, e_file, e_player in combinations: player = pick_media_file_player(media, browser = browser, version = version, player_type = p_type, include_embedded = embedded ) if player: file = player.file browser, version = player.browser else: file, browser, version = None, None, None print "Unsized:", browser, version, p_type, embedded, e_file, e_player player_class = player and player.__class__ or None assert player_class == players[e_player], "Expected %r but was %r" % (players[e_player], player_class) assert file == media_files[e_file], "Expected %r but got %r" % (media_files[e_file], file)
def comment(self, slug, name='', email=None, body='', **kwargs): """Post a comment from :class:`~mediacore.forms.comments.PostCommentForm`. :param slug: The media :attr:`~mediacore.model.media.Media.slug` :returns: Redirect to :meth:`view` page for media. """ def result(success, message=None, comment=None): if request.is_xhr: result = dict(success=success, message=message) if comment: result['comment'] = render('comments/_list.html', {'comment_to_render': comment}, method='xhtml') return result elif success: return redirect(action='view') else: return self.view(slug, name=name, email=email, body=body, **kwargs) if request.settings['comments_engine'] != 'mediacore': abort(404) akismet_key = request.settings['akismet_key'] if akismet_key: akismet = Akismet(agent=USER_AGENT) akismet.key = akismet_key akismet.blog_url = request.settings['akismet_url'] or \ url_for('/', qualified=True) akismet.verify_key() data = {'comment_author': name.encode('utf-8'), 'user_ip': request.environ.get('REMOTE_ADDR'), 'user_agent': request.environ.get('HTTP_USER_AGENT', ''), 'referrer': request.environ.get('HTTP_REFERER', 'unknown'), 'HTTP_ACCEPT': request.environ.get('HTTP_ACCEPT')} if akismet.comment_check(body.encode('utf-8'), data): return result(False, _(u'Your comment has been rejected.')) media = fetch_row(Media, slug=slug) request.perm.assert_permission(u'view', media.resource) c = Comment() name = filter_vulgarity(name) c.author = AuthorWithIP(name, email, request.environ['REMOTE_ADDR']) c.subject = 'Re: %s' % media.title c.body = filter_vulgarity(body) require_review = request.settings['req_comment_approval'] if not require_review: c.reviewed = True c.publishable = True media.comments.append(c) DBSession.flush() send_comment_notification(media, c) if require_review: message = _('Thank you for your comment! We will post it just as ' 'soon as a moderator approves it.') return result(True, message=message) else: return result(True, comment=c)
def add_new_media_file(media, file=None, url=None): """Create a MediaFile instance from the given file or URL. This function MAY modify the given media object. :type media: :class:`~mediacore.model.media.Media` instance :param media: The media object that this file or URL will belong to. :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: :class:`~mediacore.model.media.MediaFile` :returns: A newly created media file instance. :raises StorageError: If the input file or URL cannot be stored with any of the registered storage engines. """ sorted_engines = enabled_engines() for engine in sorted_engines: try: meta = engine.parse(file=file, url=url) log.debug('Engine %r returned meta %r', engine, meta) break except UnsuitableEngineError: log.debug('Engine %r unsuitable for %r/%r', engine, file, url) continue else: raise StorageError(_('Unusable file or URL provided.'), None, None) from mediacore.model import DBSession, MediaFile mf = MediaFile() mf.storage = engine mf.media = media mf.type = meta['type'] mf.display_name = meta.get('display_name', default_display_name(file, url)) mf.unique_id = meta.get('unique_id', None) mf.container = meta.get('container', None) mf.size = meta.get('size', None) mf.bitrate = meta.get('bitrate', None) mf.width = meta.get('width', None) mf.height = meta.get('height', None) media.files.append(mf) DBSession.flush() unique_id = engine.store(media_file=mf, file=file, url=url, meta=meta) if unique_id: mf.unique_id = unique_id elif not mf.unique_id: raise StorageError('Engine %r returned no unique ID.', engine) if not media.duration and meta.get('duration', 0): media.duration = meta['duration'] if not media.description and meta.get('description'): media.description = clean_xhtml(meta['description']) if not media.title: media.title = meta.get('title', None) or mf.display_name if media.type is None: media.type = mf.type if ('thumbnail_url' in meta or 'thumbnail_file' in meta) \ and (not has_thumbs(media) or has_default_thumbs(media)): thumb_file = meta.get('thumbnail_file', None) if thumb_file is not None: thumb_filename = thumb_file.filename else: thumb_url = meta['thumbnail_url'] thumb_filename = os.path.basename(thumb_url) # Download the image to a buffer and wrap it as a file-like object try: temp_img = urlopen(thumb_url) thumb_file = StringIO(temp_img.read()) temp_img.close() except URLError, e: log.exception(e) if thumb_file is not None: create_thumbs_for(media, thumb_file, thumb_filename) thumb_file.close()
def add_file(self, id, file=None, url=None, **kwargs): """Save action for the :class:`~mediacore.forms.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.media.EditFileForm` for this file. status_form The rendered XHTML :class:`~mediacore.forms.media.UpdateStatusForm` """ if id == 'new': media = create_media_stub() else: media = fetch_row(Media, id, incl_trash=True) try: 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) elif url: media_file = MediaFile() # Parse the URL checking for known embeddables like YouTube for type, info in config.embeddable_filetypes.iteritems(): match = re.match(info['pattern'], url) if match: media_file.type = type media_file.url = match.group('id') media_file.enable_feed = False break else: # Check for types we can play ourselves type = os.path.splitext(url)[1].lower()[1:] for playable_types in config.playable_types.itervalues(): if type in playable_types: media_file.type = type media_file.url = url break else: raise Exception, 'Unsupported URL %s' % url else: raise Exception, 'Given no action to perform.' media.files.append(media_file) media.update_type() media.update_status() DBSession.add(media) DBSession.flush() # 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)) return dict( success = True, media_id = media.id, file_id = media_file.id, edit_form = edit_form_xhtml, status_form = status_form_xhtml, ) except Exception, e: return dict( success = False, message = e.message, )