예제 #1
0
    def test_observe_group(self):
        cmd_id = IdentityService.random()
        handler = Mock()
        event = DummyEvent(cmd_id, IdentityService.random())
        self.dispatcher.observe_group(
            {
                self.cmd_id: {
                    type(self.evt): self.handler
                },
                cmd_id: {
                    type(event): handler
                },
            },
            times=1,
        )

        self.dispatcher.dispatch(self.evt)
        handler.assert_not_called()
        self.handler.assert_called_once_with(self.evt)
        handler.reset_mock()
        self.handler.reset_mock()

        self.dispatcher.dispatch(event)
        handler.assert_not_called()
        self.handler.assert_not_called()
예제 #2
0
    def test_queue_front_playlist_while_playing(self):
        collection_1_id = IdentityService.random()
        collection_2_id = IdentityService.random()
        self.data_producer.player().video(
            "source1", collection_id=collection_1_id
        ).video("source2", collection_id=collection_1_id).play(
            "source1"
        ).parent_producer().video(
            "source3", collection_id=collection_2_id
        ).video(
            "source4", collection_id=collection_2_id
        ).populate(
            self.data_facade
        )

        queue = self.playlist_repo.get(self.queue_id)
        videos = self.video_repo.list()
        playlist2 = [
            video for video in videos if video.collection_id == collection_2_id
        ]
        for video in playlist2:
            queue.ids = self.service.queue(queue, video.id, front=True)

        expected = [videos[0].id, videos[2].id, videos[3].id, videos[1].id]
        self.assertListEqual(expected, queue.ids)
예제 #3
0
 def test_construction(self):
     collection_id = IdentityService.random()
     artist_id = (IdentityService.id_artist("artist"), )
     album_id = (IdentityService.id_album("album_name"), )
     video = Video(
         IdentityService.random(),
         "source",
         collection_id,
         artist_id,
         album_id,
         "title",
         timedelta(seconds=300),
         timedelta(),
         None,
         "protocol",
         "thumbnail_url",
         "/tmp/file",
         [],
         "subtitle",
     )
     self.assertEqual("source", video.source)
     self.assertEqual(collection_id, video.collection_id)
     self.assertEqual(artist_id, video.artist_id)
     self.assertEqual(album_id, video.album_id)
     self.assertEqual("title", video.title)
     self.assertEqual(300, video.duration)
     self.assertEqual("/tmp/file", video.location)
     self.assertEqual([], video.streams)
     self.assertEqual("subtitle", video.subtitle)
     self.expect_events(video, Evt.VideoCreated)
예제 #4
0
    def test_add(self):
        first = IdentityService.random()
        self.album.add(first)
        self.assertListEqual([first], self.album.ids)

        second = IdentityService.random()
        self.album.add(second)
        self.assertListEqual([first, second], self.album.ids)

        self.expect_events(self.album, Evt.AlbumVideosUpdated,
                           Evt.AlbumVideosUpdated)
예제 #5
0
 def test_construction(self):
     name = "name"
     ids = [IdentityService.random()]
     thumbnail = "thumbnail"
     id = IdentityService.id_artist(name)
     artist = Artist(id, name, ids, thumbnail)
     self.expect_events(artist, Evt.ArtistCreated)
예제 #6
0
    def test_create_video(self):
        source = "source"
        video_id = IdentityService.id_video(source)
        collection_id = IdentityService.random()

        metadata = {
            "title": "title",
            "duration": 300,
            "source_protocol": "http",
            "artist": "artist",
            "album": "album",
            "thumbnail": "thumbnail_url",
        }
        self.downloader.download_metadata.return_value = metadata
        self.deezer.search.return_value = []

        attrs = deepcopy(metadata)
        attrs["artist_id"] = IdentityService.id_artist(attrs.pop("artist"))
        attrs["album_id"] = IdentityService.id_album(attrs.pop("album"))
        self.evt_expecter.expect(
            VideoEvt.VideoCreated,
            video_id,
            source,
            collection_id,
            **attrs,
            state=VideoState.CREATED,
        ).from_(Cmd.CreateVideo, video_id, source, collection_id)
예제 #7
0
 def test_construction(self):
     name = "name"
     ids = [IdentityService.random()]
     thumbnail = "thumbnail"
     id = IdentityService.id_album(name)
     album = Album(id, name, ids, thumbnail)
     self.expect_events(album, Evt.AlbumCreated)
