Generates and manages static html of mpd currently playing music.

git clone git://watertao.xyz/programs/mpdhh.git

commit af10d7ad17d0d2e6d7d64a9d6110fa6afda269e3
Author: Jeff <dev@watertao.xyz>
Date:   Sun, 24 Mar 2024 22:08:32 -0700

Initial commit

Diffstat:
AREADME | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aa_filter_track_data.awk | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Aa_write_html.awk | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ah_analysis_artists_tmpl.md | 13+++++++++++++
Ah_analysis_tracks_tmpl.md | 13+++++++++++++
Ah_playlist_empty_tmpl.md | 20++++++++++++++++++++
Ah_playlist_tmpl.md | 23+++++++++++++++++++++++
Ampdhh.sh | 636+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 965 insertions(+), 0 deletions(-)

diff --git a/README b/README @@ -0,0 +1,67 @@ +mpdhh - mpd history html + +mpc's current track from mpd, generates playlist, manages history and +analyses. Static html file generation. With every track change, db files +are modified or generated if need be, and html is rendered. + +By default the html is rendered as hugo content files. This can be +modified by editing the *tmpl.md files. + +Requirements: +mpd +mpc +posix compliant shell tools: awk/sed/grep/sort + +hugo or full html markup needed + +note: watertao.xyz is hugo project bin. Doesn't have to be hugo. +Can be whatever. + +This program assumes the following tree: +(run mpdhh.sh 4 to create the tree) + +project/ +----content/ +-------- music/ +------------ _index.[html|md] +------------ analysis/ +---------------- _index.[html|md] +---------------- tracks/ +-------------------- _index.[html/md] +-------------------- tracks.db +---------------- artists/ +-------------------- _index.[html|md] +-------------------- artists.db +------------ db/ +---------------- [date].db +------------ historia/ +---------------- _index.[html|md] +---------------- db.index +---------------- [date_bin]/ +-------------------- _index.[html|md] + +Important note on hugo +This has been designed for portability thus it does not need hugo. As +such, I've had to keep a menu bit out of this program. If using hugo, +you'll need the following menus injected in the hugo config for +"Analysis" menus to work: + +menus: + analysis: + - name: Artists + pageRef: /music/analysis/artists + - name: Tracks + pageRef: /music/analysis/tracks + artists: + - name: Artist + pageRef: /music/analysis/artists/by-artist + - name: Play Count + pageRef: /music/analysis/artists/by-play-count + tracks: + - name: Artist + pageRef: /music/analysis/tracks/by-artist + - name: Track + pageRef: /music/analysis/tracks/by-track + - name: Play Count + pageRef: /music/analysis/tracks/by-play-count + diff --git a/a_filter_track_data.awk b/a_filter_track_data.awk @@ -0,0 +1,49 @@ +#!/bin/awk + +# Sanitize Field +function sf(s) { + + p="";r="" + + # analyze chars, create whitepace + # as needed to break long words + # apart + while (s){ + c=substr(s,1,1) + + # Space after case change + if (p ~ /[a-z]/){ + if (c ~ /[A-Z]/){ + r = r " " + } + + # Space after colons + }else if (p == ":") { + if (c ~ /[a-zA-Z0-9]/){ + r = r " " + } + } + r = r c + s=substr(s,2) + p=c + } + gsub( /[_.#]+/, " ",r) # rm underscores + gsub(/[-/////\\]+/," & ",r) # pad [-/] with space + gsub(/[ ]{2,}/," ",r) # squeeze spaces + gsub(/^ - $/,"-",r) # remove spaces from empty fields + return r +} +{ + # If metadata is emtpy, set track field to filename + if ($0 == "\t\t") { + $1 = filename + } + + # If value is empty, replace with dash + for (i=1; i<=NF; i++){ + gsub(/^$/, d, $i) + } + + OFS="\t" + print played_date, sf($1), sf($2), sf($3) +} diff --git a/a_write_html.awk b/a_write_html.awk @@ -0,0 +1,144 @@ +#!/bin/awk + +# Add slash escapes to protect hugo +# front matter yaml values from awk +# Ampersands need to be escaped, else +# gsub substitutes amp with matched term +function hf(s){ + gsub(/[&]/,"\\\\&",s) + return s +} +function df(s){ + gsub (/[-T]/," ",$s) + $s = substr($s, 1, 16) +} + +BEGIN { + gsub(/[ ,]/, "", page_menuidentifier) + page_menu_id = tolower(page_menuidentifier) + + if (html_type == "playlist") { + + if (! track_data) { + page_header=page_summary=page_summary_title= "Nothing Recently Played" + syndicate = 1 + } + else if (today_day == played_day) { + + page_header = page_header_html played_day_h + + # Sanitize tab delimited track data for + # rss xml title and description tags + split(hf(track_data), a, "\t") + track_data = sprintf("%s<br><br>Track: %s<br>Album: %s<br>Artist: %s", + a[1], a[2], a[3], a[4]) + + page_summary = "Most recently played:<br><br>" track_data + page_summary_title = sprintf("Recently Played %s > %s, %s, %s", + $a[1], a[2], a[3], a[4]) + syndicate = 1 + + }else{ + # Page header and rss tags for historia pages + # Many nulled vars here to force default rss behavior + # that is otherwise specialized for music's + # main currently playing playlist page + page_summary = sprintf("%s playlist has been archived to Sonus Historia.", played_day_h) + page_summary_title = "" + page_header = "" + syndicate = 0 + description = "" + rss_title = "" + rss_data_file = "" + } + + } else if ( html_type == "analysis" ) { + page_summary_title = "" + page_summary = "" + } + + # Use a default for music playlist tables + if ( !th_values ) { th_values = "Time::Title::Album::Artist" } + if ( !pfields ) { pfields = "1,2,3,4" } + + # Now split into arrays + split( th_values, th_values_a, "::" ) + pfields_a_l = split( pfields, pfields_a, "," ) +} +{ + # Track file inputs w/ x + if ( FNR == 1) { x++ } + + # First input file, hugo archetype, sub values + if ( x==1 ) { + gsub(/%%header%%/, page_header) + gsub(/%%menu%%/, page_menu) + gsub(/%%menutitle%%/, page_menutitle) + gsub(/%%title%%/, page_title) + gsub(/%%date%%/, today_date) + gsub(/%%day%%/, played_day_h) + gsub(/%%menuidentifier%%/, page_menuidentifier) + gsub(/%%pagemenuid%%/, page_menu_id) + gsub(/%%pagesummary%%/, page_summary) + gsub(/%%pagesummarytitle%%/, page_summary_title) + gsub(/%%syndicate%%/, syndicate) + gsub(/%%rssdata%%/, rss_data_file) + gsub(/%%description%%/, description) + gsub(/%%rsstitle%%/, rss_title) + gsub(/%%tally%%/, tally) + + # Check for foot of body (begins after opening tr tag) + # Then store lines from rest of archetype file to print + # after data file parsing. + if ( is_foot == 1 ) { + + # store rest in html_footer + html_footer = html_footer $0 ORS + next + } else { + if ( /%%table%%/ ) { + is_foot = 1 + next + } + } + print + } + + # Now db data (input file 2) + # Fairly self explanitory + if ( x==2 ){ + if ( FNR == 1 ) { + printf("<table id=\"%s\">\n", html_type) + printf("<tr>") + #<tr><th>+</th><th>Title</th><th>Album</th><th>Artist</th></tr> + for (i=1;i<=pfields_a_l;i++){ + printf("<th>%s</th>", th_values_a[pfields_a[i]]) + } + printf("</tr>\n") + printf("<tr class=\"spacer\"><td colspan=\"%s\">&nbsp;</td></tr>\n", pfields_a_l) + + } + + # gsub(/[0-9]{4}-[0-9]{2}-[0-9]{2}T([0-9]{2}:[0-9]{2}).*/,"&",$1) + printf("<tr>") + + # extract time from date in playlist db + if (html_type == "playlist") { $1 = substr($1, 12, 5) } + + for(i=1;i<=pfields_a_l;i++){ + + # Format date for analysis sections + if (page_menu_id == "tracks") { if (pfields_a[i] == 4 || pfields_a[i] == 5) { df( pfields_a[i] ) }} + if (page_menu_id == "artists") { if (pfields_a[i] == 2 || pfields_a[i] == 3) { df( pfields_a[i] ) }} + + printf("<td>%s</td>", $pfields_a[i]) + } + + printf("</tr>\n") + } +} +END{ + # print body footer from archetype (input file 1) + printf("</table>\n") + print html_footer +} diff --git a/h_analysis_artists_tmpl.md b/h_analysis_artists_tmpl.md @@ -0,0 +1,13 @@ +--- +layout: single +title: %%title%% +description: %%description%% +pagemenuid: %%pagemenuid%% +date: %%date%% +draft: false + +--- +<p>Tally: %%tally%%</p> + +%%table%% + diff --git a/h_analysis_tracks_tmpl.md b/h_analysis_tracks_tmpl.md @@ -0,0 +1,13 @@ +--- +layout: single +title: %%title%% +description: %%description%% +pagemenuid: %%pagemenuid%% +date: %%date%% +draft: false + +--- +<p>Tally: %%tally%%</p> + +%%table%% + diff --git a/h_playlist_empty_tmpl.md b/h_playlist_empty_tmpl.md @@ -0,0 +1,20 @@ +--- +layout: single +title: %%title%% +description: %%description%% +syndicate: %%syndicate%% +rss_data: %%rssdata%% +rss_title: %%rsstitle%% +summary: > + %%pagesummary%% +summarytitle: >- + %%pagesummarytitle%% +pagemenuid: %%pagemenuid%% +date: %%date%% +draft: false +menus: + %%menu%%: + identifier: %%menuidentifier%% + name: %%menutitle%% +--- +<h2>%%header%%</h2> diff --git a/h_playlist_tmpl.md b/h_playlist_tmpl.md @@ -0,0 +1,23 @@ +--- +layout: single +title: %%title%% +description: %%description%% +syndicate: %%syndicate%% +rss_data: %%rssdata%% +rss_title: %%rsstitle%% +summary: > + %%pagesummary%% +summarytitle: >- + %%pagesummarytitle%% +pagemenuid: %%pagemenuid%% +date: %%date%% +draft: false +menus: + %%menu%%: + identifier: %%menuidentifier%% + name: %%menutitle%% +--- +<h2>%%header%%</h2> + +%%table%% + diff --git a/mpdhh.sh b/mpdhh.sh @@ -0,0 +1,636 @@ +#!/bin/sh + +# Important customization: +mpdhh_bin=~/progs/mpdhh +hugo_proj="watertao.xyz" +work_bin="${HOME}/w/proj" +publish_sh="publish.sh" + +# All else, modify to your liking +artists="artists" +tracks="tracks" +index_md_name="_index.html" +music_bin_proj_local="content/music" +music_bin="${work_bin}/${hugo_proj}/${music_bin_proj_local}" +db_bin="${music_bin}/db" +historia_bin="${music_bin}/historia" +db_index_file="${historia_bin}/db.index" +rss_index_name="rss.index" +rss_index="${music_bin}/${rss_index_name}" + +analysis_bin="${music_bin}/analysis" +analysis_artists_bin="${analysis_bin}/${artists}" +analysis_tracks_bin="${analysis_bin}/${tracks}" +analysis_tracks_db="${analysis_tracks_bin}/${tracks}.db" +analysis_artists_db="${analysis_artists_bin}/${artists}.db" +analysis_tracks_html="${analysis_tracks_bin}/${index_md_name}" +analysis_artists_html="${analysis_artists_bin}/${index_md_name}" +analysis_tracks_byartist_html="${analysis_tracks_bin}/by-artist/${index_md_name}" +analysis_tracks_bytrack_html="${analysis_tracks_bin}/by-track/${index_md_name}" +analysis_tracks_bycount_html="${analysis_tracks_bin}/by-play-count/${index_md_name}" +analysis_tracks_byinitial_html="${analysis_tracks_bin}/by-initial/${index_md_name}" +analysis_tracks_byrecent_html="${analysis_tracks_bin}/by-recent/${index_md_name}" +analysis_artists_byartist_html="${analysis_artists_bin}/by-artist/${index_md_name}" +analysis_artists_bycount_html="${analysis_artists_bin}/by-play-count/${index_md_name}" +analysis_artists_byinitial_html="${analysis_artists_bin}/by-initial/${index_md_name}" +analysis_artists_byrecent_html="${analysis_artists_bin}/by-recent/${index_md_name}" +th_playlist="Time::Title::Album::Artist" +th_analysis_tracks="Title::Album::Artist::Initial::Recent::+" +th_analysis_artists="Artist::Initial::Recent::+" +analysis_byinitial_title="By Initial" +analysis_byrecent_title="By Recent" +analysis_byartist_title="By Artist" +analysis_bytrack_title="By Track" +analysis_bycount_title="By Play Count" +analysis_tracks_title="Tracks" +analysis_artists_title="Artists" + +commit_msg="dojo music update" +music_description="The sweet sounds from my pinephone" +rss_title="Sonus" + +# Set rss_data_file to data file to force hugo to parse data file for rss stream +# for currently playing playlist page. This is unset in awk for historia page creation +rss_data_file="${music_bin_proj_local}/${rss_index_name}" + +awk_prog_1="${mpdhh_bin}/a_write_html.awk" +awk_prog_2="${mpdhh_bin}/a_filter_track_data.awk" +playlist_html="${mpdhh_bin}/h_playlist_tmpl.md" +playlist_empty_html="${mpdhh_bin}/h_playlist_empty_tmpl.md" +analysis_tracks_tmpl="${mpdhh_bin}/h_analysis_${tracks}_tmpl.md" +analysis_artists_tmpl="${mpdhh_bin}/h_analysis_${artists}_tmpl.md" + +page_header_html='Recently Played<span class="delimiter"> > </span>' +dash="-" + +# Track meta (tab delim (important)) +formatstr='[%title%|%name%] [%album%] [%artist%|%albumartist%|%composer%]' + +# 4 modes: +# 0 > default - update data [ & site ] +# 1 > stdout current track +# 2 > update historia only +# 3 > update analysis only +# 4 > build bin tree +mode="${1:-0}" + +[ -z "$@" ] && tput civis +cleanup(){ tput cnorm; exit 0; } +trap cleanup SIGINT + +update_historia(){ + + # Manage historia files + [ ! -d "$historia_bin" ] && printf "Historia bin no existo, create first, then try again.\n" && exit 0 + + while IFS= read -r date_day; do + + printf "Historia: today: %s, index date: %s\n" "$today_day" "$date_day" + # If today's date, skip as it is not yet history + [ "$today_day" = "$date_day" ] && continue + + # if exists, stop updating through historia + [ -d "${historia_bin}/${date_day}" ] && break; + + # Get date_day date vars + get_date_vars "$date_day" + + # Update Historia index html date + sed -i -e "s#^\(date: \).*\$#\1${today_date}#" "${historia_bin}/${index_md_name}" + + # Write date_day historia + write_playlist_html "$date_day" "historia" "$played_day_h" "$played_day_h" + + done <"$db_index_file" +} + +update_db_index_file(){ + + [ -z "$1" ] && return 1 + + # Add db file to historia index file + # Sed will not inject anything before line 1 + # if there is no line 1 (empty/new file) + # so in this case just throw the line in there + if [ ! -f "$db_index_file" ]; then + printf "%s\n" "$1" > "$db_index_file" + + elif [ "$(<"$db_index_file" wc -l)" -gt 0 ]; then + + ! grep "$1" "$db_index_file" && \ + sed -i '1i '"$1"' + ' "$db_index_file" + fi + sort -r -o "$db_index_file" "$db_index_file" +} + +update_rss(){ + + # Build rss data line with iso + # date format for hugo parsing + + [ ! -f "$rss_index" ] && \ + printf "%s\n" "$track_data" > "$rss_index" || \ + sed -i '1i '"$track_data"' + ' "${rss_index}" +} + +get_matching_line_from_db(){ + + # $1 track_data + # $2 db file + # $3 track data fields + regex=; track_match= + a="${3:-"2,3,4"}" + + if [ -z "$1" ] || [ -z "$2" ]; then return 1; fi + + # Define grep pattern from track data + # - cut > remove the time by cutting/using fields 2,3,4 only + # - sed > escape special pattern matching characters from track data + regex="$(printf "%s" "$1" | cut -f "$a" | sed -e 's#\([][]\)#\\\1#g')" + + # Find line no of first matching track + # - grep > run pattern as regex (-e flag) else '-' in pattern + # string gets interpreted as param flag + track_match=$(grep -ns -m1 -e "$regex" "$2" | cut -d: -f1) + + # Can't test on empty variable(if no matches)... + # so make it 0 if need be + track_match="${track_match:-0}" +} + +get_matching_line_from_analysis_db(){ + + # $1 track_data + # $2 db file + # $3 track data fields + + # Get line number from db using awk + track_match="$(awk -vtd="$1" -vf="$3" ' + BEGIN{ + FS=OFS="\t" + falen=split(f,fa,",") + split(td,tda,FS) + } + { + for (i=1;i<=falen;i++){ + if ($i != tda[fa[i]]) { + # On any field that does not match, + # exit loop, go to next line + next + } + } + # match made, print line number then exit + print NR + exit + }' "$2" )" + + track_match="${track_match:-0}" +} + +update_csv(){ + + # First check for existing bin + [ ! -d "$db_bin" ] && \ + printf "%s\nDirectory does not exist. Exiting.\n" "$db_bin" && exit 0 + + pl_file="${db_bin}/${played_day}.db" + + # if playlist.db no existo, + # if track data not empty, + # - create pl and add to it + # update historia regardless + + if [ ! -f "$pl_file" ]; then + if [ -n "$track_data" ]; then + printf "%s\n" "$track_data" > "$pl_file" + update_rss + update_db_index_file "$played_day" + fi + + update_historia + + [ -n "$track_data" ] && return 0 || return 1 + + # if playlist file not empty, + # if track data not empty + # - insert new track + # else if track data empty + # - do nothing but return 1 + elif [ "$(<"$pl_file" wc -l)" -gt 0 ]; then + + [ -z "$track_data" ] && return 1 + + get_matching_line_from_db "$track_data" "$pl_file" + + # If track already last track posted (line 1) + # - do not add to csv to mitigate redundancy + [ "$track_match" -eq 1 ] && return 1 + + update_rss + sed -i '1i '"$track_data"' + ' "$pl_file" + + return 0 + fi +} + +__update_analysis_sort(){ + + # $1 - db_file + # $2 - track data fields + + # Count sort fields, need this for trim off sort fields post sort + field_count=$(printf "%s" "$2"| awk 'BEGIN{FS=","}{print NF}') + + if [ ! -f "$1" ]; then + # scan music db omnia, freshly populating tracks db + printf "Db file:\n%s\ndoes not exist.\nCreating with fresh sonus db sort...\n" "$1" + + # Sort all tracks played, remove any single space or single dash lines + #cut -f "$2" "${db_bin}"/*.db | sort -u | sed '/^[- \t]\+$\|^$/d' > "$1" + + # First awk entire playlist db into a tmpfile + tmpfile=$(mktemp) + + #cat "$db_bin"/*db | \ + awk -v f="$2" ' + BEGIN { + OFS=FS="\t" + falen=split(f,fa,",") + } + { + for (i=1; i<=falen; i++) { + printf("%s%s", $fa[i], OFS) + } + print $0 + + }' "$db_bin"/*db | \ + sort -n | \ + cut -f$((field_count + 1))- \ + > "$tmpfile" + + # Now sort the tmp file into the final db file using awk + awk -v f="$2" ' + BEGIN { + OFS = FS = "\t" + split( f, fa, ",") + } + { + curr = "" + for (i=1; i<=length(fa); i++) { + curr = curr $fa[i] OFS + } + if (tolower(curr) == tolower(prev)) { + pcount++ + lastdate = $1 + } else { + if (NR > 0) { + print prev firstdate, lastdate, pcount + } + firstdate = lastdate = $1 + pcount = 1 + } + prev = curr + } + END { + print prev firstdate, lastdate, pcount + + }' "$tmpfile" > "$1" + + # Cleanup + rm -v "$tmpfile" + + printf "Done.\n" + else + # Only add files to analysis if on mode 0 i.e. while adding to playlist db files too + # as the entire purpose of anaylsis is to analyze what we've played, recorded, and + # published to the site and related db files + [ "$mode" -ne 0 ] && printf "Not mode 0. exiting.\n" && return 0 + + # Set/check for existing data in db + ! get_matching_line_from_analysis_db "$track_data" "$1" "$2" \ + && printf "Exiting on from failed get_matching_line.\n" && exit 0 + + + # If track not in db, add it + if [ "$track_match" -ne 0 ]; then + printf "Updating %s..." "${1##*/}" + + # Get new count + newcount="$(sed -n "${track_match}p" "$1" | cut -f "$((field_count+3))" )" + newcount=$((newcount+1)) + sed -i "${track_match}s/\([0-9]\{4\}[-0-9T:]\{21\}\)\t\([0-9]\+\)$/$played_date\t$newcount/" $1 + printf "done.\n" + else + # Track no exist, add it, then sort + printf "Adding to %s..." "${1##*/}" + a="$(printf "%s" "$track_data" | cut -f "$2")" + regex="^[- ]$" + if [[ ! "$a" =~ $regex ]]; then + + printf "%s\t%s\t%s\t%s\n" "$a" "$played_date" "$played_date" "1" >> "$1" + sort -n -o "$1" "$1" + fi + printf "done.\n" + fi + + fi +} + +update_analysis(){ + # First check for existing bin + if [ ! -d "$analysis_bin" ] || [ ! -d "$analysis_tracks_bin" ] || [ ! -d "$analysis_artists_bin" ]; then + printf "Analysis bins do not exist. Exiting.\n" && exit 0 + fi + + # First - update tracks db + __update_analysis_sort "$analysis_tracks_db" "2,3,4" + + # Second - update artists db + __update_analysis_sort "$analysis_artists_db" "4" + + # Write artists index files + write_analysis_html "$artists" "4,1" "$th_analysis_artists" + # Write tracks index files + write_analysis_html "$tracks" "6,1,2,3" "$th_analysis_tracks" + + # Write tracks sortby's + # 1|track 2|album 3|artist 4|firstdate 5|lastdate 6|playcount + __update_analysis_sortby "$tracks" "3,2" "" "$analysis_byartist_title" "$analysis_tracks_byartist_html" + __update_analysis_sortby "$tracks" "1" "" "$analysis_bytrack_title" "$analysis_tracks_bytrack_html" + __update_analysis_sortby "$tracks" "6" "-r" "$analysis_bycount_title" "$analysis_tracks_bycount_html" + __update_analysis_sortby "$tracks" "4" "-r" "$analysis_byinitial_title" "$analysis_tracks_byinitial_html" "4,1,2,3" + __update_analysis_sortby "$tracks" "5" "-r" "$analysis_byrecent_title" "$analysis_tracks_byrecent_html" "5,1,2,3" + __update_analysis_sortby "$artists" "1" "" "$analysis_byartist_title" "$analysis_artists_byartist_html" + __update_analysis_sortby "$artists" "4" "-r" "$analysis_bycount_title" "$analysis_artists_bycount_html" + __update_analysis_sortby "$artists" "2" "-r" "$analysis_byinitial_title" "$analysis_artists_byinitial_html" "2,1" + __update_analysis_sortby "$artists" "3" "-r" "$analysis_byrecent_title" "$analysis_artists_byrecent_html" "3,1" + +} + +__update_analysis_sortby(){ + + # $1 - artists or tracks + # $2 - fields to sort by + # $3 - sort flags (for reverse sorting) + # $4 - sortby title + # $5 - sortby html file + + if [ "$1" = "$artists" ]; then + db_file="$analysis_artists_db" + th_values="$th_analysis_artists" + print_fields="${6:-"4,1"}" + + elif [ "$1" = "$tracks" ]; then + db_file="$analysis_tracks_db" + th_values="$th_analysis_tracks" + print_fields="${6:-"6,1,2,3"}" + fi + + field_count=$(printf "%s" "$2" | awk 'BEGIN{FS=","}{print NF}') + tmpfile="$(mktemp)" + + # Add sorting fields to front for.. well sorting of course + # Then sort, then remove the sorting fields + awk -vf="$2" ' + + BEGIN{ OFS=FS="\t"; fl=split(f,fa,",") } + { + for (i=1; i<=fl; i++){ + printf("%s%s", $fa[i], OFS) + } + print $0 + } + + ' \ + "$db_file" | \ + sort -n ${3} | \ + cut -f$((field_count + 1))- \ + > "$tmpfile" + + write_analysis_html "$1" "$print_fields" "$th_values" "$tmpfile" "$4" "$5" + + rm -v "$tmpfile" +} + +write_playlist_html(){ + # $1 = played_day + # $2 = page menu + # $3 = menu title + # $4 = page title + # + # get date vars if date param ($1) + # set else use date vars set when + # new track change for current + # playlist (see while loop) + # + # date param will be set for + # historia pages, where menu ($2) and + # title ($3) params will also be passed + if [ -n "$1" ]; then + mkdir -p "${historia_bin}/${played_day}" || exit 0 + md_file="${historia_bin}/${played_day}/${index_md_name}" + else + md_file="${music_bin}/${index_md_name}" + + # udpate date vars if historia updated html files (dates + # will be historical, but we need todays) + [ ! "$today_date" = "$played_date" ] && get_date_vars + fi + + datafile="${db_bin}/${played_day}.db" + awk_htmltmpl="$playlist_html" + + [ ! -f "$datafile" ] && \ + datafile="" && \ + awk_htmltmpl="$playlist_empty_html" + + printf "Awking html for %s..." "$played_day" + + # generate html with awk + awk \ + -F "\t" \ + -v today_date="$today_date" \ + -v today_day="$today_day" \ + -v played_date="$played_date" \ + -v played_day="$played_day" \ + -v played_day_h="$played_day_h" \ + -v page_menu="${2:-"main"}" \ + -v page_menutitle="${3:-"Music"}" \ + -v page_menuidentifier="${3:-"Music"}" \ + -v page_title="${4:-"Music"}" \ + -v page_header_html="$page_header_html" \ + -v track_data="$track_data" \ + -v rss_data_file="$rss_data_file" \ + -v description="$music_description" \ + -v rss_title="$rss_title" \ + -v html_type="playlist" \ + -v pfields="" \ + -v th_values="" \ + -v tally="$(wc -l "$datafile" 2>/dev/null | cut -d" " -f1)" \ + -f $awk_prog_1 \ + "$awk_htmltmpl" "$datafile" > "$md_file" + + printf "done.\n" +} +write_analysis_html(){ + + # $1 tracks or artists + # $2 field list (comma delim'd) + # $3 [ table th values ( delim "::" ) ] + # $4 [ database file ] + # $5 [ title ] + # $6 [ output html file ] + + if [ "$1" = "$tracks" ]; then + awk_datafile="${4:-"$analysis_tracks_db"}" + awk_htmltmpl="$analysis_tracks_tmpl" + awk_html_file="${6:-"$analysis_tracks_html"}" + awk_title="${5:-"$analysis_tracks_title"}" + elif [ "$1" = "$artists" ]; then + awk_datafile="${4:-"$analysis_artists_db"}" + awk_htmltmpl="$analysis_artists_tmpl" + awk_html_file="${6:-"$analysis_artists_html"}" + awk_title="${5:-"$analysis_artists_title"}" + fi + + awk_menuidentifier="${1}" + + printf "Awking html for %s %s..." "$1" "$awktitle" + + # generate html with awk + awk \ + -F "\t" \ + -v today_date="$today_date" \ + -v today_day="$today_day" \ + -v played_date="$played_date" \ + -v played_day="$played_day" \ + -v played_day_h="$played_day_h" \ + -v page_menu="analysis" \ + -v page_menutitle="${awk_title}" \ + -v page_menuidentifier="$awk_menuidentifier" \ + -v page_title="${awk_title}" \ + -v page_header_html="$page_header_html" \ + -v track_data="$track_data" \ + -v rss_data_file="$rss_data_file" \ + -v description="$music_description" \ + -v rss_title="$rss_title" \ + -v html_type="analysis" \ + -v pfields="$2" \ + -v th_values="$3" \ + -v tally="$(<"${awk_datafile}" wc -l)" \ + -f $awk_prog_1 \ + "${awk_htmltmpl}" "${awk_datafile}" > "${awk_html_file}" + printf "done.\n" +} + +publish_site(){ + + # Run simple shell script that + # 1. Updates hugo (hugo cmd) + # 2. git add . + # 3. git commit -m "message" + # 4. git push + + [ "$MPDHH_PUBLISH" = "n" ] && printf "Not publishing.\n" && return + + # Must change to hugo project bin to run hugo command (in publish.sh) + cur_bin="$(pwd)" + cd "${work_bin}/${hugo_proj}" + [ -f ./"${publish_sh}" ] && sh ./"${publish_sh}" "${commit_msg}" + cd "$cur_bin" +} + +get_track_data(){ + #mpc current -f "$formatstr" 2>/dev/null | grep -v '^[a-zA-Z]*:\s*$' + mpc current -f "$formatstr" 2>/dev/null | \ + awk \ + -F"\t" \ + -v filename="$(mpc current -f '%file%' 2>/dev/null | awk -F "/" '{print $NF}')" \ + -v played_date="$played_date" \ + -v d="$dash" \ + -f $awk_prog_2 +} + +get_date_vars(){ + today_date="$(date -Iseconds)" + today_day="$(date --date="$today_date" +"%Y%m%d")" + played_date="${1:-"$today_date"}" + played_day="$(date --date="$played_date" +"%Y%m%d")" + played_day_h="$(date --date="$played_date" +"%Y %m %d | %A")" +} + +site_git_merge(){ + printf "Git fetch && merge...\n" + cur_bin="$(pwd)" + cd "${work_bin}/${hugo_proj}" && \ + git fetch && git merge + cd "$cur_bin" +} + +bin_struct(){ + # Make the bins + [ ! -d "$work_bin" ] && printf "Please create proj bin, then continue. Exiting.\n" && exit 0 + __bin_struct "$music_bin" + __bin_struct "$db_bin" + __bin_struct "$historia_bin" + __bin_struct "$analysis_bin" + __bin_struct "$analysis_artists_bin" + __bin_struct "${analysis_artists_bycount_html%/*}" + __bin_struct "${analysis_artists_byartist_html%/*}" + __bin_struct "${analysis_artists_byinitial_html%/*}" + __bin_struct "${analysis_artists_byrecent_html%/*}" + __bin_struct "$analysis_tracks_bin" + __bin_struct "${analysis_tracks_bytrack_html%/*}" + __bin_struct "${analysis_tracks_byartist_html%/*}" + __bin_struct "${analysis_tracks_bycount_html%/*}" + __bin_struct "${analysis_tracks_byinitial_html%/*}" + __bin_struct "${analysis_tracks_byrecent_html%/*}" +} + +__bin_struct(){ + [ ! -d "$1" ] && mkdir -v "$1" || printf "Bin already exists: %s\n" "$1" +} + +while true; do + clear + + get_date_vars + track_data="$(get_track_data)" + + if [ "$mode" = "0" ]; then + # merge with site repo first + site_git_merge + # Update playlists csvs + # If new track then update + # analysis db/html files + update_csv && update_analysis + # Write playlist html files + write_playlist_html + # Publish site + publish_site + + elif [ "$mode" = "1" ]; then + printf "%s\n" "$track_data" + break; + + elif [ "$mode" = "2" ]; then + ls -1d "$historia_bin"/????????/ | xargs -I{} rm -rv "{}" + update_historia && printf "Done.\n"; exit 0 + + elif [ "$mode" = "3" ]; then + [ ! "$MPDHH_PUBLISH" = "n" ] && site_git_merge + # Refresh the analysis db + [ -f "$analysis_artists_db" ] && rm -v "$analysis_artists_db" + [ -f "$analysis_tracks_db" ] && rm -v "$analysis_tracks_db" + update_analysis && publish_site && printf "Done.\n"; exit 0 + + elif [ "$mode" = "4" ]; then + bin_struct + exit 0 + fi + + >/dev/null mpc idle player sticker +done