This commit is contained in:
Jaidyn Ann 2020-11-21 19:59:57 -06:00
commit 138ffbbba3
4 changed files with 372 additions and 0 deletions

29
README.txt Normal file
View File

@ -0,0 +1,29 @@
================================================================================
SONGATTR
================================================================================
songattr.sh uses FFMPEG to fill the Audio:* & Media:* attributes for audio
files. It will populate Audio:Artist, Audio:Album, Audio:Track, Media:Title,
and Media:Year, as possible. Additionally, if lyrics are embedded in the file,
it will set the non-standard Audio:Lyrics attribute.
In addition, it can set the Album:Artist and Media:Year attributes for the
parent directory (assumed to be the Album folder), using a custom audio/x-album
filetype. You can add the Album type to your system by building and running
album_attr/ once.
========================================
USAGE
========================================
usage: songattr [-ha] file
-h print more detailed help info
-a treat the parent directory as an Album file
Since songattr can only take one file at a time, you'll probably end up using
it like this:
$ for file in ./*.mp3; do songattr "$file"; done
========================================
BORING STUFF
========================================
MIT License
Jaidyn Ann, jadedctrl@teknik.io

131
album_attr/Makefile Normal file
View File

@ -0,0 +1,131 @@
## Haiku Generic Makefile v2.6 ##
## Fill in this file to specify the project being created, and the referenced
## Makefile-Engine will do all of the hard work for you. This handles any
## architecture of Haiku.
##
## For more information, see:
## file:///system/develop/documentation/makefile-engine.html
# The name of the binary.
NAME = album_attr
# The type of binary, must be one of:
# APP: Application
# SHARED: Shared library or add-on
# STATIC: Static library archive
# DRIVER: Kernel driver
TYPE = APP
# If you plan to use localization, specify the application's MIME signature.
APP_MIME_SIG =
# The following lines tell Pe and Eddie where the SRCS, RDEFS, and RSRCS are
# so that Pe and Eddie can fill them in for you.
#%{
# @src->@
# Specify the source files to use. Full paths or paths relative to the
# Makefile can be included. All files, regardless of directory, will have
# their object files created in the common object directory. Note that this
# means this Makefile will not work correctly if two source files with the
# same name (source.c or source.cpp) are included from different directories.
# Also note that spaces in folder names do not work well with this Makefile.
SRCS = main.cpp
# Specify the resource definition files to use. Full or relative paths can be
# used.
RDEFS =
# Specify the resource files to use. Full or relative paths can be used.
# Both RDEFS and RSRCS can be utilized in the same Makefile.
RSRCS =
# End Pe/Eddie support.
# @<-src@
#%}
# Specify libraries to link against.
# There are two acceptable forms of library specifications:
# - if your library follows the naming pattern of libXXX.so or libXXX.a,
# you can simply specify XXX for the library. (e.g. the entry for
# "libtracker.so" would be "tracker")
#
# - for GCC-independent linking of standard C++ libraries, you can use
# $(STDCPPLIBS) instead of the raw "stdc++[.r4] [supc++]" library names.
#
# - if your library does not follow the standard library naming scheme,
# you need to specify the path to the library and it's name.
# (e.g. for mylib.a, specify "mylib.a" or "path/mylib.a")
LIBS = be $(STDCPPLIBS)
# Specify additional paths to directories following the standard libXXX.so
# or libXXX.a naming scheme. You can specify full paths or paths relative
# to the Makefile. The paths included are not parsed recursively, so
# include all of the paths where libraries must be found. Directories where
# source files were specified are automatically included.
LIBPATHS =
# Additional paths to look for system headers. These use the form
# "#include <header>". Directories that contain the files in SRCS are
# NOT auto-included here.
SYSTEM_INCLUDE_PATHS =
# Additional paths paths to look for local headers. These use the form
# #include "header". Directories that contain the files in SRCS are
# automatically included.
LOCAL_INCLUDE_PATHS =
# Specify the level of optimization that you want. Specify either NONE (O0),
# SOME (O1), FULL (O3), or leave blank (for the default optimization level).
OPTIMIZE :=
# Specify the codes for languages you are going to support in this
# application. The default "en" one must be provided too. "make catkeys"
# will recreate only the "locales/en.catkeys" file. Use it as a template
# for creating catkeys for other languages. All localization files must be
# placed in the "locales" subdirectory.
LOCALES =
# Specify all the preprocessor symbols to be defined. The symbols will not
# have their values set automatically; you must supply the value (if any) to
# use. For example, setting DEFINES to "DEBUG=1" will cause the compiler
# option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" would pass
# "-DDEBUG" on the compiler's command line.
DEFINES =
# Specify the warning level. Either NONE (suppress all warnings),
# ALL (enable all warnings), or leave blank (enable default warnings).
WARNINGS =
# With image symbols, stack crawls in the debugger are meaningful.
# If set to "TRUE", symbols will be created.
SYMBOLS :=
# Includes debug information, which allows the binary to be debugged easily.
# If set to "TRUE", debug info will be created.
DEBUGGER :=
# Specify any additional compiler flags to be used.
COMPILER_FLAGS =
# Specify any additional linker flags to be used.
LINKER_FLAGS =
# Specify the version of this binary. Example:
# -app 3 4 0 d 0 -short 340 -long "340 "`echo -n -e '\302\251'`"1999 GNU GPL"
# This may also be specified in a resource.
APP_VERSION :=
# (Only used when "TYPE" is "DRIVER"). Specify the desired driver install
# location in the /dev hierarchy. Example:
# DRIVER_PATH = video/usb
# will instruct the "driverinstall" rule to place a symlink to your driver's
# binary in ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will
# appear at /dev/video/usb when loaded. The default is "misc".
DRIVER_PATH =
## Include the Makefile-Engine
DEVEL_DIRECTORY := \
$(shell findpaths -r "makefile_engine" B_FIND_PATH_DEVELOP_DIRECTORY)
include $(DEVEL_DIRECTORY)/etc/makefile-engine

41
album_attr/main.cpp Normal file
View File

@ -0,0 +1,41 @@
#include <iostream>
#include <InterfaceDefs.h>
#include <Message.h>
#include <MimeType.h>
// add the given attribute to a BMessage for use as attr info
// borrowed from mailserver, thanks!
static void addAttribute
( BMessage& msg, const char* name, const char* publicName, int32 type, int32 width )
{
msg.AddString( "attr:name", name );
msg.AddString( "attr:public_name", publicName );
msg.AddInt32( "attr:type", type );
msg.AddInt32( "attr:width", width );
msg.AddInt32( "attr:alignment", B_ALIGN_LEFT );
msg.AddBool( "attr:extra", false );
msg.AddBool( "attr:viewable", true );
msg.AddBool( "attr:editable", true );
}
// install the x-album filetype for folders containing music
int main ( int argc, char** argv )
{
BMessage info;
BMimeType mime( "audio/x-album" );
if ( mime.IsInstalled() ) return 2;
std::cout << "DAD";
mime.GetAttrInfo( &info );
mime.SetShortDescription( "Album" );
mime.SetLongDescription( "Generic audio container" );
addAttribute( info, "Audio:Artist", "", B_STRING_TYPE, 200 );
addAttribute( info, "Album:Title", "", B_STRING_TYPE, 200 );
addAttribute( info, "Media:Year", "Year", B_INT32_TYPE, 200 );
mime.SetAttrInfo( &info );
return 0;
}

171
songattr Executable file
View File

@ -0,0 +1,171 @@
#!/bin/sh
# --------------------------------------
# name: music2attr
# main: jadedctrl<@teknik.io>
# lisc: MIT
# date: 2020-11
# --------------------------------------
# ======================================
# FFMPEG PARSING
# ======================================
# prints metadata output from FFMPEG of the given file
function song_metadata {
local file="$1"
ffmpeg -i "$file" 2>&1 \
| sed '1,/Metadata/d' \
| head -n -1 \
| sed 's% : %:%'
}
# get value of song's metadata key, from it's `song_metadata` output
function get_value {
local trait="$1"
sed -n "/^ *${trait}.*:/I,\$p" \
| sed "s/$trait//i" \
| print_until_nonempty
}
# ======================================
# ATTRIBUTES
# ======================================
# set a song's metadata attribute, if file contains it
# pipe in output from `song_metadata`
function set_attr {
local file="$1"
local key="$2"
local attr="$3"
local type="$4"
local value="$(get_value "$key")"
if test "$type" = "time"; then set_time_attr "$file" "$attr" "$value"; return; fi
if echo "$type"|grep -q "^int";then set_int_attr "$file" "$attr" "$value" "$type";return;fi
if test -n "$value"; then
addattr -t "$type" "$attr" "$value" "$file"
fi
}
# we have some special sanitization to do for time attributes (helper of 'set_attr')
function set_time_attr {
local file="$1"; local attr="$2"; local value="$3"
if test 5 -eq "$(echo "$value" | wc -c)"; then
value="${value}-01-01"
fi
if test -n "$value"; then
addattr -t "time" "$attr" "$value" "$file"
fi
}
# we have some special sanitization to do for ints, too (helper of 'set_attr')
function set_int_attr {
local file="$1"; local attr="$2"; local value="$3"; local type="$4"
value="$(echo "$value" | sed 's%[A-z/, -].*%%')"
if test -n "$value"; then
addattr -t "$type" "$attr" "$value" "$file"
fi
}
# set a file's entire all song-related attributes
function set_song_attrs {
local file="$1"
meta="$(song_metadata "$file")"
echo "$meta" | set_title_attr "$file" "Media:title"
echo "$meta" | set_year_attr "$file" "Media:Year"
echo "$meta" | set_lyrics_attr "$file" "Audio:Lyrics"
echo "$meta" | set_artist_attr "$file" "Audio:Artist"
echo "$meta" | set_album_attr "$file" "Audio:Album"
echo "$meta" | set_track_attr "$file" "Audio:Track"
}
# set all of an album's necessary attributes
function set_album_attrs {
song="$1"
album="$(dirname "$song")"
meta="$(song_metadata "$song")"
addattr -t mime "BEOS:TYPE" "audio/x-album" "$album"
echo "$meta" | set_artist_attr "$album" "Album:Artist"
echo "$meta" | set_year_attr "$album" "Media:Year"
}
function set_title_attr { set_attr "$1" "TITLE" "$2" "string"; }
function set_year_attr { set_attr "$1" "DATE" "$2" "int32"; }
function set_lyrics_attr { set_attr "$1" "LYRICS" "$2" "string"; }
function set_artist_attr { set_attr "$1" "ARTIST" "$2" "string"; }
function set_album_attr { set_attr "$1" "ALBUM" "$2" "string"; }
function set_track_attr { set_attr "$1" "TRACK" "$2" "int32"; }
# ======================================
# UTIL
# ======================================
# selects all fields except the first, until a a line's first field is non-empty
# delimiter used is a colon.
function print_until_nonempty {
awk -F ':' \
'{ lines[NR] = $0 }
END { i = 1
split( lines[i], L )
while ( i <= NR && match( L[1], /^( )+$/ ) ) {
for ( j = 2; j <= length(L); j = j + 1 ) {
if ( j > 2 )
printf ":"
printf L[j]
}
printf "\n"
i = i + 1
split( lines[i], L )
}
}'
}
# ======================================
# INVOCATION
# ======================================
function help {
echo "usage: $(basename $0) [-hi] [-A|a] file"
echo
echo \
"Use a song file's metadata to populate related attributes. The attributes set
are 'Media:Title', 'Audio:Artist', 'Audio:Album', 'Audio:Track', and 'Media:year'.
In addition, the parent directory is assumed to be the 'album' folder, its
type is set to 'audio/x-album', and has its attributes populated with relevant
metadata. The attributes set to 'album' folders are 'Album:Artist' and
'Media:Year', based on the song files' metadata.
$(basename $0) requires 'ffmpeg' to be installed.
-a don't edit the parent directory's attributes
-A only edit the parent directory's attributes
-h prints this message."
exit 1
}
ALBUM=1
SONG=1
while getopts ":haAi" arg; do
case $arg in
a) ALBUM=0;;
A) ALBUM=1; SONG=0;;
h) help;;
esac
done
shift $(($OPTIND - 1))
if test -z "$@"; then help; fi
if test ! -e /bin/ffmpeg; then help; fi
if test "$SONG" -eq 1; then set_song_attrs "$@"; fi
if test "$ALBUM" -eq 1; then set_album_attrs "$@"; fi