예제 #8
0
    async def test_update(self):
        req_body = {
            "name": "test_playlist",
            "ids": [str(IdentityService.random())]
        }
        playlist = self.playlist_repo.get(self.playlist_id)
        self.expect_and_raise_l([
            {
                "cmd":
                make_cmd(PlaylistCmd.RenamePlaylist, playlist.id,
                         req_body["name"]),
                "evt":
                PlaylistEvt.PlaylistRenamed,
                "args": {
                    "name": req_body["name"]
                },
            },
            {
                "cmd":
                make_cmd(PlaylistCmd.UpdatePlaylistContent, playlist.id,
                         req_body["ids"]),
                "evt":
                PlaylistEvt.PlaylistContentUpdated,
                "args": {
                    "ids": req_body["ids"]
                },
            },
        ])

        resp = await self.client.patch(f"/api/playlists/{playlist.id}",
                                       json=req_body)
        body = await resp.json()
        self.assertEqual(200, resp.status)
        self.assertEqual(playlist.to_dict(), body)
예제 #9
0
    def test_retrieving_to_finalizing(self):
        event = Evt.VideoCreated(
            IdentityService.random(),
            *self.video.to_tuple(),
            IdentityService.id_artist("artist"),
            IdentityService.id_album("album"),
            "title",
            300,
            "m3u8",
            "thumbnail",
            VideoState.CREATED,
        )
        self.workflow.to_RETRIEVING(event)

        cmd = self.expect_dispatch(
            Cmd.RetrieveVideo, self.video.id, settings["downloader.output_directory"]
        )

        def return_video(id):
            self.assertEqual(self.video.id, id)
            return VideoModel(self.video.id, self.video.source, source_protocol="m3u8")

        self.video_repo.get.side_effect = return_video

        self.raise_event(
            Evt.VideoRetrieved,
            cmd.id,
            self.video.id,
            "https://url.m3u8",
        )
        self.assertTrue(self.workflow.is_FINALIZING())
예제 #10
0
    async def queue(self, req):
        source = req.query["url"]
        video_id = IdentityService.id_video(source)
        playlist_id = self._player_repo.get_player().queue

        if self._source_service.is_playlist(source):
            collection_id = IdentityService.random()
            self._evt_dispatcher.dispatch(
                Notification(
                    collection_id,
                    NotifLevel.INFO,
                    "unfolding playlist",
                    {"source": source},
                ))

            loop = asyncio.get_running_loop()
            with ThreadPoolExecutor() as pool:
                sources = await loop.run_in_executor(
                    pool, partial(self._source_service.unfold, source))
                if not sources:
                    return self._internal_error(
                        "Could not unfold the playlist URL")

                self._evt_dispatcher.dispatch(
                    Notification(
                        collection_id,
                        NotifLevel.INFO,
                        "downloading playlist",
                        {
                            "source": source,
                            "count": f"{len(sources)} media"
                        },
                    ))
                videos = [
                    Video(IdentityService.id_video(source), source,
                          collection_id) for source in sources
                ]

                workflow_id = IdentityService.id_workflow(
                    QueuePlaylistWorkflow, video_id)
                self._start_workflow(
                    QueuePlaylistWorkflow,
                    workflow_id,
                    self._data_facade,
                    videos,
                    playlist_id,
                )
                return self._no_content()

        video = Video(video_id, source, collection_id=None)
        self._start_workflow(
            QueueVideoWorkflow,
            video_id,
            self._data_facade,
            video,
            playlist_id,
            queue_front=False,
        )

        return self._no_content()
예제 #11
0
 def test_empty(self):
     self.assertTrue(self.artist.empty())
     self.artist = Artist(
         IdentityService.id_artist("name"),
         "name",
         [IdentityService.random()],
         "thumbnail",
     )
     self.assertFalse(self.artist.empty())
예제 #12
0
    def test_observe_event_by_id(self):
        self.dispatcher.observe_result(self.cmd_id,
                                       {type(self.evt): self.handler})
        # Unrelated event should not call the handler
        self.dispatcher.observe_result(IdentityService.random(),
                                       {type(self.evt): self.handler})

        self.dispatcher.dispatch(self.evt)
        self.handler.assert_called_once_with(self.evt)
예제 #13
0
 def test_empty(self):
     self.assertTrue(self.album.empty())
     self.album = Album(
         IdentityService.id_album("name"),
         "name",
         [IdentityService.random()],
         "thumbnail",
     )
     self.assertFalse(self.album.empty())
