選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. #!/bin/bash
  2. # Requirements: bash, mktemp, basename, curl, (g)awk, sed, sort, bc
  3. # Declarations
  4. version="0.98"
  5. htmlname="$(basename $0)"
  6. logname="$htmlname"
  7. htmltemp="$(mktemp -t ${htmlname}.XXXXX).html" || exit 1
  8. time_start="$(date +%s)"
  9. preserve_flag="FALSE"
  10. silent_flag="FALSE"
  11. debug_flag="FALSE"
  12. function main()
  13. {
  14. debug "Passed arguments to main: $@"
  15. debug "html temp = $htmltemp"
  16. album_urls=(`parse_album_urls "$@"`)
  17. debug "Full album_urls list: ${album_urls[@]}"
  18. album_urls=(`remove_duplicate_array_elements "${album_urls[@]}"`)
  19. debug "Truncated album_urls: ${album_urls[@]}"
  20. # make sure album_urls isn't empty.
  21. if [[ -z "${album_urls[0]}" ]]
  22. then
  23. debug "album_urls[0] is empty"
  24. short_desc
  25. exit 1
  26. fi
  27. # Program Begins
  28. for url in "${album_urls[@]}"
  29. do
  30. count=0 # Reset counter
  31. url="imgur.com/a/$url"
  32. # Download the html source to a temp file for quick parsing.
  33. curl -s "$url" > "$htmltemp"
  34. # Create a new folder for the images.
  35. folder_name="$(parse_folder_name)"
  36. stdout "$folder_name"
  37. debug "folder_name = $folder_name"
  38. # Save link to album in a text file with the images.
  39. echo "$url" >> "$folder_name/permalink.txt"
  40. debug "permalink: $folder_name/permalink.txt"
  41. # Get total number of images to properly display percent done.
  42. total_images=0
  43. for image_url in $(awk -F\" '/data-src/ {print $10}' "$htmltemp" | sed '/^$/d')
  44. do
  45. let "total_images = $total_images + 1"
  46. done
  47. let "persistent_image_count += $total_images"
  48. debug "Total images = $total_images"
  49. # Iterate over all images found.
  50. for image_url in $(awk -F\" '/data-src/ {print $10}' "$htmltemp" | sed '/^$/d')
  51. do
  52. # Some albums have the thumbnail images out of order in the html source,
  53. # this fixes that.
  54. data_index_new="$(grep -m 2 $image_url $htmltemp | awk -F\" '{print $12}')"
  55. data_index_new="$(echo $data_index_new)" # necessary to remove preceding newline.
  56. if [[ "$data_index_new" == "" ]]
  57. then
  58. let "data_index_new = $data_index + 1"
  59. fi
  60. data_index="$(echo $data_index_new)"
  61. # let "data_index = $data_index + 1"
  62. debug "data_index: $data_index"
  63. # Ensure no images are thumbnails.
  64. # Always works because all images that could be in $image_url are currently
  65. # thumbnails.
  66. image_url=$(sed 's/s.jpg/.jpg/g' <<< "$image_url")
  67. debug "image_url dethumbnailed: $image_url"
  68. if [[ "$preserve_flag" == "TRUE" ]]
  69. then # Preserve imgur naming conventions.
  70. image_name="$(basename "$image_url")"
  71. else # name images based on index value.
  72. image_name="$data_index.jpg"
  73. fi
  74. # This is where the file is actually downloaded
  75. debug "Downloading image: $(($count+1))"
  76. if [[ "$silent_flag" == "TRUE" ]]
  77. then
  78. curl_args="-s"
  79. fi
  80. image_url=`echo http:$image_url`
  81. debug "image_url: $image_url"
  82. debug "curl $curl_args $image_url > $folder_name/$image_name"
  83. curl "$curl_args" "$image_url" > "$folder_name"/"$image_name" ||
  84. debug "failed to download: $image_url \n"
  85. if [[ "$preserve_flag" == "TRUE" ]]
  86. then # rename current file to force {1..11} sorting.
  87. # This is needed so the next if statement can always get the right file.
  88. new_image_name="$image_name"
  89. debug "Preserved Image Name: $new_image_name"
  90. else
  91. # brief expl: force 5 digits basename extension
  92. number_of_placeholders="$(grep -o "[0-9]" <<< "$total_images" | wc -l)"
  93. number_of_placeholders="$(echo $number_of_placeholders)"
  94. new_image_name="$(printf "%0$(echo $number_of_placeholders)d.%s" ${image_name%.*} ${image_name##*.})"
  95. if [[ "$image_name" != "$new_image_name" ]]
  96. then
  97. mv "$folder_name"/"$image_name" "$folder_name"/"$new_image_name"
  98. fi
  99. debug "New Image Name: $new_image_name"
  100. fi
  101. # Read the mimetype to ensure proper image renaming.
  102. if [[ "$(file --brief --mime "$folder_name"/"$new_image_name" | awk -F\; '{print $1}')" == "image/gif" ]]
  103. then # rename the image with the proper extension.
  104. mv "$folder_name"/"$new_image_name" \
  105. "$folder_name"/"$(basename $new_image_name .jpg).gif"
  106. fi
  107. let "count = $count + 1"
  108. if [[ "$silent_flag" == "FALSE" && "$count" != 0 && "$debug_flag" == "FALSE" ]]
  109. then # display download progress.
  110. percent="$(evaluate 2 "100 * $count / $total_images")"
  111. percent="${percent/.*}"
  112. prog="$(evaluate 2 "60 * $count / $total_images")"
  113. if [[ "$percent" =~ ^[0-9]+$ ]]
  114. then
  115. progress_bar "$percent" "$prog"
  116. fi
  117. debug "Progress: $percent%"
  118. fi
  119. done
  120. stdout ""
  121. done
  122. stdout ""
  123. stdout "Finished with $persistent_image_count files downloaded."
  124. debug "Completed successfully."
  125. exit 0
  126. }
  127. function long_desc()
  128. {
  129. cat << EOF
  130. NAME
  131. imgur - a simple album downloader
  132. Version: $version
  133. SYNOPSIS
  134. Download albums from imgur.com while retaining order.
  135. OPTIONS
  136. -h Show this message.
  137. -p Preserve imgur's naming. (Warning! This will not retain order.)
  138. -s Silent mode. Overrides debug mode.
  139. -d Debug mode. Overrides stdout.
  140. ERROR CODES
  141. 1: General failure.
  142. 6: Could not resolve host (cURL failure).
  143. 127: Command not found.
  144. AUTHOR
  145. manabutameni
  146. https://github.com/manabutameni/Imgur
  147. EOF
  148. exit 0
  149. }
  150. function short_desc()
  151. {
  152. stdout "usage: $0 [-ps] URL [URL]"
  153. exit 1
  154. }
  155. function update_check()
  156. {
  157. new_version="$(curl -s https://raw.github.com/manabutameni/Imgur/master/version)"
  158. debug "Github Script Version: $new_version"
  159. if [[ "$new_version" > "$version" ]]
  160. then
  161. debug "======"
  162. debug "There is an update for this script."
  163. if [[ "$(command -v imgur)" != "" ]]
  164. then
  165. debug "Please update with the following shell command:"
  166. debug "curl -sL https://raw.github.com/manabutameni/Imgur/master/imgur.sh -o `command -v imgur`"
  167. debug "======"
  168. fi
  169. fi
  170. }
  171. function systems_check()
  172. {
  173. failed="FALSE"
  174. command -v bash > /dev/null || { failed="TRUE"; echo Bash not installed.; }
  175. command -v mktemp > /dev/null || { failed="TRUE"; echo mktemp not installed.; }
  176. command -v curl > /dev/null || { failed="TRUE"; echo cURL not installed.; }
  177. command -v awk > /dev/null || { failed="TRUE"; echo awk not installed.; }
  178. command -v sed > /dev/null || { failed="TRUE"; echo sed not installed.; }
  179. command -v sort > /dev/null || { failed="TRUE"; echo sort not installed.; }
  180. command -v bc > /dev/null || { failed="TRUE"; echo bc not installed.; }
  181. if [[ "$failed" == "TRUE" ]]
  182. then
  183. exit 127
  184. fi
  185. debug 'All system requirements met.'
  186. debug "Local Script Version: $version"
  187. }
  188. function stdout()
  189. {
  190. # Normal output is suppressed when debug flag is raised.
  191. if [[ "$debug_flag" == "FALSE" ]] && [[ "$silent_flag" == "FALSE" ]]
  192. then
  193. echo "$@"
  194. fi
  195. }
  196. function debug()
  197. {
  198. # Debug output is suppressed when silent flag is raised.
  199. if [[ "$debug_flag" == "TRUE" ]] && [[ "$silent_flag" == "FALSE" ]]
  200. then
  201. echo "[$(echo "$(date +%s) - $time_start" | bc)] DEBUG: $@" 1>&2
  202. fi
  203. curl_args="-s"
  204. }
  205. function parse_album_urls()
  206. {
  207. # Populate album_urls with imgur albums.
  208. main_url=("$@")
  209. debug "urls to parse: ${main_url[@]}"
  210. for (( i = 0 ; i < "${#@}" ; i++ )); do
  211. debug "Downloading html source (${main_url[$i]})..."
  212. curl -sL "${main_url[$i]}" > "$htmltemp" || exit 6
  213. debug "Parsing HTML..."
  214. # 1) pull imgur album links
  215. # 2) print out everything after /a/ but before anything else like /all#
  216. album_urls+=" $(sed "s,>,\\`echo -e '\n\r'`,g" "$htmltemp" \
  217. | grep 'imgur.com/a/' \
  218. | awk -F'//imgur.com/a/' '{print $2}' \
  219. | awk -F'/all' '{print $1}' \
  220. | sed 's,[^a-zA-Z0-9],,g' \
  221. | xargs) "
  222. done
  223. debug "Urls parsed: ${album_urls[@]}"
  224. echo "${album_urls[@]}"
  225. }
  226. function parse_folder_name()
  227. {
  228. # ;exit is needed since sometimes data-title appears twice
  229. temp_folder_name="$(awk -F\" '/data-title/ {print $6; exit}' $htmltemp)"
  230. temp_folder_name="$(sed 's,&#039;,,g' <<< "$temp_folder_name")"
  231. temp_folder_name="$(sed 's,\&amp;,\&,g' <<< "$temp_folder_name")"
  232. temp_folder_name="$(sed 's,[^a-zA-Z0-9&],_,g' <<< "$temp_folder_name")"
  233. if [[ "$preserve_flag" == "TRUE" ]] || [[ "$temp_folder_name" == "" ]]
  234. then # Create a name for a folder name based on the URL.
  235. temp_folder_name="$(basename "$url" | sed 's/\#.*//g')"
  236. fi
  237. # It only takes one album named Pictures to possibly screw up
  238. # an entire folder. This will also save images to a new directory
  239. # if the script is used twice on the same album in the same folder.
  240. folderexists="TRUE"
  241. test -d "$temp_folder_name" || folderexists="FALSE"
  242. if [[ "$folderexists" == "TRUE" ]]
  243. then
  244. tempdir="$(mktemp -d "$temp_folder_name"_XXXXX)" || exit 1
  245. temp_folder_name="$tempdir"
  246. fi
  247. mkdir -p "$temp_folder_name"
  248. echo "$temp_folder_name"
  249. }
  250. function remove_duplicate_array_elements()
  251. {
  252. array=($@)
  253. printf '%s\n' "${array[@]}" | sort -u
  254. }
  255. function evaluate()
  256. {
  257. # Evaluate a floating point number expression.
  258. # There must be an argument and it must be an integer.
  259. # Example: evaluate 3 "4 * 5.2" ; # would set the scale to 3
  260. scale="$1"
  261. shift 1
  262. echo "$(echo "scale=$scale; $@" | bc -q 2> /dev/null)"
  263. }
  264. function progress_bar()
  265. {
  266. printf "[%60s] \r" " " # clear each time in case of accidental input.
  267. printf "[%60s] $1\045\r" " " # Print off the percent completed passed to $1
  268. printf "[%${2}s>\r" " " | tr ' ' '=' # Print progress bar as '=>'
  269. if [[ "$2" == "60.00" ]]
  270. then # Display completed progress bar.
  271. printf "[%${2}s]\r" " " | tr ' ' '='
  272. fi
  273. }
  274. # Option Parsing
  275. while getopts ":hdps" OPTION
  276. do
  277. case $OPTION in
  278. h)
  279. long_desc
  280. ;;
  281. d)
  282. # print debugging messages
  283. debug_flag="TRUE" && debug "Debug Flag Raised"
  284. ;;
  285. p)
  286. # Preserve Imgur's naming scheme. Please note that this will not keep the
  287. # order of the images. While this does break the spirit of the script it
  288. # is included here for the sake of completion.
  289. preserve_flag="TRUE" && debug "Preserve Flag Raised"
  290. ;;
  291. s)
  292. # Run silently.
  293. silent_flag="TRUE" && debug "Silent Flag Raised"
  294. ;;
  295. '?' | *)
  296. stdout "Invalid option: -$OPTARG" >&2
  297. short_desc
  298. ;;
  299. esac
  300. done
  301. shift $((OPTIND - 1))
  302. systems_check
  303. if [[ "$debug_flag" == "TRUE" ]]
  304. then # Run a check to see if this script is the latest version.
  305. update_check
  306. fi
  307. main $@