2023-11-30 18:48:15 +01:00
|
|
|
#!/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
|
2023-11-30 18:48:15 +01:00
|
|
|
from tinytag import TinyTag
|
2024-01-11 00:20:43 +01:00
|
|
|
|
2024-01-07 03:07:30 +01:00
|
|
|
from random import shuffle
|
|
|
|
|
2024-01-14 02:56:15 +01:00
|
|
|
import sqlite3
|
|
|
|
|
|
|
|
from mk_web import *
|
|
|
|
|
|
|
|
con = sqlite3.connect("music.db")
|
|
|
|
|
2023-11-30 18:48:15 +01:00
|
|
|
DATE = datetime.datetime.now().strftime("%Y-%m-%d")
|
2024-01-14 02:56:15 +01:00
|
|
|
total_show_dur = 0
|
2024-01-08 18:01:22 +01:00
|
|
|
complete_playlist = []
|
2023-11-30 18:48:15 +01:00
|
|
|
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-14 02:56:15 +01:00
|
|
|
episode_number = sys.argv[1]
|
|
|
|
|
2023-11-30 18:48:15 +01:00
|
|
|
|
2024-01-14 02:56:15 +01:00
|
|
|
show_name = "SHOWNAME" # 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
|
|
|
|
2023-11-30 18:48:15 +01:00
|
|
|
# /////////////////////////////////////////////////
|
|
|
|
|
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()
|
|
|
|
|
2024-01-14 02:56:15 +01:00
|
|
|
global total_show_dur
|
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
|
|
|
|
2024-01-14 02:56:15 +01:00
|
|
|
while total_show_dur < 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
|
2024-01-14 02:56:15 +01:00
|
|
|
track_count += 1; print(track_count)
|
|
|
|
total_show_dur = total_show_dur + 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
|
|
|
|
2024-01-14 02:56:15 +01:00
|
|
|
total_show_dur = timedelta(seconds=round(total_show_dur))
|
|
|
|
|
|
|
|
print("total tracks = {0} \n total duration = {1} ".format(track_count, total_show_dur))
|
|
|
|
|
|
|
|
return show_array, total_show_dur
|
|
|
|
|
|
|
|
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
|
|
|
|
2024-01-11 00:20:43 +01:00
|
|
|
|
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-11 00:20:43 +01:00
|
|
|
|
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(DATE,episode_number), fill="white", font=mf_h3)
|
|
|
|
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((1560,1888), ''' http://{0}.rizom.si '''\
|
|
|
|
.format(show_name, DATE,episode_number), fill="white", font=mf_h4)
|
|
|
|
|
|
|
|
# TiTiTi (Jure Boršič, Jošt Drašler, Vid Drašler)
|
|
|
|
|
|
|
|
show_cover = 'img/cover.png'.format(episode_number,DATE, variants)
|
|
|
|
#pathlib.Path.touch(show_cover)
|
|
|
|
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
|
|
|
|
2024-01-14 02:56:15 +01:00
|
|
|
# global show_array
|
|
|
|
#print(show_array)
|
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(file)
|
|
|
|
|
|
|
|
# print("\n ++++ show jpgs: +++++ {0} +++++++++number of jpgs: {1} +++++++\n"\
|
|
|
|
# .format(show_cover_jpgs, len(show_cover_jpgs) ) )
|
|
|
|
|
|
|
|
|
|
|
|
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-14 02:56:15 +01:00
|
|
|
|
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
|
2024-01-08 02:06:18 +01:00
|
|
|
with open("shows/antena_playlist_" + 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-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]
|
|
|
|
|
|
|
|
show_intro = playlist_songs.pop(0)
|
|
|
|
first_song = playlist_songs[0].fade_in(3000)
|
|
|
|
intro_and_first = first_song.overlay(show_intro)
|
|
|
|
first_three_blurb = playlist_songs.pop(0)
|
|
|
|
second_three_blurb = playlist_songs.pop(0)
|
|
|
|
final_songs_blurb = playlist_songs.pop(0)
|
|
|
|
final_show_outro = playlist_songs.pop(0)
|
|
|
|
playlist = intro_and_first
|
|
|
|
|
|
|
|
for song in playlist_songs[2:3]: # 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
|
|
|
|
playlist = playlist.append(song, crossfade=(10 * 1000))
|
2024-01-08 02:06:18 +01:00
|
|
|
|
2024-01-08 18:01:22 +01:00
|
|
|
# blurb about first three tracks
|
|
|
|
playlist = playlist.append(first_three_blurb) # <--------------BLURB INSERT
|
|
|
|
|
|
|
|
for song in playlist_songs[4:6]: # second three songs
|
|
|
|
# We don't want an abrupt stop at the end, so let's do a 1 second crossfades
|
|
|
|
playlist = playlist.append(song, crossfade=(10 * 1000))
|
|
|
|
playlist = playlist.append(second_three_blurb) # <--------------BLURB INSERT
|
|
|
|
|
2024-01-11 00:20:43 +01:00
|
|
|
for song in playlist_songs[7:]: # second three song # We don't want an abrupt stop at the end, so let's do a 1 second crossfades
|
2024-01-08 18:01:22 +01:00
|
|
|
playlist = playlist.append(song, crossfade=(10 * 1000))
|
|
|
|
playlist = playlist.append(final_songs_blurb) # <--------------BLURB INSERT
|
|
|
|
|
|
|
|
playlist = playlist.append(final_show_outro) # <-------------- OUTRO SEQUENCE
|
|
|
|
|
|
|
|
# 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:
|
2024-01-08 18:01:22 +01:00
|
|
|
playlist.export(out_f, format='flac')
|
2024-01-11 00:20:43 +01:00
|
|
|
|
2024-01-14 02:56:15 +01:00
|
|
|
### ------------------------------------------------------------
|
|
|
|
|
|
|
|
def create_html_from_template():
|
|
|
|
|
|
|
|
from jinja2 import Template, Environment, FileSystemLoader
|
|
|
|
|
|
|
|
env = Environment(loader=FileSystemLoader('html/templates'))
|
|
|
|
episode_template = env.get_template('episode.jinja')
|
|
|
|
output_from_parsed_template = episode_template.render(episode_author="rrrrrrrr", episode_dur="123", about_show="bla bla", episode_playlist="playlist_songs", episode_image="episode/{0}/img/cover.png".format(episode_number))
|
|
|
|
|
|
|
|
with open("html/episode.html".format(episode_number), "w") as episode_page:
|
|
|
|
episode_page.write(output_from_parsed_template)
|
|
|
|
|
|
|
|
create_show_playlist(show_array, complete_playlist)
|
|
|
|
create_show_coverart(show_array, 1) #total_show_dur = 100
|
|
|
|
#create_animated_gif()
|
|
|
|
#convert -delay 100 -loop 0 html/episode/2/img/show_cover_2024-01-12* animatedGIF.gif
|
2024-01-08 18:01:22 +01:00
|
|
|
#create_intro(show_array)
|
|
|
|
create_pls_file()
|
2024-01-14 02:56:15 +01:00
|
|
|
create_html_from_template()
|
|
|
|
#create_web_page(show_name, show_array, episode_number, artists_played, show_cover, total_show_dur)
|
2024-01-11 00:20:43 +01:00
|
|
|
#create_podcast(show_array)
|
2024-01-14 02:56:15 +01:00
|
|
|
|
|
|
|
|
|
|
|
|