Esempio n. 1
0
    def test_fetch_duration_oserror(self, mock_popen, rhead):

        def mocked_head(url, **options):
            return Response(
                '',
                200
            )

        rhead.side_effect = mocked_head

        def mocked_popen(command, **kwargs):

            class Inner:
                def communicate(self):
                    raise OSError('Something Bad')

            return Inner()

        mock_popen.side_effect = mocked_popen

        event = Event.objects.get(title='Test event')
        video_url = 'https://example.com/file.mov'
        try:
            videoinfo.fetch_duration(event, video_url=video_url)
            raise AssertionError("not supposed to happen")
        except OSError as exception:
            message = str(exception)
            ok_('Something Bad' in message)
            ok_('ffmpeg -i %s' % video_url in message)
Esempio n. 2
0
def vidly_media_webhook(request):
    if not request.POST.get('xml'):
        return http.HttpResponseBadRequest("no 'xml'")

    xml_string = request.POST['xml'].strip()
    try:
        struct = xmltodict.parse(xml_string)
    except ExpatError:
        return http.HttpResponseBadRequest("Bad 'xml'")

    try:
        task = struct['Response']['Result']['Task']
        try:
            vidly_submission = VidlySubmission.objects.get(
                url=task['SourceFile'],
                tag=task['MediaShortLink']
            )
            if task['Status'] == 'Finished':
                if not vidly_submission.finished:
                    vidly_submission.finished = timezone.now()
                    vidly_submission.save()

                event = vidly_submission.event

                # Awesome!
                # This event now has a fully working transcoded piece of
                # media.
                event.archive_time = timezone.now()
                event.save()

                # More awesome! We can start processing the transcoded media.
                if not event.duration:
                    videoinfo.fetch_duration(
                        event,
                        save=True,
                        verbose=settings.DEBUG
                    )
                    event = Event.objects.get(id=event.id)
                if event.duration:
                    if not Picture.objects.filter(event=event):
                        videoinfo.fetch_screencapture(
                            event,
                            save=True,
                            verbose=settings.DEBUG,
                            set_first_available=True,
                        )
            elif task['Status'] == 'Error':
                if not vidly_submission.errored:
                    vidly_submission.errored = timezone.now()
                    vidly_submission.save()
        except VidlySubmission.DoesNotExist:
            # remember, we can't trust the XML since it's publically
            # available and exposed as a webhook
            pass
    except KeyError:
        # If it doesn't have a "Result" or "Task", it was just a notification
        # that the media was added.
        pass

    return http.HttpResponse('OK\n')
Esempio n. 3
0
def event_screencaptures(request, event):
    if event.status != Event.STATUS_INITIATED:
        return http.HttpResponseBadRequest(
            "Events NOT in the state of initiated."
        )
    upload = event.upload
    video_url = upload.url

    context = {}

    cache_key = 'fetching-{0}'.format(event.id)

    # This function sets the cache `fetching-{id}` before and after calling
    # those functions in the videoinfo module.
    # The reason is that those calls might take many many seconds
    # and the webapp might send async calls to the event_picture view
    # which will inform the webapp that the slow videoinfo processes
    # are running and thus that the webapp shouldn't kick if off yet.

    seconds = event.duration
    if not event.duration:
        # it's a poor man's lock
        if not cache.get(cache_key):
            cache.set(cache_key, True, 60)
            seconds = videoinfo.fetch_duration(
                event,
                video_url=video_url,
                save=True,
                verbose=settings.DEBUG
            )
            cache.delete(cache_key)
            event = Event.objects.get(id=event.id)
    context['seconds'] = seconds
    # The reason we can't use `if event.duration:` is because the
    # fetch_duration() does an inline-update instead of modifying
    # the instance object.
    no_pictures = Picture.objects.filter(event=event).count()
    if event.duration and not no_pictures:
        if not cache.get(cache_key):
            cache.set(cache_key, True, 60)
            event = Event.objects.get(id=event.id)
            no_pictures = videoinfo.fetch_screencapture(
                event,
                video_url=video_url,
                save=True,
                verbose=settings.DEBUG,
                set_first_available=not event.picture,
                import_immediately=True,
            )
            cache.delete(cache_key)
            event = Event.objects.get(id=event.id)
    if no_pictures and not event.picture:
        # no picture has been chosen previously
        pictures = Picture.objects.filter(event=event).order_by('created')[:1]
        for picture in pictures:
            event.picture = picture
            event.save()
            break
    context['no_pictures'] = no_pictures
    return context
