View difference between Paste ID: dfifNv3z and wPXZuPrU
SHOW: | | - or go back to the newest paste.
1
#!/bin/bash
2-
#Dependencies: usual gnu utils, ffmpeg or ffprobe
2+
#Dependencies: ffmpeg or ffprobe, standard gnu utils (including bc)
3
#
4-
##june 07 2012 edited to remove unwanted \ in regex expression which ###prevented ogg files from being parsed.
4+
#april 21 2014 edited to also work with locales that
5
#use , instead of .for decimal position (thanks to Tina Keil).
6
#march 20 2013 edited to accommodate opus files and to fix error in fetching
7
#durations, caused by changes in ffprobe.
8
#june 07 2012 edited to remove unwanted \ in regex expression which
9
#prevented ogg files from being parsed.
10
#december 22 2015 edited to add support for relative paths, thanks to Dave.
11
# january 9 2016 removed problemaatic relative paths function.
12
13-
\t-r  recurses through subdirectories and writes file names with
13+
#also work with locales that use , instead of .for decimal position.
14
LC_NUMERIC=C LC_COLLATE=C
15
16
function usage ()
17
{
18
	printf "\nUSAGE:
19
\t$(basename "$0") [options] {-o out} <directory>\n
20
OPTIONS:
21
\t-D  Don't overwrite existing playlist (default is to replace)\n
22
\t-s  Simple m3u8 playlist instead of extended m3u8\n
23
\t-p  writes the file names in .m3u with full path\n\
24
\t    (default is simple file name without path)\n
25
\t-d  Set the recursion depth (default is 1)\n
26
\t-r  Recurses through subdirectories and writes file names with
27
\t    full path\n
28
\t-c  Format playlist for Sansa Clip+ Internal Memory (implies -p)
29
\t
30-
ffprobe -show_format "$f">"$DATA"
30+
\t-C  Format playlist for Sansa Clip+ MicroSDHC (implies -p)
31
\t
32
\t-H  Format playlist for iriver H10/100/300 series players (implies -p)
33
\t    You MUST change the MicroSDHC card label and mount point in
34
\t    the sed expressions to the ACTUAL MicroSDHC card label and
35
\t    mount point on your OS.  The Clip internal storage and iRiver H
36-
SEC=$(printf %.2f\\n $(grep -m 1 -i -e "^duration" "$DATA" |\
36+
\t    values are quite generic but Clip external storage values could be
37
\t    anything - user must check this.\n
38
\t-o <output directory>  (default is target directory)\n
39
\t$(basename "$0") finds the audio files in the directory, parses 
40
\tthe metadata, then writes an extended .m3u playlist\n
41
\t$(basename "$0") understands the same files as  your
42
\tinstalled version of ffmpeg.\n
43
\tIf $(basename "$0") fails please check output directory exists
44
\tand is writeable.\n\n"
45
}
46
47
#dump file data;grep metadata relevant to extm3u.
48-
while getopts 'o:pr' OPTION
48+
49
#track duration so all times are rounded UP to integer i.e. 38.00 secs
50
#becomes 38 seconds but 38.10 secs or 38.95 seconds become 39 seconds.
51
function getdata ()
52
{
53
ffprobe -v quiet -show_format -show_streams "$f">"$DATA"
54
55
PERF=$(grep -m 1 -i tag:artist "$DATA" |\
56
awk -F "=" '{$1="";$0=substr($0,2)}1' |cleantag)
57
TIT=$(grep -m 1 -i tag:title "$DATA" |\
58
awk -F "=" '{$1="";$0=substr($0,2)}1' |cleantag)
59
SEC=$(printf %.2f\\n $(grep -m 1 -i -e "^duration=" "$DATA" |\
60
awk -F "=" '{print $2}'))
61
SEC=$(printf %0.f\\n $(echo "$SEC+0.5"|bc))
62
}
63
64
#remove problematic characters from metadata.
65
function cleantag ()
66
{
67
	sed 's/[;]/-/g;s/[/]/-/g;s/[<]/-/g;s/[>]/-/g;s/[:]/-/g;s/[|]/-/g'
68
}
69
70
#user options
71
while getopts 'CcDHo:prs' OPTION
72
do
73
	case $OPTION in
74
	o)	oflag=1
75
		oval=$OPTARG
76
		;;
77
	p)	pflag=1
