def test_form_valid__scraped__embed(self):
        """
        Checks that, if the form represents a scraped video with embed code,
        the success_url is the url of the scraped_video view, and that the
        session data contains the scraped video as 'video' and the video's
        url as 'url'.

        """
        scraped_url = reverse('localtv_submit_scraped_video')
        view = SubmitURLView(scraped_url=scraped_url)
        video_url = "http://google.com"
        url = "%s?url=%s" % (reverse('localtv_submit_video'), video_url)
        view.request = self.factory.get(url)
        expected_success_url = "%s?%s" % (scraped_url,
                                          view.request.GET.urlencode())
        form = view.get_form(view.get_form_class())

        video = VidscraperVideo(video_url)
        video.embed_code = "blink"
        form.video_cache = video
        form.cleaned_data = {'url': video_url}

        view.form_valid(form)
        self.assertEqual(view.request.session[view.get_session_key()], {
            'video': video,
            'url': video_url
        })
        self.assertEqual(view.success_url, expected_success_url)
    def test_items(self):
        video = Video("http://www.youtube.com/watch?v=J_DV9b0x7v4")

        # Make sure items can be iterated over and that there's one
        # for every field.
        for i, item in enumerate(video.items()):
            self.assertEqual(item[0], Video._all_fields[i])
    def test_form_valid__scraped__embed(self):
        """
        Checks that, if the form represents a scraped video with embed code,
        the success_url is the url of the scraped_video view, and that the
        session data contains the scraped video as 'video' and the video's
        url as 'url'.

        """
        scraped_url = reverse('localtv_submit_scraped_video')
        view = SubmitURLView(scraped_url=scraped_url)
        video_url = "http://google.com"
        url = "%s?url=%s" % (reverse('localtv_submit_video'),
                             video_url)
        view.request = self.factory.get(url)
        expected_success_url = "%s?%s" % (scraped_url,
                                          view.request.GET.urlencode())
        form = view.get_form(view.get_form_class())

        video = VidscraperVideo(video_url)
        video.embed_code = "blink"
        form.video_cache = video
        form.cleaned_data = {'url': video_url}

        view.form_valid(form)
        self.assertEqual(view.request.session[view.get_session_key()],
                         {'video': video, 'url': video_url})
        self.assertEqual(view.success_url, expected_success_url)
    def _test_submit__succeed(self, url, next_view, **kwargs):
        """
        A GET request to the SubmitURLView with GET data should submit the form
        if the GET data overlaps with the form field(s). On success, the user
        should be redirected to the correct submission completion view,
        preserving GET data.

        All the views to which the user could be redirected are instances of
        the same class-based view. This is essentially a test for
        backwards-compatibility.

        """
        data = {'url': url,
                'q': 'hello',
                'next': 'blink'}
        expected_url = "%s?%s" % (
            reverse(next_view),
            urlencode(data)
        )
        video = VidscraperVideo(url)
        video._loaded = True
        for attr, value in kwargs.iteritems():
            setattr(video, attr, value)
        with patch.object(vidscraper, 'auto_scrape', return_value=video):
            response = self.client.get(self.url, data)
        self.assertRedirects(response, expected_url)
    def test_items_with_fields(self):
        fields = ['title', 'user']
        video = Video("http://www.youtube.com/watch?v=J_DV9b0x7v4",
                            fields=fields)

        # Make sure items can be iterated over and that there's one
        # for every field.
        for i, item in enumerate(video.items()):
            self.assertEqual(item[0], fields[i])
    def test_form_valid__embedrequest(self):
        """
        Checks that, if the form represents an embedrequest video - i.e. a video
        that vidscraper can't scrape and which doesn't look like a direct link -
        the success_url is set to the url of the embedrequest view, and that the
        session data contains the scraped video (or ``None``) as 'video' and the
        video's url as 'url'.

        """
        embed_url = reverse('localtv_submit_embedrequest_video')
        view = SubmitURLView(embed_url=embed_url)
        video_url = 'http://google.com'
        url = "%s?url=%s" % (reverse('localtv_submit_video'), video_url)
        view.request = self.factory.get(url)
        expected_success_url = "%s?%s" % (embed_url,
                                          view.request.GET.urlencode())
        form = view.get_form(view.get_form_class())

        # Option 1: no video
        form.video_cache = None
        form.cleaned_data = {'url': video_url}

        view.form_valid(form)
        self.assertEqual(view.request.session[view.get_session_key()], {
            'video': None,
            'url': video_url
        })
        self.assertEqual(view.success_url, expected_success_url)

        # Option two: video missing embed & file_url
        video = VidscraperVideo(video_url)
        form.video_cache = video
        form.cleaned_data = {'url': video_url}

        view.form_valid(form)
        self.assertEqual(view.request.session[view.get_session_key()], {
            'video': video,
            'url': video_url
        })
        self.assertEqual(view.success_url, expected_success_url)

        # Option three: video with expiring file_url.
        video.file_url = 'hola'
        video.file_url_expires = datetime.datetime.now() + datetime.timedelta(
            1)

        view.form_valid(form)
        self.assertEqual(view.request.session[view.get_session_key()], {
            'video': video,
            'url': video_url
        })
        self.assertEqual(view.success_url, expected_success_url)
    def test_serialize__json(self):
        """
        Tests that serialized videos can be transformed to and from json.

        """
        video = Video("http://www.youtube.com/watch?v=J_DV9b0x7v4")
        # we load the video data this way to avoid depending on the network
        video_data = CARAMELL_DANSEN_API_DATA.copy()
        video_data['tags'] = list(video_data['tags'])
        video._apply(video_data)
        data = video.serialize()
        new_data = json.loads(json.dumps(data))
        self.assertEqual(new_data, data)
    def test_serialize__pickle(self):
        """
        Tests that serialized videos can be pickled and unpickled.

        """
        video = Video("http://www.youtube.com/watch?v=J_DV9b0x7v4")
        # we load the video data this way to avoid depending on the network
        video_data = CARAMELL_DANSEN_API_DATA.copy()
        video_data['tags'] = list(video_data['tags'])
        video._apply(video_data)
        data = video.serialize()
        new_data = pickle.loads(pickle.dumps(data, pickle.HIGHEST_PROTOCOL))
        self.assertEqual(new_data, data)