Esempio n. 4
0
    def handle(self, *args, **options):
        identifiers = options['slug-or-url-or-id']

        if not identifiers:
            raise CommandError('slug-or-url-or-id')

        verbose = int(options['verbosity']) > 1

        for arg in identifiers:
            if arg.isdigit():
                event = Event.objects.get(pk=arg)
            else:
                if '://' in arg:
                    slug = urlparse(arg).path.split('/')[1]
                else:
                    slug = arg
                event = Event.objects.get(slug=slug)

            result = fetch_duration(
                event,
                save=not options['dry_run'],
                save_locally=options['save_locally'],
                verbose=verbose,
            )
            if verbose:
                print result
Esempio n. 5
0
    def handle(self, *args, **options):
        identifiers = options['slug-or-url-or-id']

        if not identifiers:
            raise CommandError('slug-or-url-or-id')

        verbose = int(options['verbosity']) > 1

        for arg in identifiers:
            if arg.isdigit():
                event = Event.objects.get(pk=arg)
            else:
                if '://' in arg:
                    slug = urlparse(arg).path.split('/')[1]
                else:
                    slug = arg
                event = Event.objects.get(slug=slug)

            result = fetch_duration(
                event,
                save=not options['dry_run'],
                save_locally=options['save_locally'],
                verbose=verbose,
            )
            if verbose:
                print result
Esempio n. 6
0
def event_screencaptures(request, event):
    if event.status != Event.STATUS_INITIATED:
        return http.HttpResponseBadRequest(
            "Events NOT in the state of initiated."
        )
    upload = event.upload
    video_url = upload.url

    context = {}

    cache_key = 'fetching-{0}'.format(event.id)

    # This function sets the cache `fetching-{id}` before and after calling
    # those functions in the videoinfo module.
    # The reason is that those calls might take many many seconds
    # and the webapp might send async calls to the event_picture view
    # which will inform the webapp that the slow videoinfo processes
    # are running and thus that the webapp shouldn't kick if off yet.

    seconds = event.duration
    if not event.duration:
        # it's a poor man's lock
        if not cache.get(cache_key):
            cache.set(cache_key, True, 60)
            seconds = videoinfo.fetch_duration(
                event,
                video_url=video_url,
                save=True,
                verbose=settings.DEBUG
            )
            cache.delete(cache_key)
            event = Event.objects.get(id=event.id)
    context['seconds'] = seconds
    # The reason we can't use `if event.duration:` is because the
    # fetch_duration() does an inline-update instead of modifying
    # the instance object.
    no_pictures = Picture.objects.filter(event=event).count()
    if event.duration and not no_pictures:
        if not cache.get(cache_key):
            cache.set(cache_key, True, 60)
            event = Event.objects.get(id=event.id)
            no_pictures = videoinfo.fetch_screencapture(
                event,
                video_url=video_url,
                save=True,
                verbose=settings.DEBUG,
                set_first_available=not event.picture,
                import_immediately=True,
            )
            cache.delete(cache_key)
            event = Event.objects.get(id=event.id)
    if no_pictures and not event.picture:
        # no picture has been chosen previously
        pictures = Picture.objects.filter(event=event).order_by('created')[:1]
        for picture in pictures:
            event.picture = picture
            event.save()
            break
    context['no_pictures'] = no_pictures
    return context
Esempio n. 7
0
    def test_fetch_duration_oserror(self, mock_popen, rhead):
        def mocked_head(url, **options):
            return Response('', 200)

        rhead.side_effect = mocked_head

        def mocked_popen(command, **kwargs):
            class Inner:
                def communicate(self):
                    raise OSError('Something Bad')

            return Inner()

        mock_popen.side_effect = mocked_popen

        event = Event.objects.get(title='Test event')
        video_url = 'https://example.com/file.mov'
        try:
            videoinfo.fetch_duration(event, video_url=video_url)
            raise AssertionError("not supposed to happen")
        except OSError as exception:
            message = str(exception)
            ok_('Something Bad' in message)
            ok_('ffmpeg -i %s' % video_url in message)
