uho/mk_show.py

551 lines
21 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
import uuid
2024-01-19 01:50:32 +01:00
from pypika import Query, Table, Field, Column
2024-01-14 02:56:15 +01:00
#from mk_web import *
2024-01-14 02:56:15 +01:00
path = "/home/rob/antena/"
show_name = "The_SLO_Indie"
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Š"
episode_author="Rob Canning"
episode_number = int(sys.argv[1])
2024-01-15 12:10:58 +01:00
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 = []
episode_playlist = []
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
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 = ''
2024-01-19 01:50:32 +01:00
def database_create_episodes_table():
2024-01-15 12:10:58 +01:00
# the show database
global conn
conn = sqlite3.connect("database/show.db")
2024-01-19 01:50:32 +01:00
q = Query \
.create_table("EPISODES") \
.columns(
Column("id", "INT", nullable=True),
Column("episode", "INT", nullable=True),
Column("date", 'DATETIME', nullable=True),
Column("album", "VARCHAR(200)", nullable=True),
Column("track", "VARCHAR(120)", nullable=True),
Column("artist", "VARCHAR(120)", nullable=True),
Column("trackdur", "FLOAT", nullable=True),
Column("genre", "VARCHAR(120)", nullable=True),
Column("year", 'DATETIME', nullable=True),
Column("path", "VARCHAR(120)", nullable=False))\
.primary_key("path")
#.unique("path") \
#TODO get the unique path back into action find bug
conn.execute(str(q))
print("EPISODES Table created successfully");
2024-01-15 12:10:58 +01:00
def create_intro(episode_playlist):
intropath = path + "audio/texts/clips/this_is"
2024-01-08 02:06:18 +01:00
intro = random.choice(os.listdir(intropath))
episode_playlist.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 create_episode_playlist(episode_playlist: list, complete_playlist:list):
2024-01-08 18:01:22 +01:00
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 = 9
min_track_dur = 2
# TODO what is most important 12 tracks or 60 minutes
2024-01-18 15:07:44 +01:00
# what will
while episode_duration < 60 * 60 and track_count < 12 :
cursor = conn.cursor()
2024-01-19 01:50:32 +01:00
cursor.execute("SELECT * FROM MUSIC_LIBRARY ORDER BY RANDOM() LIMIT 1 ;")
r = cursor.fetchone() # FETCH ONE RANDOM TRACK FROM THE DATABASE
print(str(r)+"ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss")
# for t in r:
song = str(r[9])
track_label = str(r[1])
track_album = str(r[2])
track_title = str(r[3])
track_artist = str(r[4])
track_duration = float(r[6])
track_genre = str(r[5])
track_year = str(r[7])
track_path = '/'.join(song.split('/')[0:-1])
2024-01-19 01:50:32 +01:00
# SOME LOGIC TO SEE IF WE ALLOW THAT TRACK OR NOT
# TODO here we need to append to DB not the static file
if track_artist not in artists_played:
if check_archive(track_title) is True:
if track_duration > min_track_dur * 60:
if int(track_duration) < max_track_dur * 60:
episode_playlist.append(song.rstrip()) # if 'not in' is true then add the song
art = string=re.sub("\(.*?\)","",track_artist)
2024-01-19 01:50:32 +01:00
print(art + "?????????????????????????????????????????????????????????????????????????????????????")
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
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
2024-01-19 01:50:32 +01:00
e = Table('EPISODES')
q = e.insert(1, episode_number, episode_date, \
track_album, track_title, track_artist, \
track_duration,track_genre, track_year, track_path)
2024-01-19 01:50:32 +01:00
cursor.execute(str(q))
# ID, EPISODE, DATE, ALBUM, TRACK, ARTIST, TRACKDUR, YEAR, PATH) \
# VALUES (NULL, ?, ?, ?, ?, ?,?,?,? )", [episode_number, episode_date, \
# track_album, track_title, track_artist, \
# track_duration, track_year, track_path]);
conn.commit()
print("sqlite: Episode track successfully inserted into SHOW table");
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")
#
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 episode_playlist, 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)
#img = img.rotate(random.randrange(360))
2024-01-11 00:20:43 +01:00
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 ----------------------------------------
2024-01-14 02:56:15 +01:00
# some logic to shuffle the list if sub sections of list are too long for layout
str_length_thresh = 50
#TODO if an artist is listed as Various Arist then remove it from cover display and think of logic
#TODO exit while loop if it cant find a solution and restart script or shrink font and adjust rules
2024-01-14 02:56:15 +01:00
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('''one of the lines is longer than fits the page...
2024-01-19 01:50:32 +01:00
...................shuffling the list for a better look: {0}'''.format(artist_abreviated))
2024-01-14 02:56:15 +01:00
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
def create_show_coverart(episode_playlist, variants):
2024-01-11 00:20:43 +01:00
show_cover_jpgs = []
# in the directory containing songs find jpg and pngs containing string "cover"
for dir in episode_playlist:
2024-01-11 00:20:43 +01:00
path = pathlib.Path(dir).parent
for file in os.listdir(path):
for p in [".png", ".jpg", ".jpeg"]:
if p in file:
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(''''\n ------------------------
2024-01-14 02:56:15 +01:00
creating show cover art
------------------------ ''')
2024-01-14 02:56:15 +01:00
# 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=10, 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:
file.writelines("\n".join(episode_playlist))
2024-01-08 18:01:22 +01:00
def create_podcast(episode_playlist: list):
2024-01-08 18:01:22 +01:00
print('''------------------------
2024-01-14 02:56:15 +01:00
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 episode_playlist]
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)
2024-01-19 01:50:32 +01:00
# save the entire poidcast as FLAC
# with open("html/episode/{0}/show.flac".format(episode_number), 'wb') as out_f:
# print("FLAC output file opened...writing to file...")
# playlist.export(out_f, format='flac')
# print("FLAC audio file exported...")
2024-01-19 01:50:32 +01:00
# save the entire poidcast as MP3
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_homepage_from_template(episode_playlist):
# TODO "on this weeks show" varients fed to html from list here
from jinja2 import Template, Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('html/templates'))
homepage_template = env.get_template('homepage.jinja')
conn = sqlite3.connect("database/show.db")
cursor = conn.cursor()
show_info = []
episode_artists = []
for i in range(10):
artists = []
2024-01-19 01:50:32 +01:00
cursor.execute("SELECT artist FROM EPISODES WHERE episode=?", [i])
rows = cursor.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 = []
for i in range(10): # get this from new table EPISODE_STATS number of tracks in DB
print(episode_artists[i])
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
cursor = conn.cursor()
2024-01-19 01:50:32 +01:00
cursor.execute('SELECT * FROM EPISODES WHERE episode=?', [episode_number])
r = cursor.fetchall()
2024-01-19 01:50:32 +01:00
for t in r:
song = str(t[0])
2024-01-19 01:50:32 +01:00
#track_label = str(t[1])
track_album = str(t[2])
track_title = str(t[3])
track_artist = str(t[4])
track_duration = float(t[6])
2024-01-19 01:50:32 +01:00
track_genre = str(t[7])
track_year = str(t[8])
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[episode_number], \
2024-01-15 12:10:58 +01:00
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)
def create_html_episode_from_template(episode_playlist):
2024-01-15 12:10:58 +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
cursor = conn.cursor()
2024-01-19 01:50:32 +01:00
e = Table('EPISODES')
q = Query.from_(e).select(
e.episode
).where(
e.episode == episode_number)
# raw 'SELECT * FROM EPISODES WHERE EPISODE=?', [episode_number]
cursor.execute('SELECT * FROM EPISODES WHERE EPISODE=?', [episode_number])
r = cursor.fetchall()
for t in r:
song = str(t[0])
2024-01-19 01:50:32 +01:00
#track_label = str(t[1])
track_album = str(t[3])
track_title = str(t[4])
track_artist = str(t[5]).upper()
track_duration = float(t[6])
2024-01-19 01:50:32 +01:00
track_genre = str(t[7])
track_year = str(t[8])
detail = str(track_artist) + " | " + str(track_album) + \
" | " + str(track_title) + " | " + str(track_year) + \
" | " + str(timedelta(seconds=round(track_duration)))
2024-01-15 12:10:58 +01:00
show_info.append("" + detail)
2024-01-19 01:50:32 +01:00
#TODO FIX THIS UP TO SEND COLUMNS FROM LIST TO JINJA
2024-01-15 12:10:58 +01:00
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)
2024-01-15 12:10:58 +01:00
def create_RSS_XML_from_template():
2024-01-15 12:10:58 +01:00
from jinja2 import Template, Environment, FileSystemLoader
2024-01-15 12:10:58 +01:00
env = Environment(loader=FileSystemLoader('html/templates'))
rss_template = env.get_template('show_RSS.jinja.xml')
2024-01-15 12:10:58 +01:00
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-19 01:50:32 +01:00
def main():
2024-01-15 12:28:05 +01:00
2024-01-19 01:50:32 +01:00
database_create_episodes_table()
set_episode_date(input_date)
create_episode_playlist(episode_playlist, complete_playlist)
create_show_coverart(episode_playlist, 1) #episode_duration = 100
#create_animated_gif()
create_intro(episode_playlist)
create_pls_file()
create_html_episode_from_template(episode_playlist)
create_html_homepage_from_template(episode_playlist)
create_RSS_XML_from_template()
conn.close()
create_podcast(episode_playlist)
2024-01-15 12:10:58 +01:00
2024-01-14 02:56:15 +01:00
2024-01-19 01:50:32 +01:00
main()
2024-01-15 12:10:58 +01:00
2024-01-14 02:56:15 +01:00
#convert -delay 100 -loop 0 html/episode/2/img/show_cover_2024-01-12* animatedGIF.gif