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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: talklib
3
- Version: 3.0.0
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "talklib"
3
- version = "3.0.0"
3
+ version = "3.2.0"
4
4
  description = "A package to automate processing of shows/segments airing on the TL"
5
5
  readme = "README.md"
6
6
  license = {file = "LICENSE.txt"}
@@ -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
- args = parser.parse_args()
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(notifications=notifications)
352
+ episode: Type[Episode] = Episode()
345
353
  ffmpeg: Type[FFMPEG] = FFMPEG()
346
- ssh: Type[SSH] = SSH(notifications=notifications)
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"Converted audio file will be {output_filename}")
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 = output_filename
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 = converted_file
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=converted_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.delete_local_file(file=feed_file)
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.0.0
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