예제 #14
0
 async def test_update_not_found(self):
     playlist_id = IdentityService.id_playlist()
     req_body = {
         "name": "test_playlist",
         "ids": [str(IdentityService.random())]
     }
     resp = await self.client.patch(f"/api/playlists/{playlist_id}",
                                    json=req_body)
     self.assertEqual(404, resp.status)
예제 #15
0
 def make_test_workflow(self, video_count=2):
     collection_id = IdentityService.random()
     sources = [f"src{i}" for i in range(video_count)]
     videos = [
         Video(IdentityService.id_video(source), source, collection_id)
         for source in sources
     ]
     return self.make_workflow(StreamPlaylistWorkflow, videos,
                               self.player_playlist_id)
예제 #16
0
    def test_download_video_error(self):
        self.ydl.download.side_effect = RuntimeError("error")

        op_id = IdentityService.random()
        video_id = IdentityService.id_video("url")
        self.downloader.download_video(op_id, video_id, "url",
                                       "/tmp/media.mp4")

        self.dispatcher.dispatch.assert_called_with(
            DownloadError(op_id, "error"))
예제 #17
0
 def test_parsing_to_deleting(self):
     event = Evt.VideoRetrieved(
         IdentityService.random(),
         self.video.id,
         f"{settings['downloader.output_directory']}/video.mp4",
     )
     self.workflow.to_PARSING(event)
     cmd = self.expect_dispatch(Cmd.ParseVideo, self.video.id)
     self.raise_error(cmd)
     self.assertTrue(self.workflow.is_DELETING())
예제 #18
0
    def test_download_video(self, path_cls):
        path_mock = path_cls.return_value
        path_mock.exists.return_value = True

        op_id = IdentityService.random()
        video_id = IdentityService.id_video("url")
        self.downloader.download_video(op_id, video_id, "url",
                                       "/tmp/media.mp4")

        self.dispatcher.dispatch.assert_called_with(DownloadSuccess(op_id))
예제 #19
0
    def test_download_video_missing(self, path_cls):
        path_mock = path_cls.return_value
        path_mock.exists.return_value = False

        op_id = IdentityService.random()
        video_id = IdentityService.id_video("url")
        self.downloader.download_video(op_id, video_id, "url",
                                       "/tmp/media.mp4")

        self.dispatcher.dispatch.assert_called_with(
            DownloadError(op_id, "video path points to non existent file"))
예제 #20
0
    async def test_update_validation_error(self):
        req_body = {"name": 2, "ids": [str(IdentityService.random())]}
        playlist = self.playlist_repo.get(self.playlist_id)

        resp = await self.client.patch(f"/api/playlists/{playlist.id}",
                                       json=req_body)
        body = await resp.json()
        self.assertEqual(422, resp.status)
        self.assertEqual(
            {"name": ["Not a valid string."]},
            body,
        )
예제 #21
0
 def test_deleting_to_aborted(self):
     cmd = Cmd.CreateVideo(
         IdentityService.random(), self.video.id, "source", collection_id=None
     )
     error = OperationError(cmd, "")
     self.workflow.to_DELETING(error)
     cmd = self.expect_dispatch(Cmd.DeleteVideo, self.video.id)
     self.raise_event(
         Evt.VideoDeleted,
         cmd.id,
         self.video.id,
     )
     self.assertTrue(self.workflow.is_ABORTED())
예제 #22
0
    def test_queue_front_playlist_empty_queue(self):
        collection_id = IdentityService.random()
        self.data_producer.video("source1", collection_id=collection_id).video(
            "source2", collection_id=collection_id
        ).video("source3", collection_id=collection_id).populate(self.data_facade)

        queue = self.playlist_repo.get(self.queue_id)
        videos = self.video_repo.list()
        for video in videos:
            queue.ids = self.service.queue(queue, video.id, front=True)

        expected = [video.id for video in videos]
        self.assertListEqual(expected, queue.ids)
예제 #23
0
    def from_event(self, evt_cls, model_id, *args, **kwargs):
        cmd_id = IdentityService.random()

        for cls, handler_data in self.evt_to_handler.items():
            self.evt_dispatcher.observe_result(cmd_id,
                                               {cls: handler_data.functor})

        evt = evt_cls(cmd_id, model_id, *args, **kwargs)
        self.evt_dispatcher.dispatch(evt)

        for cls, handler_data in self.evt_to_handler.items():
            handler_data.functor.assert_called_once_with(
                cls(cmd_id, *handler_data.attrs, **handler_data.dict_attrs))
