talklib 3.0.0__tar.gz → 3.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {talklib-3.0.0/src/talklib.egg-info → talklib-3.2.0}/PKG-INFO +2 -2
- {talklib-3.0.0 → talklib-3.2.0}/README.md +1 -1
- {talklib-3.0.0 → talklib-3.2.0}/pyproject.toml +1 -1
- {talklib-3.0.0 → talklib-3.2.0}/src/talklib/cli.py +30 -4
- {talklib-3.0.0 → talklib-3.2.0}/src/talklib/pod.py +54 -12
- {talklib-3.0.0 → talklib-3.2.0/src/talklib.egg-info}/PKG-INFO +2 -2
- {talklib-3.0.0 → talklib-3.2.0}/LICENSE.txt +0 -0
- {talklib-3.0.0 → talklib-3.2.0}/requirements.txt +0 -0
- {talklib-3.0.0 → talklib-3.2.0}/setup.cfg +0 -0
- {talklib-3.0.0 → talklib-3.2.0}/src/talklib/__init__.py +0 -0
- {talklib-3.0.0 → talklib-3.2.0}/src/talklib/ev.py +0 -0
- {talklib-3.0.0 → talklib-3.2.0}/src/talklib/ffmpeg.py +0 -0
- {talklib-3.0.0 → talklib-3.2.0}/src/talklib/notify.py +0 -0
- {talklib-3.0.0 → talklib-3.2.0}/src/talklib/show.py +0 -0
- {talklib-3.0.0 → talklib-3.2.0}/src/talklib/utils.py +0 -0
- {talklib-3.0.0 → talklib-3.2.0}/src/talklib.egg-info/SOURCES.txt +0 -0
- {talklib-3.0.0 → talklib-3.2.0}/src/talklib.egg-info/dependency_links.txt +0 -0
- {talklib-3.0.0 → talklib-3.2.0}/src/talklib.egg-info/entry_points.txt +0 -0
- {talklib-3.0.0 → talklib-3.2.0}/src/talklib.egg-info/requires.txt +0 -0
- {talklib-3.0.0 → talklib-3.2.0}/src/talklib.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: talklib
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: A package to automate processing of shows/segments airing on the TL
|
|
5
5
|
Author-email: Ben Weddle <ben.weddle@gmail.com>
|
|
6
6
|
Maintainer-email: Ben Weddle <ben.weddle@gmail.com>
|
|
@@ -523,7 +523,7 @@ nyt.run()
|
|
|
523
523
|
|
|
524
524
|
To disable ALL notifications, add a line like this:
|
|
525
525
|
|
|
526
|
-
> This will disable all notifications **including** syslog messages
|
|
526
|
+
> This will disable all notifications **including** syslog messages (shell print statements will not be disabled)
|
|
527
527
|
|
|
528
528
|
````python
|
|
529
529
|
from talklib import TLPod
|
|
@@ -423,7 +423,7 @@ nyt.run()
|
|
|
423
423
|
|
|
424
424
|
To disable ALL notifications, add a line like this:
|
|
425
425
|
|
|
426
|
-
> This will disable all notifications **including** syslog messages
|
|
426
|
+
> This will disable all notifications **including** syslog messages (shell print statements will not be disabled)
|
|
427
427
|
|
|
428
428
|
````python
|
|
429
429
|
from talklib import TLPod
|
|
@@ -3,7 +3,7 @@ import os
|
|
|
3
3
|
import sys
|
|
4
4
|
import xml.etree.ElementTree as ET
|
|
5
5
|
|
|
6
|
-
from talklib.pod import SSH
|
|
6
|
+
from talklib.pod import SSH, Notifications
|
|
7
7
|
|
|
8
8
|
def parse_args():
|
|
9
9
|
parser = argparse.ArgumentParser(description="use talklib in the terminal")
|
|
@@ -15,10 +15,32 @@ def parse_args():
|
|
|
15
15
|
You MUST have an RSS feed (feed.xml) and logo (image.jpg) in the current directory."
|
|
16
16
|
parser.add_argument('--new-pod-dir', type=str, help=new_podcast_directory_help, required=False)
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
download_feed_help:str = "Download the RSS feed from the folder on the server you specify."
|
|
19
|
+
parser.add_argument('--download-feed', type=str, help=download_feed_help, required=False)
|
|
20
|
+
|
|
21
|
+
upload_feed_help:str = "Upload the RSS feed to the folder on the server you specify."
|
|
22
|
+
parser.add_argument('--upload-feed', type=str, help=upload_feed_help, required=False)
|
|
19
23
|
|
|
24
|
+
args = parser.parse_args()
|
|
20
25
|
return args
|
|
21
26
|
|
|
27
|
+
def get_SSH():
|
|
28
|
+
Notifications.prefix = "talklib CLI"
|
|
29
|
+
notifications = Notifications()
|
|
30
|
+
notifications.notify.email_enable = False
|
|
31
|
+
ssh = SSH(notifications=notifications)
|
|
32
|
+
return ssh
|
|
33
|
+
|
|
34
|
+
def download_feed(name: str):
|
|
35
|
+
ssh = get_SSH()
|
|
36
|
+
ssh.get_feed_from_folder(folder=name)
|
|
37
|
+
|
|
38
|
+
def upload_feed(name:str):
|
|
39
|
+
if not os.path.isfile("feed.xml"):
|
|
40
|
+
return print(f"cannot find 'feed.xml' in {os.getcwd()}. You must have this file in the current directory.")
|
|
41
|
+
ssh = get_SSH()
|
|
42
|
+
ssh.upload_feed_to_folder(folder=name)
|
|
43
|
+
|
|
22
44
|
def generate_feed_template():
|
|
23
45
|
ET.register_namespace(prefix="atom", uri="http://www.w3.org/2005/Atom")
|
|
24
46
|
ET.register_namespace(prefix="itunes", uri="http://www.itunes.com/dtds/podcast-1.0.dtd")
|
|
@@ -52,9 +74,13 @@ def main():
|
|
|
52
74
|
args = parse_args()
|
|
53
75
|
|
|
54
76
|
if args.feed_template:
|
|
55
|
-
generate_feed_template()
|
|
77
|
+
return generate_feed_template()
|
|
56
78
|
if args.new_pod_dir:
|
|
57
|
-
new_podcast_dir(name=args.new_pod_dir)
|
|
79
|
+
return new_podcast_dir(name=args.new_pod_dir)
|
|
80
|
+
if args.download_feed:
|
|
81
|
+
return download_feed(name=args.download_feed)
|
|
82
|
+
if args.upload_feed:
|
|
83
|
+
return upload_feed(name=args.upload_feed)
|
|
58
84
|
|
|
59
85
|
feed_template: str = """
|
|
60
86
|
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0">
|
|
@@ -4,12 +4,14 @@ import glob
|
|
|
4
4
|
import math
|
|
5
5
|
import os
|
|
6
6
|
import re
|
|
7
|
+
import subprocess
|
|
7
8
|
import time
|
|
8
9
|
from typing import ClassVar, Type
|
|
9
10
|
|
|
10
11
|
from fabric import Connection, Result
|
|
11
12
|
from paramiko.ssh_exception import SSHException as paramiko_SSH_exception
|
|
12
13
|
from pydantic import BaseModel, Field, model_validator
|
|
14
|
+
import requests
|
|
13
15
|
|
|
14
16
|
from talklib.ev import EV
|
|
15
17
|
from talklib.notify import Notify
|
|
@@ -18,7 +20,7 @@ from talklib.utils import today_is_weekday
|
|
|
18
20
|
|
|
19
21
|
class Notifications(BaseModel):
|
|
20
22
|
prefix: ClassVar[str] = None # prefix all messages with identifier for the show/podcast
|
|
21
|
-
notify: Type[Notify] = Notify()
|
|
23
|
+
notify: ClassVar[Type[Notify]] = Notify()
|
|
22
24
|
|
|
23
25
|
def prep_syslog(self, message: str, level: str = 'info'):
|
|
24
26
|
'''send message to syslog server'''
|
|
@@ -65,6 +67,7 @@ class SSH(BaseModel):
|
|
|
65
67
|
raise e
|
|
66
68
|
|
|
67
69
|
def download_file(self, file: str, folder: str) -> None:
|
|
70
|
+
folder = folder.lower()
|
|
68
71
|
try:
|
|
69
72
|
self.notifications.prep_syslog(message=f"Attempting to download '{file}' from {folder}/ on server")
|
|
70
73
|
self.connection.get(remote=f"shows/{folder}/{file}")
|
|
@@ -92,6 +95,7 @@ The error from the SSH library is: {e}"
|
|
|
92
95
|
subject="Error")
|
|
93
96
|
|
|
94
97
|
def make_new_folder(self, folder: str) -> None:
|
|
98
|
+
folder = folder.lower()
|
|
95
99
|
if self.check_folder_exists_no_exception(folder=folder):
|
|
96
100
|
raise Exception (f"{folder}/ already exists on server! Exiting...")
|
|
97
101
|
self.connection.run(f"cd shows && mkdir {folder}", hide=True)
|
|
@@ -128,8 +132,12 @@ The error from the SSH library is: {e}"
|
|
|
128
132
|
return ret_val
|
|
129
133
|
|
|
130
134
|
def get_feed_from_folder(self, folder: str):
|
|
135
|
+
self.check_folder_exists(folder=folder)
|
|
131
136
|
self.download_file(file="feed.xml", folder=folder)
|
|
132
137
|
|
|
138
|
+
def upload_feed_to_folder(self, folder:str):
|
|
139
|
+
self.upload_file(file="feed.xml", folder=folder)
|
|
140
|
+
|
|
133
141
|
def check_folder_exists(self, folder: str) -> bool:
|
|
134
142
|
self.notifications.prep_syslog(message=f"checking if {folder}/ exists on server...")
|
|
135
143
|
folders = self.get_folders()
|
|
@@ -341,9 +349,9 @@ class TLPod(BaseModel):
|
|
|
341
349
|
override_filename: bool = False
|
|
342
350
|
audio_folders:list = EV().destinations
|
|
343
351
|
notifications: Type[Notifications] = Notifications()
|
|
344
|
-
episode: Type[Episode] = Episode(
|
|
352
|
+
episode: Type[Episode] = Episode()
|
|
345
353
|
ffmpeg: Type[FFMPEG] = FFMPEG()
|
|
346
|
-
ssh: Type[SSH] = SSH(
|
|
354
|
+
ssh: Type[SSH] = SSH()
|
|
347
355
|
|
|
348
356
|
@model_validator(mode='after')
|
|
349
357
|
def post_update(self):
|
|
@@ -362,6 +370,14 @@ class TLPod(BaseModel):
|
|
|
362
370
|
|
|
363
371
|
self.display_name = f"{self.display_name} ({datetime.now().strftime('%a, %d %b')})"
|
|
364
372
|
|
|
373
|
+
# before we carry on, make sure we can successfully connect to the server
|
|
374
|
+
# try:
|
|
375
|
+
# self.ssh.connection.run("ls")
|
|
376
|
+
# except Exception as e:
|
|
377
|
+
# to_send:str = f"Cannot connect to server. Are you sure the SSH keys are set up correctly? Here is the error: {e}"
|
|
378
|
+
# self.notifications.send_notifications(message=to_send, subject="Error")
|
|
379
|
+
# raise e
|
|
380
|
+
|
|
365
381
|
return self
|
|
366
382
|
|
|
367
383
|
def get_filename_to_match(self) -> str:
|
|
@@ -418,15 +434,13 @@ class TLPod(BaseModel):
|
|
|
418
434
|
output_filename = output_filename[0]
|
|
419
435
|
output_filename = os.path.basename(output_filename).lower()
|
|
420
436
|
output_filename = output_filename + '.mp3'
|
|
421
|
-
self.notifications.prep_syslog(message=f"
|
|
437
|
+
self.notifications.prep_syslog(message=f"final audio file will be {output_filename}")
|
|
422
438
|
return output_filename
|
|
423
439
|
|
|
424
440
|
def convert(self, file:str):
|
|
425
|
-
output_filename = self.create_converted_filename(file=file)
|
|
426
|
-
|
|
427
441
|
self.ffmpeg.input_file = file
|
|
428
|
-
self.ffmpeg.output_file =
|
|
429
|
-
self.ffmpeg.compression = False # this is for podcasts. these files should already be edited
|
|
442
|
+
self.ffmpeg.output_file = "out.mp3"
|
|
443
|
+
self.ffmpeg.compression = False # this is for podcasts. these files should already be edited
|
|
430
444
|
|
|
431
445
|
ffmpeg_commands = self.ffmpeg.get_commands()
|
|
432
446
|
self.notifications.prep_syslog(message=f"FFmppeg commands: {ffmpeg_commands}")
|
|
@@ -439,6 +453,32 @@ class TLPod(BaseModel):
|
|
|
439
453
|
except Exception as ffmpeg_exception:
|
|
440
454
|
self.notifications.send_notifications(message=f'FFmpeg error: {ffmpeg_exception}', subject='Error')
|
|
441
455
|
raise ffmpeg_exception
|
|
456
|
+
|
|
457
|
+
def concat(self, preroll:str, program_audio: str, output_filename: str):
|
|
458
|
+
self.notifications.prep_syslog(message="concatenating preroll and program audio together...")
|
|
459
|
+
subprocess.run(f'ffmpeg -hide_banner -loglevel quiet -i "concat:{preroll}|{program_audio}" -c copy {output_filename}')
|
|
460
|
+
self.notifications.prep_syslog(message=f"files successfully concatenated as: {output_filename}")
|
|
461
|
+
return output_filename
|
|
462
|
+
|
|
463
|
+
def download_preroll(self):
|
|
464
|
+
download_URL = "https://assets.library.nashville.org/talkinglibrary/pod_preroll.mp3"
|
|
465
|
+
input_file = 'preroll.mp3'
|
|
466
|
+
with open (input_file, mode='wb') as downloaded_file:
|
|
467
|
+
self.notifications.prep_syslog(message=f"downloading preroll audio from {download_URL}...")
|
|
468
|
+
a = requests.get(download_URL)
|
|
469
|
+
downloaded_file.write(a.content)
|
|
470
|
+
downloaded_file.close()
|
|
471
|
+
self.notifications.prep_syslog(message="preroll audio successfully downloaded")
|
|
472
|
+
return downloaded_file.name
|
|
473
|
+
|
|
474
|
+
def post_cleaup(self):
|
|
475
|
+
self.notifications.prep_syslog(message="looking for local files to delete...")
|
|
476
|
+
XML_files = glob.glob("*.xml")
|
|
477
|
+
for file in XML_files:
|
|
478
|
+
self.delete_local_file(file=file)
|
|
479
|
+
MP3_files = glob.glob("*.mp3")
|
|
480
|
+
for file in MP3_files:
|
|
481
|
+
self.delete_local_file(file=file)
|
|
442
482
|
|
|
443
483
|
def delete_local_file(self, file: str):
|
|
444
484
|
try:
|
|
@@ -457,11 +497,14 @@ class TLPod(BaseModel):
|
|
|
457
497
|
|
|
458
498
|
audio_file = self.match_file()
|
|
459
499
|
converted_file = self.convert(file=audio_file)
|
|
500
|
+
output_filename = self.create_converted_filename(file=audio_file)
|
|
501
|
+
preroll = self.download_preroll()
|
|
502
|
+
concat_file = self.concat(preroll=preroll, program_audio=converted_file, output_filename=output_filename)
|
|
460
503
|
|
|
461
504
|
feed_file = self.ssh.download_file(folder=self.bucket_folder, file='feed.xml') # all XML files on server should have the same name
|
|
462
505
|
|
|
463
506
|
self.episode.feed_file = feed_file
|
|
464
|
-
self.episode.audio_filename =
|
|
507
|
+
self.episode.audio_filename = concat_file
|
|
465
508
|
self.episode.bucket_folder = self.bucket_folder
|
|
466
509
|
self.episode.episode_title = self.display_name
|
|
467
510
|
self.episode.max_episodes = self.max_episodes_in_feed
|
|
@@ -469,10 +512,9 @@ class TLPod(BaseModel):
|
|
|
469
512
|
self.episode.add_new_episode()
|
|
470
513
|
self.episode.remove_old_episodes()
|
|
471
514
|
|
|
472
|
-
self.ssh.upload_file(folder=self.bucket_folder, file=
|
|
515
|
+
self.ssh.upload_file(folder=self.bucket_folder, file=concat_file)
|
|
473
516
|
self.ssh.upload_file(folder=self.bucket_folder, file=feed_file)
|
|
474
517
|
|
|
475
|
-
self.
|
|
476
|
-
self.delete_local_file(file=converted_file)
|
|
518
|
+
self.post_cleaup()
|
|
477
519
|
|
|
478
520
|
self.notifications.prep_syslog(message="All done.")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: talklib
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: A package to automate processing of shows/segments airing on the TL
|
|
5
5
|
Author-email: Ben Weddle <ben.weddle@gmail.com>
|
|
6
6
|
Maintainer-email: Ben Weddle <ben.weddle@gmail.com>
|
|
@@ -523,7 +523,7 @@ nyt.run()
|
|
|
523
523
|
|
|
524
524
|
To disable ALL notifications, add a line like this:
|
|
525
525
|
|
|
526
|
-
> This will disable all notifications **including** syslog messages
|
|
526
|
+
> This will disable all notifications **including** syslog messages (shell print statements will not be disabled)
|
|
527
527
|
|
|
528
528
|
````python
|
|
529
529
|
from talklib import TLPod
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|