Procházet zdrojové kódy

add manual sermon file uploading option via a gui file picker

Noah Vogt před 2 měsíci
rodič
revize
ee36e1232a

+ 0 - 1
README.md

@@ -389,7 +389,6 @@ These are some issues and possible changes that will be addressed or at least co
     - changing time
 - sermon uploading
     - add docs for new config variables and explain difference between uploading systems
-    - maybe add manual file uploading option via a gui file picker
 
 ## Licensing
 

+ 2 - 2
burn_cds_of_today.py

@@ -17,9 +17,9 @@
 
 import colorama
 
-from utils import get_yyyy_mm_dd_date
+from utils import get_current_yyyy_mm_dd_date
 from recording import burn_cds_of_day
 
 if __name__ == "__main__":
     colorama.init()
-    burn_cds_of_day(get_yyyy_mm_dd_date())
+    burn_cds_of_day(get_current_yyyy_mm_dd_date())

+ 1 - 0
input/__init__.py

@@ -30,5 +30,6 @@ from .validate_config import (
     validate_cd_record_config,
     validate_sermon_upload_config,
     validate_cd_burn_config,
+    validate_manual_filedrop_sermon_upload_config,
 )
 from .slide_selection_iterator import slide_selection_iterator

+ 6 - 3
input/validate_config.py

@@ -68,9 +68,7 @@ def validate_cd_record_config() -> None:
     general_config_validator(needed_constants, gui_error_out=True)
 
 
