Unified · Split
| @@ -0,0 +1,374 @@ | ||
| 1 | +#!/bin/sh | |
| 2 | +# Copyright (c) 2009 Serge "ftrvxmtrx" Ziryukin | |
| 3 | +# | |
| 4 | +# Permission is hereby granted, free of charge, to any person obtaining | |
| 5 | +# a copy of this software and associated documentation files (the | |
| 6 | +# "Software"), to deal in the Software without restriction, including | |
| 7 | +# without limitation the rights to use, copy, modify, merge, publish, | |
| 8 | +# distribute, sublicense, and/or sell copies of the Software, and to | |
| 9 | +# permit persons to whom the Software is furnished to do so, subject to | |
| 10 | +# the following conditions: | |
| 11 | +# | |
| 12 | +# The above copyright notice and this permission notice shall be | |
| 13 | +# included in all copies or substantial portions of the Software. | |
| 14 | +# | |
| 15 | +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| 16 | +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
| 17 | +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
| 18 | +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |
| 19 | +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
| 20 | +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
| 21 | +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| 22 | + | |
| 23 | +CONFIG="${HOME}/.split2flac" | |
| 24 | +TMPCUE="${HOME}/.split2flac_sheet.cue" | |
| 25 | +TMPPIC="${HOME}/.split2flac_cover.jpg" | |
| 26 | + | |
| 27 | +NOSUBDIRS=0 | |
| 28 | +NORENAME=0 | |
| 29 | +NOPIC=0 | |
| 30 | +REMOVE=0 | |
| 31 | +PIC_SIZE="192x192" | |
| 32 | + | |
| 33 | +# load settings | |
| 34 | +eval $(cat "${CONFIG}" 2>/dev/null) | |
| 35 | +DRY=0 | |
| 36 | +SAVE=0 | |
| 37 | +unset PIC | |
| 38 | +unset FILE | |
| 39 | +unset CUE | |
| 40 | +FORCE=0 | |
| 41 | + | |
| 42 | +HELP="Usage: split2flac.sh [OPTIONS] FILE | |
| 43 | + -o DIRECTORY * - set output directory | |
| 44 | + -cue FILE - use file as a cue sheet | |
| 45 | + -c FILE * - use file as a cover image | |
| 46 | + -nc * - do not set any cover images | |
| 47 | + -cs WxH * - set cover image size (current is ${PIC_SIZE}) | |
| 48 | + -d * - create artist/album subdirs | |
| 49 | + -nd * - do not create any subdirs | |
| 50 | + -r * - rename tracks to include title | |
| 51 | + -nr * - do not rename tracks (numbers only, e.g. '01.flac') | |
| 52 | + -p - dry run | |
| 53 | + -D * - delete original file | |
| 54 | + -nD * - do not remove the original | |
| 55 | + -f - force deletion without asking | |
| 56 | + -s - save configuration to \"${CONFIG}\" | |
| 57 | + -h - print this message | |
| 58 | + -H - print README | |
| 59 | + | |
| 60 | +* - option has effect on configuration if -s option passed. | |
| 61 | +NOTE: '-c some_file.jpg -s' only allows cover images, it doesn't set a default one." | |
| 62 | + | |
| 63 | +README="split2flac.sh splits one big APE/FLAC/WV file to FLAC tracks with tagging and renaming. | |
| 64 | + It's better to pass '-p' option to see what will happen when actually splitting tracks. | |
| 65 | + You may want to pass '-s' option for the first run to save default configuration | |
| 66 | +(output dir, cover image size, etc.) so you won't need to pass a lot of options | |
| 67 | +every time, only a filename. | |
| 68 | + Script will try to find CUE sheet if it wasn't specified." | |
| 69 | + | |
| 70 | +# parse arguments | |
| 71 | +while [ "$1" ] | |
| 72 | +do | |
| 73 | + case $1 in | |
| 74 | + -o) DIR=$2; shift;; | |
| 75 | + -cue) CUE=$2; shift;; | |
| 76 | + -c) NOPIC=0; PIC=$2; shift;; | |
| 77 | + -nc) NOPIC=1;; | |
| 78 | + -cs) PIC_SIZE=$2; shift;; | |
| 79 | + -d) NOSUBDIRS=0;; | |
| 80 | + -nd) NOSUBDIRS=1;; | |
| 81 | + -r) NORENAME=0;; | |
| 82 | + -nr) NORENAME=1;; | |
| 83 | + -p) DRY=1;; | |
| 84 | + -D) REMOVE=1;; | |
| 85 | + -nD) REMOVE=0;; | |
| 86 | + -f) FORCE=1;; | |
| 87 | + -s) SAVE=1;; | |
| 88 | + -h) echo "${HELP}"; exit 0;; | |
| 89 | + -H) echo "${README}"; exit 0;; | |
| 90 | + *) | |
| 91 | + if [ -r "${FILE}" ] | |
| 92 | + then | |
| 93 | + echo "Unknown option $1" | |
| 94 | + echo "${HELP}" | |
| 95 | + exit 1 | |
| 96 | + elif [ ! -r "$1" ] | |
| 97 | + then | |
| 98 | + echo "Unable to read $1" | |
| 99 | + exit 1 | |
| 100 | + else | |
| 101 | + FILE="$1" | |
| 102 | + fi;; | |
| 103 | + esac | |
| 104 | + shift | |
| 105 | +done | |
| 106 | + | |
| 107 | +METAFLAC="metaflac --no-utf8-convert" | |
| 108 | + | |
| 109 | +# search for a cue sheet if not specified | |
| 110 | +if [ -z "${CUE}" ] | |
| 111 | +then | |
| 112 | + CUE="${FILE}.cue" | |
| 113 | + if [ ! -r "${CUE}" ] | |
| 114 | + then | |
| 115 | + CUE=$(echo ${FILE} | sed 's/[^\.]*$//')cue | |
| 116 | + if [ ! -r "${CUE}" ] | |
| 117 | + then | |
| 118 | + # try to extract internal one | |
| 119 | + # MacOSX sed doesn't have 'I' (case insensitive) flag! | |
| 120 | + CUESHEET=$(${METAFLAC} --show-tag=CUESHEET "${FILE}" 2>/dev/null | sed 's/[Cc][Uu][Ee][Ss][Hh][Ee][Ee][Tt]=//') | |
| 121 | + | |
| 122 | + if [ -z "${CUESHEET}" ] | |
| 123 | + then | |
| 124 | + CUESHEET=$(wvunpack -q -c "${FILE}" 2>/dev/null) | |
| 125 | + fi | |
| 126 | + | |
| 127 | + if [ "${CUESHEET}" ] | |
| 128 | + then | |
| 129 | + CUE="${TMPCUE}" | |
| 130 | + echo "${CUESHEET}" > "${CUE}" | |
| 131 | + | |
| 132 | + if [ $? -ne 0 ] | |
| 133 | + then | |
| 134 | + echo "Unable to save internal cue sheet" | |
| 135 | + exit 1 | |
| 136 | + fi | |
| 137 | + else | |
| 138 | + unset CUE | |
| 139 | + fi | |
| 140 | + fi | |
| 141 | + fi | |
| 142 | +fi | |
| 143 | + | |
| 144 | +# print some info and check arguments | |
| 145 | +echo "Input file :" ${FILE:?"${HELP}"} | |
| 146 | +echo "Cue sheet :" ${CUE:?"No cue sheet"} | |
| 147 | + | |
| 148 | +# search for a front cover image | |
| 149 | +if [ ${NOPIC} -eq 1 ] | |
| 150 | +then | |
| 151 | + unset PIC | |
| 152 | +elif [ -z "${PIC}" ] | |
| 153 | +then | |
| 154 | + # try common names | |
| 155 | + SDIR=$(dirname "${FILE}") | |
| 156 | + | |
| 157 | + for i in cover.jpg front_cover.jpg folder.jpg | |
| 158 | + do | |
| 159 | + if [ -r "${SDIR}/$i" ] | |
| 160 | + then | |
| 161 | + PIC="${SDIR}/$i" | |
| 162 | + break | |
| 163 | + fi | |
| 164 | + done | |
| 165 | + | |
| 166 | + # try to extract internal one | |
| 167 | + if [ -z "${PIC}" ] | |
| 168 | + then | |
| 169 | + ${METAFLAC} --export-picture-to="${TMPPIC}" "${FILE}" 2>/dev/null | |
| 170 | + if [ $? -ne 0 ] | |
| 171 | + then | |
| 172 | + echo "Unable to export internal front cover image" | |
| 173 | + unset PIC | |
| 174 | + else | |
| 175 | + PIC="${TMPPIC}" | |
| 176 | + fi | |
| 177 | + fi | |
| 178 | +fi | |
| 179 | + | |
| 180 | +echo "Cover image :" ${PIC:-"not set"} | |
| 181 | +echo "Output dir :" ${DIR:?"Output directory wasn't set"} | |
| 182 | + | |
| 183 | + | |
| 184 | +if [ ${REMOVE} -eq 1 ] | |
| 185 | +then | |
| 186 | + echo -n "Also remove original" | |
| 187 | + if [ ${FORCE} -eq 1 ] | |
| 188 | + then | |
| 189 | + echo | |
| 190 | + else | |
| 191 | + echo " if user says 'y'" | |
| 192 | + fi | |
| 193 | +fi | |
| 194 | + | |
| 195 | +# save configuration if needed | |
| 196 | +if [ ${SAVE} -eq 1 ] | |
| 197 | +then | |
| 198 | + echo "DIR=\"${DIR}\"" > "${CONFIG}" | |
| 199 | + echo "NOSUBDIRS=${NOSUBDIRS}" >> "${CONFIG}" | |
| 200 | + echo "NORENAME=${NORENAME}" >> "${CONFIG}" | |
| 201 | + echo "NOPIC=${NOPIC}" >> "${CONFIG}" | |
| 202 | + echo "REMOVE=${REMOVE}" >> "${CONFIG}" | |
| 203 | + echo "PIC_SIZE=${PIC_SIZE}" >> "${CONFIG}" | |
| 204 | + echo "Configuration saved" | |
| 205 | +fi | |
| 206 | + | |
| 207 | +GETTAG="cueprint -n 1 -t" | |
| 208 | +VALIDATE="tr -d -C \"[:space:][:alnum:]&\-_#,.'\"" | |
| 209 | + | |
| 210 | +# get common tags | |
| 211 | +TAG_ARTIST=$(${GETTAG} %P "${CUE}") | |
| 212 | +TAG_ALBUM=$(${GETTAG} %T "${CUE}") | |
| 213 | +TRACKS_NUM=$(${GETTAG} %N "${CUE}") | |
| 214 | + | |
| 215 | +YEAR=$(awk '{ if (/REM[ \t]+DATE/) { printf "%i", $3; exit } }' < "${CUE}") | |
| 216 | +YEAR=$(echo ${YEAR} | tr -d -C '[:digit:]') | |
| 217 | + | |
| 218 | +unset TAG_DATE | |
| 219 | + | |
| 220 | +if [ -n "${YEAR}" ] | |
| 221 | +then | |
| 222 | + if [ ${YEAR} -ne 0 ] | |
| 223 | + then | |
| 224 | + TAG_DATE="${YEAR}" | |
| 225 | + fi | |
| 226 | +fi | |
| 227 | + | |
| 228 | +echo | |
| 229 | +echo "Artist : ${TAG_ARTIST}" | |
| 230 | +echo "Album : ${TAG_ALBUM}" | |
| 231 | +if [ -n "${TAG_DATE}" ] | |
| 232 | +then | |
| 233 | + echo "Year : ${TAG_DATE}" | |
| 234 | +fi | |
| 235 | +echo "Tracks : ${TRACKS_NUM}" | |
| 236 | +echo | |
| 237 | + | |
| 238 | +# prepare output directory | |
| 239 | +OUT="${DIR}" | |
| 240 | + | |
| 241 | +if [ ${NOSUBDIRS} -ne 1 ] | |
| 242 | +then | |
| 243 | + DIR_ARTIST=$(echo ${TAG_ARTIST} | ${VALIDATE}) | |
| 244 | + DIR_ALBUM=$(echo ${TAG_ALBUM} | ${VALIDATE}) | |
| 245 | + | |
| 246 | + if [ "${TAG_DATE}" ] | |
| 247 | + then | |
| 248 | + DIR_ALBUM="${TAG_DATE} - ${DIR_ALBUM}" | |
| 249 | + fi | |
| 250 | + | |
| 251 | + OUT="${OUT}/${DIR_ARTIST}/${DIR_ALBUM}" | |
| 252 | +fi | |
| 253 | + | |
| 254 | +echo "Saving tracks to \"${OUT}\"" | |
| 255 | + | |
| 256 | +if [ ${DRY} -ne 1 ] | |
| 257 | +then | |
| 258 | + # create output dir | |
| 259 | + mkdir -p "${OUT}" | |
| 260 | + | |
| 261 | + if [ $? -ne 0 ] | |
| 262 | + then | |
| 263 | + echo "Failed to create output directory" | |
| 264 | + exit 1 | |
| 265 | + fi | |
| 266 | + | |
| 267 | + # split to tracks | |
| 268 | + cuebreakpoints "${CUE}" | \ | |
| 269 | + shnsplit -O never -o "flac flac -8 - -o %f" -d "${OUT}" -t "%n" "${FILE}" | |
| 270 | + if [ $? -ne 0 ] | |
| 271 | + then | |
| 272 | + echo "Failed to split" | |
| 273 | + exit 1 | |
| 274 | + fi | |
| 275 | + | |
| 276 | + # prepare cover image | |
| 277 | + if [ "${PIC}" ] | |
| 278 | + then | |
| 279 | + convert "${PIC}" -resize "${PIC_SIZE}" "${TMPPIC}" | |
| 280 | + if [ $? -eq 0 ] | |
| 281 | + then | |
| 282 | + PIC="${TMPPIC}" | |
| 283 | + else | |
| 284 | + echo "Failed to convert cover image" | |
| 285 | + unset PIC | |
| 286 | + fi | |
| 287 | + fi | |
| 288 | +fi | |
| 289 | + | |
| 290 | +# set tags and rename | |
| 291 | +echo | |
| 292 | +echo "Setting tags" | |
| 293 | + | |
| 294 | +i=1 | |
| 295 | +while [ $i -le ${TRACKS_NUM} ] | |
| 296 | +do | |
| 297 | + TAG_TITLE=$(cueprint -n $i -t %t "${CUE}") | |
| 298 | + f="${OUT}/$(printf %02i $i).flac" | |
| 299 | + FILE_TRACK=$(basename "$f" .flac) | |
| 300 | + FILE_TITLE=$(echo ${TAG_TITLE} | ${VALIDATE}) | |
| 301 | + | |
| 302 | + echo "$i: ${TAG_TITLE}" | |
| 303 | + | |
| 304 | + if [ ${NORENAME} -ne 1 ] | |
| 305 | + then | |
| 306 | + FINAL="${OUT}/${FILE_TRACK} - ${FILE_TITLE}.flac" | |
| 307 | + if [ ${DRY} -ne 1 ] | |
| 308 | + then | |
| 309 | + mv "$f" "${FINAL}" | |
| 310 | + if [ $? -ne 0 ] | |
| 311 | + then | |
| 312 | + echo "Failed to rename track file" | |
| 313 | + exit 1 | |
| 314 | + fi | |
| 315 | + fi | |
| 316 | + else | |
| 317 | + FINAL="$f" | |
| 318 | + fi | |
| 319 | + | |
| 320 | + if [ ${DRY} -ne 1 ] | |
| 321 | + then | |
| 322 | + ${METAFLAC} --remove-all-tags \ | |
| 323 | + --set-tag="ARTIST=${TAG_ARTIST}" \ | |
| 324 | + --set-tag="ALBUM=${TAG_ALBUM}" \ | |
| 325 | + --set-tag="TITLE=${TAG_TITLE}" \ | |
| 326 | + --set-tag="TRACKNUMBER=$i" \ | |
| 327 | + "${FINAL}" | |
| 328 | + RES=$? | |
| 329 | + | |
| 330 | + if [ -n "${TAG_DATE}" ] | |
| 331 | + then | |
| 332 | + ${METAFLAC} --set-tag="DATE=${TAG_DATE}" "${FINAL}" | |
| 333 | + RES=$((${RES} + $?)) | |
| 334 | + fi | |
| 335 | + | |
| 336 | + if [ -n "${PIC}" ] | |
| 337 | + then | |
| 338 | + ${METAFLAC} --import-picture-from="${PIC}" "${FINAL}" | |
| 339 | + RES=$((${RES} + $?)) | |
| 340 | + fi | |
| 341 | + | |
| 342 | + if [ ${RES} -ne 0 ] | |
| 343 | + then | |
| 344 | + echo "Failed to set tags for track" | |
| 345 | + exit 1 | |
| 346 | + fi | |
| 347 | + fi | |
| 348 | + | |
| 349 | + echo " -> ${FINAL}" | |
| 350 | + | |
| 351 | + i=$(($i + 1)) | |
| 352 | +done | |
| 353 | + | |
| 354 | +rm -f "${TMPPIC}" | |
| 355 | +rm -f "${TMPCUE}" | |
| 356 | + | |
| 357 | +if [ ${DRY} -ne 1 -a ${REMOVE} -eq 1 ] | |
| 358 | +then | |
| 359 | + YEP="n" | |
| 360 | + | |
| 361 | + if [ ${FORCE} -ne 1 ] | |
| 362 | + then | |
| 363 | + echo -n "Are you sure you want to delete original? [y] >" | |
| 364 | + read YEP | |
| 365 | + fi | |
| 366 | + | |
| 367 | + if [ "${YEP}" = "y" -o ${FORCE} -eq 1 ] | |
| 368 | + then | |
| 369 | + rm -f "${FILE}" | |
| 370 | + fi | |
| 371 | +fi | |
| 372 | + | |
| 373 | +echo | |
| 374 | +echo "Finished" | |