album-dl-advanced 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. #!/bin/bash
  2. # Copyright 2021, soneca e cv8minix3.
  3. #
  4. # soneca acenos@danwin1210.me
  5. # cv8minix3 terroristcv8@keemail.me
  6. #
  7. # album-dl-advanced é um software livre; você pode redistribuí-lo e/ou
  8. # modificá-lo sob os termos da Licença Pública Geral GNU como publicada
  9. # pela Free Software Foundation; na versão 3 da Licença, ou
  10. # (a seu critério) qualquer versão posterior.
  11. #
  12. # Este programa é distribuído na esperança de que possa ser útil,
  13. # mas SEM NENHUMA GARANTIA; sem uma garantia implícita de ADEQUAÇÃO
  14. # a qualquer MERCADO ou APLICAÇÃO EM PARTICULAR. Veja a
  15. # Licença Pública Geral GNU para mais detalhes.
  16. #
  17. # Você deve ter recebido uma cópia da Licença Pública Geral GNU junto
  18. # com este programa. Se não, veja <http://www.gnu.org/licenses/>.
  19. ## Formatação de saída
  20. INTE="[\e[33mINTE\e[0m]"
  21. INFO="[\e[32mINFO\e[0m]"
  22. ERRO="[\e[31mERRO\e[0m]"
  23. ## Variáveis úteis
  24. ua="Mozilla/5.0 (Android 7.0; Mobile; rv:54.0) Gecko/54.0 Firefox/54.0"
  25. headers='--header="Accept-Language: pt-BR,pt" --header="Accept-Encoding: identity"'
  26. # Tentativa de padronizar ambiente.
  27. export LANG=pt_BR.UTF-8
  28. # Conversões/traduções de gêneros comuns (original|gringo).
  29. DICIO_GEN="s/poprock/pop-rock/g; s/jovem-guarda/samba-rock-pop-other/g; s/pagode/samba/g; \
  30. s/mpb/samba-acoustic-pop-other/g; s/sertanejo/country-pop-acoustic-other/g; \
  31. s/gospelreligioso/gospel/g; s/romantico/pop-other/g; s/gotico/pop-rock-punk-dream-other/g; \
  32. s/velha-guarda/samba-rock-pop-other/g;"
  33. # A lista de gêneros padrão (se não existe, será gerada).
  34. LISTA_GEN=/tmp/lista_gen.txt
  35. ## Imprime em tela os padrões de uso.
  36. function USO(){
  37. echo -e "Uso: $0 \e[92m[AÇÃO]\e[0m \e[33m[OPÇÃO]\e[0m"
  38. echo -e "\t\e[92m[-d|--dl|--download]\e[0m \e[33m[URL] [QUALIDADE]\e[0m :\e[94mBaixa álbum.\e[0m"
  39. echo -e "\t\e[92m[-f|--fix|--fixname]\e[0m \e[33m[STRING]\e[0m :\e[94mPadroniza nomes dos arquivos e remove string especificada.\e[0m"
  40. echo -e "\t\e[92m[-s|--set|--set-tags]\e[0m \e[33m[URL_METADADOS]\e[0m :\e[94mInsere metadados nos arquivos.\e[0m"
  41. echo -e "\t\e[92m[-v|--show|--show-tags]\e[0m :\e[94mMostra metadados dos arquivos.\e[0m"
  42. echo -e "\t\e[92m[-r|--rn|--renumera]\e[0m :\e[94mRenumera arquivos fora da ordem do álbum.\e[0m"
  43. exit 1;
  44. }
  45. # Checa dependências para execução do script.
  46. function DEP_CHECK(){
  47. # Todos os comandos externos de que o script depende.
  48. local IFS=' ' cmd libs="id3v2 youtube-dl ffmpeg sed egrep wget sort uniq ls mv cat rev cut rm iconv"
  49. for cmd in $libs
  50. do
  51. type -tf $cmd &> /dev/null; test $? -ne 0 && echo -e "$ERRO \"$cmd\" não instalado!" && exit 2
  52. done
  53. }
  54. # Checa existência de arquivos mp3.
  55. function MP3_CHECK(){
  56. local arqs IFS=$'\n'; arqs=$( echo *.mp3 ); test "$arqs" = '*.mp3' && \
  57. echo -e "$ERRO Não existem arquivos .mp3 neste diretório!" && exit 2
  58. }
  59. # Gera lista de gêneros padrão ID3, caso não exista.
  60. function GERA_LISTA_GENEROS(){
  61. # Para evitar guardar os gêneros aqui, são 30 linhas.
  62. local generos_lista="https://en.wikipedia.org/wiki/List_of_ID3v1_Genres"
  63. # Para padronizar em qualquer ambiente.
  64. local ua="Mozilla/5.0 (Android 7.0; Mobile; rv:54.0) Gecko/54.0 Firefox/54.0"
  65. local headers='--header="Accept-Language: pt-BR,pt" --header="Accept-Encoding: identity"'
  66. # Apenas se não existe.
  67. test -f $LISTA_GEN && return 0
  68. # Baixa HTML.
  69. local retorno=2
  70. while [ "$retorno" -ne "0" ]
  71. do
  72. generos_lista=$( wget -q --user-agent="$ua" "$headers" "$generos_lista" -O - )
  73. retorno=$?
  74. done
  75. # Converte em lista textual enumerada.
  76. generos_lista=$( echo "$generos_lista" | egrep '^<td>' | sed 's/<[^>]*>//g; s/\&amp;/\&/g;' )
  77. local gen='' IFS=$'\n' n=0
  78. for gen in $generos_lista
  79. do
  80. echo -e "$n\t $gen" >> $LISTA_GEN
  81. let n++
  82. done
  83. }
  84. # Busca gêneros recebidos do site na lista de gêneros padrão.
  85. function BUSCA_GEN(){
  86. local entrada="$1" gen IFS lista_final l1 l2
  87. # Converte gêneros "desconhecidos" para seus correspondentes ID3.
  88. entrada=$( echo "$entrada" | sed "$DICIO_GEN" )
  89. # Cortando e pesquisando.
  90. IFS='-'
  91. for gen in $entrada
  92. do
  93. # Grepa.
  94. test -n "$lista_final" && \
  95. lista_final="$( egrep -i "$gen" $LISTA_GEN )\n$lista_final" || \
  96. lista_final=$( egrep -i "$gen" $LISTA_GEN )
  97. done
  98. # Formata 2 colunas. Evita que linhas sumam quando muitas ocorrem.
  99. while read -t 1 -r l1
  100. do
  101. read -t 1 -r l2; printf "|%-25s\t |%s\n" "$l1" "$l2"
  102. done <<< "$( echo -e "$lista_final" | sort | uniq | sort -n )"
  103. }
  104. ## Substitui espaços e remove caractere estranhos
  105. function FIXNAME(){
  106. num=1;
  107. while true; do
  108. ls ${num}-* 1>/dev/null 2>/dev/null
  109. if [ $? -eq 0 ]; then
  110. file=$(ls ${num}-* 2>/dev/null)
  111. # Remover espaços
  112. newname=${file// /_}
  113. # Remover caracteres bagunceiros
  114. newname=${newname//[\!\@\#\$\%\&\*\?\;\(\)\[\]\]\{\}\<\>\'\"\`\\]/}
  115. # Remover padrão especificado em $2 ex.: album-dl --fixname "_Áudio_Oficial"
  116. [[ ! -z $1 ]] && newname=${newname//$1/};
  117. [[ "$file" != "$newname" ]] && mv "$file" "$newname" && echo "$newname";
  118. else
  119. # Sem mais arquivos
  120. break
  121. fi
  122. let num++
  123. done
  124. }
  125. ## Renumera arquivos mp3, se playlist estiver fora da ordem do álbum.
  126. function RENUMERA_MP3(){
  127. local IFS=$'\n' arqs arq narq=1 faixa faixa_ nfaixa=0 tmp lista i pto
  128. local dicio="áàâã|a éèêẽ|e íìîĩ|i óòôõ|o úùûũ|u ç|c"
  129. # Sem arquivos .mp3, não há o que renumerar.
  130. MP3_CHECK
  131. # Se não possui títulos, deve obter.
  132. if [ "${#titulo[@]}" -eq "0" ]; then if [ -n "$1" ]; then GET_METADATA "$1";
  133. else LETRAS_URL_FINDER && GET_METADATA $url_letras; fi fi
  134. # Listando arquivos mp3.
  135. # OBS: FIXNAME() pode ter alterado os nomes e grep -w pede espaços.
  136. arqs=$( ls *.mp3 | sort -n | cut -d'-' -f 2-9999 ); arqs=${arqs//_/ };
  137. # As faixas do letras.mus.br estão na ordem correta.
  138. for faixa in "${titulo[@]}"
  139. do
  140. # Guarda núm. da faixa e seu nome original.
  141. # A põe em minúsculo e remove acentos.
  142. let nfaixa++; faixa_=$faixa; faixa=${faixa,,*}; for i in \
  143. ${dicio// /$'\n'}; do faixa=${faixa//[${i%|*}]/${i#*|}}; done
  144. # Remove metainfos de feat, part e prod.
  145. for i in feat part prod; do faixa=${faixa//\($i*\)/}
  146. faixa_=${faixa_//\($i*\)/}; done
  147. # Primeiro filtro, buscando bytes com ou sem acentos.
  148. # Lista arquivos que mais possuem, em sequência, os bytes da faixa.
  149. i=0; lista=''; while [ "$i" -lt "${#faixa_}" ]
  150. do
  151. lista=$lista$'\n'$( echo "$arqs" | \
  152. egrep -i "\\${faixa:$i:2}|\\${faixa_:$i:2}" )
  153. lista=$lista$'\n'$( echo "$arqs" | \
  154. egrep -i "\\${faixa:$i:3}|\\${faixa_:$i:3}" )
  155. lista=$lista$'\n'$( echo "$arqs" | \
  156. egrep -i "\\${faixa:$i:4}|\\${faixa_:$i:4}" )
  157. lista=$lista$'\n'$( echo "$arqs" | \
  158. egrep -i "\\${faixa:$i:5}|\\${faixa_:$i:5}" )
  159. let i++
  160. done
  161. # Segundo filtro, buscando palavras com ou sem acentos.
  162. # Os arquivos que mais possuirem as palavras da faixa.
  163. i=''; for i in ${faixa// /$'\n'} ${faixa_// /$'\n'}; do
  164. lista=$lista$'\n'$( echo -ne "$arqs" | egrep -i -w "$i" ); done
  165. # Limpa lista e add pontuações. Remove falso-positivos (linhas em branco).
  166. lista=$( echo -ne "$lista" | sort | uniq -c | sort -nr ); tmp=''
  167. for i in $lista; do if [ "${#i}" -gt "8" ]; then test -n "$tmp" && \
  168. tmp=$tmp$'\n'$i || tmp=$i; fi done; lista=$tmp
  169. # Terceiro filtro, descontando pontos por bytes.
  170. # Para subir arquivo que mesmo com nome curto apareceu mais vezes.
  171. tmp=''; for i in $lista; do pto=${i:0:7}; pto=${pto//[![:digit:]]/};
  172. test -n "$tmp" && tmp=$tmp$'\n'"$(($pto-${#i})) ${i#* *[[:digit:]] }" || \
  173. tmp="$(($pto-${#i})) ${i#* *[[:digit:]] }"; done; lista=$tmp
  174. lista=$( echo -ne "$lista" | sort -nr )
  175. # Quarto filtro. Mantendo na lista apenas as maiores pontuações.
  176. # Arquivos com baixa pontuação são menos prováveis.
  177. # OBS: Enquanto o próximo possuir até 4 pontos a menos, continua.
  178. pto=${lista%% *}; tmp=''; for i in $lista; do if [ "${i%% *}" -ge "$(($pto-4))" ]
  179. then test -n "$tmp" && tmp=$tmp$'\n'"$i" || tmp="$i"; pto=${i%% *}; fi done
  180. lista="$tmp"
  181. # Quinto filtro. Intervenção manual, se necessário.
  182. # Dois ou mais ou nenhum arquivos na lista, necessita de intervenção manual.
  183. tmp=0; for i in $lista; do let tmp++; done; if [ "$tmp" -ge 2 ] || \
  184. [ "$tmp" -eq 0 ]; then echo -e "$INTE Que arquivo se refere a faixa $nfaixa: \"$faixa_\"?" && \
  185. select arq in $arqs; do lista="1 $arq"; break 1; done; fi
  186. # O arquivo correspondente, por aparecer mais vezes, é o primeiro.
  187. read -r arq <<<$( echo -ne "$lista" ); arq=${arq#*[0-999] }
  188. arq=$( ls *-${arq// /_} *-$arq 2> /dev/null | uniq ); narq=${arq%%-*};
  189. # Se número do arquivo não é igual ao da faixa, renomeia arquivo.
  190. if [ -n "$arq" ]; then if [ "$narq" -ne "$nfaixa" ]; then
  191. echo -e "${ERRO/ERRO/INFO} Movendo \"$arq\" => \"$nfaixa-${arq#*-}\""
  192. mv "$arq" "$nfaixa-${arq#*-}"; else echo -e "$INFO OK => $arq"; fi fi
  193. # Remove de $arqs o arquivo já trabalhado.
  194. arq=${arq//_/ }; arq=${arq#*-}; arqs=${arqs/$arq/}
  195. done
  196. }
  197. ## Encontra link do www.letras.mus.br pelo DuckDuckGo.
  198. function LETRAS_URL_FINDER(){
  199. # Variáveis locais.
  200. local pes_album pes_artista query
  201. # Pede dados para busca ao usuário.
  202. echo -ne "$INTE Nome do álbum: "
  203. read pes_album
  204. echo -ne "$INTE Nome da banda ou artista: "
  205. read pes_artista
  206. # Montando o que pesquisar...
  207. query="$pes_album Discografia $pes_artista \"- LETRAS.MUS.BR\""
  208. # Debugzinho...
  209. echo -e "$INFO Pesquisando no \e[93mduckduckgo\e[0m: \e[32m$query\e[0m"
  210. # Realiza busca.
  211. resultado=$(
  212. wget -qO- --user-agent="$ua" "$headers" \
  213. "https://html.duckduckgo.com/html/?q=${query// /+}" | \
  214. egrep -o "http.*letras.mus.br.*discografia/[^\"]+" | uniq
  215. );
  216. # Checa se pesquisa foi concluída.
  217. [[ -z "$resultado" ]] && echo -e "$ERRO Problema ao procurar url";
  218. # Pede que o usuário escolha uma url como fonte dos metadados.
  219. select url_letras in $resultado "Nenhum"
  220. do
  221. if [ "$url_letras" == "Nenhum" ]
  222. then
  223. unset url_letras
  224. break
  225. elif [ ! -z "$url_letras" ]
  226. then
  227. echo -e "$INFO URL: \e[36m$url_letras\e[0m"
  228. break
  229. else
  230. echo -e "$ERRO Escolha uma das opções listadas"
  231. fi
  232. done
  233. }
  234. ## Captura metadados do www.letras.mus.br
  235. function GET_METADATA(){
  236. # Para padronizar em qualquer ambiente.
  237. local link_tmp="$1" link="$1" IFS=$'\n' n=0 tmp i dados_html="" retorno=2
  238. local error_msg="Passar link do albúm https://www.letras.mus.br/[Artista]/discografia/[Nome do albúm]/"
  239. # Filtrando domínio para conferir.
  240. link_tmp=${link_tmp#*.}; link_tmp=${link_tmp%%/*}
  241. # Deve ser um link do www.letras.mus.br ou m.letras.mus.br
  242. [[ "$link_tmp" != "letras.mus.br" ]] && echo "$error_msg" && return 2;
  243. # Obtém os metadados brutos.
  244. while [ "$retorno" -ne "0" ]
  245. do
  246. dados_html=$( wget -q --user-agent="$ua" "$headers" $link -O - )
  247. retorno=$?; test $retorno -ne 0 && echo -e "$ERRO Erro ao obter metadados :("
  248. done
  249. # Nome do artista/banda.
  250. artista=${dados_html#*Discografia de }; artista=${artista%% - LETRAS.MUS.BR*}
  251. # Nome do albúm.
  252. album=${dados_html#*\<title\>}; album=${album%% |*}
  253. # O ano vem na url.
  254. ano=${link##*-}; ano=${ano/\//}
  255. # Gênero. Se vazio, usa "other".
  256. genero=${dados_html##*\"genre\":\"}; genero=${genero%%\",*};
  257. test "${genero:0:1}" = "<" && genero="other"
  258. # Títulos das músicas.
  259. tmp=$( echo "$dados_html" | sed 's/\<li\>/\n/g' | egrep ' data-name=' )
  260. for i in $tmp
  261. do
  262. i=${i##*\<b\>}; i=${i%%\</b\>*}; titulo[$n]="$i"; let n++
  263. done
  264. # A capa do disco.
  265. # ATENÇÃO: O id3v2 do sourceforge atualmente NÃO FUNCIONA para adicionar capas!
  266. # Instale a versão do github, que segundo o próprio desenvolvedor está corrigida.
  267. # Reclamação: https://sourceforge.net/p/id3v2/patches/17/
  268. # Solução: https://github.com/myers/id3v2/pull/2
  269. tmp=""; tmp=${dados_html#*artworkModal-image\" src=\"}; tmp=${tmp%%\"*}
  270. capa=capa_$RANDOM.${tmp##*.} # Nome do arquivo de imagem e sua extensão.
  271. retorno=2
  272. while [ "$retorno" -ne "0" ]
  273. do
  274. wget -q --user-agent="$ua" "$headers" $tmp -O $capa
  275. retorno=$?; test $retorno -ne 0 && echo -e "$ERRO Erro ao baixar capa :("
  276. done
  277. }
  278. ## Insere metadados nos arquivos de música.
  279. function SET_TAGS(){
  280. ## Sem arquivos .mp3, não há o que tagar.
  281. MP3_CHECK
  282. ## Pode receber url como parâmetro ou não. Se não recebe, chama LETRAS_URL_FINDER.
  283. test -n "$1" && url_letras="$1" || LETRAS_URL_FINDER
  284. ## Busca metadados sobre o albúm.
  285. GET_METADATA $url_letras && echo -e "$INFO Gênero registrado : \e[1;7;94m$genero\e[0m"
  286. ## Necessário possuir a lista de gêneros ID3.
  287. GERA_LISTA_GENEROS
  288. ## Pede que o usuário escolha um gênero do padrão ID3 para o albúm.
  289. local valido=0 genero_old=$genero
  290. while [ "$valido" -eq "0" ]
  291. do
  292. BUSCA_GEN $genero
  293. echo -ne "$INTE Escolha (número) ou digite um novo gênero: "; read id_genero
  294. ## Valida ou não ID digitado.
  295. if [[ ${id_genero:0:1} = [[:digit:]] ]]
  296. then
  297. test $( BUSCA_GEN $genero | sed 's/ |/\n/g; s/|//g;' | \
  298. egrep --count "^$id_genero " ) -eq 1 && valido=1
  299. else
  300. test -z "$id_genero" && genero=$genero_old || genero=$id_genero && genero_old=$genero
  301. fi
  302. done
  303. ## Define gênero (seu nome e não mais id. Id está em $id_genero).
  304. genero=$( egrep "^$id_genero " $LISTA_GEN | cut -f 2 ); genero=${genero/ /}
  305. ## Infos gerais.
  306. echo -e "$INFO Artista: \e[91m$artista\e[0m"
  307. echo -e "$INFO Álbum : \e[96m$album\e[0m"
  308. echo -e "$INFO Ano : \e[33m$ano\e[0m"
  309. echo -e "$INFO Gênero : \e[94m$genero\e[0m"
  310. # Lista de arquivos mp3.
  311. local files=$( ls *.mp3 | sort -n ) faixa=1 n=0 s IFS=$'\n'
  312. # Imprime infos específicas.
  313. for s in ${files[@]}; do
  314. echo -e "$INFO Faixa $faixa: \e[92m${titulo[$n]}\e[0m ==> \e[93m$s\e[0m"
  315. let n++ faixa++
  316. done
  317. ## Aplica etiquetas (usando codificação ISO-8859-1)
  318. read -p "Aplicar? (Sim/Não): " op
  319. if [[ "$op" == "Sim" || "$op" == "sim" || "$op" == "S" || "$op" == "s" ]];then
  320. n=0 faixa=1
  321. for s in ${files[@]}; do
  322. [[ ! -z "${titulo[$n]}" ]] && id3v2 -t "$( echo -n ${titulo[$n]} | iconv -f UTF-8 -t ISO-8859-1 )" $s;
  323. [[ ! -z "$artista" ]] && id3v2 -a "$( echo -n $artista | iconv -f UTF-8 -t ISO-8859-1 )" $s;
  324. [[ ! -z "$album" ]] && id3v2 -A "$( echo -n $album | iconv -f UTF-8 -t ISO-8859-1 )" $s;
  325. [[ ! -z "$id_genero" ]] && id3v2 -g "$id_genero" $s;
  326. [[ ! -z "$faixa" ]] && id3v2 -T "$faixa/${#titulo[@]}" $s;
  327. [[ ! -z "$ano" ]] && id3v2 -y "$ano" $s;
  328. [[ -f "$capa" ]] && id3v2 --APIC "$capa" $s; # Leia o ATENÇÃO em GET_METADATA()
  329. let n++ faixa++
  330. done
  331. # Imagem de capa já não é necessária.
  332. rm "$capa"
  333. fi
  334. }
  335. # Imprime informações.
  336. function SHOW_TAGS(){
  337. local IFS=$'\n' s res artista album genero ano titulo
  338. # Sem arquivos, sem metadados.
  339. MP3_CHECK
  340. for s in $( ls *.mp3 | sort -n ); do
  341. # Coleta metadados (estão em ISO-8859-1) e filtra.
  342. res=$( id3v2 -l "$s" | iconv -f ISO-8859-1 -t UTF-8 ); res="${res##*.mp3:$'\n'}"
  343. artista="${res#*Soloist\(s\)\)\: }"; artista="${artista%%$'\n'*}"
  344. album="${res#* title\)\: }"; album="${album%%$'\n'*}"
  345. genero="${res#*Content type\): }"; genero="${genero%% \(*}"
  346. ano="${res#*\(Year\)\: }"; ano="${ano%%$'\n'*}"
  347. titulo="${res#*content description\)\: }"; titulo="${titulo%%$'\n'*}"
  348. # Imprime.
  349. echo -e "$INFO Arquivo: \e[93m$s\e[0m"
  350. echo -e "$INFO Título : \e[92m$titulo\e[0m"
  351. echo -e "$INFO Artista: \e[91m$artista\e[0m"
  352. echo -e "$INFO Álbum : \e[96m$album\e[0m"
  353. echo -e "$INFO Ano : \e[33m$ano\e[0m"
  354. echo -e "$INFO Gênero : \e[94m$genero\e[0m\n"
  355. done
  356. }
  357. # Baixar album
  358. function DL(){
  359. ## Recebe link da playlist, se não recebido em $1
  360. test -z $1 && read -p "$( echo -ne "$INTE" ) Endereço da playlist: " url || url="$1"
  361. ## A qualidade pode ser definida entre 0 (mais alta) a 9 (mais baixa) em $2.
  362. test -z $2 && local qualidade=5 || local qualidade=$2
  363. ## Recebe Instâncias Invidious e testa recebimento.
  364. local instancias=$(
  365. wget -qO- "https://api.invidious.io/instances.json?pretty=1&sort_by=health" | \
  366. egrep -v "\.onion|\.i2p" | egrep -o "https*://[^/\",]*"
  367. )
  368. [[ -z "$instancias" ]] && echo -e "$ERRO Erro no recebimento de instâncias" && exit 1;
  369. ## Põe como prioridade, entre as instâncias, o domínio da playlist.
  370. local instancia_on=''
  371. instancias=${instancias/${url%/*}$'\n'/}; instancias=${url%/*}$'\n'$instancias
  372. ## Captura de links das músicas a partir da playlist.
  373. links=$( wget --no-check-certificate "$url" -qO- | egrep -o 'watch\?v=[^\"\&]*' | \
  374. cat -n | rev | sort | uniq -w 11 | rev | sort -n | cut -f 2 );
  375. [[ -z "$links" ]] && echo -e "$ERRO Erro no recebimento da playlist" && exit 1;
  376. num=1;
  377. for song in ${links[@]}; do
  378. local arq=$num-*.mp3; test $arq != $num'-*.mp3' && \
  379. echo -e "$INFO O arquivo parece já ter sido baixado: \e[93m$(ls ${num}-*.mp3)\e[0m" && let num++ && continue
  380. # Percorrendo instâncias.
  381. for instancia in $instancia_on ${instancias[@]}; do
  382. # O comando.
  383. local CMD="youtube-dl --no-call-home -x --audio-format mp3 \
  384. --audio-quality $qualidade -o ${num}-%(title)s.%(ext)s"
  385. # Debug.
  386. echo -e "$INFO Executando: \e[93m${CMD//[[:cntrl:]]/}\" \"\e[36m${instancia}/${song}&listen=1\e[93m\"\e[0m"
  387. # Tenta baixar.
  388. CMD="${CMD//[[:cntrl:]]/} ${instancia}/${song}&listen=1"; $CMD
  389. # Guarda instância funcional, se funcionar.
  390. if [ $? -eq 0 ];then
  391. instancia_on=$instancia
  392. break
  393. else
  394. # Se a falha foi com a instancia funcional, a descarta.
  395. test "$instancia" = "$instancia_on" && instancia_on=''
  396. echo -e "$ERRO O youtube-dl falhou"
  397. continue
  398. fi
  399. done
  400. ## Depois de tentar todas as instâncias testa se o arquivo foi baixado
  401. if [ ! -z "$(ls ${num}-* 2>/dev/null)" ];then
  402. #Sucesso
  403. echo -e "$INFO Arquivo salvo: \e[95m$(ls $num-* 2>/dev/null)\e[0m"
  404. else
  405. #Falha
  406. echo -e "$ERRO Instâncias esgotadas! Verifique a sua conexão" && exit 1
  407. fi
  408. let num++
  409. done
  410. }
  411. # Checa dependências a cada execução.
  412. DEP_CHECK
  413. # Verifica por comandos aceitos, início.
  414. case "$1" in
  415. '--dl'|'--download'|'-d') DL $2 $3 ;;
  416. '--fix'|'--fixname'|'-f') FIXNAME $2 ;;
  417. '--set'|'--set-tags'|'-s') SET_TAGS $2 ;;
  418. '--sh'|'--show-tags'|'-v') SHOW_TAGS ;;
  419. '--rn'|'--renumera'|'-r' ) RENUMERA_MP3 $2 ;;
  420. *) USO ;;
  421. esac