feat: Intial POC of GoodGames
Includes basic Video editing, OBS intergration, game detecting and clip editor
This commit is contained in:
parent
1530a5aa10
commit
16fa81d5af
2
.gitignore
vendored
2
.gitignore
vendored
@ -138,3 +138,5 @@ dmypy.json
|
|||||||
# Cython debug symbols
|
# Cython debug symbols
|
||||||
cython_debug/
|
cython_debug/
|
||||||
|
|
||||||
|
|
||||||
|
credentials.storage
|
@ -0,0 +1 @@
|
|||||||
|
{"API_TOKEN_KEYS": "<YOUTUBE_API_TOKEN_HERE>"}
|
4
config.toml
Normal file
4
config.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[connection]
|
||||||
|
host = "localhost"
|
||||||
|
port = 4455
|
||||||
|
password = "<OBS_PASSWORD_HERE>"
|
87
main.py
Normal file
87
main.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import sys
|
||||||
|
from video_editor import MainWindow
|
||||||
|
from obs_recorder_and_game_dector import run_bg_app
|
||||||
|
from PySide6.QtCore import QStandardPaths, Qt, Slot, QThread, QTimer, QObject, Signal
|
||||||
|
from PySide6.QtGui import QAction, QIcon, QKeySequence, QScreen
|
||||||
|
from PySide6.QtWidgets import QApplication, QSystemTrayIcon, QMenu, QMainWindow, QLabel, QVBoxLayout, QWidget, QPushButton
|
||||||
|
from PySide6.QtMultimediaWidgets import QVideoWidget
|
||||||
|
|
||||||
|
page_url = None
|
||||||
|
|
||||||
|
class BackgroundThread(QThread):
|
||||||
|
def __init__(self,):
|
||||||
|
super().__init__()
|
||||||
|
def run(self):
|
||||||
|
global page_url
|
||||||
|
# Implement your background service logic here
|
||||||
|
while True:
|
||||||
|
new_video = run_bg_app()
|
||||||
|
|
||||||
|
if new_video is not None:
|
||||||
|
self.sleep(3)
|
||||||
|
page_url = new_video
|
||||||
|
self.open_main_page.emit()
|
||||||
|
|
||||||
|
self.sleep(1) # Sleep for 1 second
|
||||||
|
|
||||||
|
# Define a signal for opening a new main page
|
||||||
|
open_main_page = Signal()
|
||||||
|
|
||||||
|
class MainPage(QMainWindow):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.setWindowTitle("Main Page")
|
||||||
|
self.resize(300, 200)
|
||||||
|
|
||||||
|
# Create a label and a button
|
||||||
|
label = QLabel("Hello, World!")
|
||||||
|
button = QPushButton("Open New Page")
|
||||||
|
|
||||||
|
# Create a layout and set it on a central widget
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
layout.addWidget(label)
|
||||||
|
layout.addWidget(button)
|
||||||
|
|
||||||
|
central_widget = QWidget()
|
||||||
|
central_widget.setLayout(layout)
|
||||||
|
self.setCentralWidget(central_widget)
|
||||||
|
self.new_page = None
|
||||||
|
|
||||||
|
def open_new_page(self):
|
||||||
|
global page_url
|
||||||
|
self.new_page = MainWindow(page_url)
|
||||||
|
self.new_page.show()
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
event.ignore()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
|
||||||
|
tray_icon = QSystemTrayIcon(app)
|
||||||
|
menu = QMenu()
|
||||||
|
|
||||||
|
# Create the main page
|
||||||
|
main_page = MainPage()
|
||||||
|
|
||||||
|
open_main_window = QAction("Open", app)
|
||||||
|
open_main_window.triggered.connect(main_page.open_new_page)
|
||||||
|
menu.addAction(open_main_window)
|
||||||
|
|
||||||
|
exit_action = QAction("Exit", app)
|
||||||
|
exit_action.triggered.connect(app.quit)
|
||||||
|
menu.addAction(exit_action)
|
||||||
|
|
||||||
|
tray_icon.setContextMenu(menu)
|
||||||
|
tray_icon.show()
|
||||||
|
|
||||||
|
# Start the background thread
|
||||||
|
background_thread = BackgroundThread()
|
||||||
|
background_thread.open_main_page.connect(main_page.open_new_page)
|
||||||
|
background_thread.start()
|
||||||
|
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
124
obs_recorder_and_game_dector.py
Normal file
124
obs_recorder_and_game_dector.py
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
import obsws_python as obs
|
||||||
|
import time
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
subprocess.run("obs-studio &",shell=True)
|
||||||
|
time.sleep(5)
|
||||||
|
# pass conn info if not in config.toml
|
||||||
|
cl = obs.ReqClient(host='localhost', port=4455, password='AXB1hYYIeaCUQd9v', timeout=3)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SOURCE_NAME = "..auto_game_dector_source"
|
||||||
|
SCENE_NAME = "..auto_game_dector_scene"
|
||||||
|
SOURCE_INPUT_TYPE = "xcomposite_input"
|
||||||
|
GAMES_WM_CLASS_NAME_TO_DETECT = ["steam_app_1304930",
|
||||||
|
"league of legends.exe",
|
||||||
|
"steam_app_582010",
|
||||||
|
"steam_app_739630",
|
||||||
|
"steam_app_438490",
|
||||||
|
"steam_app_321040",
|
||||||
|
"steam_app_820520"]
|
||||||
|
|
||||||
|
class SceneStatus:
|
||||||
|
OK = 0
|
||||||
|
MISSING_SCENE = 1
|
||||||
|
SCENE_NOT_SELECTED = 2
|
||||||
|
|
||||||
|
class SourceStatus:
|
||||||
|
OK = 0
|
||||||
|
MISSING_SOURCE = 1
|
||||||
|
UNEXPECTED_SOURCES_FOUND = 2
|
||||||
|
SOURCE_NOT_ENABLED = 3
|
||||||
|
SOURCE_NOT_CREATED_WITH_DIFFERENT_VALUES = 4
|
||||||
|
|
||||||
|
|
||||||
|
def verify_obs_setup():
|
||||||
|
scene_status = verify_scene()
|
||||||
|
|
||||||
|
if scene_status is SceneStatus.MISSING_SCENE:
|
||||||
|
init_scene()
|
||||||
|
|
||||||
|
source_status = verify_source()
|
||||||
|
|
||||||
|
if scene_status is SourceStatus.MISSING_SOURCE:
|
||||||
|
init_source()
|
||||||
|
|
||||||
|
def verify_scene() -> SceneStatus:
|
||||||
|
get_scenes_response = cl.get_scene_list()
|
||||||
|
scenes = get_scenes_response.scenes
|
||||||
|
|
||||||
|
for scene in scenes:
|
||||||
|
if scene['sceneName'] == SCENE_NAME:
|
||||||
|
if scene['sceneName'] == get_scenes_response.current_program_scene_name:
|
||||||
|
return SceneStatus.OK
|
||||||
|
else:
|
||||||
|
return SceneStatus.SCENE_NOT_SELECTED
|
||||||
|
|
||||||
|
return SceneStatus.MISSING_SCENE
|
||||||
|
|
||||||
|
def init_scene():
|
||||||
|
cl.create_scene(name=SCENE_NAME)
|
||||||
|
cl.set_current_program_scene(name=SCENE_NAME)
|
||||||
|
|
||||||
|
def verify_source() -> SourceStatus:
|
||||||
|
sources = cl.get_input_list().inputs
|
||||||
|
|
||||||
|
for source in sources:
|
||||||
|
if source['inputName'] == SOURCE_NAME:
|
||||||
|
return SourceStatus.OK
|
||||||
|
|
||||||
|
return SourceStatus.MISSING_SOURCE
|
||||||
|
|
||||||
|
def init_source():
|
||||||
|
cl.create_input(sceneName=SCENE_NAME,inputName=SOURCE_NAME,inputKind=SOURCE_INPUT_TYPE, inputSettings=None, sceneItemEnabled=True)
|
||||||
|
|
||||||
|
def game_dector():
|
||||||
|
windows = cl.get_input_properties_list_property_items(SOURCE_NAME,"capture_window").property_items
|
||||||
|
|
||||||
|
for window in windows:
|
||||||
|
wmClassName = window['itemValue'].split("\r\n")[2]
|
||||||
|
|
||||||
|
if wmClassName in GAMES_WM_CLASS_NAME_TO_DETECT:
|
||||||
|
return window['itemValue']
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
verify_obs_setup()
|
||||||
|
|
||||||
|
recording = cl.get_record_status().output_active
|
||||||
|
|
||||||
|
def run_bg_app():
|
||||||
|
global recording
|
||||||
|
global cl
|
||||||
|
|
||||||
|
game_detected = game_dector()
|
||||||
|
|
||||||
|
if game_detected is None:
|
||||||
|
if recording:
|
||||||
|
cl.stop_record()
|
||||||
|
|
||||||
|
directory_path = cl.get_record_directory()
|
||||||
|
|
||||||
|
list_of_files = glob.glob(directory_path.record_directory + "/*") # * means all if need specific format then *.csv
|
||||||
|
latest_file = max(list_of_files, key=os.path.getctime)
|
||||||
|
print(latest_file)
|
||||||
|
|
||||||
|
recording = False
|
||||||
|
return latest_file
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not recording:
|
||||||
|
cl.set_input_settings(name=SOURCE_NAME, settings={'capture_window': game_detected}, overlay=True)
|
||||||
|
cl.start_record()
|
||||||
|
recording = True
|
||||||
|
return None
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
while True:
|
||||||
|
run_bg_app()
|
||||||
|
time.sleep(1)
|
299
video_editor.py
Normal file
299
video_editor.py
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
import sys
|
||||||
|
from PySide6.QtCore import QStandardPaths, Qt, Slot
|
||||||
|
from PySide6.QtGui import QAction, QIcon, QKeySequence, QScreen
|
||||||
|
from PySide6.QtWidgets import (QApplication, QDialog, QFileDialog,
|
||||||
|
QMainWindow, QSlider, QStyle, QToolBar, QPushButton)
|
||||||
|
from PySide6.QtMultimedia import (QAudio, QAudioOutput, QMediaFormat,
|
||||||
|
QMediaPlayer)
|
||||||
|
from PySide6.QtMultimediaWidgets import QVideoWidget
|
||||||
|
from moviepy.editor import *
|
||||||
|
from youtube_upload import upload_video
|
||||||
|
import uuid
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
|
AVI = "video/x-msvideo" # AVI
|
||||||
|
|
||||||
|
|
||||||
|
MP4 = 'video/mp4'
|
||||||
|
|
||||||
|
|
||||||
|
def get_supported_mime_types():
|
||||||
|
result = []
|
||||||
|
for f in QMediaFormat().supportedFileFormats(QMediaFormat.Decode):
|
||||||
|
mime_type = QMediaFormat(f).mimeType()
|
||||||
|
result.append(mime_type.name())
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow):
|
||||||
|
|
||||||
|
def __init__(self, fileUrl):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self._url = fileUrl
|
||||||
|
|
||||||
|
self._playlist = [] # FIXME 6.3: Replace by QMediaPlaylist?
|
||||||
|
self._playlist_index = -1
|
||||||
|
self._audio_output = QAudioOutput()
|
||||||
|
self._player = QMediaPlayer()
|
||||||
|
self._player.setAudioOutput(self._audio_output)
|
||||||
|
|
||||||
|
self._player.errorOccurred.connect(self._player_error)
|
||||||
|
|
||||||
|
tool_bar = QToolBar()
|
||||||
|
self.addToolBar(tool_bar)
|
||||||
|
|
||||||
|
file_menu = self.menuBar().addMenu("&File")
|
||||||
|
icon = QIcon.fromTheme("document-open")
|
||||||
|
open_action = QAction(icon, "&Open...", self,
|
||||||
|
shortcut=QKeySequence.Open, triggered=self.open)
|
||||||
|
file_menu.addAction(open_action)
|
||||||
|
tool_bar.addAction(open_action)
|
||||||
|
icon = QIcon.fromTheme("application-exit")
|
||||||
|
exit_action = QAction(icon, "E&xit", self,
|
||||||
|
shortcut="Ctrl+Q", triggered=self.close)
|
||||||
|
file_menu.addAction(exit_action)
|
||||||
|
|
||||||
|
play_menu = self.menuBar().addMenu("&Play")
|
||||||
|
style = self.style()
|
||||||
|
icon = QIcon.fromTheme("media-playback-start.png",
|
||||||
|
style.standardIcon(QStyle.SP_MediaPlay))
|
||||||
|
self._play_action = tool_bar.addAction(icon, "Play")
|
||||||
|
self._play_action.triggered.connect(self._player.play)
|
||||||
|
play_menu.addAction(self._play_action)
|
||||||
|
|
||||||
|
icon = QIcon.fromTheme("media-skip-backward-symbolic.svg",
|
||||||
|
style.standardIcon(QStyle.SP_MediaSkipBackward))
|
||||||
|
self._previous_action = tool_bar.addAction(icon, "Previous")
|
||||||
|
self._previous_action.triggered.connect(self.previous_clicked)
|
||||||
|
play_menu.addAction(self._previous_action)
|
||||||
|
|
||||||
|
icon = QIcon.fromTheme("media-playback-pause.png",
|
||||||
|
style.standardIcon(QStyle.SP_MediaPause))
|
||||||
|
self._pause_action = tool_bar.addAction(icon, "Pause")
|
||||||
|
self._pause_action.triggered.connect(self._player.pause)
|
||||||
|
play_menu.addAction(self._pause_action)
|
||||||
|
|
||||||
|
icon = QIcon.fromTheme("media-skip-forward-symbolic.svg",
|
||||||
|
style.standardIcon(QStyle.SP_MediaSkipForward))
|
||||||
|
self._next_action = tool_bar.addAction(icon, "Next")
|
||||||
|
self._next_action.triggered.connect(self.next_clicked)
|
||||||
|
play_menu.addAction(self._next_action)
|
||||||
|
|
||||||
|
icon = QIcon.fromTheme("media-playback-stop.png",
|
||||||
|
style.standardIcon(QStyle.SP_MediaStop))
|
||||||
|
self._stop_action = tool_bar.addAction(icon, "Stop")
|
||||||
|
self._stop_action.triggered.connect(self._ensure_stopped)
|
||||||
|
play_menu.addAction(self._stop_action)
|
||||||
|
|
||||||
|
self._scrub_slider = QSlider()
|
||||||
|
self._scrub_slider.setOrientation(Qt.Horizontal)
|
||||||
|
self._scrub_slider.setMinimum(0)
|
||||||
|
self._scrub_slider.setMaximum(100)
|
||||||
|
available_width = self.screen().availableGeometry().width()
|
||||||
|
self._scrub_slider.setFixedWidth(available_width / 8)
|
||||||
|
#self._scrub_slider.setValue(self._audio_output.volume())
|
||||||
|
self._scrub_slider.setTickInterval(10)
|
||||||
|
#self._scrub_slider.setTickPosition(QSlider.TicksBelow)
|
||||||
|
self._scrub_slider.setToolTip("Scrub")
|
||||||
|
self._scrub_slider.sliderMoved.connect(self.set_position)
|
||||||
|
tool_bar.addWidget(self._scrub_slider)
|
||||||
|
|
||||||
|
self._audio_output.setVolume(10)
|
||||||
|
self._volume_slider = QSlider()
|
||||||
|
self._volume_slider.setOrientation(Qt.Horizontal)
|
||||||
|
self._volume_slider.setMinimum(0)
|
||||||
|
self._volume_slider.setMaximum(100)
|
||||||
|
available_width = self.screen().availableGeometry().width()
|
||||||
|
self._volume_slider.setFixedWidth(available_width / 10)
|
||||||
|
self._volume_slider.setValue(self._audio_output.volume())
|
||||||
|
self._volume_slider.setTickInterval(10)
|
||||||
|
self._volume_slider.setTickPosition(QSlider.TicksBelow)
|
||||||
|
self._volume_slider.setToolTip("Volume")
|
||||||
|
self._volume_slider.valueChanged.connect(self.volume_change)
|
||||||
|
tool_bar.addWidget(self._volume_slider)
|
||||||
|
|
||||||
|
self._15SecondClip = QPushButton()
|
||||||
|
self._15SecondClip.setText("+ 15 Clip")
|
||||||
|
self._15SecondClip.setToolTip("+15 Second Clip")
|
||||||
|
self._15SecondClip.pressed.connect(self.clip_15_seconds)
|
||||||
|
tool_bar.addWidget(self._15SecondClip)
|
||||||
|
|
||||||
|
self._30SecondClip = QPushButton()
|
||||||
|
self._30SecondClip.setText("+ 30 Clip")
|
||||||
|
self._30SecondClip.setToolTip("+30 Second Clip")
|
||||||
|
self._30SecondClip.pressed.connect(self.clip_30_seconds)
|
||||||
|
tool_bar.addWidget(self._30SecondClip)
|
||||||
|
|
||||||
|
self._60SecondClip = QPushButton()
|
||||||
|
self._60SecondClip.setText("+ 60 Clip")
|
||||||
|
self._60SecondClip.setToolTip("+60 Second Clip")
|
||||||
|
self._60SecondClip.pressed.connect(self.clip_60_seconds)
|
||||||
|
tool_bar.addWidget(self._60SecondClip)
|
||||||
|
|
||||||
|
self._upload = QPushButton()
|
||||||
|
self._upload.setText("YT")
|
||||||
|
self._upload.setToolTip("yt")
|
||||||
|
self._upload.pressed.connect(self.upload_video_youtube)
|
||||||
|
tool_bar.addWidget(self._upload)
|
||||||
|
|
||||||
|
self._copy = QPushButton()
|
||||||
|
self._copy.setText("Copy")
|
||||||
|
self._copy.setToolTip("Copy")
|
||||||
|
self._copy.pressed.connect(self.copy)
|
||||||
|
tool_bar.addWidget(self._copy)
|
||||||
|
|
||||||
|
about_menu = self.menuBar().addMenu("&About")
|
||||||
|
about_qt_act = QAction("About &Qt", self, triggered=qApp.aboutQt)
|
||||||
|
about_menu.addAction(about_qt_act)
|
||||||
|
|
||||||
|
self._video_widget = QVideoWidget()
|
||||||
|
self.setCentralWidget(self._video_widget)
|
||||||
|
self._player.playbackStateChanged.connect(self.update_buttons)
|
||||||
|
self._player.setVideoOutput(self._video_widget)
|
||||||
|
|
||||||
|
self.update_buttons(self._player.playbackState())
|
||||||
|
self._mime_types = []
|
||||||
|
|
||||||
|
self._player.positionChanged.connect(self.position_changed)
|
||||||
|
self._player.durationChanged.connect(self.duration_changed)
|
||||||
|
|
||||||
|
if self._url is not None:
|
||||||
|
self._playlist.append(self._url )
|
||||||
|
self._playlist_index = len(self._playlist) - 1
|
||||||
|
self._player.setSource(self._url)
|
||||||
|
self._player.play()
|
||||||
|
self._player.pause()
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
self._ensure_stopped()
|
||||||
|
event.accept()
|
||||||
|
|
||||||
|
def position_changed(self, position):
|
||||||
|
self._scrub_slider.setValue(position)
|
||||||
|
|
||||||
|
def duration_changed(self, duration):
|
||||||
|
self._scrub_slider.setRange(0, duration)
|
||||||
|
|
||||||
|
def set_position(self):
|
||||||
|
self._player.setPosition(self._scrub_slider.value())
|
||||||
|
|
||||||
|
def volume_change(self, position):
|
||||||
|
self._audio_output.setVolume(position / 100)
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
event.ignore()
|
||||||
|
self._player.stop()
|
||||||
|
self.hide()
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def open(self):
|
||||||
|
self._ensure_stopped()
|
||||||
|
file_dialog = QFileDialog(self)
|
||||||
|
|
||||||
|
is_windows = sys.platform == 'win32'
|
||||||
|
if not self._mime_types:
|
||||||
|
self._mime_types = get_supported_mime_types()
|
||||||
|
if (is_windows and AVI not in self._mime_types):
|
||||||
|
self._mime_types.append(AVI)
|
||||||
|
elif MP4 not in self._mime_types:
|
||||||
|
self._mime_types.append(MP4)
|
||||||
|
|
||||||
|
file_dialog.setMimeTypeFilters(self._mime_types)
|
||||||
|
|
||||||
|
default_mimetype = AVI if is_windows else MP4
|
||||||
|
if default_mimetype in self._mime_types:
|
||||||
|
file_dialog.selectMimeTypeFilter(default_mimetype)
|
||||||
|
|
||||||
|
movies_location = QStandardPaths.writableLocation(QStandardPaths.MoviesLocation)
|
||||||
|
file_dialog.setDirectory(movies_location)
|
||||||
|
if file_dialog.exec() == QDialog.Accepted:
|
||||||
|
self._url = file_dialog.selectedUrls()[0].toString()
|
||||||
|
self._playlist.append(self._url )
|
||||||
|
self._playlist_index = len(self._playlist) - 1
|
||||||
|
self._player.setSource(self._url)
|
||||||
|
self._player.play()
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def _ensure_stopped(self):
|
||||||
|
if self._player.playbackState() != QMediaPlayer.StoppedState:
|
||||||
|
self._player.stop()
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def previous_clicked(self):
|
||||||
|
# Go to previous track if we are within the first 5 seconds of playback
|
||||||
|
# Otherwise, seek to the beginning.
|
||||||
|
if self._player.position() <= 5000 and self._playlist_index > 0:
|
||||||
|
self._playlist_index -= 1
|
||||||
|
self._playlist.previous()
|
||||||
|
self._player.setSource(self._playlist[self._playlist_index])
|
||||||
|
else:
|
||||||
|
self._player.setPosition(0)
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def next_clicked(self):
|
||||||
|
if self._playlist_index < len(self._playlist) - 1:
|
||||||
|
self._playlist_index += 1
|
||||||
|
self._player.setSource(self._playlist[self._playlist_index])
|
||||||
|
|
||||||
|
@Slot("QMediaPlayer::PlaybackState")
|
||||||
|
def update_buttons(self, state):
|
||||||
|
media_count = len(self._playlist)
|
||||||
|
self._play_action.setEnabled(media_count > 0
|
||||||
|
and state != QMediaPlayer.PlayingState)
|
||||||
|
self._pause_action.setEnabled(state == QMediaPlayer.PlayingState)
|
||||||
|
self._stop_action.setEnabled(state != QMediaPlayer.StoppedState)
|
||||||
|
self._previous_action.setEnabled(self._player.position() > 0)
|
||||||
|
self._next_action.setEnabled(media_count > 1)
|
||||||
|
|
||||||
|
def show_status_message(self, message):
|
||||||
|
self.statusBar().showMessage(message, 5000)
|
||||||
|
|
||||||
|
@Slot("QMediaPlayer::Error", str)
|
||||||
|
def _player_error(self, error, error_string):
|
||||||
|
print(error_string, file=sys.stderr)
|
||||||
|
self.show_status_message(error_string)
|
||||||
|
|
||||||
|
def clip_15_seconds(self):
|
||||||
|
self.clip_video(15)
|
||||||
|
|
||||||
|
def clip_30_seconds(self):
|
||||||
|
self.clip_video(30)
|
||||||
|
|
||||||
|
def clip_60_seconds(self):
|
||||||
|
self.clip_video(60)
|
||||||
|
|
||||||
|
def clip_video(self, clip_length):
|
||||||
|
start_time = self._player.position() / 1000
|
||||||
|
|
||||||
|
dirname = os.path.dirname(__file__)
|
||||||
|
output_filepath = os.path.join(os.path.expanduser('~'), "Videos/gameplay/clips/"+str(uuid.uuid4())+".mp4")
|
||||||
|
|
||||||
|
# Perform the saving operation with the selected file path
|
||||||
|
clip = VideoFileClip(self._url).subclip(start_time, start_time + clip_length)
|
||||||
|
clip.write_videofile(output_filepath)
|
||||||
|
clip.close()
|
||||||
|
|
||||||
|
self.clip_window = MainWindow(output_filepath)
|
||||||
|
self.clip_window.show()
|
||||||
|
|
||||||
|
def upload_video_youtube(self):
|
||||||
|
upload_video(self._url)
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
video_type = self._url.split(".")[-1]
|
||||||
|
subprocess.run("""echo "{url}" | xclip -sel clip -t text/uri-list -i""".format(video_type=video_type, url=self._url),shell=True)
|
||||||
|
|
||||||
|
|
||||||
|
def open_media_screen():
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
main_win = MainWindow('~/Videos/gameplay/2023-07-02 21-17-35.mkv')
|
||||||
|
available_geometry = main_win.screen().availableGeometry()
|
||||||
|
main_win.resize(available_geometry.width() / 3,
|
||||||
|
available_geometry.height() / 2)
|
||||||
|
main_win.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
open_media_screen()
|
35
youtube_upload.py
Normal file
35
youtube_upload.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
from simple_youtube_api.Channel import Channel
|
||||||
|
from simple_youtube_api.LocalVideo import LocalVideo
|
||||||
|
|
||||||
|
|
||||||
|
def upload_video(file_path):
|
||||||
|
# loggin into the channel
|
||||||
|
channel = Channel()
|
||||||
|
channel.login("client_secret_6793728376-alv7pcqjm3psoibm3rd0cvuhu9uomolr.apps.googleusercontent.com.json", "credentials.storage")
|
||||||
|
|
||||||
|
# setting up the video that is going to be uploaded
|
||||||
|
video = LocalVideo(file_path=file_path)
|
||||||
|
|
||||||
|
# setting snippet
|
||||||
|
video.set_title("Testing link sharing")
|
||||||
|
video.set_description("This is a description")
|
||||||
|
video.set_tags(["this", "tag"])
|
||||||
|
video.set_category("gaming")
|
||||||
|
video.set_default_language("en-US")
|
||||||
|
|
||||||
|
# setting status
|
||||||
|
video.set_embeddable(True)
|
||||||
|
video.set_license("creativeCommon")
|
||||||
|
video.set_privacy_status("private")
|
||||||
|
video.set_public_stats_viewable(True)
|
||||||
|
|
||||||
|
# setting thumbnail
|
||||||
|
# video.set_thumbnail_path('86106086e9594672ad7408913b5a3a24.jpg')
|
||||||
|
|
||||||
|
# uploading video and printing the results
|
||||||
|
video = channel.upload_video(video)
|
||||||
|
print(video.id)
|
||||||
|
print(video)
|
||||||
|
|
||||||
|
# liking video
|
||||||
|
# video.like()
|
Loading…
x
Reference in New Issue
Block a user