Example #9
0
    def get_video(self, url, fields=None, api_keys=None, require_loaders=True):
        """
        For each registered :mod:`suite <vidscraper.suites>`, calls
        :meth:`~BaseSuite.get_video` with the given ``url``, ``fields``, and
        ``api_keys``, until a suite returns a :class:`.Video` instance.

        :param require_loaders: Changes the behavior if no suite is found
                                which handles the given parameters. If
                                ``True`` (default), :exc:`.UnhandledVideo`
                                will be raised; otherwise, a video will 
                                returned with the given ``url`` and
                                ``fields``, but it will not be able to load
                                any additional data.
        :raises: :exc:`.UnhandledVideo` if ``require_loaders`` is ``True`` and
                 no registered suite returns a video for the given parameters.
        :returns: :class:`.Video` instance with no data loaded.

        """
        for suite in self.suites:
            try:
                return suite.get_video(url, fields=fields, api_keys=api_keys)
            except UnhandledVideo:
                pass

        if require_loaders:
            raise UnhandledVideo(url)

        return Video(url, fields=fields)
Example #10
0
    def test_get_file__open(self):
        """
        Tests that open video formats are preferred over proprietary.

        """
        video = Video("http://www.youtube.com/watch?v=J_DV9b0x7v4")
        file1 = VideoFile(url='http://google.com',
                          mime_type="video/ogg")
        file2 = VideoFile(url='http://xkcd.com',
                          mime_type="application/x-shockwave-flash")
        file3 = VideoFile(url='http://example.com',
                          mime_type="video/mp4")
        video.files = [file1, file2, file3]
        self.assertEqual(video.get_file(), file1)
        video.files = [file3, file2, file1]
        self.assertEqual(video.get_file(), file1)
    def test_form_valid__embedrequest(self):
        """
        Checks that, if the form represents an embedrequest video - i.e. a video
        that vidscraper can't scrape and which doesn't look like a direct link -
        the success_url is set to the url of the embedrequest view, and that the
        session data contains the scraped video (or ``None``) as 'video' and the
        video's url as 'url'.

        """
        embed_url = reverse('localtv_submit_embedrequest_video')
        view = SubmitURLView(embed_url=embed_url)
        video_url = 'http://google.com'
        url = "%s?url=%s" % (reverse('localtv_submit_video'),
                             video_url)
        view.request = self.factory.get(url)
        expected_success_url = "%s?%s" % (embed_url,
                                          view.request.GET.urlencode())
        form = view.get_form(view.get_form_class())

        # Option 1: no video
        form.video_cache = None
        form.cleaned_data = {'url': video_url}

        view.form_valid(form)
        self.assertEqual(view.request.session[view.get_session_key()],
                         {'video': None, 'url': video_url})
        self.assertEqual(view.success_url, expected_success_url)

        # Option two: video missing embed & file_url
        video = VidscraperVideo(video_url)
        form.video_cache = video
        form.cleaned_data = {'url': video_url}

        view.form_valid(form)
        self.assertEqual(view.request.session[view.get_session_key()],
                         {'video': video, 'url': video_url})
        self.assertEqual(view.success_url, expected_success_url)

        # Option three: video with expiring file_url.
        video.file_url = 'hola'
        video.file_url_expires = datetime.datetime.now() + datetime.timedelta(1)

        view.form_valid(form)
        self.assertEqual(view.request.session[view.get_session_key()],
                         {'video': video, 'url': video_url})
        self.assertEqual(view.success_url, expected_success_url)