예제 #24
0
    def test_queue_front_merge_playlist(self):
        collection_id = IdentityService.random()
        self.data_producer.video("source1", collection_id=collection_id).video(
            "source2"
        ).video("source3", collection_id=collection_id).populate(self.data_facade)

        queue = self.playlist_repo.get(self.queue_id)
        videos = self.video_repo.list()
        queue.ids = self.service.queue(queue, videos[0].id, front=True)
        queue.ids = self.service.queue(queue, videos[1].id, front=False)
        queue.ids = self.service.queue(queue, videos[2].id, front=True)
        expected = [videos[0].id, videos[2].id, videos[1].id]
        self.assertListEqual(expected, queue.ids)
예제 #25
0
    def test_list_containing(self):
        videos = [IdentityService.id_video(f"source{i}") for i in range(4)]

        artists = [
            Artist(IdentityService.random(), "artist_1", videos[:2]),
            Artist(IdentityService.random(), "artist_2", videos[2:]),
            Artist(
                IdentityService.random(),
                "artist_3",
                [videos[0], videos[2]],
            ),
        ]
        for artist in artists:
            self.repo.create(artist)

        result = self.repo.list_containing(videos[0])
        self.assertEqual([artists[0], artists[2]], result)

        result = self.repo.list_containing(videos[3])
        self.assertEqual([artists[1]], result)

        result = self.repo.list_containing(IdentityService.random())
        self.assertEqual([], result)
예제 #26
0
    def test_list_containing(self):
        videos = [IdentityService.id_video(f"source{i}") for i in range(4)]

        albums = [
            Album(IdentityService.random(), "album_1", videos[:2]),
            Album(IdentityService.random(), "album_2", videos[2:]),
            Album(
                IdentityService.random(),
                "album_3",
                [videos[0], videos[2]],
            ),
        ]
        for album in albums:
            self.repo.create(album)

        result = self.repo.list_containing(videos[0])
        self.assertEqual([albums[0], albums[2]], result)

        result = self.repo.list_containing(videos[3])
        self.assertEqual([albums[1]], result)

        result = self.repo.list_containing(IdentityService.random())
        self.assertEqual([], result)
예제 #27
0
 def test_finalizing_to_completed(self):
     event = Evt.VideoSubtitleFetched(
         IdentityService.random(), self.video.id, Path()
     )
     self.workflow.to_FINALIZING(event)
     cmd = self.expect_dispatch(Cmd.SetVideoReady, self.video.id)
     self.raise_event(
         Evt.VideoStateUpdated,
         cmd.id,
         self.video.id,
         VideoState.CREATED,
         VideoState.READY,
         timedelta(),
         None,
     )
예제 #28
0
 def test_parsing_to_sub_fetching(self):
     event = Evt.VideoRetrieved(
         IdentityService.random(),
         self.video.id,
         f"{settings['downloader.output_directory']}/video.mp4",
     )
     self.workflow.to_PARSING(event)
     cmd = self.expect_dispatch(Cmd.ParseVideo, self.video.id)
     self.raise_event(
         Evt.VideoParsed,
         cmd.id,
         self.video.id,
         {},
     )
     self.assertTrue(self.workflow.is_SUB_RETRIEVING())
예제 #29
0
 def test_parsing_to_finalizing(self):
     settings["subtitle.enabled"] = False
     event = Evt.VideoRetrieved(
         IdentityService.random(),
         self.video.id,
         f"{settings['downloader.output_directory']}/video.mp4",
     )
     self.workflow.to_PARSING(event)
     cmd = self.expect_dispatch(Cmd.ParseVideo, self.video.id)
     self.raise_event(
         Evt.VideoParsed,
         cmd.id,
         self.video.id,
         {},
     )
     self.assertTrue(self.workflow.is_FINALIZING())
예제 #30
0
    def test_next_loop_last_album_no_album(self):
        collection_id = IdentityService.random()
        self.data_producer.player().video(
            "source1", collection_id=collection_id, state=VideoState.READY
        ).video("source2", state=VideoState.READY).video(
            "source3", state=VideoState.READY
        ).populate(
            self.data_facade
        )

        videos = self.video_repo.list()
        expected = videos[2].id
        self.assertEqual(
            expected,
            self.service.next_video(self.queue_id, videos[2].id, loop_last="album"),
        )