From 2715358487116dcc85f4283df54f5b78a2b76cd4 Mon Sep 17 00:00:00 2001 From: Rob Canning Date: Thu, 18 Jan 2024 14:07:57 +0100 Subject: [PATCH] sqlite deals now with playlist generation etc --- database/show.db | Bin 278528 -> 532480 bytes mk_music_library_db.py | 16 ++-- mk_show.py | 134 ++++++++++++++++------------ playlists/track_playout_history.txt | 24 ++--- 4 files changed, 97 insertions(+), 77 deletions(-) diff --git a/database/show.db b/database/show.db index a0c0022c34dbc7f0050d9b7aad17602656d25ded..0bcd59e6eb9180a22f0baa4494cf7272bcd5afb3 100644 GIT binary patch delta 64603 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%0D=h$GOI1%?U`T;4_nt9%3hdb}ZV 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 delta 826 zcmX}q%WD%+6bInkc_pctM^bBTYMRlsjcIFBYpbobcA6F>;v*oUh)Sdgf(Y3tib6Aw z8|W^YI%`qL)<7uP=1=LW>$sD2Kz}Dx1NrWmoAbDtnQGUpR^#<#Lfj06LfiQM`>@Y* zi?lnx!&K}ES|+5u)iUk4*;a*;&^S_aOl%lhHX32!(Nv1@owlXjXN|A=VoXMbrR`C# z?MBR~{)n5}?pAFL*M(XhZq}xtRU3yJwPAR(7KQ8l6THDIaE--5^n1b7SwpDXJWL3ZnNw zgv!EHrR0E2_f}Hr;W7PJNI!TX_gLFBf2+F6#FTLN;e+DVonk?>zFP}lN>W>@2kF7u zJz0A}dY>sB#bo`oU#6&pXrDp66rr#C6@l^*H7&ttmIbp} z7YzEjqqGEc=?W-56at;114#_>O-nTViim`=*xzWjMAPqylq3deM3`Vm$7#PLVb7AV zH;5|#qi+(L)n(*$rQ^KcmFWO79ff*Yavys%v?`-^5VhpsB(Fz#b*eBFL?!C7prA`t gK~z!x=$af&hP0pRn^=CR9Zllxk3>7kJ>^LG3pFLV(*OVf diff --git a/mk_music_library_db.py b/mk_music_library_db.py index 39e8196..a01235a 100755 --- a/mk_music_library_db.py +++ b/mk_music_library_db.py @@ -12,12 +12,12 @@ conn = '' music_library_path = "/home/rob/antena/music/" conn = sqlite3.connect("database/show.db") -labelnames = ["sploh", "terraformer", "pharamafabric" ] +#TODO fix getting bandcamp urls into db +labelnames = [("sploh", "https://sploh.bandcamp.com"), ("terraformer"), ("pharamafabric") ] -def database_create(conn): - +def database_create(conn): # the MUSIC LIBRARY TABLE - + #TODO UNIQUE constraint prevents duplicats but what if tracks are in another locaton?fixme conn.execute('''CREATE TABLE IF NOT EXISTS MUSICLIB( ID INTEGER PRIMARY KEY AUTOINCREMENT, LABEL TEXT NOT NULL, @@ -28,19 +28,21 @@ def database_create(conn): TRACKDUR TEXT , YEAR TEXT, URL TEXT, - PATH TEXT , + PATH TEXT UNIQUE, LASTPLAY TEXT, COMMENT TEXT );''') print("Table created successfully"); - ####################################################### + def mk_db_entry(conn): import os + label_url = "https://fixme.bandcamp.com/" + for subdir, dirs, files in os.walk(music_library_path): for file in files: for m in [".flac", ".FLAC", ".mp3"]: # get audio files @@ -50,7 +52,7 @@ def mk_db_entry(conn): track = TinyTag.get(os.path.join(subdir, file))# get metadata from file cursor = conn.cursor() - cursor.execute("INSERT INTO MUSICLIB (\ + cursor.execute("INSERT OR IGNORE INTO MUSICLIB (\ ID, LABEL, ALBUM, TRACK, ARTIST,\ GENRE, TRACKDUR, YEAR, URL, PATH, LASTPLAY, COMMENT) \ VALUES (NULL, ?, ?, ?, ?,?, ?,?,?,?,?,? )",\ diff --git a/mk_show.py b/mk_show.py index 918c136..f056b8b 100755 --- a/mk_show.py +++ b/mk_show.py @@ -60,7 +60,8 @@ def database_create(): ALBUM TEXT , TRACK TEXT NOT NULL, ARTIST TEXT NOT NULL, - TRACKDUR INT NOT NULL, + TRACKDUR FLOAT NOT NULL, + GENRE TEXT NOT NULL, YEAR TEXT NOT NULL, PATH TEXT NOT NULL );''') @@ -88,19 +89,7 @@ def check_archive(track): print("____ TRACK ALREADY PLAYED _____") return False -def load_all_music(): - with open('playlists/complete_music_archive.pls') as playlist_file: - for line in playlist_file: - complete_playlist.append(line) - print(''' - ------------------------------- - loaded {0} tracks from playlist - ------------------------------- - '''.format(str(len(complete_playlist)))) - return complete_playlist - def create_episode_playlist(episode_playlist: list, complete_playlist:list): - load_all_music() global episode_duration global archive @@ -113,49 +102,58 @@ def create_episode_playlist(episode_playlist: list, complete_playlist:list): # TODO what is most important 12 tracks or 60 minutes while episode_duration < 60 * 60 and track_count < 12 : - song = random.choice(random.sample(\ - complete_playlist, len(complete_playlist) )).rstrip() # pick a song - track = TinyTag.get(song) # get its metadata - # check if the artist not in the played list and the song is less than 8mins + cursor = conn.cursor() + cursor.execute("SELECT * FROM MUSICLIB ORDER BY RANDOM() LIMIT 1 ;") + r = cursor.fetchall() + for t in r: + song = str(t[9]) + 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]) + track_genre = str(t[5]) + track_year = str(t[7]) + track_path = '/'.join(song.split('/')[0:-1]) - if track.artist not in artists_played: - if check_archive(track.title) is True: - if int(track.duration) > min_track_dur * 60: - if int(track.duration) < max_track_dur * 60: + 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) + art = string=re.sub("\(.*?\)","",track_artist) # shorten verbose artist names such as trojnik Trojnik (Cene Resnik, Tomaž Grom, Vid Drašler) art = string=re.sub("and","&",art) 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 + 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 + if not track_year: # where missing metadata give a dummy value + track_year = 0000 - cursor = conn.cursor() + #long_string = json.dumps(["' SomeWord"]) print([episode_number, episode_date, \ - track.album, track.title, track.artist, \ - track.duration, track.year, track_path]) + track_album, track_title, track_artist, \ + track_duration, track_year, track_path]) cursor.execute("INSERT INTO SHOW (\ 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]); + track_album, track_title, track_artist, \ + track_duration, track_year, track_path]); conn.commit() - print("DB Record created successfully"); + print("sqlite: Episode track successfully inserted into SHOW table"); track_count += 1; print(track_count) - episode_duration = episode_duration + track.duration + episode_duration = episode_duration + track_duration 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() + # episode_duration = timedelta(seconds=round(episode_duration)) @@ -265,11 +263,9 @@ def create_show_coverart(episode_playlist, variants): # 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) - + combine_images(columns=4, space=10, images=random.sample(x,len(x)),variants=i) return show_cover - def create_animated_gif(): import contextlib from PIL import Image @@ -377,15 +373,15 @@ def create_html_homepage_from_template(episode_playlist): homepage_template = env.get_template('homepage.jinja') conn = sqlite3.connect("database/show.db") - cur = conn.cursor() + cursor = conn.cursor() show_info = [] episode_artists = [] for i in range(10): artists = [] - cur.execute("SELECT ARTIST FROM SHOW WHERE EPISODE=?", [i]) - rows = cur.fetchall() + cursor.execute("SELECT ARTIST FROM SHOW WHERE EPISODE=?", [i]) + rows = cursor.fetchall() for artist in rows: art = string=re.sub("\(.*?\)","", artist[0]) @@ -404,19 +400,24 @@ def create_html_homepage_from_template(episode_playlist): episodes.append(an_episode) episodes = reversed(episodes) # reversed order to most recent episode appears first in list - #TODO get database sorted - music table with metadata, bandcamp, label info - cur.execute('SELECT * FROM SHOW WHERE EPISODE=?', [episode_number]) - # database query instead of the below - # maybe a jinja2 template loop here instead - for i in episode_playlist: # liar od files - #for i in cur: # liar od files + cursor = conn.cursor() + cursor.execute('SELECT * FROM SHOW WHERE EPISODE=?', [episode_number]) + r = cursor.fetchall() + for t in r: + song = str(t[0]) + 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]) + track_genre = str(t[5]) + track_year = str(t[7]) - track = TinyTag.get(i) - detail = str(track.artist) + " | " + str(track.album) + \ - " | " + str(track.title) + " | " + str(track.year) + \ - " | " + str(timedelta(seconds=round(track.duration))) + 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 = homepage_template.render(\ show_name=''.join(random.choice((str.upper,str.lower))(x) for x in show_name), \ episodes=episodes, episode_author="Rob Canning",\ @@ -439,11 +440,26 @@ def create_html_episode_from_template(episode_playlist): show_info = [] # maybe a jinja2 template loop here instead - for i in episode_playlist: - track = TinyTag.get(i) - detail = str(track.artist) + " | " + str(track.album) + \ - " | " + str(track.title) + " | " + str(track.year) + \ - " | " + str(timedelta(seconds=round(track.duration))) + cursor = conn.cursor() + cursor.execute('SELECT * FROM SHOW WHERE EPISODE=?', [episode_number]) + r = cursor.fetchall() + for t in r: + song = str(t[0]) + 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]) + track_genre = str(t[5]) + track_year = str(t[7]) + + # for i in episode_playlist: # liar od files + #for i in cur: # liar od files + + #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(\ @@ -485,11 +501,13 @@ create_show_coverart(episode_playlist, 1) #episode_duration = 100 create_intro(episode_playlist) create_pls_file() -create_html_episode_from_template(episode_playlist) create_html_homepage_from_template(episode_playlist) +create_html_episode_from_template(episode_playlist) + create_RSS_XML_from_template() -#create_podcast(episode_playlist) +conn.close() +create_podcast(episode_playlist) #convert -delay 100 -loop 0 html/episode/2/img/show_cover_2024-01-12* animatedGIF.gif diff --git a/playlists/track_playout_history.txt b/playlists/track_playout_history.txt index 99af59b..3735aff 100644 --- a/playlists/track_playout_history.txt +++ b/playlists/track_playout_history.txt @@ -1,13 +1,13 @@ -Speshlafer -Tomaž Grom - Sam, za... - 09 N.N. -YuWrong -Vertex -Carve4 -Dromon -Blue Waters Turn Black (P.C.M. remix) -Cifre (feat. Eno) -Lynch - Oro zatvorenih očiju -KIURIKI - Killem All -postcell (Tetsuo remix) -Stampede +一点一滴 +BE CREEP - LIVE +Todestriebe +The Great White Buffalo +Liqweed +Keep An Eye On That Ice Cream +Kaverna +Jošt Drašler - The Balloon Catcher - 03 Water Balloon +Magie de la Pleine Lune +Domen Gnezda - Misnomer II - 16 Misnomer 38 +All is silent, All is dead +Exit Lover