talklib 2.2.1__tar.gz → 3.1.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: 2.2.1
3
+ Version: 3.1.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>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "talklib"
3
- version = "2.2.1"
3
+ version = "3.1.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"}
@@ -23,3 +23,7 @@ build-backend = "setuptools.build_meta"
23
23
  where = ["src"]
24
24
  include = ["talklib*"]
25
25
  exclude = [".tests*"]
26
+
27
+
28
+ [project.scripts]
29
+ talklib = "talklib.cli:main"
@@ -0,0 +1,88 @@
1
+ import argparse
2
+ import os
3
+ import sys
4
+ import xml.etree.ElementTree as ET
5
+
6
+ from talklib.pod import SSH
7
+
8
+ def parse_args():
9
+ parser = argparse.ArgumentParser(description="use talklib in the terminal")
10
+
11
+ feed_template_help = "Generate an RSS feed template in the current directory"
12
+ parser.add_argument('--feed-template', action='store_true', help=feed_template_help, required=False)
13
+
14
+ new_podcast_directory_help = "Creates a new podcast directory on the server with the value you pass in. \
15
+ You MUST have an RSS feed (feed.xml) and logo (image.jpg) in the current directory."
16
+ parser.add_argument('--new-pod-dir', type=str, help=new_podcast_directory_help, required=False)
17
+
18
+ args = parser.parse_args()
19
+
20
+ return args
21
+
22
+ def generate_feed_template():
23
+ ET.register_namespace(prefix="atom", uri="http://www.w3.org/2005/Atom")
24
+ ET.register_namespace(prefix="itunes", uri="http://www.itunes.com/dtds/podcast-1.0.dtd")
25
+ feed = ET.fromstring(feed_template)
26
+ tree = ET.ElementTree(feed)
27
+ tree.write("feed.xml", encoding="utf-8", xml_declaration=True)
28
+ # feed.write("feed.xml", encoding="utf-8", xml_declaration=True)
29
+ print("'feed.xml' file created in " + os.getcwd())
30
+ return
31
+
32
+ def new_podcast_dir(name: str):
33
+ if not os.path.isfile("feed.xml"):
34
+ return print(f"cannot find 'feed.xml' in {os.getcwd()}. You must have this file in the current directory.")
35
+
36
+ if not os.path.isfile("image.jpg"):
37
+ return print(f"cannot find 'image.jpg' in {os.getcwd()}. You must have this file in the current directory.")
38
+
39
+ print("generating new podcast directory called " + name)
40
+
41
+ ssh = SSH()
42
+ ssh.make_new_folder(folder=name)
43
+ ssh.upload_file(file="feed.xml", folder=name)
44
+ ssh.upload_file(file="image.jpg", folder=name)
45
+
46
+ print("done! you can now delete the local copies of the files")
47
+ return
48
+
49
+ def main():
50
+ if len(sys.argv) == 1: # if no arguments are passed
51
+ return print("talklib -h for help")
52
+ args = parse_args()
53
+
54
+ if args.feed_template:
55
+ generate_feed_template()
56
+ if args.new_pod_dir:
57
+ new_podcast_dir(name=args.new_pod_dir)
58
+
59
+ feed_template: str = """
60
+ <rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0">
61
+ <channel>
62
+ <title>!!CHANGEME!!</title>
63
+ <link>http://nashvilletalkinglibrary.org/</link>
64
+ <atom:link href="https://assets.library.nashville.org/talkinglibrary/shows/!!CHANGEME!!/feed.xml" rel="self" type="application/rss+xml" />
65
+ <description>
66
+ !!CHANGEME!!
67
+ </description>
68
+ <copyright>© 1975-2022 Nashville Talking Library - Do not copy or redistribute</copyright>
69
+ <docs>https://cyber.harvard.edu/rss/rss.html</docs>
70
+ <generator>NTL Python Magic</generator>
71
+ <webMaster>nashvilletalkinglibrary@gmail.com (Darth Vader)</webMaster>
72
+ <itunes:owner>
73
+ <itunes:name>Nashville Talking Library</itunes:name>
74
+ <itunes:email>ntl@nashville.gov</itunes:email>
75
+ </itunes:owner>
76
+ <itunes:category text="Education" />
77
+ <itunes:explicit>true</itunes:explicit>
78
+ <itunes:image href="https://assets.library.nashville.org/talkinglibrary/shows/!!CHANGEME!!/image.jpg" />
79
+ <image>
80
+ <url>https://assets.library.nashville.org/talkinglibrary/shows/!!CHANGEME!!/image.jpg</url>
81
+ <title>!!CHANGEME!!</title>
82
+ <link>http://nashvilletalkinglibrary.org/</link>
83
+ </image>
84
+ <language>en</language>
85
+ <lastBuildDate>leave me alone</lastBuildDate>
86
+ </channel>
87
+ </rss>
88
+ """
@@ -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
@@ -90,6 +92,12 @@ The error from the SSH library is: {e}"
90
92
  self.notifications.send_notifications(
91
93
  message=f"Unable to delete '{file}' from {folder}: {e}. Continuing automation...",
92
94
  subject="Error")
