From 1bf045ced99dd60201bf9d72c35a4fb4db0562fb Mon Sep 17 00:00:00 2001 From: BarsTiger Date: Fri, 9 Dec 2022 17:46:15 +0200 Subject: [PATCH] Fixed cutting end of sound, developing micro restreaming --- .gitignore | 1 + gui/modules/initialize/fill_settings.py | 21 +++++++++++++++++ gui/modules/initialize/setup_ui.py | 4 +++- gui/modules/settings/handlers.py | 11 +++++++-- modules/config/model.py | 5 ++++ modules/config/settings.py | 7 +++++- modules/player/add_second.py | 31 +++++++++++++++++++++++++ modules/player/player.py | 18 ++++++++++---- modules/restream/__init__.py | 1 + modules/restream/devices.py | 24 +++++++++++++++++++ modules/restream/restream.py | 21 +++++++++++++++++ requirements.txt | 5 +++- 12 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 gui/modules/initialize/fill_settings.py create mode 100644 modules/player/add_second.py create mode 100644 modules/restream/__init__.py create mode 100644 modules/restream/devices.py create mode 100644 modules/restream/restream.py diff --git a/.gitignore b/.gitignore index 0fd54a3..c64f654 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ /dist/ /tests/ /data/ +/temp/ *.spec diff --git a/gui/modules/initialize/fill_settings.py b/gui/modules/initialize/fill_settings.py new file mode 100644 index 0000000..8fca869 --- /dev/null +++ b/gui/modules/initialize/fill_settings.py @@ -0,0 +1,21 @@ +from gui.gui import Ui_MainWindow +from modules.config import Config +from modules.restream import get_streaming_devices + + +def fill_settings(ui: Ui_MainWindow): + ui.volume_box.setValue(Config.get().volume) + + ui.theme_box.setCurrentText(Config.get().theme) + + # ui.output_device_play_box.addItems() + + ui.restream_micro_checkbox.setChecked(Config.get().restream) + ui.input_device_restream_box.addItems(get_streaming_devices().in_l) + ui.output_device_restream_box.addItems(get_streaming_devices().out_l) + + if Config.get().in_micro in get_streaming_devices().in_l: + ui.input_device_restream_box.setCurrentText(Config.get().in_micro) + + if Config.get().out_micro in get_streaming_devices().out_l: + ui.output_device_restream_box.setCurrentText(Config.get().out_micro) diff --git a/gui/modules/initialize/setup_ui.py b/gui/modules/initialize/setup_ui.py index dae1209..4964d24 100644 --- a/gui/modules/initialize/setup_ui.py +++ b/gui/modules/initialize/setup_ui.py @@ -1,6 +1,7 @@ from gui.gui import Ui_MainWindow from gui.modules.core.blur import GlobalBlur from gui.modules.initialize import styles +from gui.modules.initialize import fill_settings from gui.modules.handlers import register from PyQt5.QtWidgets import QMainWindow from PyQt5 import QtCore @@ -16,7 +17,6 @@ def on_load(ui: Ui_MainWindow, MainWindow: QMainWindow): :return: """ ui.content.setCurrentIndex(0) - ui.volume_box.setValue(Config.get().volume) MainWindow.setStyleSheet(styles.centralwidget()) ui.menu.setStyleSheet(styles.menupage()) @@ -28,4 +28,6 @@ def on_load(ui: Ui_MainWindow, MainWindow: QMainWindow): p = Player() + fill_settings.fill_settings(ui) + register.register_handlers(ui, MainWindow, p) diff --git a/gui/modules/settings/handlers.py b/gui/modules/settings/handlers.py index 204ad53..7fa2c84 100644 --- a/gui/modules/settings/handlers.py +++ b/gui/modules/settings/handlers.py @@ -9,6 +9,13 @@ def register_handlers(ui: Ui_MainWindow): :return: """ - ui.theme_box.setCurrentText(Config.get().theme) - ui.theme_box.currentTextChanged.connect(lambda: Config.update("theme", ui.theme_box.currentText())) + ui.restream_micro_checkbox.clicked.connect(lambda: Config.update("restream", + ui.restream_micro_checkbox.isChecked())) + + ui.output_device_restream_box.currentTextChanged.connect( + lambda: Config.update("out_micro", ui.output_device_restream_box.currentText()) + ) + ui.input_device_restream_box.currentTextChanged.connect( + lambda: Config.update("in_micro", ui.input_device_restream_box.currentText()) + ) diff --git a/modules/config/model.py b/modules/config/model.py index 8d3f9d0..78f28d8 100644 --- a/modules/config/model.py +++ b/modules/config/model.py @@ -7,3 +7,8 @@ from dataclasses_json import dataclass_json class ConfigModel: theme: str volume: int + out_device: str + preview_device: str + in_micro: str + out_micro: str + restream: bool diff --git a/modules/config/settings.py b/modules/config/settings.py index 9b897df..3a5503c 100644 --- a/modules/config/settings.py +++ b/modules/config/settings.py @@ -8,7 +8,12 @@ class Config: def default(): return { "theme": "Dark gray", - "volume": 100 + "volume": 100, + "out_device": str(), + "preview_device": str(), + "in_micro": str(), + "out_micro": str(), + "restream": False } @staticmethod diff --git a/modules/player/add_second.py b/modules/player/add_second.py new file mode 100644 index 0000000..241e3e1 --- /dev/null +++ b/modules/player/add_second.py @@ -0,0 +1,31 @@ +import pydub +import validators +from urllib.request import urlopen +from io import BytesIO +from rich import print +import pafy +import hashlib +import os + + +def get_silenced_media(original: str) -> str | None: + if not os.path.isdir('temp'): + os.mkdir('temp') + + try: + name = original + namehash = 'temp\\' + hashlib.md5(name.encode('utf-8')).hexdigest() + if not os.path.isfile(namehash): + if validators.url(original): + if 'youtu' in original: + original = pafy.new(original).getbestaudio().url + original = BytesIO(urlopen(original).read()) + + (pydub.AudioSegment.from_file(original) + pydub.AudioSegment.silent(1500))\ + .export(namehash, format='mp3') + return namehash + + except Exception as e: + print(e) + raise e + return None diff --git a/modules/player/player.py b/modules/player/player.py index 4205ebf..d5b1a6d 100644 --- a/modules/player/player.py +++ b/modules/player/player.py @@ -1,5 +1,7 @@ import vlc from gui.gui import Ui_MainWindow +from gui.modules.core import popup +from modules.player.add_second import get_silenced_media def get_instance() -> vlc.Instance: @@ -23,16 +25,22 @@ def get_devices(mediaplayer: vlc.MediaPlayer) -> dict: class Player(object): def __init__(self): - self.instance = get_instance() - self.mediaplayer_preview = get_player(self.instance) + self.instance_preview = get_instance() + self.instance_out = get_instance() + self.mediaplayer_preview = get_player(self.instance_preview) self.mediaplayer_preview.audio_output_device_set(None, get_devices(self.mediaplayer_preview)['Default']) - self.mediaplayer_out = get_player(self.instance) + self.mediaplayer_out = get_player(self.instance_out) self.mediaplayer_out.audio_output_device_set(None, get_devices( self.mediaplayer_out)['CABLE Input (VB-Audio Virtual Cable)']) def set_media(self, media: str) -> None: - self.mediaplayer_preview.set_media(self.instance.media_new(media)) - self.mediaplayer_out.set_media(self.instance.media_new(media)) + if get_silenced_media(media): + self.mediaplayer_preview.set_media(self.instance_preview.media_new(get_silenced_media(media))) + self.mediaplayer_out.set_media(self.instance_out.media_new(get_silenced_media(media))) + else: + popup.popup('Error', 'Error playing this media. \nIf it uses link, check is this link valid.') + self.mediaplayer_preview.set_media(None) + self.mediaplayer_out.set_media(None) def set_volume(self, volume: int): self.mediaplayer_preview.audio_set_volume(volume) diff --git a/modules/restream/__init__.py b/modules/restream/__init__.py new file mode 100644 index 0000000..94de037 --- /dev/null +++ b/modules/restream/__init__.py @@ -0,0 +1 @@ +from .devices import get_streaming_devices diff --git a/modules/restream/devices.py b/modules/restream/devices.py new file mode 100644 index 0000000..3e4f6a3 --- /dev/null +++ b/modules/restream/devices.py @@ -0,0 +1,24 @@ +from dataclasses import dataclass +import sounddevice as sd + + +@dataclass +class StreamingDevices: + output: dict + out_l: list + input: dict + in_l: list + + +def get_streaming_devices() -> StreamingDevices: + devices = StreamingDevices(dict(), list(), dict(), list()) + + for device in sd.query_hostapis()[0]['devices']: + if sd.query_devices(device)['max_output_channels'] == 0: + devices.input[sd.query_devices(device)['name']] = sd.query_devices(device)['index'] + devices.in_l.append(sd.query_devices(device)['name']) + else: + devices.output[sd.query_devices(device)['name']] = sd.query_devices(device)['index'] + devices.out_l.append(sd.query_devices(device)['name']) + + return devices diff --git a/modules/restream/restream.py b/modules/restream/restream.py new file mode 100644 index 0000000..cb2c154 --- /dev/null +++ b/modules/restream/restream.py @@ -0,0 +1,21 @@ +from gui.gui import Ui_MainWindow +import sounddevice as sd +from . import get_streaming_devices + + +class Restreamer(object): + def __init__(self): + self.stream = sd.Stream() + + @staticmethod + def callback(indata, outdata, frames, time, status): + if status: + print(status) + outdata[:] = indata + + def restart(self, ui: Ui_MainWindow): + self.stream.stop() + self.stream = sd.Stream(device=(get_streaming_devices().input[ui.input_device_restream_box.currentText()], + get_streaming_devices().output[ui.output_device_restream_box.currentText()]), + callback=Restreamer.callback) + self.stream.start() diff --git a/requirements.txt b/requirements.txt index 093ce34..16bc518 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,7 @@ requests python-vlc sounddevice numpy -validators \ No newline at end of file +validators +pydub +pafy +youtube-dl==2020.12.2 \ No newline at end of file