Example #12
0
def video_from_vidscraper_video(video_dict, site_pk,
                                import_app_label=None, import_model=None,
                                import_pk=None, status=None, author_pks=None,
                                category_pks=None, clear_rejected=False):
    vidscraper_video = VidscraperVideo.deserialize(video_dict, API_KEYS)
    import_class = get_model(import_app_label, import_model)
    try:
        source_import = import_class.objects.get(
           pk=import_pk,
           status=import_class.STARTED)
    except import_class.DoesNotExist:
        logging.warn('Retrying %r: expected %s instance (pk=%r) missing.',
                     vidscraper_video.url, import_class.__name__, import_pk)
        video_from_vidscraper_video.retry()

    try:
        try:
            vidscraper_video.load()
        except Exception:
            source_import.handle_error(
                ('Skipped %r: Could not load video data.'
                 % vidscraper_video.url),
                is_skip=True, with_exception=True)
            return

        if category_pks:
            categories = Category.objects.filter(pk__in=category_pks)
        else:
            categories = None

        if author_pks:
            authors = User.objects.filter(pk__in=author_pks)
        else:
            authors = None

        video = Video.from_vidscraper_video(vidscraper_video, status=status,
                                            source_import=source_import,
                                            authors=authors,
                                            categories=categories,
                                            site_pk=site_pk,
                                            commit=False,
                                            update_index=False)
        try:
            video.clean_fields()
            # If clear_rejected is True, we've already deleted any rejected
            # videos, so there's no need to explicitly exclude them.
            # If clear_rejected is False, this is not the first run, and
            # so rejected videos need to not be excluded in this check.
            video._check_for_duplicates(exclude_rejected=False)
            video.validate_unique()
        except ValidationError, e:
            source_import.handle_error(("Skipping %r: %r" % (
                                        vidscraper_video.url, e.message)),
                                       is_skip=True)
            return
        else:
    def test_m2m_errors(self):
        """
        If video.save_m2m raises an exception during import, the video should
        be deleted and the error reraised.

        """
        class FakeException(Exception):
            pass
        video = mock.MagicMock(save_m2m=mock.MagicMock(
                                                   side_effect=FakeException))
        kwargs = {'from_vidscraper_video.return_value': video}
        vidscraper_video = VidscraperVideo(None)

        with mock.patch('localtv.tasks.get_model'):
            with mock.patch('localtv.tasks.Video', **kwargs):
                with self.assertRaises(FakeException):
                    video_from_vidscraper_video.apply(args=(vidscraper_video.serialize(), 1))

        video.save.assert_called_once_with(update_index=False)
        video.save_m2m.assert_called_once_with()
        video.delete.assert_called_once_with()