95
+
96
+ def make_new_folder(self, folder: str) -> None:
97
+ if self.check_folder_exists_no_exception(folder=folder):
98
+ raise Exception (f"{folder}/ already exists on server! Exiting...")
99
+ self.connection.run(f"cd shows && mkdir {folder}", hide=True)
100
+ self.notifications.prep_syslog(message=f"{folder}/ created on server")
93
101
 
94
102
  def get_folders(self) -> list:
95
103
  ret_val: list = []
@@ -135,6 +143,13 @@ The error from the SSH library is: {e}"
135
143
  self.notifications.send_notifications(message=to_send, subject='Error')
136
144
  raise Exception (to_send)
137
145
 
146
+ def check_folder_exists_no_exception(self, folder: str):
147
+ self.notifications.prep_syslog(message=f"checking if {folder}/ exists on server...")
148
+ folders = self.get_folders()
149
+ if folder.lower() in folders:
150
+ self.notifications.prep_syslog(message=f"{folder}/ exists on server!")
151
+ return True
152
+
138
153
 
139
154
  class Episode(BaseModel):
140
155
  feed_file: str = Field(min_length=1, default=None)
@@ -405,15 +420,13 @@ class TLPod(BaseModel):
405
420
  output_filename = output_filename[0]
406
421
  output_filename = os.path.basename(output_filename).lower()
407
422
  output_filename = output_filename + '.mp3'
408
- self.notifications.prep_syslog(message=f"Converted audio file will be {output_filename}")
423
+ self.notifications.prep_syslog(message=f"final audio file will be {output_filename}")
409
424
  return output_filename
410
425
 
411
426
  def convert(self, file:str):
412
- output_filename = self.create_converted_filename(file=file)
413
-
414
427
  self.ffmpeg.input_file = file
415
- self.ffmpeg.output_file = output_filename
416
- self.ffmpeg.compression = False # this is for podcasts. these files should already be edited
428
+ self.ffmpeg.output_file = "out.mp3"
429
+ self.ffmpeg.compression = False # this is for podcasts. these files should already be edited
417
430
 
418
431
  ffmpeg_commands = self.ffmpeg.get_commands()
419
432
  self.notifications.prep_syslog(message=f"FFmppeg commands: {ffmpeg_commands}")
@@ -426,6 +439,32 @@ class TLPod(BaseModel):
426
439
  except Exception as ffmpeg_exception:
427
440
  self.notifications.send_notifications(message=f'FFmpeg error: {ffmpeg_exception}', subject='Error')
428
441
  raise ffmpeg_exception
