uho/mk_show.py

535 lines
20 KiB
Python
Raw Normal View History

#!/usr/bin/python3
2024-01-14 02:56:15 +01:00
import sys, os, datetime, fnmatch, glob, random, time, pathlib, re
from datetime import timedelta
2024-01-11 00:20:43 +01:00
from os.path import join
from tinytag import TinyTag
2024-01-07 03:07:30 +01:00
from random import shuffle
import sqlite3, json
2024-01-14 02:56:15 +01:00
from mk_web import *
2024-01-15 12:28:05 +01:00
show_short_description = "An eclectic selection of independent and experimental music from Slovenia. \
Published weekly by The Rizoma Institute. Hosted and compiled by Rob Canning. \
Broadcast in Slovenia on FM by Mariborski radio student - MARŠ"
2024-01-14 02:56:15 +01:00
2024-01-15 12:10:58 +01:00
episode_number = sys.argv[1]
input_date = sys.argv[2]
episode_date = datetime.datetime.now().strftime("%Y-%m-%d")
episode_duration = 0
2024-01-08 18:01:22 +01:00
complete_playlist = []
show_array = []
2024-01-11 00:20:43 +01:00
show_cover = ""
2024-01-08 02:06:18 +01:00
archive = []
2024-01-14 02:56:15 +01:00
artists_played = []
2024-01-11 00:20:43 +01:00
artist_abreviated = []
2024-01-15 12:10:58 +01:00
show_name = "The_SLO_Indie" # OBED
2024-01-08 18:01:22 +01:00
path = "/home/rob/antena/"
2024-01-14 02:56:15 +01:00
web_path = "/home/rob/antena/html/episode/{0}/img".format(episode_number)
if os.path.exists(web_path):
print("path_exists_doing_nothing")
else: os.makedirs(web_path)
2024-01-08 18:01:22 +01:00
# /////////////////////////////////////////////////
2024-01-15 12:10:58 +01:00
def set_episode_date(input_date):
2024-01-15 12:28:05 +01:00
global episode_date
date_str = input_date
date_format = '%Y-%m-%d'
episode_date = str(datetime.datetime.strptime(date_str, date_format))
#return episode_date
2024-01-15 12:10:58 +01:00
print(episode_date)
conn = ''
def database_create():
# the show database
global conn
conn = sqlite3.connect("database/show.db")
#cursor = conn.cursor()
#cursor.execute("DROP TABLE SHOW")
#conn.commit()
conn.execute('''CREATE TABLE IF NOT EXISTS SHOW(
ID INTEGER PRIMARY KEY AUTOINCREMENT,
EPISODE INT NOT NULL,
DATE TEXT NOT NULL,
DURATION INT NOT NULL,
ALBUM TEXT NOT NULL,
TRACK TEXT NOT NULL,
ARTIST TEXT NOT NULL,
TRACKDUR INT NOT NULL,
YEAR TEXT NOT NULL
);''')
print("Table created successfully");
#conn.execute("INSERT INTO SHOW (ID, EPISODE,DATE,TRACK,ARTIST) \
#VALUES (1, 1, 'wednesday', 'Some song', 'Some Artist' )");
#conn.commit()
#print("DB Record created successfully");
#conn.close()
2024-01-08 18:01:22 +01:00
def create_intro(show_array):
intropath = path + "texts/clips/this_is"
2024-01-08 02:06:18 +01:00
intro = random.choice(os.listdir(intropath))
2024-01-08 18:01:22 +01:00
show_array.insert(0, str(os.path.abspath(intropath)) + "/" + str(intro))
2024-01-08 02:06:18 +01:00
def add_to_tracks_played(add_to_played: str):
2024-01-11 00:20:43 +01:00
with open('playlists/track_playout_history.txt', "a") as tracks_played_file:
2024-01-14 02:56:15 +01:00
tracks_played_file.write(str(add_to_played) + "\n") # newline \n needed here?
2024-01-08 02:06:18 +01:00
2024-01-08 18:01:22 +01:00
def check_archive(track):
2024-01-08 02:06:18 +01:00
global archive
2024-01-11 00:20:43 +01:00
with open('playlists/track_playout_history.txt') as archive_file:
2024-01-08 02:06:18 +01:00
for line in archive_file:
archive.append(line)
2024-01-08 18:01:22 +01:00
if track not in archive:
print("____ TRACK NOT YET PLAYED ... ADDING _____")
return True
else:
print("____ TRACK ALREADY PLAYED _____")
return False
def load_all_music():
2024-01-11 00:20:43 +01:00
with open('playlists/complete_music_archive.pls') as playlist_file:
2024-01-08 18:01:22 +01:00
for line in playlist_file:
complete_playlist.append(line)
2024-01-14 02:56:15 +01:00
print('''
-------------------------------
loaded {0} tracks from playlist
-------------------------------
'''.format(str(len(complete_playlist))))
2024-01-08 18:01:22 +01:00
return complete_playlist
def create_show_playlist(show_array: list, complete_playlist:list):
load_all_music()
global episode_duration
2024-01-08 02:06:18 +01:00
global archive
track_count = 0
2024-01-14 02:56:15 +01:00
global artists_played
max_track_dur = 10
min_track_dur = 1.8
2024-01-07 03:07:30 +01:00
while episode_duration < 60 * 60 and track_count < 12 :
2024-01-08 18:01:22 +01:00
song = random.choice(random.sample(\
complete_playlist, len(complete_playlist) )).rstrip() # pick a song
2024-01-08 02:06:18 +01:00
track = TinyTag.get(song) # get its metadata
# check if the artist not in the played list and the song is less than 8mins
2024-01-14 02:56:15 +01:00
if track.artist not in artists_played:
2024-01-08 18:01:22 +01:00
if check_archive(track.title) is True:
if int(track.duration) > min_track_dur * 60:
if int(track.duration) < max_track_dur * 60:
show_array.append(song.rstrip()) # if 'not in' is true then add the song
2024-01-11 00:20:43 +01:00
art = string=re.sub("\(.*?\)","",track.artist)
2024-01-14 02:56:15 +01:00
# shorten verbose artist names such as trojnik Trojnik (Cene Resnik, Tomaž Grom, Vid Drašler)
2024-01-11 00:20:43 +01:00
art = string=re.sub("and","&",art)
2024-01-14 02:56:15 +01:00
artist_abreviated.append(art)
artists_played.append(track.artist) # and add the artist to the played list
2024-01-08 18:01:22 +01:00
add_to_tracks_played(track.title) # and write entry to archive file
if not track.year: # where missing metadata give a dummy value
track.year = 0000
cursor = conn.cursor()
#long_string = json.dumps(["' SomeWord"])
cursor.execute("INSERT INTO SHOW (\
ID, EPISODE, DATE, DURATION, ALBUM, TRACK, ARTIST, TRACKDUR, YEAR) \
VALUES (NULL, ?, ?, ?, ?, ?, ?,?,?)", [episode_number, episode_date, episode_duration, \
track.album, track.title, track.artist, track.duration, track.year]);
conn.commit()
print("DB Record created successfully");
2024-01-14 02:56:15 +01:00
track_count += 1; print(track_count)
episode_duration = episode_duration + track.duration
2024-01-11 00:20:43 +01:00
else: print("TRACK TOO SHORT..........." )
else: print("TRACK TOO LONG..........." )
else: print("SONG PLAYED IN PREVIOUS EPISODE" )
else: print("ARTIST ALREADY IN PODCAST")
conn.close()
2024-01-08 18:01:22 +01:00
episode_duration = timedelta(seconds=round(episode_duration))
2024-01-14 02:56:15 +01:00
print("total tracks = {0} \n total duration = {1} ".format(track_count, episode_duration))
2024-01-14 02:56:15 +01:00
return show_array, episode_duration
2024-01-14 02:56:15 +01:00
def combine_images(columns, space, images, variants:int):
global show_cover
2024-01-11 00:20:43 +01:00
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
rows = len(images) // columns
if len(images) % columns:
rows += 1
2024-01-08 02:06:18 +01:00
2024-01-11 00:20:43 +01:00
width_max = 500 #max([Image.open(image).width for image in images])
height_max = 500# max([Image.open(image).height for image in images])
background_width = width_max*columns + (space*columns)-space
background_height = height_max*rows + (space*rows)-space
#background = Image.new('RGBA', (background_width, background_height), (0, 0, 0, 255))
background = Image.new('RGBA', (width_max*columns , height_max*columns), (0, 0, 0, 255))
2024-01-08 18:01:22 +01:00
2024-01-11 00:20:43 +01:00
x = 0
y = 0
for i, image in enumerate(images):
imga = Image.open(image)
size = (500,500)
img = imga.resize(size)
x_offset = int((width_max-img.width)/2)
y_offset = int((height_max-img.height)/2)
background.paste(img, (x+x_offset, y+y_offset+100))
x += width_max + space
if (i+1) % columns == 0:
y += height_max + space
x = 0
im = ImageDraw.Draw(background)
mf_h1 = ImageFont.truetype('fonts/Antonio-Light.ttf', 280)
2024-01-14 02:56:15 +01:00
mf_h2 = ImageFont.truetype('fonts/Antonio-Light.ttf', 65)
2024-01-11 00:20:43 +01:00
mf_h3 = ImageFont.truetype('fonts/Antonio-Regular.ttf', 50)
2024-01-14 02:56:15 +01:00
mf_h4 = ImageFont.truetype('fonts/Antonio-Light.ttf', 50)
2024-01-11 00:20:43 +01:00
h2_spc = 85
h2_baseline = 1530
2024-01-14 02:56:15 +01:00
# Add Text to the image ----------------------------------------
# -------------------------------------------------------------------
# some logic to shuffle the list if sub sections of list are too long for layout
str_length_thresh = 50
while \
[len(s) for s in [''.join(artist_abreviated[0:3])]][0] > str_length_thresh or\
[len(s) for s in [''.join(artist_abreviated[3:6])]][0] > str_length_thresh or\
[len(s) for s in [''.join(artist_abreviated[6:9])]][0] > str_length_thresh or \
[len(s) for s in [''.join(artist_abreviated[9:12])]][0] > str_length_thresh:
print("on of the lines is longer than fits the page... shuffling the list for a better look")
random.shuffle(artist_abreviated)
2024-01-14 02:56:15 +01:00
im.text((30,10), '''an eclectic selection of contemporary independent music from slovenia: {0} - E P I S O D E #{1}
'''\
.format(episode_date,episode_number), fill="white", font=mf_h3)
2024-01-14 02:56:15 +01:00
im.text((30,280), ''' THIS WEEK ON \n EPISODE #{0} of \n {1}!'''.upper()\
.format(episode_number, show_name), fill="white", font=mf_h1, stroke_width=2, stroke_fill='black')
im.text((30, h2_baseline + (h2_spc*1) ), '''m u s i c _ f r o m _ : {0}'''\
.format(' | '.join(artist_abreviated[0:3])), (255,255,255), font=mf_h2)
im.text((30, h2_baseline + (h2_spc*2) ), "{0}"\
.format(' | '.join(artist_abreviated[3:6])), (255,255,255), font=mf_h2)
im.text((30, h2_baseline + (h2_spc*3)), "{0}"\
.format(' | '.join(artist_abreviated[6:9])), (255,255,255), font=mf_h2)
im.text((30, h2_baseline + (h2_spc*4)), "{0}"\
.format(' | '.join(artist_abreviated[9:12])), (255,255,255), font=mf_h2)
im.text((1540,1888), ''' http://{0}.rizom.si '''\
.format(show_name, episode_date,episode_number), fill="white", font=mf_h4)
2024-01-14 02:56:15 +01:00
show_cover = 'img/cover.png'.format(episode_number,episode_date, variants)
2024-01-14 02:56:15 +01:00
background.save("html/" + "episode/{0}/{1}".format(episode_number, show_cover))
return show_cover
2024-01-11 00:20:43 +01:00
2024-01-14 02:56:15 +01:00
def create_show_coverart(show_array, variants):
2024-01-11 00:20:43 +01:00
show_cover_jpgs = []
for dir in show_array:
path = pathlib.Path(dir).parent
for file in os.listdir(path):
for i in ["cover", "COVER"]:
if i in file:
show_cover_jpgs.append(str(path) + "/" + file)
2024-01-14 02:56:15 +01:00
print('''
------------------------
creating show cover art
------------------------
''')
# if len(show_cover_jpgs) > 0: # duplicate this for variations of geometry
for i in range(variants):
x = show_cover_jpgs[:12]
combine_images(columns=4, space=3, images=random.sample(x,len(x)),variants=i)
2024-01-11 00:20:43 +01:00
return show_cover
2024-01-14 02:56:15 +01:00
def create_animated_gif():
import contextlib
from PIL import Image
2024-01-11 00:20:43 +01:00
2024-01-14 02:56:15 +01:00
# filepaths
fp_in = "/home/rob/antena/html/episode/2/img/*.png".format(episode_number)
fp_out = "/home/rob/antena/html/episode/2/img/show_cover.gif"
2024-01-11 00:20:43 +01:00
2024-01-14 02:56:15 +01:00
# use exit stack to automatically close opened images
with contextlib.ExitStack() as stack:
2024-01-08 18:01:22 +01:00
2024-01-14 02:56:15 +01:00
# lazily load images
imgs = (stack.enter_context(Image.open(f))
for f in sorted(glob.glob(fp_in)))
2024-01-08 18:01:22 +01:00
2024-01-14 02:56:15 +01:00
# extract first image from iterator
img = next(imgs)
2024-01-07 03:07:30 +01:00
2024-01-14 02:56:15 +01:00
# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif
img.save(fp=fp_out, format='GIF', append_images=imgs,
save_all=True, duration=200, loop=0)
2024-01-11 00:20:43 +01:00
2024-01-08 18:01:22 +01:00
def create_pls_file():
# write the selection as a playlist file
with open("shows/antena_playlist_" + episode_date + ".pls","w") as file:
2024-01-08 18:01:22 +01:00
file.writelines("\n".join(show_array))
def create_podcast(show_array: list):
2024-01-14 02:56:15 +01:00
print('''
------------------------
creating show audio
2024-01-15 12:10:58 +01:00
------------------------''')
2024-01-14 02:56:15 +01:00
2024-01-08 18:01:22 +01:00
from glob import glob
from pydub import AudioSegment
playlist_songs = [AudioSegment.from_file(flac_file) for flac_file in show_array]
2024-01-15 12:10:58 +01:00
print(playlist_songs)
show_intro = playlist_songs[0]
# first_song = playlist_songs[0].fade_in(0) # only fadein if used over show intro - currently not used
# intro_and_first = first_song.overlay(show_intro)
first_three_blurb = playlist_songs[0]
second_three_blurb = playlist_songs[0]
final_songs_blurb = playlist_songs[0]
final_show_outro = playlist_songs[0]
# next two commented lines are for if intro goes over first track or not
#playlist = intro_and_first
playlist = show_intro
2024-01-15 12:10:58 +01:00
# playlist = []
#for song in playlist_songs[2:3]:
for song in playlist_songs[1:4]: # first three songs (first added with intro)
# We don't want an abrupt stop at the end, so let's do a 1 second crossfades
2024-01-15 12:10:58 +01:00
playlist = playlist.append(song)
print(song)
print("first songs added")
2024-01-08 18:01:22 +01:00
# blurb about first three tracks
2024-01-15 12:10:58 +01:00
# playlist = playlist.append(first_three_blurb) # <--------------BLURB INSERT
2024-01-08 18:01:22 +01:00
for song in playlist_songs[4:7]: # second three songs
2024-01-15 12:10:58 +01:00
playlist = playlist.append(song)
print(song)
print("second songs added")
2024-01-15 12:10:58 +01:00
# playlist = playlist.append(second_three_blurb) # <--------------BLURB INSERT
2024-01-08 18:01:22 +01:00
for song in playlist_songs[7:10]: # second three song
2024-01-15 12:10:58 +01:00
#playlist = playlist.append(song, crossfade=(1 * 1000))
playlist = playlist.append(song)
print(song)
print("third songs added")
2024-01-15 12:10:58 +01:00
# playlist = playlist.append(final_songs_blurb) # <--------------BLURB INSERT
2024-01-08 18:01:22 +01:00
for song in playlist_songs[10:13]: # second three song
2024-01-15 12:10:58 +01:00
playlist = playlist.append(song)
print(song)
print("final songs added")
2024-01-15 12:10:58 +01:00
# playlist = playlist.append(final_show_outro) # <-------------- OUTRO SEQUENCE
2024-01-08 18:01:22 +01:00
# get length of final show / podcast
playlist_length = len(playlist) / (1000*60)
# save the entire poidcast
2024-01-14 02:56:15 +01:00
with open("html/episode/{0}/show.flac".format(episode_number), 'wb') as out_f:
print("FLAC output file opened...writing to file...")
2024-01-08 18:01:22 +01:00
playlist.export(out_f, format='flac')
print("FLAC audio file exported...")
with open("html/episode/{0}/show.mp3".format(episode_number), 'wb') as out_f:
print("MP3 output file opened...writing to file...")
playlist.export(out_f, format='mp3')
print("MP3 audio file exported...")
2024-01-11 00:20:43 +01:00
2024-01-14 02:56:15 +01:00
### ------------------------------------------------------------
def create_html_episode_from_template():
from jinja2 import Template, Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('html/templates'))
episode_template = env.get_template('episode.jinja')
show_info = []
# maybe a jinja2 template loop here instead
for i in show_array:
track = TinyTag.get(i)
detail = str(track.artist) + " | " + str(track.album) + \
" | " + str(track.title) + " | " + str(track.year) + \
" | " + str(timedelta(seconds=round(track.duration)))
show_info.append("" + detail)
output_from_parsed_template = episode_template.render(episode_author="rrrrrrrr",\
2024-01-15 12:10:58 +01:00
episode_duration=episode_duration, episode_date=episode_date, \
about_show=show_short_description, episode_playlist=show_info, \
episode_image="img/cover.png".format(episode_number))
with open("html/episode/{0}/index.html".format(episode_number), "w") as episode_page:
episode_page.write(output_from_parsed_template)
def create_html_episode_from_template():
2024-01-14 02:56:15 +01:00
from jinja2 import Template, Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('html/templates'))
episode_template = env.get_template('episode.jinja')
show_info = []
# maybe a jinja2 template loop here instead
for i in show_array:
track = TinyTag.get(i)
detail = str(track.artist) + " | " + str(track.album) + \
" | " + str(track.title) + " | " + str(track.year) + \
" | " + str(timedelta(seconds=round(track.duration)))
show_info.append("" + detail)
output_from_parsed_template = episode_template.render(episode_author="rrrrrrrr",\
2024-01-15 12:10:58 +01:00
episode_duration="123", about_show=show_short_description, episode_playlist=show_info, \
episode_image="img/cover.png".format(episode_number))
with open("html/episode/{0}/index.html".format(episode_number), "w") as episode_page:
episode_page.write(output_from_parsed_template)
def create_html_homepage_from_template():
from jinja2 import Template, Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('html/templates'))
homepage_template = env.get_template('homepage.jinja')
show_info = []
episode_artists = []
for i in range(10):
artists = []
2024-01-15 12:10:58 +01:00
conn = sqlite3.connect("database/show.db")
cur = conn.cursor()
cur.execute("SELECT ARTIST FROM SHOW WHERE EPISODE=?", [i])
rows = cur.fetchall()
for artist in rows:
art = string=re.sub("\(.*?\)","", artist[0])
# shorten verbose artist names such as trojnik Trojnik (Cene Resnik, Tomaž Grom, Vid Drašler)
artist = string=re.sub("and","&",art)
artists.append(artist)
episode_artists.append(artists)
episodes = []
2024-01-15 12:10:58 +01:00
for i in range(10):
print(episode_artists)
2024-01-15 12:10:58 +01:00
an_episode = dict(date="2012-02-", \
episode_artists=episode_artists[i], episode_number=i, \
episode_date=episode_date, \
episode_duration=episode_duration)
episodes.append(an_episode)
episodes = reversed(episodes) # reversed order to most recent episode appears first in list
# maybe a jinja2 template loop here instead
for i in show_array:
track = TinyTag.get(i)
detail = str(track.artist) + " | " + str(track.album) + \
" | " + str(track.title) + " | " + str(track.year) + \
" | " + str(timedelta(seconds=round(track.duration)))
show_info.append("" + detail)
2024-01-15 12:10:58 +01:00
output_from_parsed_template = homepage_template.render(\
show_name=''.join(random.choice((str.upper,str.lower))(x) for x in show_name), \
episodes=episodes, episode_author="Rob Canning",\
episode_duration=episode_duration, episode_number=episode_number, \
episode_artists=episode_artists, \
about_show=show_short_description, episode_playlist=show_info, \
episode_image="episode/{0}/img/cover.png".format(episode_number))
with open("html/index.html".format(episode_number), "w") as episode_page:
2024-01-14 02:56:15 +01:00
episode_page.write(output_from_parsed_template)
2024-01-15 12:10:58 +01:00
def create_html_episode_from_template():
from jinja2 import Template, Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('html/templates'))
episode_template = env.get_template('episode.jinja')
show_info = []
# maybe a jinja2 template loop here instead
for i in show_array:
track = TinyTag.get(i)
detail = str(track.artist) + " | " + str(track.album) + \
" | " + str(track.title) + " | " + str(track.year) + \
" | " + str(timedelta(seconds=round(track.duration)))
show_info.append("" + detail)
output_from_parsed_template = episode_template.render(\
show_name=show_name, episode_author="Rob Canning",\
episode_duration=episode_duration, \
episode_date=episode_date, about_show=show_short_description, \
episode_playlist=show_info, \
episode_image="img/cover.png".format(episode_number))
with open("html/episode/{0}/index.html".format(episode_number), "w") as episode_page:
episode_page.write(output_from_parsed_template)
def create_RSS_XML_from_template():
from jinja2 import Template, Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('html/templates'))
rss_template = env.get_template('show_RSS_xml.jinja')
output_from_parsed_template = rss_template.render(\
show_name=show_name, \
episode_number=int(episode_number), episode_author="Rob Canning",\
episode_duration=episode_duration, about_show=show_short_description, \
episode_image="img/cover.png".format(episode_number))
with open("html/show_rss.xml".format(episode_number), "w") as rss_page:
rss_page.write(output_from_parsed_template)
2024-01-15 12:28:05 +01:00
2024-01-15 12:10:58 +01:00
database_create()
2024-01-15 12:28:05 +01:00
set_episode_date(input_date)
2024-01-14 02:56:15 +01:00
create_show_playlist(show_array, complete_playlist)
create_show_coverart(show_array, 1) #episode_duration = 100
2024-01-14 02:56:15 +01:00
#create_animated_gif()
create_intro(show_array)
2024-01-08 18:01:22 +01:00
create_pls_file()
2024-01-14 02:56:15 +01:00
create_html_episode_from_template()
create_html_homepage_from_template()
2024-01-15 12:10:58 +01:00
create_RSS_XML_from_template()
create_podcast(show_array)
2024-01-14 02:56:15 +01:00
#convert -delay 100 -loop 0 html/episode/2/img/show_cover_2024-01-12* animatedGIF.gif