Example #14
0
    def _test_submit__succeed(self, url, next_view, **kwargs):
        """
        A GET request to the SubmitURLView with GET data should submit the form
        if the GET data overlaps with the form field(s). On success, the user
        should be redirected to the correct submission completion view,
        preserving GET data.

        All the views to which the user could be redirected are instances of
        the same class-based view. This is essentially a test for
        backwards-compatibility.

        """
        data = {'url': url, 'q': 'hello', 'next': 'blink'}
        expected_url = "%s?%s" % (reverse(next_view), urlencode(data))
        video = VidscraperVideo(url)
        video._loaded = True
        for attr, value in kwargs.iteritems():
            setattr(video, attr, value)
        with patch.object(vidscraper, 'auto_scrape', return_value=video):
            response = self.client.get(self.url, data)
        self.assertRedirects(response, expected_url)
    def test_serialize__files(self):
        """
        Tests that a video with associated files can still be serialized and
        deserialized.

        """
        video = Video("http://www.youtube.com/watch?v=J_DV9b0x7v4")
        now = datetime.datetime.now()
        video.files = [VideoFile(url='http://google.com',
                                 expires=now,
                                 length=100,
                                 width=50,
                                 height=50,
                                 mime_type="video/x-flv"),
                       VideoFile(url='http://xkcd.com',
                                 expires=now,
                                 length=75,
                                 width=80,
                                 height=80,
                                 mime_type="application/x-shockwave-flash"),]

        data = video.serialize()
        # verify that the data we expect is in the serialized version.
        self.assertEqual(data['files'][0]['url'], "http://google.com")
        self.assertEqual(data['files'][1]['mime_type'],
                         "application/x-shockwave-flash")
        self.assertEqual(data['files'][0]['expires'], now.isoformat())

        # Verify that the data can be deserialized as a video.
        new_video = Video.deserialize(data)
        self.assertEqual(dict(video.items()), dict(new_video.items()))
Example #16
0
    def test_m2m_errors(self):
        """
        If video.save_m2m raises an exception during import, the video should
        be deleted and the error reraised.

        """
        class FakeException(Exception):
            pass

        video = mock.MagicMock(save_m2m=mock.MagicMock(
            side_effect=FakeException))
        kwargs = {'from_vidscraper_video.return_value': video}
        vidscraper_video = VidscraperVideo(None)

        with mock.patch('localtv.tasks.get_model'):
            with mock.patch('localtv.tasks.Video', **kwargs):
                with self.assertRaises(FakeException):
                    video_from_vidscraper_video.apply(
                        args=(vidscraper_video.serialize(), 1))

        video.save.assert_called_once_with(update_index=False)
        video.save_m2m.assert_called_once_with()
        video.delete.assert_called_once_with()
    def test_get_file__none(self):
        """
        If there are no files, get_file() should return None.

        """
        video = Video("http://www.youtube.com/watch?v=J_DV9b0x7v4")
        video.files = None
        self.assertTrue(video.get_file() is None)
        video.files = []
        self.assertTrue(video.get_file() is None)
Example #18
0
    def test_serialize(self):
        video = Video("http://www.youtube.com/watch?v=J_DV9b0x7v4")
        # we load the video data this way to avoid depending on the network
        video_data = CARAMELL_DANSEN_API_DATA.copy()
        video_data['tags'] = list(video_data['tags'])
        video._apply(video_data)

        data = video.serialize()
        # verify that the data we expect is in the serialized version.
        self.assertEqual(data['url'], video.url)
        self.assertEqual(data['title'], video.title)
        self.assertEqual(data['publish_datetime'],
                         video.publish_datetime.isoformat())

        # Verify that the data can be deserialized as a video.
        new_video = Video.deserialize(data)
        self.assertEqual(video.url, new_video.url)
        self.assertEqual(dict(video.items()), dict(new_video.items()))

        # Verify that data can be deserialized more than once.
        # (i.e. that it is not modified in-place during deserialization.)
        Video.deserialize(data)