442
+
443
+ def concat(self, preroll:str, program_audio: str, output_filename: str):
444
+ self.notifications.prep_syslog(message="concatenating preroll and program audio together...")
445
+ subprocess.run(f'ffmpeg -hide_banner -loglevel quiet -i "concat:{preroll}|{program_audio}" -c copy {output_filename}')
446
+ self.notifications.prep_syslog(message=f"files successfully concatenated as: {output_filename}")
447
+ return output_filename
448
+
449
+ def download_preroll(self):
450
+ download_URL = "https://assets.library.nashville.org/talkinglibrary/pod_preroll.mp3"
451
+ input_file = 'preroll.mp3'
452
+ with open (input_file, mode='wb') as downloaded_file:
453
+ self.notifications.prep_syslog(message=f"downloading preroll audio from {download_URL}...")
454
+ a = requests.get(download_URL)
455
+ downloaded_file.write(a.content)
456
+ downloaded_file.close()
457
+ self.notifications.prep_syslog(message="preroll audio successfully downloaded")
458
+ return downloaded_file.name
459
+
460
+ def post_cleaup(self):
461
+ self.notifications.prep_syslog(message="looking for local files to delete...")
462
+ XML_files = glob.glob("*.xml")
463
+ for file in XML_files:
464
+ self.delete_local_file(file=file)
465
+ MP3_files = glob.glob("*.mp3")
466
+ for file in MP3_files:
467
+ self.delete_local_file(file=file)
429
468
 
430
469
  def delete_local_file(self, file: str):
431
470
  try:
@@ -444,11 +483,14 @@ class TLPod(BaseModel):
444
483
 
445
484
  audio_file = self.match_file()
446
485
  converted_file = self.convert(file=audio_file)
486
+ output_filename = self.create_converted_filename(file=audio_file)
487
+ preroll = self.download_preroll()
488
+ concat_file = self.concat(preroll=preroll, program_audio=converted_file, output_filename=output_filename)
447
489
 
448
490
  feed_file = self.ssh.download_file(folder=self.bucket_folder, file='feed.xml') # all XML files on server should have the same name
449
491
 
450
492
  self.episode.feed_file = feed_file
451
- self.episode.audio_filename = converted_file
493
+ self.episode.audio_filename = concat_file
452
494
  self.episode.bucket_folder = self.bucket_folder
453
495
  self.episode.episode_title = self.display_name
454
496
  self.episode.max_episodes = self.max_episodes_in_feed
@@ -456,10 +498,9 @@ class TLPod(BaseModel):
456
498
  self.episode.add_new_episode()
457
499
  self.episode.remove_old_episodes()
458
500
 
459
- self.ssh.upload_file(folder=self.bucket_folder, file=converted_file)
501
+ self.ssh.upload_file(folder=self.bucket_folder, file=concat_file)
460
502
  self.ssh.upload_file(folder=self.bucket_folder, file=feed_file)
461
503
 
462
- self.delete_local_file(file=feed_file)
463
- self.delete_local_file(file=converted_file)
504
+ self.post_cleaup()
464
505
 
465
506
  self.notifications.prep_syslog(message="All done.")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: talklib
3
- Version: 2.2.1
3
+ Version: 3.1.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>
@@ -3,6 +3,7 @@ README.md
3
3
  pyproject.toml
4
4
  requirements.txt
5
5
  src/talklib/__init__.py
6
+ src/talklib/cli.py
6
7
  src/talklib/ev.py
7
8
  src/talklib/ffmpeg.py
8
9
  src/talklib/notify.py
@@ -12,5 +13,6 @@ src/talklib/utils.py
12
13
  src/talklib.egg-info/PKG-INFO
13
14
  src/talklib.egg-info/SOURCES.txt
14
15
  src/talklib.egg-info/dependency_links.txt
16
+ src/talklib.egg-info/entry_points.txt
15
17
  src/talklib.egg-info/requires.txt
16
18
  src/talklib.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ talklib = talklib.cli:main
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