mp3preview.sh 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #!/bin/bash
  2. # Best settings like in mixcloud.com
  3. SETT_PART_COUNT=5
  4. SETT_PART_DURATION=5
  5. SETT_CROSSFADE=1
  6. SETT_FORMAT="mp3"
  7. # Get system utilites with full path
  8. UTIL_FFMPEG=`whereis ffmpeg | awk {'print $2'}`
  9. UTIL_CUT=`whereis cut | awk {'print $2'}`
  10. UTIL_ECHO=`whereis echo | awk {'print $2'}`
  11. UTIL_EXPR=`whereis expr | awk {'print $2'}`
  12. UTIL_RM=`whereis rm | awk {'print $2'}`
  13. UTIL_MV=`whereis mv | awk {'print $2'}`
  14. # Get current process ID
  15. UNIQ_STR="$$"
  16. # Input and output files
  17. INPUT_FILE="$1"
  18. OUTPUT_FILE="$2"
  19. # Temp dir, RAM disk is the best place
  20. TEMP_DIR="$3"
  21. # Set default temp dir if not set
  22. if [ "$TEMP_DIR" != "" ]; then
  23. TEMP_DIR=${3%/}
  24. else
  25. TEMP_DIR="/tmp"
  26. fi
  27. # Check if temp dir is exists
  28. if [ ! -d "$TEMP_DIR" ]; then
  29. $UTIL_ECHO " ✗ Temporary directory ($TEMP_DIR) is not available"
  30. exit 1
  31. fi
  32. # Checks, if all system utilites are present
  33. if [ "$UTIL_FFMPEG" = "" ] || [ "$UTIL_CUT" = "" ] || [ "$UTIL_ECHO" = "" ] || [ "$UTIL_EXPR" = "" ] || [ "$UTIL_RM" = "" ] || [ "$UTIL_MV" = "" ]; then
  34. $UTIL_ECHO " ✗ Some utility, what needed for work is not present in system"
  35. exit 1
  36. fi
  37. # Check if input file is set
  38. if [ "$INPUT_FILE" = "" ]; then
  39. $UTIL_ECHO " ✗ Please set source file name"
  40. exit 1
  41. fi
  42. # Check if output file is set
  43. if [ "$OUTPUT_FILE" = "" ]; then
  44. $UTIL_ECHO " ✗ Please set output file name"
  45. exit 1
  46. fi
  47. # Check if input file is exist
  48. if [ ! -f "$INPUT_FILE" ]; then
  49. $UTIL_ECHO " ✗ Source file is not exist"
  50. exit 1
  51. fi
  52. # Perfomance check
  53. PROC_START=`date +%s`
  54. # Extract file length
  55. INPUT_LEN_STR=`$UTIL_FFMPEG -i $INPUT_FILE 2>&1 | awk '/Duration/ { print substr($2,0,length($2)-1) }' | $UTIL_CUT -d. -f1`
  56. if [ "$INPUT_LEN_STR" = "" ]; then
  57. $UTIL_ECHO " ✗ Can't get file duration"
  58. exit 1
  59. fi
  60. # Convert length to integer
  61. INPUT_LEN_HOURS=`$UTIL_ECHO $INPUT_LEN_STR | $UTIL_CUT -d: -f1`
  62. INPUT_LEN_MINUTES=`$UTIL_ECHO $INPUT_LEN_STR | $UTIL_CUT -d: -f2`
  63. INPUT_LEN_SECONDS=`$UTIL_ECHO $INPUT_LEN_STR | $UTIL_CUT -d: -f3`
  64. INPUT_LEN_HOURS=`$UTIL_EXPR $INPUT_LEN_HOURS + 0`
  65. INPUT_LEN_MINUTES=`$UTIL_EXPR $INPUT_LEN_MINUTES + 0`
  66. INPUT_LEN_SECONDS=`$UTIL_EXPR $INPUT_LEN_SECONDS + 0`
  67. # Convert length to seconds
  68. INPUT_LENGTH=$((INPUT_LEN_HOURS * 60 * 60))
  69. INPUT_LENGTH=$((INPUT_LENGTH + INPUT_LEN_MINUTES * 60))
  70. INPUT_LENGTH=$((INPUT_LENGTH + INPUT_LEN_SECONDS))
  71. # Some temp vars
  72. TMP_STEP=$((INPUT_LENGTH / SETT_PART_COUNT))
  73. # Check for minimum length
  74. INPUT_LEN_MINIMUM=$((SETT_PART_COUNT * SETT_PART_DURATION + SETT_CROSSFADE * SETT_PART_DURATION))
  75. if (( INPUT_LENGTH < INPUT_LEN_MINIMUM )); then
  76. $UTIL_ECHO " ✗ File length is too small"
  77. exit 1
  78. fi
  79. # Some temp vars
  80. TMP_LEN=$((SETT_PART_DURATION + SETT_CROSSFADE))
  81. TMP_CMD_FILES=""
  82. TMP_CMD_FILTERS=""
  83. TMP_CMD_CROSSFADE=""
  84. TMP_CMD_LAST=""
  85. # Split file to parts and generate filters
  86. for ((i = 1; i <= SETT_PART_COUNT; i++)); do
  87. TMP_S=$((i * TMP_STEP - TMP_STEP))
  88. TMP_E=$((i * TMP_STEP - TMP_STEP))
  89. TMP_E=$((TMP_E + SETT_PART_DURATION + SETT_CROSSFADE))
  90. TMP_CMD="$UTIL_FFMPEG -i $INPUT_FILE -ss $TMP_S -to $TMP_E -c copy -y $TEMP_DIR/$UNIQ_STR_$i.$SETT_FORMAT"
  91. TMP_OUTPUT=`$TMP_CMD 2>&1`
  92. k=$((i - 1))
  93. TMP_CMD_FILES="$TMP_CMD_FILES -i $TEMP_DIR/$UNIQ_STR_$i.$SETT_FORMAT"
  94. TMP_CMD_FILTERS="$TMP_CMD_FILTERS[$k]atrim=0:$TMP_LEN[a$i];"
  95. if (( i >= 2 )); then
  96. if (( i == 2 )); then
  97. TMP_CMD_CROSSFADE="$TMP_CMD_CROSSFADE[a$k][a$i]acrossfade=d=$SETT_CROSSFADE[r$k];"
  98. TMP_CMD_LAST="r$k"
  99. else
  100. r=$((k - 1))
  101. if (( i >= SETT_PART_COUNT )); then
  102. TMP_CMD_CROSSFADE="$TMP_CMD_CROSSFADE[r$r][a$i]acrossfade=d=$SETT_CROSSFADE[r$k]"
  103. else
  104. TMP_CMD_CROSSFADE="$TMP_CMD_CROSSFADE[r$r][a$i]acrossfade=d=$SETT_CROSSFADE[r$k];"
  105. fi
  106. TMP_CMD_LAST="r$k"
  107. fi
  108. fi
  109. done
  110. $UTIL_ECHO " ✓ Particles created ($SETT_PART_COUNT)"
  111. # Connect all parts with crosfade effect
  112. TMP_OUTPUT=`$UTIL_FFMPEG $TMP_CMD_FILES -filter_complex "$TMP_CMD_FILTERS$TMP_CMD_CROSSFADE" -map [$TMP_CMD_LAST] -y $OUTPUT_FILE 2>&1`
  113. $UTIL_ECHO " ✓ Particles connected together"
  114. # Make fade-in at start and fade-out at the end
  115. TMP_OUTPUT=`$UTIL_FFMPEG -i $OUTPUT_FILE -af 'afade=t=in:ss=0:d=0.8,afade=t=out:st=25:d=0.8' -y tmp.$OUTPUT_FILE 2>&1`
  116. $UTIL_RM $OUTPUT_FILE
  117. $UTIL_MV tmp.$OUTPUT_FILE $OUTPUT_FILE
  118. $UTIL_ECHO " ✓ FadeIn/FadeOut created"
  119. # Delete temp parts
  120. for ((i = 1; i <= SETT_PART_COUNT; i++)); do
  121. $UTIL_RM $TEMP_DIR/$UNIQ_STR_$i.$SETT_FORMAT
  122. done
  123. # Perfomance check
  124. PROC_END=`date +%s`
  125. PROC_ALL=$((PROC_END - PROC_START))
  126. $UTIL_ECHO " ✓ Particle files deleted"
  127. # Done
  128. $UTIL_ECHO " ✓ Done in $PROC_ALL second(s)"
  129. exit 0