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" | ||