Esempio n. 8
0
    def handle(self, *args, **options):
        if not args:
            raise CommandError(self.args)
        verbose = int(options["verbosity"]) > 1

        for arg in args:
            if arg.isdigit():
                event = Event.objects.get(pk=arg)
            else:
                if "://" in arg:
                    slug = urlparse(arg).path.split("/")[1]
                else:
                    slug = arg
                event = Event.objects.get(slug=slug)

            result = fetch_duration(
                event, save=not options["dry_run"], save_locally=options["save_locally"], verbose=verbose
            )
            if verbose:
                print result
Esempio n. 9
0
def vidly_media_webhook(request):
    if not request.POST.get('xml'):
        return http.HttpResponseBadRequest("no 'xml'")

    xml_string = request.POST['xml'].strip()
    try:
        struct = xmltodict.parse(xml_string)
    except ExpatError:
        return http.HttpResponseBadRequest("Bad 'xml'")

    try:
        task = struct['Response']['Result']['Task']
        try:
            vidly_submission = VidlySubmission.objects.get(
                url=task['SourceFile'], tag=task['MediaShortLink'])
            if task['Status'] == 'Finished':
                if not vidly_submission.finished:
                    vidly_submission.finished = timezone.now()
                    vidly_submission.save()

                event = vidly_submission.event

                if (task['Private'] == 'false'
                        and event.privacy != Event.PRIVACY_PUBLIC):
                    # the event is private but the video is not
                    vidly.update_media_protection(
                        vidly_submission.tag,
                        True  # make it private
                    )
                    if not vidly_submission.token_protection:
                        vidly_submission.token_protection = True
                        vidly_submission.save()

                # Awesome!
                # This event now has a fully working transcoded piece of
                # media.
                if (event.status == Event.STATUS_PENDING
                        or event.status == Event.STATUS_PROCESSING):
                    event.status = Event.STATUS_SCHEDULED
                event.archive_time = timezone.now()
                event.save()

                # More awesome! We can start processing the transcoded media.
                # XXX move this to a background task.
                if not event.duration:
                    videoinfo.fetch_duration(event,
                                             save=True,
                                             verbose=settings.DEBUG)
                    event = Event.objects.get(id=event.id)
                if event.duration:
                    if not Picture.objects.filter(event=event):
                        videoinfo.fetch_screencapture(
                            event,
                            save=True,
                            verbose=settings.DEBUG,
                            set_first_available=True,
                        )
            elif task['Status'] == 'Error':
                if not vidly_submission.errored:
                    vidly_submission.errored = timezone.now()
                    vidly_submission.save()
        except VidlySubmission.DoesNotExist:
            # remember, we can't trust the XML since it's publicly
            # available and exposed as a webhook
            pass

    except KeyError:
        # If it doesn't have a "Result" or "Task", it was just a notification
        # that the media was added.
        pass

    return http.HttpResponse('OK\n')