Example #19
0
    def test_get_file__open(self):
        """
        Tests that open video formats are preferred over proprietary.

        """
        video = Video("http://www.youtube.com/watch?v=J_DV9b0x7v4")
        file1 = VideoFile(url='http://google.com', mime_type="video/ogg")
        file2 = VideoFile(url='http://xkcd.com',
                          mime_type="application/x-shockwave-flash")
        file3 = VideoFile(url='http://example.com', mime_type="video/mp4")
        video.files = [file1, file2, file3]
        self.assertEqual(video.get_file(), file1)
        video.files = [file3, file2, file1]
        self.assertEqual(video.get_file(), file1)
    def test_get_file__no_mimetypes(self):
        """
        If none of the videos have mime types, the first file should be
        returned.

        """
        video = Video("http://www.youtube.com/watch?v=J_DV9b0x7v4")
        file1 = VideoFile(url='http://google.com')
        file2 = VideoFile(url='http://xkcd.com')
        file3 = VideoFile(url='http://example.com')
        video.files = [file1, file2, file3]
        self.assertEqual(video.get_file(), file1)
        video.files = [file3, file2, file1]
        self.assertEqual(video.get_file(), file3)
Example #21
0
    def test_serialize(self):
        video = Video("http://www.youtube.com/watch?v=J_DV9b0x7v4")
        # we load the video data this way to avoid depending on the network
        video_data = CARAMELL_DANSEN_API_DATA.copy()
        video_data['tags'] = list(video_data['tags'])
        video._apply(video_data)

        data = video.serialize()
        # verify that the data we expect is in the serialized version.
        self.assertEqual(data['url'], video.url)
        self.assertEqual(data['title'], video.title)
        self.assertEqual(data['publish_datetime'],
                         video.publish_datetime.isoformat())

        # Verify that the data can be deserialized as a video.
        new_video = Video.deserialize(data)
        self.assertEqual(video.url, new_video.url)
        self.assertEqual(dict(video.items()), dict(new_video.items()))
    def test_serialize__partial(self):
        """
        Tests that a video with only some fields can still be serialized and
        deserialized.

        """
        video = Video("http://www.youtube.com/watch?v=J_DV9b0x7v4",
                      fields=('title', 'embed_code'))
        # we load the video data this way to avoid depending on the network
        video_data = CARAMELL_DANSEN_API_DATA.copy()
        video._apply(video_data)
        data = video.serialize()

        # verify that the data we expect is in the serialized version.
        self.assertEqual(data['url'], video.url)
        self.assertEqual(data['title'], video.title)
        self.assertEqual(data['embed_code'], video.embed_code)

        # Verify that the data can be deserialized as a video.
        new_video = Video.deserialize(data)
        self.assertEqual(video.url, new_video.url)
        self.assertEqual(dict(video.items()), dict(new_video.items()))
Example #23
0
    def get_video(self, url, fields=None, api_keys=None):
        """
        Returns a video using this suite's loaders. This instance will not
        have data loaded.

        :param url: A video URL. Video website URLs generally work; more
                    obscure urls (like API urls) might work as well.
        :param fields: A list of fields to be fetched for the video. Limiting this
                       may decrease the number of HTTP requests required for
                       loading the video.

                       .. seealso:: :ref:`video-fields`
        :param api_keys: A dictionary of API keys for various services. Check
                         the documentation for each
                         :mod:`suite <vidscraper.suites>` to find what API
                         keys they may want or require.
        :raises: :exc:`.UnhandledVideo` if none of this suite's loaders can
                 handle the given url and api keys.

        """
        # Sanity-check the url.
        if not url:
            raise UnhandledVideo(url)

        loaders = []

        for cls in self.loader_classes:
            try:
                loader = cls(url, api_keys=api_keys)
            except UnhandledVideo:
                continue

            loaders.append(loader)
        if not loaders:
            raise UnhandledVideo(url)
        return Video(url, loaders=loaders, fields=fields)