-def validate_sermon_upload_config() -> None:
-    validate_cd_burn_config()
-
+def validate_manual_filedrop_sermon_upload_config() -> None:
     needed_constants: dict = {
         "SERMON_UPLOAD_USE_FTP": const.SERMON_UPLOAD_USE_FTP,
         "SERMON_UPLOAD_SUITABLE_SEGMENT_FRAMES": const.SERMON_UPLOAD_SUITABLE_SEGMENT_FRAMES,
@@ -94,6 +92,11 @@ def validate_sermon_upload_config() -> None:
         general_config_validator(needed_constants, gui_error_out=True)
 
 
+def validate_sermon_upload_config() -> None:
+    validate_cd_burn_config()
+    validate_manual_filedrop_sermon_upload_config()
+
+
 def general_config_validator(
     needed_constants: dict, gui_error_out=False
 ) -> None:

+ 48 - 0
manually_upload_sermon_file.py

@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+
+# Copyright © 2025 Noah Vogt <noah@noahvogt.com>
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import colorama
+
+from PyQt5.QtWidgets import (  # pylint: disable=no-name-in-module
+    QApplication,
+)
+
+from utils import (
+    log,
+    DatePickerDialog,
+    get_mp3_file_via_picker_dialog,
+)
+from recording import upload_sermon_audiofile
+from input import validate_manual_filedrop_sermon_upload_config
+
+
+if __name__ == "__main__":
+    colorama.init()
+    validate_manual_filedrop_sermon_upload_config()
+
+    app = QApplication([])
+    dialog = DatePickerDialog()
+    if dialog.exec_():
+        date = dialog.selected_date()
+        yyyy_mm_dd = date.toString("yyyy-MM-dd")
+        log("Selected date: {}".format(yyyy_mm_dd))
+        file_path = get_mp3_file_via_picker_dialog()
+        if file_path:
+            del app
+            upload_sermon_audiofile(file_path, yyyy_mm_dd)
+        else:
+            log("No file selected.")

+ 1 - 0
recording/__init__.py

@@ -16,6 +16,7 @@
 from .sermon import (
     make_sermon_mp3,
     upload_sermon_for_day,
+    upload_sermon_audiofile,
 )
 from .verify import (
     is_valid_cd_record_checkfile,

+ 19 - 1
recording/sermon.py

@@ -16,6 +16,7 @@
 import sys
 from os import path, listdir
 from shlex import split
+from shutil import copyfile
 from re import match, sub
 from subprocess import Popen
 import ftplib
@@ -99,6 +100,22 @@ def get_audio_base_path_from_segment(segment: SermonSegment) -> str:
 
 
 def make_sermon_mp3(source_audio: str, target_audio: str) -> None:
+    _, extension = path.splitext(source_audio)
+    if extension == ".mp3":
+        log("Copying source mp3 to final destination...")
+        try:
+            copyfile(source_audio, target_audio)
+        except (FileNotFoundError, PermissionError, IOError) as error:
+            app = QApplication([])
+            InfoMsgBox(
+                QMessageBox.Critical,
+                "Error",
+                f"could not move '{source_audio}'to '{target_audio}'",
+            )
+            del app
+            sys.exit(1)
+        return
+
     log("Generating final mp3...")
     cmd = 'ffmpeg -y -i "{}" -acodec libmp3lame "{}"'.format(
         source_audio,
@@ -114,6 +131,7 @@ def make_sermon_mp3(source_audio: str, target_audio: str) -> None:
             "ffmpeg terminated with " + f"exit code {process.returncode}",
         )
         del app
+        sys.exit(1)
 
 
 def generate_wav_for_segment(segment: SermonSegment) -> None:
@@ -341,7 +359,7 @@ def upload_mp3_to_wordpress(filename: str) -> UploadedSermon:
 
     with open(mp3_final_path, "rb") as f:
         try:
-            log(f"uploading f{mp3_final_path} to wordpress...")
+            log(f"uploading {mp3_final_path} to wordpress...")
             response = requests.post(
                 const.SERMON_UPLOAD_WPSM_API_BASE_URL + "/media",
                 headers=headers,

+ 2 - 2
recording/verify.py

@@ -24,7 +24,7 @@ from PyQt5.QtWidgets import (  # pylint: disable=no-name-in-module
 from psutil import pid_exists
 
 import config as const
-from utils import get_yyyy_mm_dd_date, InfoMsgBox, expand_dir
+from utils import get_current_yyyy_mm_dd_date, InfoMsgBox, expand_dir
 from input import get_cachefile_content
 
 
@@ -64,7 +64,7 @@ def ongoing_cd_recording_detected() -> bool:
     if path.isfile(expand_dir(const.CD_RECORD_CACHEFILE)):
         cachefile_content = get_cachefile_content(const.CD_RECORD_CACHEFILE)
         if is_valid_cd_record_checkfile(
-            cachefile_content, get_yyyy_mm_dd_date()
+            cachefile_content, get_current_yyyy_mm_dd_date()
         ):
             if cachefile_content[1].strip() != "9001" and pid_exists(
                 int(cachefile_content[2].strip())

+ 3 - 3
set_cd_marker.py

@@ -28,7 +28,7 @@ from PyQt5.QtWidgets import (  # pylint: disable=no-name-in-module
 )
 
 from utils import (
-    get_yyyy_mm_dd_date,
+    get_current_yyyy_mm_dd_date,
     make_sure_file_exists,
     get_unix_milis,
     log,
@@ -59,7 +59,7 @@ def get_reset_marker(yyyy_mm_dd: str) -> int:
 
 def start_cd_recording() -> None:
     cachefile_content = get_cachefile_content(const.CD_RECORD_CACHEFILE)
-    yyyy_mm_dd = get_yyyy_mm_dd_date()
+    yyyy_mm_dd = get_current_yyyy_mm_dd_date()
     cd_num = get_reset_marker(yyyy_mm_dd)
 
     ensure_output_dir_exists(yyyy_mm_dd)
@@ -276,7 +276,7 @@ def update_cue_sheet(
 
 def set_cd_marker() -> None:
     cachefile_content = get_cachefile_content(const.CD_RECORD_CACHEFILE)
-    yyyy_mm_dd = get_yyyy_mm_dd_date()
+    yyyy_mm_dd = get_current_yyyy_mm_dd_date()
     unix_milis = get_unix_milis()
     cachefile_and_time_data = (cachefile_content, yyyy_mm_dd, unix_milis)
 

+ 3 - 3
song_switcher/switch.py

@@ -23,7 +23,7 @@ from PyQt5.QtWidgets import (  # pylint: disable=no-name-in-module
 )
 from utils import (
     log,
-    get_yyyy_mm_dd_date,
+    get_current_yyyy_mm_dd_date,
     expand_dir,
     InfoMsgBox,
 )
@@ -49,7 +49,7 @@ def cycle_to_song_direction(song_direction: SongDirection):
             and match(r"[0-9]{4}-[0-9]{2}-[0-9]{2}$", cachefile_content[0])
             and match(r"^[0-9]+$", cachefile_content[1])
         )
-        or cachefile_content[0].strip() != get_yyyy_mm_dd_date()
+        or cachefile_content[0].strip() != get_current_yyyy_mm_dd_date()
     ):
         switch_to_song(1)
     else:
@@ -70,7 +70,7 @@ def create_cachfile_for_song(song) -> None:
     cachefile = expand_dir(const.NEXTSONG_CACHE_FILE)
     try:
         with open(cachefile, mode="w", encoding="utf-8-sig") as file_writer:
-            file_writer.write(get_yyyy_mm_dd_date() + "\n")
+            file_writer.write(get_current_yyyy_mm_dd_date() + "\n")
             file_writer.write(str(song) + "\n")
     except (FileNotFoundError, PermissionError, IOError) as error:
         app = QApplication

+ 2 - 2
stop_cd_recording.py

@@ -25,7 +25,7 @@ from PyQt5.QtWidgets import (  # pylint: disable=no-name-in-module
 )
 
 from utils import (
-    get_yyyy_mm_dd_date,
+    get_current_yyyy_mm_dd_date,
     make_sure_file_exists,
     get_unix_milis,
     warn,
@@ -41,7 +41,7 @@ from os_agnostic import kill_process
 def stop_cd_recording() -> None:
     filename = expand_dir(const.CD_RECORD_CACHEFILE)
     cachefile_content = get_cachefile_content(filename)
-    yyyy_mm_dd = get_yyyy_mm_dd_date()
+    yyyy_mm_dd = get_current_yyyy_mm_dd_date()
 
     if is_valid_cd_record_checkfile(cachefile_content, yyyy_mm_dd):
         unix_milis = get_unix_milis()

+ 3 - 3
upload_sermon_of_today.py

@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 
-# Copyright © 2024 Noah Vogt <noah@noahvogt.com>
+# Copyright © 2025 Noah Vogt <noah@noahvogt.com>
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 import colorama
 
 from utils import (
-    get_yyyy_mm_dd_date,
+    get_current_yyyy_mm_dd_date,
 )
 from recording import (
     make_sure_there_is_no_ongoing_cd_recording,
@@ -33,4 +33,4 @@ if __name__ == "__main__":
     colorama.init()
     validate_sermon_upload_config()
     make_sure_there_is_no_ongoing_cd_recording()
-    upload_sermon_for_day(get_yyyy_mm_dd_date())
+    upload_sermon_for_day(get_current_yyyy_mm_dd_date())

+ 6 - 2
utils/__init__.py

@@ -23,5 +23,9 @@ from .img import get_empty_image
 from .create_min_obs_subdirs import create_min_obs_subdirs
 from .clear_obs_slides_dir import clear_obs_slides_dir
 from .path import expand_dir, make_sure_file_exists
-from .date import get_yyyy_mm_dd_date, get_unix_milis
-from .choose import RadioButtonDialog
+from .date import get_current_yyyy_mm_dd_date, get_unix_milis
+from .choose import (
+    RadioButtonDialog,
+    DatePickerDialog,
+    get_mp3_file_via_picker_dialog,
+)

+ 41 - 0
utils/choose.py

@@ -22,8 +22,12 @@ from PyQt5.QtWidgets import (  # pylint: disable=no-name-in-module
     QButtonGroup,
     QScrollArea,
     QWidget,
+    QCalendarWidget,
+    QFileDialog,
 )
 
+from PyQt5.QtCore import QDate  # pylint: disable=no-name-in-module
+
 
 class RadioButtonDialog(QDialog):  # pylint: disable=too-few-public-methods
     def __init__(self, options: list[str], window_title: str):
@@ -69,3 +73,40 @@ class RadioButtonDialog(QDialog):  # pylint: disable=too-few-public-methods
                 "No Selection",
                 "Please select an option before proceeding.",
             )
+
+
+class DatePickerDialog(QDialog):  # pylint: disable=too-few-public-methods
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self.setWindowTitle("Select a Date")
+        self.setMinimumWidth(300)
+
+        # Layout
+        layout = QVBoxLayout()
+
+        # Calendar widget
+        self.calendar = QCalendarWidget(self)
+        self.calendar.setGridVisible(True)
+        self.calendar.setSelectedDate(QDate.currentDate())
+        layout.addWidget(self.calendar)
+
+        # OK button
+        self.ok_button = QPushButton("OK", self)
+        self.ok_button.clicked.connect(self.accept)
+        layout.addWidget(self.ok_button)
+
+        self.setLayout(layout)
+
+    def selected_date(self):
+        return self.calendar.selectedDate()
+
+
+def get_mp3_file_via_picker_dialog(parent=None) -> str | None:
+    dialog = QFileDialog(parent)
+    dialog.setFileMode(QFileDialog.ExistingFile)
+    dialog.setNameFilter("MP3 Files (*.mp3)")
+    if dialog.exec_():
+        selected_files = dialog.selectedFiles()
+        # Return the first selected file
+        return selected_files[0]
+    return None

+ 1 - 1
utils/date.py

@@ -17,7 +17,7 @@ from datetime import date
 from time import time
 
 
-def get_yyyy_mm_dd_date() -> str:
+def get_current_yyyy_mm_dd_date() -> str:
     return date.strftime(date.today(), "%Y-%m-%d")