From 11dc370ed9d5ba5049af8bd74356e720fff0fef3 Mon Sep 17 00:00:00 2001 From: Roland Date: Fri, 4 Oct 2024 16:32:48 -0600 Subject: [PATCH] Channel can be created with Tag. --- app/src/components/Channels.js | 138 +++++++++++++----------- app/src/hooks/customHooks.js | 1 + modules/videos/channel/test/test_api.py | 20 ++++ modules/videos/schema.py | 3 +- 4 files changed, 99 insertions(+), 63 deletions(-) diff --git a/app/src/components/Channels.js b/app/src/components/Channels.js index 6a728582..cf0a4790 100644 --- a/app/src/components/Channels.js +++ b/app/src/components/Channels.js @@ -100,7 +100,7 @@ function ChannelPage({create, header}) { const {channel, changeValue, fetchChannel} = useChannel(channelId); const {SingleTag} = React.useContext(TagsContext); - const [tagModalOpen, setTagModalOpen] = useState(false); + const [tagEditModalOpen, setTagEditModalOpen] = useState(false); const [newTagName, setNewTagName] = useState(channel ? channel.tag_name : null); const [moveToTagDirectory, setMoveToTagDirectory] = useState(true); const [newTagDirectory, setNewTagDirectory] = useState(''); @@ -147,6 +147,7 @@ function ChannelPage({create, header}) { name: channel.name, directory: channel.directory, url: channel.url, + tag_name: channel.tag_name, }; setDisabled(true); @@ -252,13 +253,13 @@ function ChannelPage({create, header}) { if (e) { e.preventDefault(); } - setTagModalOpen(true); + setTagEditModalOpen(true); } - const handleTagChannel = async () => { + const handleTagEditChannel = async () => { try { await tagChannel(channelId, newTagName, moveToTagDirectory ? newTagDirectory : null); - setTagModalOpen(false); + setTagEditModalOpen(false); } catch (e) { console.error('Failed to tag channel', e); } finally { @@ -269,9 +270,10 @@ function ChannelPage({create, header}) { } } - const handleTagSelect = async (newTagName_) => { + const handleTagSelectMoveSuggestion = async (newTagName_) => { setNewTagName(newTagName_); try { + // Get suggested Tag directory for this Tag and Channel. const videosDestination = await tagChannelInfo(channelId, newTagName_); setNewTagDirectory(videosDestination); } catch (e) { @@ -279,53 +281,57 @@ function ChannelPage({create, header}) { } } - const tagModal = setTagModalOpen(false)} - closeIcon - > - {channel.tag_name ? 'Modify Tag' : 'Add Tag'} - - - - - handleTagSelect(null)} - /> - - - - - - - - - - setNewTagDirectory(value)} - disabled={!moveToTagDirectory} - /> - - - - - - - Save - - ; + let tagEditModal; + if (!create) { + // User is editing the Tag of the Channel. + tagEditModal = setTagEditModalOpen(false)} + closeIcon + > + {channel.tag_name ? 'Modify Tag' : 'Add Tag'} + + + + + handleTagSelectMoveSuggestion(null)} + /> + + + + + + + + + + setNewTagDirectory(value)} + disabled={!moveToTagDirectory} + /> + + + + + + + Save + + ; + } return <> @@ -383,7 +389,7 @@ function ChannelPage({create, header}) { - {channel.tag_name && } + {channel.tag_name && !create && } - - - {!create && + + + {!create ? <> Refresh + + {tagEditModal} + + : <> + changeValue('tag_name', i)} + onRemove={() => changeValue('tag_name', null)} + /> } - - {tagModal} { url: '', download_frequency: '', match_regex: '', + tag_name: null, }; const [fetched, setFetched] = useState(false); const [channel, setChannel] = useState(emptyChannel); diff --git a/modules/videos/channel/test/test_api.py b/modules/videos/channel/test/test_api.py index f17a153a..fa85e7b0 100644 --- a/modules/videos/channel/test/test_api.py +++ b/modules/videos/channel/test/test_api.py @@ -549,6 +549,26 @@ async def test_tag_channel(async_client, test_session, test_directory, channel_f assert [i.path for i in test_session.query(Directory)] == [channel.directory, ] +@pytest.mark.asyncio +async def test_create_channel_with_tag(async_client, test_session, test_directory, tag_factory): + """A Channel can be created with a single Tag.""" + tag = await tag_factory() + assert not (test_directory / 'some/deep/new/directory').exists() + + body = dict( + name='Channel Name', + directory='some/deep/new/directory', + tag_name=tag.name, + ) + request, response = await async_client.post('/api/videos/channels', json=body) + assert response.status_code == HTTPStatus.CREATED, response.content.decode() + + channel = test_session.query(Channel).one() + assert channel.tag_name == tag.name + assert channel.directory == (test_directory / 'some/deep/new/directory') + assert (test_directory / 'some/deep/new/directory').is_dir() + + @pytest.mark.asyncio async def test_move_channel(async_client, test_session, test_directory, channel_factory, tag_factory, video_factory, test_channels_config, test_download_manager, test_downloader): diff --git a/modules/videos/schema.py b/modules/videos/schema.py index a8b82a47..00c859f8 100644 --- a/modules/videos/schema.py +++ b/modules/videos/schema.py @@ -11,8 +11,9 @@ class ChannelPostRequest: directory: str calculate_duration: Optional[bool] = None generate_posters: Optional[bool] = None - url: Optional[str] = None source_id: Optional[str] = None + tag_name: Optional[str] = None + url: Optional[str] = None def __post_init__(self): self.name = self.name.strip() or None