File size: 12,375 Bytes
b293d47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20ae1f7
5773816
 
b293d47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import os
import re
import shutil

import gradio as gr

from gui.asset_components import AssetComponentsUtils
from gui.ui_abstract_component import AbstractComponentUI
from shortGPT.config.asset_db import AssetDatabase, AssetType


class AssetLibrary(AbstractComponentUI):
    def __init__(self):
        pass

    def create_ui(self):
        '''Create the asset library UI'''
        with gr.Tab("Asset library") as asset_library_ui:
            with gr.Column():
                with gr.Accordion("βž• Add your own local assets or from Youtube", open=False) as accordion:
                    remote = "Add youtube video / audio"
                    local = "Add local video / audio / image    "
                    assetFlows = gr.Radio([remote, local], label="", value=remote)
                    with gr.Column(visible=True) as youtubeFlow:
                        asset_name = gr.Textbox(label="Name (required)")
                        asset_type = gr.Radio([AssetType.BACKGROUND_VIDEO.value, AssetType.BACKGROUND_MUSIC.value,], value=AssetType.BACKGROUND_VIDEO.value, label="Type")
                        youtube_url = gr.Textbox(label="URL (https://youtube.com/xyz)")
                        add_youtube_link = gr.Button("ADD")

                    with gr.Column(visible=False) as localFileFlow:
                        local_upload_name = gr.Textbox(label="Name (required)")
                        upload_type = gr.Radio([AssetType.BACKGROUND_VIDEO.value, AssetType.BACKGROUND_MUSIC.value, AssetType.IMAGE.value], value="background video", interactive=True, label="Type")
                        video_upload = gr.Video(visible=True, sources=["upload"], interactive=True)
                        audio_upload = gr.Audio(visible=False, sources=["upload"], type="filepath", interactive=True)
                        image_upload = gr.Image(visible=False, sources=["upload"], type="filepath", interactive=True)
                        upload_button = gr.Button("ADD")
                        upload_type.change(lambda x: (gr.update(visible='video' in x),
                                                      gr.update(visible=any(type in x for type in ['audio', 'music'])),
                                                      gr.update(visible=x == 'image')),
                                           [upload_type], [video_upload, audio_upload, image_upload])
                    assetFlows.change(lambda x: (gr.update(visible=x == remote), gr.update(visible=x == local)), [assetFlows], [youtubeFlow, localFileFlow])
                with gr.Row():
                    with gr.Column(scale=3):
                        asset_dataframe_ui = gr.Dataframe(self.__fulfill_df, interactive=False)
                        video_choise = gr.Radio(["background video", "background music"], value="background video", label="Type")
                    with gr.Column(scale=2):
                        gr.Markdown("Preview")
                        asset_preview_ui = gr.HTML(self.__get_first_preview)
                        delete_button = gr.Button("πŸ—‘οΈ Delete", scale=0, variant="primary")
                        delete_button.click(self.__delete_clicked, [delete_button], [asset_dataframe_ui, asset_preview_ui, delete_button, AssetComponentsUtils.background_video_checkbox(), AssetComponentsUtils.background_music_checkbox()])
                        asset_dataframe_ui.select(self.__preview_asset, [asset_dataframe_ui], [asset_preview_ui, delete_button])

                add_youtube_link.click(
                    self.__verify_youtube_asset_inputs, [asset_name, youtube_url, asset_type], []).success(self.__add_youtube_asset, [asset_name, youtube_url, asset_type], [asset_dataframe_ui, asset_preview_ui, delete_button, accordion, AssetComponentsUtils.background_video_checkbox(), AssetComponentsUtils.background_music_checkbox()]).success(lambda: gr.update(open=False), [accordion])

                upload_button.click(
                    self.__verify_and_upload_local_asset, [upload_type, local_upload_name, video_upload, audio_upload, image_upload, ], []).success(self.__upload_local_asset, [upload_type, local_upload_name, video_upload, audio_upload, image_upload, ], [asset_dataframe_ui, asset_preview_ui, delete_button, accordion, AssetComponentsUtils.background_video_checkbox(), AssetComponentsUtils.background_music_checkbox()]).success(lambda: gr.update(open=False), [accordion])

        return asset_library_ui

    def __fulfill_df(self):
        '''Get the dataframe of assets'''
        return AssetDatabase.get_df()

    def __verify_youtube_asset_inputs(self, asset_name, yt_url, type):
        if not asset_name or not re.match("^[A-Za-z0-9 _-]*$", asset_name):
            raise gr.Error('Invalid asset name. Please provide a valid name that you will recognize (Only use letters and numbers)')
        if not yt_url.startswith("https://youtube.com/") and not yt_url.startswith("https://www.youtube.com/"):
            raise gr.Error('Invalid YouTube URL. Please provide a valid URL.')
        if AssetDatabase.asset_exists(asset_name):
            raise gr.Error('An asset already exists with this name, please choose a different name.')

    def __validate_asset_name(self, asset_name):
        '''Validate asset name'''
        if not asset_name or not re.match("^[A-Za-z0-9 _-]*$", asset_name):
            raise gr.Error('Invalid asset name. Please provide a valid name that you will recognize (Only use letters and numbers)')
        if AssetDatabase.asset_exists(asset_name):
            raise gr.Error('An asset already exists with this name, please choose a different name.')

    def __validate_youtube_url(self, yt_url):
        '''Validate YouTube URL'''
        if not yt_url.startswith("https://youtube.com/") and not yt_url.startswith("https://www.youtube.com/"):
            raise gr.Error('Invalid YouTube URL. Please provide a valid URL.')

    def __verify_and_add_youtube_asset(self, asset_name, yt_url, type):
        '''Verify and add a youtube asset to the database'''
        self.__validate_asset_name(asset_name)
        self.__validate_youtube_url(yt_url)
        return self.__add_youtube_asset(asset_name, yt_url, type)

    def __add_youtube_asset(self, asset_name, yt_url, type):
        '''Add a youtube asset'''
        AssetDatabase.add_remote_asset(asset_name, AssetType(type), yt_url)
        latest_df = AssetDatabase.get_df()
        return gr.DataFrame.update(value=latest_df), gr.HTML.update(value=self.__get_asset_embed(latest_df, 0)),\
            gr.update(value=f"πŸ—‘οΈ Delete {latest_df.iloc[0]['name']}"),\
            gr.Accordion.update(open=False),\
            gr.CheckboxGroup.update(choices=AssetComponentsUtils.getBackgroundVideoChoices(), interactive=True),\
            gr.CheckboxGroup.update(choices=AssetComponentsUtils.getBackgroundMusicChoices(), interactive=True)

    def __get_first_preview(self):
        '''Get the first preview'''
        return self.__get_asset_embed(AssetDatabase.get_df(), 0)

    def __delete_clicked(self, button_name):
        '''Delete an asset'''
        asset_name = button_name.split("πŸ—‘οΈ Delete ")[-1]
        AssetDatabase.remove_asset(asset_name)
        data = AssetDatabase.get_df()
        if len(data) > 0:
            return gr.update(value=data),\
                gr.HTML.update(value=self.__get_asset_embed(data, 0)),\
                gr.update(value=f"πŸ—‘οΈ Delete {data.iloc[0]['name']}"),\
                gr.CheckboxGroup.update(choices=AssetComponentsUtils.getBackgroundVideoChoices(), interactive=True),\
                gr.CheckboxGroup.update(choices=AssetComponentsUtils.getBackgroundMusicChoices(), interactive=True)
        return gr.Dataframe.update(value=data),\
            gr.HTML.update(visible=True),\
            gr.Button.update(value="πŸ—‘οΈ Delete"),\
            gr.CheckboxGroup.update(choices=AssetComponentsUtils.getBackgroundVideoChoices(), interactive=True),\
            gr.CheckboxGroup.update(choices=AssetComponentsUtils.getBackgroundMusicChoices(), interactive=True)

    def __preview_asset(self, data, evt: gr.SelectData):
        '''Preview the asset with the given name'''
        html_embed = self.__get_asset_embed(data, evt.index[0])
        return gr.HTML.update(value=html_embed), gr.update(value=f"πŸ—‘οΈ Delete {data.iloc[evt.index[0]]['name']}")

    def __get_asset_embed(self, data, row):
        '''Get the embed html for the asset at the given row'''
        embed_height = 300
        embed_width = 300
        asset_link = data.iloc[row]['link']

        if 'youtube.com' in asset_link:
            asset_link_split = asset_link.split('?v=')
            if asset_link_split[0] == asset_link:
                asset_link_split = asset_link.split('/')
                # if the last character is a /, remove it
                if asset_link_split[-1] == '/':
                    asset_link_split = asset_link_split[:-1]
                asset_link_split = asset_link_split[-1]
            else:
                asset_link_split = asset_link_split[-1]
            asset_link = f"https://youtube.com/embed/{asset_link_split}"
            embed_html = f'<iframe width="{embed_width}" height="{embed_height}" src="{asset_link}"></iframe>'
        elif 'public/' in asset_link:
            asset_link = f"http://localhost:31415/file={asset_link}"
            file_ext = asset_link.split('.')[-1]

            if file_ext in ['mp3', 'wav', 'ogg']:
                audio_type = 'audio/mpeg' if file_ext == 'mp3' else f'audio/{file_ext}'
                embed_html = f'<audio controls><source src="{asset_link}" type="{audio_type}">Your browser does not support the audio tag.</audio>'
            elif file_ext in ['mp4', 'webm', 'ogg', 'mov']:
                video_type = 'video/mp4' if file_ext == 'mp4' else f'video/{file_ext}'
                embed_html = f'<video width="{embed_width}" height="{embed_height}" style="max-height: 100%;" controls><source src="{asset_link}" type="{video_type}">Your browser does not support the video tag.</video>'
            elif file_ext in ['jpg', 'jpeg', 'png', 'gif']:
                embed_html = f'<img src="{asset_link}" width="{embed_width}" height="{embed_height}">'
            else:
                embed_html = 'Unsupported file type'
        return embed_html

    @staticmethod
    def __clean_filename(filename):
        '''Clean the filename'''
        return re.sub('[\\\\/:*?"<>|]', '', filename)

    def __verify_and_upload_local_asset(self, upload_type, upload_name, video_path, audio_path, image_path):
        '''Verify and upload a local asset to the database'''
        self.__validate_asset_name(upload_name)
        path_dict = {
            AssetType.VIDEO.value: video_path,
            AssetType.BACKGROUND_VIDEO.value: video_path,
            AssetType.AUDIO.value: audio_path,
            AssetType.BACKGROUND_MUSIC.value: audio_path,
            AssetType.IMAGE.value: image_path
        }
        if not os.path.exists(path_dict[upload_type]):
            raise gr.Error(f'The file does not exist at the given path.')
        return self.__upload_local_asset(upload_type, upload_name, video_path, audio_path, image_path)

    def __upload_local_asset(self, upload_type, upload_name, video_path, audio_path, image_path):
        '''Upload a local asset to the database'''
        path_dict = {
            AssetType.VIDEO.value: video_path,
            AssetType.BACKGROUND_VIDEO.value: video_path,
            AssetType.AUDIO.value: audio_path,
            AssetType.BACKGROUND_MUSIC.value: audio_path,
            AssetType.IMAGE.value: image_path
        }
        new_path = "public/" + self.__clean_filename(upload_name) + "." + path_dict[upload_type].split(".")[-1]
        shutil.move(path_dict[upload_type], new_path)
        AssetDatabase.add_local_asset(upload_name, AssetType(upload_type), new_path)
        latest_df = AssetDatabase.get_df()
        return gr.DataFrame.update(value=latest_df), gr.HTML.update(value=self.__get_asset_embed(latest_df, 0)),\
            gr.update(value=f"πŸ—‘οΈ Delete {latest_df.iloc[0]['name']}"),\
            gr.Accordion.update(open=False),\
            gr.CheckboxGroup.update(choices=AssetComponentsUtils.getBackgroundVideoChoices(), interactive=True),\
            gr.CheckboxGroup.update(choices=AssetComponentsUtils.getBackgroundMusicChoices(), interactive=True)