mirror of
https://github.com/Paillat-dev/viralfactory.git
synced 2026-01-02 09:16:19 +00:00
Add UploadEngine and its dependencies
This commit is contained in:
12
src/engines/UploadEngine/BaseUploadEngine.py
Normal file
12
src/engines/UploadEngine/BaseUploadEngine.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
from .. import BaseEngine
|
||||||
|
|
||||||
|
|
||||||
|
class BaseUploadEngine(BaseEngine):
|
||||||
|
def __init__(self, **kwargs) -> None:
|
||||||
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def upload(self):
|
||||||
|
...
|
||||||
75
src/engines/UploadEngine/TikTokUploadEngine.py
Normal file
75
src/engines/UploadEngine/TikTokUploadEngine.py
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import gradio as gr
|
||||||
|
|
||||||
|
from tiktok_uploader.upload import upload_video
|
||||||
|
|
||||||
|
from .BaseUploadEngine import BaseUploadEngine
|
||||||
|
|
||||||
|
|
||||||
|
class TikTokUploadEngine(BaseUploadEngine):
|
||||||
|
name = "TikTokUpload"
|
||||||
|
description = "Upload to TikTok"
|
||||||
|
|
||||||
|
num_options = 1
|
||||||
|
|
||||||
|
def __init__(self, options) -> None:
|
||||||
|
self.hashtags = options[0]
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def upload(self):
|
||||||
|
cookies = self.get_setting(type="cookies")["cookies"]
|
||||||
|
if cookies == None:
|
||||||
|
gr.Warning(
|
||||||
|
"Skipping upload to TikTok because no cookies were provided. Please provide cookies in the settings."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
title: str = self.ctx.title
|
||||||
|
description: str = self.ctx.description
|
||||||
|
hastags = self.hashtags.strip().split(" ")
|
||||||
|
|
||||||
|
# extract any hashtags from the description / title and remove them from the description
|
||||||
|
for word in title.split():
|
||||||
|
if word.startswith("#"):
|
||||||
|
hastags.append(word)
|
||||||
|
title = title.replace(word, "")
|
||||||
|
for word in description.split():
|
||||||
|
if word.startswith("#"):
|
||||||
|
hastags.append(word)
|
||||||
|
description = description.replace(word, "")
|
||||||
|
|
||||||
|
title = title.strip()
|
||||||
|
description = description.strip()
|
||||||
|
hastags_str = " ".join(hastags) + " " if hastags else ""
|
||||||
|
failed = upload_video(
|
||||||
|
filename=self.ctx.get_file_path("final.mp4"),
|
||||||
|
description=f"{title} {description} {hastags_str}",
|
||||||
|
cookies_str=cookies,
|
||||||
|
browser="firefox",
|
||||||
|
)
|
||||||
|
for _ in failed:
|
||||||
|
gr.Error(f"Failed to upload to TikTok")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_options(cls):
|
||||||
|
hashtags = gr.Textbox(label="hashtags", type="text", value="#fyp #foryou")
|
||||||
|
return [hashtags]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_settings(cls):
|
||||||
|
current_settings = cls.get_setting(type="cookies") or {"cookies": ""}
|
||||||
|
gr.Markdown(
|
||||||
|
"Input your TikTok session cookies. You can get them as shown [here](https://github.com/wkaisertexas/tiktok-uploader?tab=readme-ov-file#authentication)."
|
||||||
|
)
|
||||||
|
cookies_input = gr.Textbox(
|
||||||
|
lines=20,
|
||||||
|
max_lines=50,
|
||||||
|
label="cookies",
|
||||||
|
type="text",
|
||||||
|
value=current_settings["cookies"],
|
||||||
|
)
|
||||||
|
cookies_save_btn = gr.Button("Save")
|
||||||
|
|
||||||
|
def save(cookies: str):
|
||||||
|
cls.store_setting(type="cookies", data={"cookies": cookies})
|
||||||
|
gr.Info("Cookies saved successfully")
|
||||||
|
|
||||||
|
cookies_save_btn.click(save, inputs=[cookies_input])
|
||||||
115
src/engines/UploadEngine/YouTubeUploadEngine.py
Normal file
115
src/engines/UploadEngine/YouTubeUploadEngine.py
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
import gradio as gr
|
||||||
|
import orjson
|
||||||
|
|
||||||
|
from google_auth_oauthlib.flow import InstalledAppFlow
|
||||||
|
|
||||||
|
from . import BaseUploadEngine
|
||||||
|
from ...utils import youtube_uploading
|
||||||
|
|
||||||
|
class YouTubeUploadEngine(BaseUploadEngine):
|
||||||
|
name = "YouTube"
|
||||||
|
description = "Upload videos to YouTube"
|
||||||
|
|
||||||
|
num_options = 2
|
||||||
|
|
||||||
|
def __init__(self, options: list):
|
||||||
|
self.oauth_name = options[0]
|
||||||
|
self.oauth = self.retrieve_setting(type="oauth_credentials")[self.oauth_name]
|
||||||
|
self.credentials = self.retrieve_setting(type="youtube_client_secrets")[self.oauth["client_secret"]]
|
||||||
|
|
||||||
|
self.hashtags = options[1]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __oauth(cls, credentials):
|
||||||
|
flow = InstalledAppFlow.from_client_config(
|
||||||
|
credentials, scopes=["https://www.googleapis.com/auth/youtube.upload"]
|
||||||
|
)
|
||||||
|
user_credentials = flow.run_local_server(
|
||||||
|
success_message="Heyy, yippie, you're authenticated ! You can close this window now !",
|
||||||
|
authorization_prompt_message="Please authorize this app to upload videos on your YouTube account !",
|
||||||
|
)
|
||||||
|
|
||||||
|
result = user_credentials.to_json()
|
||||||
|
if isinstance(result, str):
|
||||||
|
result = orjson.loads(result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def upload(self):
|
||||||
|
options = {
|
||||||
|
"file": self.ctx.get_file_path("final.mp4"),
|
||||||
|
"title": self.ctx.title + " | " + self.hashtags,
|
||||||
|
"description": self.ctx.description,
|
||||||
|
"privacyStatus": "private",
|
||||||
|
"category": 28,
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
youtube_uploading.upload(self.oauth["credentials"], options)
|
||||||
|
except Exception as e:
|
||||||
|
#this means we need to re-authenticate likely
|
||||||
|
# use self.__oauth to re-authenticate
|
||||||
|
new_oauth = self.__oauth(self.credentials)
|
||||||
|
#also update the credentials in the settings
|
||||||
|
current_oauths = self.retrieve_setting(type="oauth_credentials") or {}
|
||||||
|
current_oauths[self.oauth_name] = {
|
||||||
|
"client_secret": self.oauth["client_secret"],
|
||||||
|
"credentials": new_oauth
|
||||||
|
}
|
||||||
|
self.store_setting(
|
||||||
|
type="oauth_credentials",
|
||||||
|
data=current_oauths,
|
||||||
|
)
|
||||||
|
self.oauth = current_oauths[self.oauth_name]
|
||||||
|
youtube_uploading.upload(self.oauth["credentials"], options)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_options(cls):
|
||||||
|
choices = cls.retrieve_setting(type="oauth_credentials") or {}
|
||||||
|
choices = list(choices.keys())
|
||||||
|
return [
|
||||||
|
gr.Dropdown(
|
||||||
|
choices=choices, label="Choose Channel", value=choices[0] if choices else "No channels available !"
|
||||||
|
),
|
||||||
|
gr.Textbox(label="Hashtags", value="#shorts", max_lines=1),
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_settings(cls):
|
||||||
|
with gr.Row():
|
||||||
|
with gr.Column() as ytb_secret:
|
||||||
|
clien_secret_name = gr.Textbox(label="Name", max_lines=1)
|
||||||
|
client_secret_file = gr.File(
|
||||||
|
label="Client Secret File", file_types=["json"], type="binary"
|
||||||
|
)
|
||||||
|
submit_button = gr.Button("Save")
|
||||||
|
def save(binary, clien_secret_name):
|
||||||
|
current_client_secrets = cls.retrieve_setting(type="youtube_client_secrets") or {}
|
||||||
|
client_secret_json = orjson.loads(binary)
|
||||||
|
current_client_secrets[clien_secret_name] = client_secret_json
|
||||||
|
cls.store_setting(
|
||||||
|
type="youtube_client_secrets",
|
||||||
|
data=current_client_secrets,
|
||||||
|
)
|
||||||
|
gr.Info(f"{clien_secret_name} saved successfully !")
|
||||||
|
|
||||||
|
submit_button.click(save, inputs=[client_secret_file, clien_secret_name])
|
||||||
|
|
||||||
|
with gr.Column() as ytb_oauth:
|
||||||
|
possible_client_secrets = cls.retrieve_setting(type="youtube_client_secrets") or {}
|
||||||
|
possible_client_secrets = list(possible_client_secrets.keys())
|
||||||
|
choosen_client_secret = gr.Dropdown(label="Login secret", choices=possible_client_secrets)
|
||||||
|
name = gr.Textbox(label="Name", max_lines=1)
|
||||||
|
login_button = gr.Button("Login", variant="primary")
|
||||||
|
def login(choosen_client_secret, name):
|
||||||
|
choosen_secret_data = cls.retrieve_setting(type="youtube_client_secrets")[choosen_client_secret]
|
||||||
|
new_oauth_entry = cls.__oauth(choosen_secret_data)
|
||||||
|
current_oauths = cls.retrieve_setting(type="oauth_credentials") or {}
|
||||||
|
current_oauths[name] = {
|
||||||
|
"client_secret": choosen_client_secret,
|
||||||
|
"credentials": new_oauth_entry
|
||||||
|
}
|
||||||
|
cls.store_setting(
|
||||||
|
type="oauth_credentials",
|
||||||
|
data=current_oauths,
|
||||||
|
)
|
||||||
|
gr.Info(f"{name} saved successfully !")
|
||||||
|
login_button.click(login, inputs=[choosen_client_secret, name])
|
||||||
3
src/engines/UploadEngine/__init__.py
Normal file
3
src/engines/UploadEngine/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from .BaseUploadEngine import BaseUploadEngine
|
||||||
|
from .TikTokUploadEngine import TikTokUploadEngine
|
||||||
|
from .YouTubeUploadEngine import YouTubeUploadEngine
|
||||||
@@ -9,6 +9,7 @@ from . import AssetsEngine
|
|||||||
from . import SettingsEngine
|
from . import SettingsEngine
|
||||||
from . import BackgroundEngine
|
from . import BackgroundEngine
|
||||||
from . import MetadataEngine
|
from . import MetadataEngine
|
||||||
|
from . import UploadEngine
|
||||||
|
|
||||||
|
|
||||||
class EngineDict(TypedDict):
|
class EngineDict(TypedDict):
|
||||||
@@ -38,7 +39,7 @@ ENGINES: dict[str, EngineDict] = {
|
|||||||
"multiple": False,
|
"multiple": False,
|
||||||
},
|
},
|
||||||
"TTSEngine": {
|
"TTSEngine": {
|
||||||
"classes": [TTSEngine.CoquiTTSEngine, TTSEngine.ElevenLabsTTSEngine],
|
"classes": [TTSEngine.CoquiTTSEngine],
|
||||||
"multiple": False,
|
"multiple": False,
|
||||||
},
|
},
|
||||||
"CaptioningEngine": {
|
"CaptioningEngine": {
|
||||||
@@ -46,7 +47,11 @@ ENGINES: dict[str, EngineDict] = {
|
|||||||
"multiple": False,
|
"multiple": False,
|
||||||
},
|
},
|
||||||
"AssetsEngine": {
|
"AssetsEngine": {
|
||||||
"classes": [AssetsEngine.DallEAssetsEngine, NoneEngine],
|
"classes": [
|
||||||
|
AssetsEngine.DallEAssetsEngine,
|
||||||
|
AssetsEngine.GoogleAssetsEngine,
|
||||||
|
NoneEngine,
|
||||||
|
],
|
||||||
"multiple": True,
|
"multiple": True,
|
||||||
},
|
},
|
||||||
"BackgroundEngine": {
|
"BackgroundEngine": {
|
||||||
@@ -57,4 +62,8 @@ ENGINES: dict[str, EngineDict] = {
|
|||||||
"classes": [MetadataEngine.ShortsMetadataEngine],
|
"classes": [MetadataEngine.ShortsMetadataEngine],
|
||||||
"multiple": False,
|
"multiple": False,
|
||||||
},
|
},
|
||||||
|
"UploadEngine": {
|
||||||
|
"classes": [UploadEngine.TikTokUploadEngine, UploadEngine.YouTubeUploadEngine, NoneEngine],
|
||||||
|
"multiple": True,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user