media2import.sh 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #
  2. # This is simple script for importing media files from source (such as memory cards)
  3. # to destination (such as local storage), creating date directories and renaming them by timestamp
  4. # of given file in desired format. Other features of script: integrity check (using sha256sum).
  5. #
  6. #
  7. #
  8. # Author: Anton TETERIN (https://2dz.fi)
  9. # Source: https://github.com/InstallAndUse/Graphics
  10. #
  11. # History:
  12. # 2023-05-07 * init /A
  13. # 2023-05-08 + read flags from CLI /A
  14. # 2023-05-16 * moved from rsync to file 'for' itiration /A
  15. # 2023-06-27 * upgrading /A
  16. # 2023-06-28 * path with spaces variables /A
  17. # 2023-06-29 + hash comparison /A
  18. # + removal on successful integrity verification /A
  19. # 2023-06-30 + add note to subdir, if specified /A
  20. # 2024-02-22 * fixed: destination path with spaces in quotes will break execution /A
  21. # + check existance of files in src /A
  22. # 2024-04-24 * changed logic for 'note', when 'skip' value is given, it sets to empty /A
  23. #
  24. # TODO
  25. # + skip files with defined mask (i.e. *.lrv, *.thm for GoPro) /A
  26. # + ask to open last directory /A
  27. function ts() {
  28. # change d
  29. ts=$(date)
  30. echo $(date )
  31. }
  32. # default help
  33. usage () {
  34. echo "Usage: $0 -s - source, -d destination, -n note";
  35. exit 1;
  36. }
  37. # read flags
  38. while getopts s:d:n: flag
  39. do
  40. case "${flag}" in
  41. s) src=${OPTARG};;
  42. d) dst=${OPTARG};;
  43. n) note=${OPTARG};;
  44. ?) usage;;
  45. esac
  46. done
  47. # read source path, by default current path (if not given)
  48. # assuming not recursive, only in-directory files will be imported
  49. if [ -z "${src}" ]; then
  50. read -p "[ $(ts) ]: Source [$(pwd)]: " src
  51. if [ -z "${src}" ]; then
  52. src="$(pwd)"
  53. fi
  54. fi
  55. # read destination path, by default current path (if not given)
  56. if [ -z "${dst}" ]; then
  57. read -p "[ $(ts) ]: Destination [$(pwd)]: " dst
  58. if [ -z "${dst}" ]; then
  59. dst="$(pwd)"
  60. fi
  61. fi
  62. # read note
  63. # if empty, ask for not
  64. if [ -z "${note}" ]; then
  65. read -p "[ $(ts) ]: Note: " note
  66. # TODO: warning, if space present. - should not be a issue anymore
  67. else
  68. # if given and it is 'skip', set to empty
  69. if [ "${note}" == "skip" ]; then
  70. printf "\n[ $(ts) ]: Note: 'skip' is given as argument, setting note to empty ..\n"
  71. note=""
  72. # otherwise, add hyphen as prefix
  73. else
  74. printf "\n[ $(ts) ]: Note: '${note}', adding hyphen ..\n"
  75. note=" - ${note}"
  76. fi
  77. fi
  78. # source and destination can not be the same, exit
  79. if [ "${src}" = "${dst}" ]; then
  80. echo "[ $(ts) ]: Source and destination are the same, exiting..."
  81. exit 2
  82. fi
  83. echo "[ $(ts) ]: ----- [ Transfer details ] ---------------------------------------------"
  84. # check that source directory exists, otherwise - exit
  85. if [ -d "${src}" ]; then
  86. # if source is empty (has no files to import), exit
  87. if [ $(ls -1 "${src}" | wc -l) -gt 0 ]; then
  88. # TODO: src, dst total and free disk space before transfer
  89. files_src_total_amount=0
  90. files_src_total_size=0
  91. for file in "${src}"/*; do
  92. file_size="$( stat -f %z "$file" )"
  93. # echo "[ $(ts) ]: file: ${file} adding file_size: $(( $file_size/1024/1024 )) MB."
  94. files_src_total_size=$(( $files_src_total_size+$file_size ))
  95. files_src_total_amount=$(( $files_src_total_amount+1 ))
  96. done
  97. echo "[ $(ts) ]: Source: [${src}]"
  98. # TODO: add nice GB figures (need to use awk or bc)
  99. echo "[ $(ts) ]: Total of $files_src_total_amount src files, total size is $(( $files_src_total_size/1024/1024 )) MB)."
  100. else
  101. echo "[ $(ts) ]: src dir is empty, nothing to import."
  102. exit 2
  103. fi
  104. else
  105. echo "[ $(ts) ]: src dir does not exist, exiting..."
  106. exit 2
  107. fi
  108. echo "[ $(ts) ]: Destination: [${dst}]"
  109. echo "[ $(ts) ]: Note: [${note}]"
  110. # confirm
  111. read -p "[ $(ts) ]: Confirm 'Y': " confirm
  112. if [ ${confirm} = "Y" ]; then
  113. # echo "[ $(ts) ]: Preparing to transfer..."
  114. # check and create destination directory, if needed
  115. if ! [ -d "${dst}" ]; then
  116. read -p "[ $(ts) ]: dst dir does not exist, do you want to create? (Y)" confirm
  117. if [ ${confirm} = "Y" ]; then
  118. # TODO: add correct check if exit code is successful
  119. mkdir -v -p -m 700 "${dst}"
  120. echo "[ $(ts) ]: dst dir created."
  121. fi
  122. fi
  123. files_copied_filename=()
  124. files_copied_total_size=0
  125. files_error_filename=()
  126. # itirating files in src
  127. for file in "${src}"/*; do
  128. # echo "[ $(ts) ]: src dir: ["${src}"]"
  129. filename="$(basename "$file")"
  130. # figure out when is the creation date
  131. file_mdate="$( stat -f %Sm -t %Y-%m-%d "$file" )"
  132. file_size="$( stat -f %z "$file" )"
  133. # appending note, if specified
  134. if [ -z "${note}" ]; then
  135. dst_subdir="${file_mdate}"
  136. else
  137. dst_subdir="${file_mdate}${note}"
  138. fi
  139. # create subdirectory for creation date
  140. mkdir -p "${dst}"/"${dst_subdir}"
  141. # TODO: echo 'show which file is being copied out of total' in the same status line below
  142. echo "[ $(ts) ]: [${filename}], modification date is: ${file_mdate}, ( $(( ${file_size}/1024/1024 )) MB )"
  143. # TODO: linux/BSD check for shasum function, if it does not run properly on linux
  144. # calulating src hash sum
  145. src_hash=$( shasum -a 256 "$file" | cut -d ' ' -f 1)
  146. # echo "[ $(ts) ]: src sha256sum: [${src_hash}]"
  147. # echo "[ $(ts) ]: dst subdir: ["${dst}"/"${dst_subdir}"]"
  148. # main operation
  149. # echo "[ $(ts) ] copying.."
  150. cp "$file" "${dst}"/"${dst_subdir}"
  151. # calulating dst hash sum
  152. dst_hash=$( shasum -a 256 "${dst}/${dst_subdir}/${filename}" | cut -d ' ' -f 1)
  153. # echo "[ $(ts) ]: dst sha256sum: [${dst_hash}]"
  154. # if shasum is the same, add to statistics and remove file
  155. if [ ${src_hash} = ${dst_hash} ]; then
  156. # add to files_copied array
  157. files_copied_filename+=("$filename")
  158. files_copied_total_size+=$file_size
  159. # TODO: add summarize sized of copied file ${file_size}
  160. # echo "[ $(ts) ]: src and dst hashes are the same, removing src file"
  161. rm "${file}"
  162. else
  163. echo "[ $(ts) ]: src and dst hashes are different, src file will not be removed."
  164. files_error_filename+=("$file")
  165. fi
  166. # TODO: add original file with fullpath to array:
  167. # files_src[]="${file}]"
  168. # TODO: add copied file with fullpath to array:
  169. # files_dst[]="${dst}"/"${dst_subdir}"/${filename}
  170. done
  171. # TODO: src, dst total and free disk space before transfer
  172. # TODO: src, dst total and free disk space after copy
  173. # TODO: time taken to transfer
  174. # TODO: avarage transfer speed
  175. # TODO: ! unmount src disk ?
  176. # diskutil unmount /Volumes/empty
  177. # TODO: open latest directory created?
  178. # open -a "${dst}"
  179. # TODO: output total amount of files and size
  180. # itirate files
  181. # read creation date of file
  182. #dst_subdir="${dst}/${file_creation_date}${note}"
  183. # TODO: list subdirs, that created (in order to see, where to files are transferred)
  184. else
  185. # not confirmed
  186. echo "[ $(ts) ]: Operation is not confirmed."
  187. exit 1
  188. fi