78
		;;
79
	r)	rflag=1
80
		pflag=1
81
		;;
82
	R)	rflag=1
83
		relpathflag=1
84
		;;
85
	c)	cflag=1
86
		;;
87
	C)	Cflag=1
88
		pflag=1
89
		;;
90
	H)	Hflag=1
91
		pflag=1
92
		;;
93
	s)	sflag=1
94
		;;
95
	D)	Dflag=1
96-
#create/overwrite .m3u and write extm3u's generic 1st line
96+
97-
printf "#EXTM3U">"$PL"
97+
98
done
99
shift $(($OPTIND-1))
100
101-
mp3\|ogg\|oga\|mka\|ac3\)$" |sort |while read f ; do
101+
102
	usage
103
	exit 1
104
fi
105
106
#recurse?
107
if [ $rflag ]; then
108
	DEPTH=''
109
else
110
	DEPTH="-maxdepth 1"
111
fi
112
113
for i in "$@" ; do
114
#ensure .m3u name is not dot file if script run within target directory.
115
PN=$(basename "$(readlink -f "$i")").m3u
116
117
#some simple error checking
118
if [ ! -d "$i" ]; then
119
	usage
120
	exit
121
fi
122
123
#set output destination. Output dir exists and writeable?
124
if [ $oflag ]; then
125
	if [ ! -d "$oval" -o ! -w "$oval" ]; then
126
	usage
127
	exit
128
	fi
129
	PL=$oval/"$PN"
130
	else
131
	PL="$i"/"$PN"
132
fi
133
134
#playlist exists? overwrite?
135
if [ $Dflag ] && [ -f "$PL" ]; then
136
    printf "\n$PL already exists.\n"
137
    continue
138
    else
139
    > "$PL"
140
fi
141
142
if [ ! $sflag ]; then
143
    #write mandatory extm3u8 header
144
    printf "#EXTM3U">"$PL"
145
    WRITE=xlist
146
    else
147
    WRITE=slist
148
fi
149
150
#find all audio files to be referenced in .m3u
151
find "$i" $DEPTH -iregex ".*\(flac\|ape\|wv\|wav\|mpc\|aac\|m4a\|wma\|\
152
mp3\|ogg\|oga\|mka\|ac3\|opus\)$" |sort |while read f ; do
153
154
#use full path or simple names?
155
if [ $pflag ]; then
156
	if [ $cflag ]; then
157
		FILENAME=$(readlink -f "$f"|sed 's/\/media\/SANSA\ CLIPP//')
158
	elif [ $Cflag ]; then
159
		FILENAME=$(readlink -f "$f"|sed 's/media\/LEX/\<microSD1\>/')
160
	elif [ $Hflag ]; then
161
		FILENAME=$(readlink -f "$f"|sed 's/media\/H[0-9]*.//')
162
	else
163
		FILENAME=$(readlink -f "$f")
164
	fi
165
elif [ $relpathflag ]; then
166
	FILENAME=$(readlink -f "$f")
167
	FILENAME=$(relpath $PWD $FILENAME)
168
else
169
	FILENAME="${f##*/}"
170
fi
171
172
#where to dump ffprobe's file info
173
DATA="${f%.*}"_data
174
175
#run getdata silently (ffprobe generates much unwanted text)
176
getdata>/dev/null 2>&1
177
178
#write to the playlist, clean up.
179
printf "\n#EXTINF:$SEC,$PERF - $TIT\n$FILENAME">>"$PL"
180
rm "$DATA"
181
done
182
183
#confirm to user, quit.
184
echo "Wrote "$PL""
185
done
186
exit 0