Esempio n. 10
0
def legacy_video_migration(request):  # pragma: no cover
    """for one off mass vid.ly submission"""

    class VideoURLError(Exception):
        pass

    def redirect_recurse(url):
        """return the URL only when it's not redirecting.
        Raise an error on all other statuses >= 400
        """
        response = requests.head(url)
        if response.status_code in (301, 302):
            return redirect_recurse(response.headers['Location'])
        elif response.status_code >= 400:
            raise VideoURLError('{} => {}'.format(
                url, response.status_code
            ))
        return url

    if request.method == 'POST':
        events = Event.objects.filter(id__in=request.POST.getlist('ids'))
        template, = Template.objects.filter(default_archive_template=True)
        for event in events:
            try:
                url = event.template_environment['url']
                url = redirect_recurse(url)
                base_url = get_base_url(request)
                webhook_url = base_url + reverse('manage:vidly_media_webhook')
                url = prepare_vidly_video_url(url)
                token_protection = event.privacy != Event.PRIVACY_PUBLIC
                shortcode, error = vidly.add_media(
                    url,
                    hd=True,
                    token_protection=token_protection,
                    notify_url=webhook_url,
                )

                VidlySubmission.objects.create(
                    event=event,
                    url=url,
                    token_protection=token_protection,
                    hd=True,
                    tag=shortcode,
                    submission_error=error
                )
                event.template_environment = {
                    'tag': shortcode,
                }
                if shortcode:
                    event.template = template
                    event.archive_time = None
                    event.status = Event.STATUS_PROCESSING
                    event.save()

                    videoinfo.fetch_duration(
                        event,
                        video_url=url,
                        save=True,
                        verbose=settings.DEBUG
                    )
                    if Event.objects.get(id=event.id).duration:
                        create_all_event_pictures.delay(
                            event.id,
                            video_url=url,
                        )
                        create_all_timestamp_pictures.delay(
                            event.id,
                            video_url=url,
                        )
            except Exception as exception:
                error = str(exception)
                messages.error(
                    request,
                    'Failed to submit "{}". Error: {}'.format(
                        event.title,
                        error,
                    )
                )

        messages.success(
            request,
            'Submitted {} events for Vid.ly processing'.format(
                events.count()
            )
        )
        return redirect('manage:legacy_video_migration')

    search = request.GET.get('search', 'http://videos.mozilla.org/')
    if search:
        events = Event.objects.filter(
            template_environment__icontains=search
        )
    else:
        events = Event.objects.none()
    context = {
        'events': events,
        'search': search,
    }
    return render(request, 'manage/legacy_video_migration.html', context)
Esempio n. 11
0
def legacy_video_migration(request):  # pragma: no cover
    """for one off mass vid.ly submission"""
    class VideoURLError(Exception):
        pass

    def redirect_recurse(url):
        """return the URL only when it's not redirecting.
        Raise an error on all other statuses >= 400
        """
        response = requests.head(url)
        if response.status_code in (301, 302):
            return redirect_recurse(response.headers['Location'])
        elif response.status_code >= 400:
            raise VideoURLError('{} => {}'.format(url, response.status_code))
        return url

    if request.method == 'POST':
        events = Event.objects.filter(id__in=request.POST.getlist('ids'))
        template, = Template.objects.filter(default_archive_template=True)
        for event in events:
            try:
                url = event.template_environment['url']
                url = redirect_recurse(url)
                base_url = get_base_url(request)
                webhook_url = base_url + reverse('manage:vidly_media_webhook')
                url = prepare_vidly_video_url(url)
                token_protection = event.privacy != Event.PRIVACY_PUBLIC
                shortcode, error = vidly.add_media(
                    url,
                    hd=True,
                    token_protection=token_protection,
                    notify_url=webhook_url,
                )

                VidlySubmission.objects.create(
                    event=event,
                    url=url,
                    token_protection=token_protection,
                    hd=True,
                    tag=shortcode,
                    submission_error=error)
                event.template_environment = {
                    'tag': shortcode,
                }
                if shortcode:
                    event.template = template
                    event.archive_time = None
                    event.status = Event.STATUS_PROCESSING
                    event.save()

                    videoinfo.fetch_duration(event,
                                             video_url=url,
                                             save=True,
                                             verbose=settings.DEBUG)
                    if Event.objects.get(id=event.id).duration:
                        create_all_event_pictures.delay(
                            event.id,
                            video_url=url,
                        )
                        create_all_timestamp_pictures.delay(
                            event.id,
                            video_url=url,
                        )
            except Exception as exception:
                error = str(exception)
                messages.error(
                    request, 'Failed to submit "{}". Error: {}'.format(
                        event.title,
                        error,
                    ))

        messages.success(
            request,
            'Submitted {} events for Vid.ly processing'.format(events.count()))
        return redirect('manage:legacy_video_migration')

    search = request.GET.get('search', 'http://videos.mozilla.org/')
    if search:
        events = Event.objects.filter(template_environment__icontains=search)
    else:
        events = Event.objects.none()
    context = {
        'events': events,
        'search': search,
    }
    return render(request, 'manage/legacy_video_migration.html', context)