MocPList - Enfileirador de áudio e locutor em voz sintetizada

Publicado por Khayla (Alexandre) Elias dos Santos (última atualização em 21/02/2019)

[ Hits: 1.480 ]

Download mocplist

Download 1549117671.mocplist-1.19.83 (versão 2)




MocPlist é um cliente enfileirador randômico de mídias de áudio para o serviço MOC Player que permite gerar "playlists" baseando-se nas Info Tags dos arquivos de mídias. Além disso, é um locutor em voz sintetizada com diversos recursos como anúncio do  título da mídia em reprodução, das horas local e do estado da caixa de email. Mais informações, nas primeiras linhas comentadas do script.

  



Versões atualizadas deste script

Versão 2 - Enviado por Khayla (Alexandre) Elias dos Santos em 02/02/2019

Changelog: Versão 1.19.83 do MocpList Enfileirador automático para o Moc Player.

Novidades:

- Inclusão de arquivo de cache para agilizar novas pesquisas.
- Alteração no algoritmo e na estrutura de dados para acelerar a pesquisa. Esta mudança visa a reduzir principalmente o custo da geração dos índices randômicos na medida em que estes se tornam mais raros de serem gerados.
- Maior confiabilidade no processo de enfileiramento e inclusão de um indicador de número de falhas de arquivos não enfileirados.
- Melhoria dos recursos já implementados.

Download 1549117671.mocplist-1.19.83


Esconder código-fonte

#!/bin/bash
#  === M O C P L I S T   -   M o c   P l a y l i s t   V e r s ã o   1 . 1 9 =================================================
#
#  DESCRIÇÃO:
#
#       Cliente enfileirador de mídias de áudio para o serviço MOC Player e locutor em voz sintetizada  com as seguintes
#       características:
#
#               - Indentifica informações (tags) da  mídia em reprodução no Moc Player.
#               - Permite o uso de palavras chaves (padrões de busca) para pesquisa e seleção de mídias que casem com
#                 as expressões fornecidas pelo usuário.
#               - Seleciona as mídias aleatoriamente e as enfileira criando um novo playlist ou ao já existente.
#               - Utilizá-se das tags contidas nas mídias e/ou do nome do arquivo destas no processo  de enfileiramento.
#               - Auto-enfileiramento de mídias quando o tocador está ocioso.
#               - Locutor(a) em voz sintetizada para anunciar:
#
#                       + Título da mídia
#                       + As horas da máquina local
#                       + Alguma mensagem de difusão fornecida pelo usuário (broadcast)
#                       + O número de mensagens não lidas da caixa de email (via fetchmail)
#                       + Sobre o programa e do tocador
#
#
#       NOTAS:
#
#               1) A pesquisa deve ser feita preenchendo-se alguns dos seguintes campos na janela de diálogo:
#
#                       + Artista/Banda
#                       + Título
#                       + Álbum
#                       + Ano
#                       + Gênero
#                       + Outros
#
#               2) No campo 'Outros' pode-se fornecer uma expressão livre que, por sua vez, pode casar com uma tag específica
#                  (fornecendo-se o padrão adequado da mesma) ou com quaisquer outras pré-filtradas ou, ainda, com o nome do
#                  arquivo.
#
#               3) A INTERSEÇÃO de casamentos de padrões ocorrerá se houver sucesso no casamento de cada um dos campos
#                  acima. Note que, com essa regra, cada mídia selecionada CASA COM TODOS OS CAMPOS, inclusive os vazios (veja
#                  exemplos 1 à 4 abaixo).
#
#               4) A UNIÃO de casamentos de padrões pode ser obtida utilizando-se "Expressões Regulares" (REGEX) separando
#                  os padrões com o operador OU (o caractere "|"). Note que, com essa regra, cada mídia selecionada CASA COM
#                  ALGUM DOS PADRÔES fornecidos num determinado campo (exemplos 3 e 4 abaixo).
#
#               5) O pŕe-filtro de busca contém as seguintes tags:
#
#                     Id3v1: Artist, Year, Genre, Title, Album, Comment.
#                     Id3v2: TP1, TALB, TYE, TCON, TCOM, TIT, TPE, TOLY, TOPE, TEXT, COMM.
#
#               6) A cada mídia selecionada durante o processo de enfileiramento, um segmento de mídias vizinhas também é
#                  pesquisado para enfileirar um conjunto de mídias que também casam com as palavras chaves fornecidas pelo
#                  usuário. A relação de vizinhança se dá na proximidade da árvore do subdiretório que elas pertencem.
#
#
#
#  PRÉ-REQUISITOS:
#
#       Os pacotes dos seguintes programas devem estar instalados para o funcionamento adequado deste script:
#
#               - MOC:      Tocador de áudio em console (Music On Console Player).
#               - ID3V2:        Editor de tags id3v2 em linha de comando.
#               - DIALOG:   Exibe caixas de diálogo amigáveis ao usuário em scripts shell.
#               - ESPEAK:   Locutor multilíngue em voz sintetizada.
#               - FETCHMAIL:   Fetch mail from a POP, IMAP, ETRN, or ODMR-capable server (opcional).
#               - FORTUNE:      Print a random, hopefully interesting, adage (opcional).
#
#
#
#   OPÇÕES:
#
#       --update, -u:   Atualiza a lista de mídias. Sempre que houver alteração no diretório padrão de músicas é
#                       necessário iniciar a execução da seguinte forma:
#
#               mocplist --update
#
#
#       --help, -h:     Ajuda básica para executar este script.
#
#
#       --about:        Exibe estas informações sobre e de ajuda.
#
#
#       --reset-theme:   restaura o arquivo de configurações do tema do dialog na home do usuário.
#
#
#
#  TECLAS DE CONTROLE DA TELA PRINCIPAL:
#
#       a:      Ativa/desativa o enfileiramento AUTOMÁTICO quando o tocador estiver ocioso.
#       b:      Toca a mídia ANTERIOR no Moc Player.
#       i:      Exibe INFO TAGS da mídia em reprodução e que podem ser usadas para pesquisa.
#       h:      Ajuda.
#       l:      ADICIONA novas mídias ao playlist atual sem limpá-lo.
#       m:      Exibe informações da caixa de EMAIL (INBOX).
#       n:      Toca a PRÓXIMA mídia no Moc Player.
#       p:      PAUSA/DESPAUSA a mídia em reprodução.
#       q:      ENCERRA o programa.
#       r:      Exibe RELATÓRIO da lista de mídias contidas no diretório padrão de músicas.
#       s:      Permite alterar as CONFIGURAÇÕES básicas.
#       L:      LIMPA o playlist atual e ADICIONA novas mídias.
#       ,:      REDUZ o volume 5%.
#       .:      AUMENTA o volume 5%.
#
#
#
#  EXEMPLOS DE USO DE PADRÕES DE BUSCA:
#
#
#       1) Para pesquisar e enfileirar músicas do álbum Falso Brilhante da cantora Elis Regina, basta preencher
#          os campos abaixo e deixar os demais vazios:
#
#               Artista/banda:   Elis Regina
#               Álbum:      Falso Brilhante
#
#       2) Para obter uma busca mais refinada, pode-se utilizar das "Expressões Regulares". Por exemplo, se quiser buscar
#          mídias do gênero Progressive Rock entre os anos de 2010 à 2018, pode-se fornecer as expressões abaixo:
#   
#               Ano:      201[0-8]
#               Gênero:      progressive rock
#
#       3) Buscando e enfileirando músicas da banda Sepultura OU Slayer OU Iron Maiden dos anos de 1983 à 1985:
#
#               Artista/banda:   sepultura|slayer|iron maiden
#               Ano:      1983|1984|1985
#
#       4) Para um casamento independente das tags, pode-se usar exclusivamente o campo 'Outros' da seguinte forma:
#
#               Outros:      techno|Kraftwerk|19[7-9][0-9]
#
#          Neste caso, serão enfileirados áudios que contém alguma tag com a expressão "techno" OU "Krafwerk" OU números
#          entre 1970 à 1999. Além das tags, vale ressaltar que o nome do arquivo também será usado para o casamento
#          de padrões no uso do campo 'Outros'.
#
#
#
#       COMENTÁRIOS:
#
#               - A busca será mais precisa quanto melhor se utilizar das "Expressões Regulares" para casamento de
#                 padrões de busca.
#
#
#
#  POR:                 Khayla Elias dos Santos (Alexandre)
#  Email:      avezdopinguim@gmail.com
#  DATA:                Julho 2009
#  ATUALIZADO EM:       Fevereiro 2018
#  PLATAFORMA DE TESTE: Linux, Ubuntu 14.04
#
#       "Ela virá, a revolução conquistará a todos o direito não somente ao pão, mas, também, a poesia." (Leon Trotsky)
#
# ============================================================================================================================



# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#
#  ESQUEMA DE PESQUISA E PARTICIONAMENTO DA LISTA DE MÍDIAS:
#
#  VETOR COM ÍNDICES DA LISTA DE MÍDIAS:
#
#                      1 2  3    n
#       [...+......<...+.+..+....++.>..+.....+...+..]
#                  ^                ^
#                  |....segmento....|
#              ponteiro          ponteiro
#              inicial           final
#              (randômico)
#
#
#
#  PARTICIONAMENTO RANDOMICO DO VETOR A CADA ITERAÇÃO:
#
#
#    NÃO PARTICIONADO         PÓS PARTICIONADO
#   (com índices sujeito a pesquisa)   (com índices pesquisados)
#
#   0   [..............<???>....]      []
#   1   [...<???>..........]      [(...)]
#   2   [.....<???>....]         [(...)(...)]
#   3   [...<???>..]         [(...)(...)(...)]
#   .   .               .
#   .   .               .
#   .   .               .
#   20 []               [(...)(...)(...) ... (...)]
#                    P0   P1   P2        P20
#
#
#
#   LEGENDA:
#
#   (.)      Índice de uma mídia qualquer da lista
#   (+)      Índice de mídia que casam com os padrões de busca
#   (1 - n)      Índices de mídias vizinhas que serão enfileirados
#   (?)      Indices de mídias sujeitas a serem pesquisadas
#   (< >)      Índices limitadores do segmento (vizinhança) a ser pesquisado
#   (P0 - P20)   Partições pesquisadas
#
# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



# ===  P A R Á M E T R O S   D E   E N T R A D A =============================================================================
UPDATE="$1"         # 1) --update ou --report ou --reset-theme ou --help ou --about 


shopt -s -o nounset      # disallow undefined variables


# === D E C L A R A Ç Ã O   D E   C O N S T A N T ES =========================================================================
# NOME DO PROCESSO:
declare -r SCRIPT=`basename $0`
declare -r PROG=`echo $SCRIPT | sed 's/\.sh$//'`
declare -r LOCATE="`ps aux|grep ".*bash.*${SCRIPT}"|grep -v "grep"|head -1 |sed "s;^.*/bin/bash ;;"|sed "s; -.*$;;"`" # local


# ARQUIVOS E DIRETÓRIOS:
declare -r BASE=$HOME/.mocplist         # diretório de arquivos do script
declare -r MUSICA=$HOME/Música         # diretório raiz de áudios
declare -r TEMP=/var/tmp/$SCRIPT      # diretório de arquivos temporários
declare -r LOG=$BASE/$SCRIPT.log      # arquivo de log do script
declare -r FICHEIROS=$BASE/media-list      # lista de todas mídias para pesquisas
declare -r INDEX=$TEMP/indices         # índices de mídias a serem pesquisadas
declare -r CHECKEDS=$TEMP/checkeds      # índices de mídias pesquisadas (partições)
declare -r WORDS_EN=$BASE/words-en      # lista de expressões para eleger idioma inglês
declare -r WORDS_ES=$BASE/words-es      # lista de expressões para eleger idioma espanhol
declare -r CONF=$BASE/mocplist.conf      # arquivo de configuração
declare -r GENRE_LIST=$BASE/genre.txt      # lista de gêneros musicais
declare -r REPORT=$BASE/report-medias.txt   # Relatório de mídias contidas em MUSICA
declare   -r DATA_MEDIA=$TEMP/data-media      # dados da mídia em reprodução
declare -r DATA_ID3=$TEMP/dataID3      # tags id3 da mídia em reprodução
declare -r TOT_FILA=$TEMP/tt-fila      # número de enfileirados
declare -r PERC_OUT=$TEMP/perc-out      # percentual geral de arquivos varridos
declare -r TT_VARRIDOS=$TEMP/tt-varridos   # total acumulado de ficheiros varridos
declare -r SINAL=$TEMP/sinal         # flag de interrupção de enfileiramento
declare -r CHMAIL=$BASE/mail.$USER      # arquivo de saída do fetchmail


# === A R Q U I V O S   E   C O N S T A N T E S   R E L A T I V O S   A O   P R O C E S S O ==================================
declare -r VERSAO="Version 1.19"
declare -r TMP_PID=$TEMP/$SCRIPT.pid      # pid deste script
declare -r SUB_PID=$TEMP/${SCRIPT}.sub.pid   # pid da rotina de enfileiramento em segundo plano
declare -r TMP_LOG=$TEMP/${SCRIPT}_$$.log   # log temporário do script em execução
declare -r TMP_TRUNC=$TEMP/${SCRIPT}_$$.trunc   # log temporário auxilar
declare -ir MAX_RETIDO=5000         # tamanho máximo do arquivo de log


# === C O N S T A N T E S   G E R A I S ======================================================================================
declare -ri PROB=50 # (%)         # probabilidade de difusão das horas do host
declare -ri INTERVAL=12            # intervalo de checagem de email (minutos modular)
declare -r UPDATE=${UPDATE:=null}      # ativa atualização da lista de 'media-list'
declare -r FRASE_EN="Music On Console Player: "   # pronúncia em inglês
declare -r FRASE_PT="Míusic On Console Player: " # pronúncia em português
declare -r FRASE_OP="M.O.C Playlist, enfileiramento de áudio configurável." # frase default
declare -a DICA=("<artist>" "<title>" "<album>" "<year>" "<genre>" "<others>")


# === V A R I Á V E I S   I N T E I R A S ====================================================================================
declare -i PID_SPK=99999         # pid do locutor em segundo plano
declare -i MAX_FILA=0            # número de mídias a enfileirar
declare -i VIZINHOS=0            # número de mídias vizinhas a enfileirar
declare -i SECAO=0            # tamanho a ser varrido do seguimento da lista
declare -i REFRESH=0            # set de retorno de atualização da tela principal
declare -i TT_FICHEIROS=0         # Total de mídias na lista de mídias
declare -i BEFORE_MINUTE=0         # minuto obtido na checagem de email
declare -i AFTER_MINUTE=-1         # minuto passado pos checagem de email
declare -i TOT_MAIL=0            # total de mensagens na caixa de entrada
declare -i NEW_MAIL=0            # &#324;umero de mensagens não lidas


# === V A R I Á V E I S   L I T E R A I S ====================================================================================
# FILTRO para pesquisa baseado na saída do programa id3v2:
declare -r FILTRO="id3v|ID3|^Title|^Album|^Comment|\
^TP1|^TALB|^TYE|^TCON|^TCOM|^TIT|^TPE|^TOLY|^TOPE|^TEXT|^COMM"
declare -a PADRAO=("" "" "" "" "" "")      # expressões regulares utilizadas nas buscas id3v2
TALK=            # ativa/desativa locutor em voz sintetizada
DIFUSAO=         # ativa/desativa anúncio de mensagens
VOZ="off"         # idioma default do locutor
CHK_MAIL=         # ativa checagem de email
MENSAGEM=         # mensagem de difusão (broadcast)
COMANDO=         # comando gerador de texto
TECLA=            # entrada de comandos (teclas de controle da tela principal)
ARTIST=            # artista da mídia em reprodução
SONG_TITLE=         # titulo da mídia em reprodução
TITLE=            # título unificado da mídia
GENRE=            # género da mídia em reprodução
YEAR=            # ano da mídia em reprodução
ALBUM=            # álbum da mídia em reprodução
TRACK=            # track da mídia em reprodução
TRACK0=            # track passado
TRACK1=            # track checked
MODO=            # estado do tocador (barra de título)
GMAIL=            # endereço de email obtido pelo fetchmail
FRAME_ART=         # dicas do dialog
FRAME_TIT=         # //
FRAME_ALB=         # //
FRAME_YER=         # //
FRAME_CON=         # //
FRAME_ALL=         # //
AUTO="no-auto"         # ativa/desativa enfileramento automático
TEXTO="      MocpList - $VERSAO\n\nBy: Khayla Elias dos Santos \
\nEmail: avezdopinguim@gmail.com\n\n \
  <3\"(: Uma dedicação do Pinguim à amada Sabiá"   # créditos do desenvolverdor
SELECAO=         # auxiliar para formatar padrões de busca


# === F U N Ç Õ E S ==========================================================================================================
function help_fn(){
   if [ "$#" != 0 ]; then
      if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
         printf "MocpList - $VERSAO\n\n"
         printf "This is searcher in data id3v2 tag and enqueuer list to moc player server.\n\n"
         printf "Use:\t$SCRIPT [ --about | <--update> | <-u> | <--help> | <-h> ]\n\n"
         exit
      else    if [ "$1" != "--update" ] && [ "$1" != "-u"  ] && [ $1 != "--about" ] && [ "$1" != "--reset-theme" ]; then
            printf "Erro: opção inválida.\nUse '$SCRIPT --help' para ajuda.\n"
            exit 1
         else   if [ "$1" = "--about" ]; then
               head -200 $LOCATE|sed -e "s;^#;;" -e "/^\!/d"|less 
               exit
            fi # about
         fi # opções
      fi # help and check parameters
   fi #   Help and check parameters
} # help_fn - help and check parameters



function fn_fim_script(){
   tail -$MAX_RETIDO $LOG > $TMP_TRUNC
   echo "$PROG: pid $$", início de linhas ===== >> $TMP_TRUNC
   cat $TMP_LOG >> $TMP_TRUNC
   mv $TMP_TRUNC $LOG
   # extermina processo em segundo plano
   [ "`cat $SUB_PID`" -gt 0 ] && kill -9 `cat $SUB_PID`
   # Remoção de arquivos temporários:
   cd $TEMP; rm -f ./*
   tput cnorm; reset
} # fn_fim_script - tratamento de encerramento



function fn_trap(){
   #fn_erro N "$PROG: Interrupção forçada"
   fn_fim_script &>/dev/null
   exit 2
} # fn_trap - tratamento de interrupções



function check_sanity(){
   if ! ( type -a mocp 2>/dev/null|grep -q "/mocp" ); then
           printf "\r`basename $0`:$LINENO: the command 'mocp' is not available\naborting\n" >&2
           exit 1
   fi # check mocp

   if ! ( type -a dialog 2>/dev/null|grep -q "/dialog" ); then
           printf "\r`basename $0`:$LINENO: the command 'dialog' is not available\naborting\n" >&2
           exit 1
   fi # check dialog

   if ! ( type -a id3v2 2>/dev/null|grep -q "/id3v2" ); then
           printf "\r`basename $0`:$LINENO: the command 'id3v2' is not available\naborting\n" >&2
           exit 1
   fi # check id3v2

   if ! ( type -a espeak 2>/dev/null|grep -q "/espeak" ); then
           printf "\r`basename $0`:$LINENO: the command 'espeak' is not available\naborting\n" >&2
           exit 1
   fi # check espeak

   [ -d "$TEMP" ] || mkdir $TEMP

   if [ -s "$TMP_PID" ]; then
      PID=`cat $TMP_PID`
      if ps -p $PID 2> /dev/null >&2; then
         echo "$PROG: Uma instância deste programa já está em execução. PID=$PID." >&2
         exit 3
      fi
   else   echo $$ > $TMP_PID
      rm -f $TMP_LOG &>/dev/null
   fi # garante a execucão de uma única instância
} # check_sanity - verificações pré-eliminares



function reset_theme(){
   [ "$UPDATE" = "--reset-theme" ] && dialog --create-rc $HOME/.dialogrc
} # reset_theme - recria arquivo do tema



function check_files(){
   # cria diretório do aplicativo na home do usuário
   [ -d "$BASE" ] || mkdir $BASE

   # padrões básicos para eleger idioma inglês (inclui o subdiretório Internacionais)
   [ ! -f "$WORDS_EN" ] && \
      printf ".*/M[úu]sica/Internacionais/\nabout[,.!?]*\n^all,* | all,* | all[.!?]*$\n^are,* | are,* | are[.!?]*$\neyes,* | eyes,* | eyes[.!?]*\n^in,* | in,* | in[.!?]*$\n^it,* | it,* | it[.!?]*$\n^how,* | how,* | how[.!?]*$\nlike[,.!?]*\n^m[ae]n,* | m[ae]n,* | m[ae]n[.!?]*$\n^of,* | of,* | of[.!?]*$\n^off,* | off,* | off[.!?]*$\n^on,* | on,* | on[.!?]*$\n^one,* | one,* | one[.!?]*$\n^she,* | she,* | she[.!?]*$\n^the,* | the,* | the[.!?]*$\nthey[,.!?]*\n^we,* | we,* | we[.!?]*$\nwhen,* | when,* |when[.!?]*\nwom[ae]n[,.!?]*\nwitho*[,.!?]*\nyear,* | year,* |year[.!?]*\nyou,* | you,* | you[.!?]*\n^up,* | up,* | up[.!?]*$\n" > $WORDS_EN

   # padrões básicos para eleger idioma espanhol (inclui o subdiretório Latinas)
   [ ! -f "$WORDS_ES" ] && \
      printf ".*/M[úu]sica/Latinas/\n.*ción[,.!?]*\ncoraz[óo]n[,.!?]*\n^cuanto,* | cuanto,* | cuanto[.!?]*$\n^el,* | el,* | el[.!?]*$\nestoy[,.!?]*\n^gustas*,* | gustas*,* | gustas*[.!?]*$\nhasta,* | hasta[.!?]*\nhola,* | hola,* | hola[.!?]*$\nhombres*[,.!?]*\n^hoy,* | hoy,* | hoy[.!?]*$\ninmortal[,.!?]*\nlibertad[,.!?]*\nllorar[,.!?]*\nmío,* | mío[.!?]*\nmujer[,.!?]*\nnecesito[,.!?]*\nquier.,* | quier.[.!?]*\nsoledad[,.!?]*\ntengo,* | tengo[.!?]*\ntiempo[,.!?]*\n^un,* | un,* | un[.!?]*$\n^un[ao],* | un[ao],* | un[ao][.!?]*$\nusted[,.!?]*\nvivir[,.!?]*\n" > $WORDS_ES

   [ ! -f "$CONF" ] &&(
      printf "# MocpList -  Configurações gerais\n\n"         > $CONF
      printf "# Ativa/desativa locutor em voz sintetizada\n"      >>$CONF
      printf "TALKER = on\n\n"               >>$CONF
      printf "# Ativa/desativa difusão de mensagens\n"      >>$CONF
      printf "BROADCAST = on\n\n"               >>$CONF
      printf "# Tamanho máximo da lista de enfileiramento\n"      >>$CONF
      printf "TAM_FILA = 12\n\n"               >>$CONF
      printf "# Número de mídias vizinhas relação ao subdiretório\n"   >>$CONF
      printf "NEIGHBOR = 4\n\n"               >>$CONF
      printf "# Tamanho de cada segmento (vizinhança) pesquisado\n"   >>$CONF
      printf "NEIGHBORHOOD = 60\n\n"               >>$CONF
      printf "# Ativa/desativa checagem da caixa de email.\n"      >>$CONF
      printf "# É necessário que o Fetchmail esteja configurado.\n"   >>$CONF
      printf "MAIL = off\n\n"                  >>$CONF
      printf "# Comando gerador de texto para difusão.\n"      >>$CONF
      printf "COMMAND = fortune\n\n"               >>$CONF
      printf "# Mensagem principal de difusão\n"         >>$CONF
      printf "MESSAGE = \"Ubuntu, Linux para seres humanos.\"\n"   >>$CONF
   ) # cria arquivo de configuração

   # lista de gêneros musicais
   [ -f $GENRE_LIST ] || id3v2 -L >$GENRE_LIST

   # variáveis arquivadas
   echo 0 > $TOT_FILA
   echo 0 > $PERC_OUT
   echo -1 > $SUB_PID
} # check_files - verifica e (re)cria arquivo de configuração



function set_variables(){
   local VALOR=


   VALOR="`grep "^[    ]*TALKER[    ]*=" $CONF| sed -r 's/^[    ]*TALKER[    ]*=[    ]*([ONFonf]{2,3})[    ]*$/\1/'`"
   case "$VALOR" in
      on|ON)
         TALK="on"
         VOZ="on";;
      off|OFF)
         TALK="off"
         VOZ="off";;
      *)
         TALK="on";;
   esac # ativa/desativa LOCUTOR


   VALOR="`grep "^[    ]*BROADCAST[    ]*=" $CONF| sed -r 's/^[    ]*BROADCAST[    ]*=[    ]*([ONFonf]{2,3})[    ]*$/\1/'`"
   case "$VALOR" in
      on|ON)
         DIFUSAO="on";;
      off|OFF)
         DIFUSAO="off";;
      *)
         DIFUSAO="on";;
   esac # ativa/desativa anúncio de MENSAGENS


   VALOR="`grep "^[    ]*MAIL[    ]*=" $CONF| sed -r 's/^[    ]*MAIL[    ]*=[    ]*([onf]{2,3})[    ]*$/\1/'`"
   case "$VALOR" in
      on|ON)
         CHK_MAIL="on";;
      off|OFF)
         CHK_MAIL="off";;
      *)
         CHK_MAIL="off";;
   esac # ativa/desativa checagem de EMAIL


   grep -q "^[    ]*TAM_FILA[    ]*=[    ]*[0-9]\{1,4\}[    ]*$" $CONF
   if [ "$?" -eq 0 ]; then
      MAX_FILA="`grep "^TAM_FILA[    ]*=[    ]*[0-9]\{1,4\}[    ]*$" $CONF| \
      sed -r 's/^TAM_FILA.*=[    ]*([0-9]{1,4})[    ]*$/\1/; s/^00*//'`"
      [ "${MAX_FILA:=0}" -eq 0 ] && MAX_FILA=12
   else   MAX_FILA=12
   fi # determina Tamanho MÁXIMO do enfileiramento


   grep -q "^[    ]*NEIGHBOR[    ]*=[    ]*[0-9]\{1,2\}[    ]*$" $CONF
   if [ "$?" -eq 0 ]; then
      VIZINHOS="`grep "^[    ]*NEIGHBOR[    ]*=[    ]*[0-9]\{1,2\}[    ]*$" $CONF| \
      sed -r 's/^[    ]*NEIGHBOR[    ]*=[    ]*([0-9]{1,2})[    ]*$/\1/; s/^00*//'`"
      [ "${VIZINHOS:=0}" -eq 0 ] && VIZINHOS=3
   else   VIZINHOS=3
   fi # determina o número de VIZINHOS a enfileirar ao varrer o segmento


   grep -q "^[    ]*NEIGHBORHOOD[    ]*=[    ]*[0-9]\{1,3\}[    ]*$" $CONF
   if [ "$?" -eq 0 ]; then
      SECAO="`grep "^[    ]*NEIGHBORHOOD[    ]*=[    ]*[0-9]\{1,3\}[    ]*$" $CONF| \
      sed -r 's/^[    ]*NEIGHBORHOOD[    ]*=[    ]*([0-9]{1,3})[    ]*$/\1/; s/^00*//'`"
      [ "${SECAO:=0}" -lt "$VIZINHOS" ] && SECAO=$VIZINHOS
   else   SECAO=50
   fi # determinha tamanho de cada SEGMENTO a ser varrido


   grep -q "^[    ]*MESSAGE[    ]*=" $CONF
   if [ "$?" -eq 0 ]; then
      MENSAGEM="`grep "^[    ]*MESSAGE[    ]*=" $CONF|sed "s/^[    ]*MESSAGE[    ]*=[    ]*//"|sed -r 's;"(.*)";\1;'`"
      MENSAGEM=${MENSAGEM:=${FRASE_OP}}
   fi # mensagem de DIFUSÃO


   grep -q "^[    ]*COMMAND[    ]*=" $CONF
   if [ "$?" -eq 0 ]; then
      COMANDO="`grep "^[    ]*COMMAND[    ]*=" $CONF|sed "s/^[    ]*COMMAND[    ]*=[    ]*//"|sed -r 's;"(.*)";\1;'`"
   else   COMANDO=
   fi # COMANDO para gerador de texto de DIFUSÃO
} # set_variables - configuração dos principais parâmetros



function report(){
   local -i SUB_TOTAL=0
   local -i TOTAL=0

   printf "RELATÓRIO DE MÍDIAS - $HOSTNAME - `date`\n\n" > $REPORT

   printf "Local:\t$MUSICA\n\n" >> $REPORT

   TOTAL="`find -L $MUSICA/ -iname "*.mp3"| wc -l`"
   printf "Mídias *.mp3:\t$TOTAL\n" >> $REPORT
   let SUB_TOTAL=SUB_TOTAL+TOTAL

   TOTAL="`find -L $MUSICA/ -iname "*.ogg"| wc -l`"
   printf "Mídias *.ogg:\t$TOTAL\n" >> $REPORT
   let SUB_TOTAL=SUB_TOTAL+TOTAL

   TOTAL="`find -L $MUSICA/ -iname "*.wmv"| wc -l`"
   printf "Mídias *.wmv:\t$TOTAL\n" >> $REPORT
   let SUB_TOTAL=SUB_TOTAL+TOTAL

   TOTAL="`find -L $MUSICA/ -iname "*.wav"| wc -l`"
   printf "Mídias *.wav:\t$TOTAL\n" >> $REPORT
   let SUB_TOTAL=SUB_TOTAL+TOTAL

   TOTAL="`find -L $MUSICA/ -iname "*.wma"| wc -l`"
   printf "Mídias *.wma:\t$TOTAL\n" >> $REPORT
   let SUB_TOTAL=SUB_TOTAL+TOTAL

   TOTAL="`find -L $MUSICA/ -iname "*.aac"| wc -l`"
   printf "Mídias *.aac:\t$TOTAL\n" >> $REPORT
   let SUB_TOTAL=SUB_TOTAL+TOTAL

   TOTAL="`find -L $MUSICA/ -iname "*.flac"| wc -l`"
   printf "Mídias *.flac:\t$TOTAL\n" >> $REPORT
   let SUB_TOTAL=SUB_TOTAL+TOTAL

   TOTAL="`find -L $MUSICA/ -iname "*.avi"| wc -l`"
   printf "Mídias *.avi:\t$TOTAL\n" >> $REPORT
   let SUB_TOTAL=SUB_TOTAL+TOTAL

   TOTAL="`find -L $MUSICA/ -iname "*.mp4"| wc -l`"
   printf "Mídias *.mp4:\t$TOTAL\n" >> $REPORT
   let SUB_TOTAL=SUB_TOTAL+TOTAL

   TOTAL="`find -L $MUSICA/ -iname "*.flv"| wc -l`"
   printf "Mídias *.flv:\t$TOTAL\n" >> $REPORT
   let SUB_TOTAL=SUB_TOTAL+TOTAL

   TOTAL="`find -L $MUSICA/ -iname "*.ac3"| wc -l`"
   printf "Mídias *.ac3:\t$TOTAL\n" >> $REPORT
   let SUB_TOTAL=SUB_TOTAL+TOTAL

   TOTAL="`find -L $MUSICA/ -iname "*.3gp"| wc -l`"
   printf "Mídias *.3gp:\t$TOTAL\n" >> $REPORT
   let SUB_TOTAL=SUB_TOTAL+TOTAL

   printf "Total:\t\t$SUB_TOTAL\n" >> $REPORT
} # report - produz relatório de mídias contidas no diretório $MUSICA

      

function atualiza(){
   if [ ! -f "$FICHEIROS" ] || [ "$UPDATE" = "--update" ] || [ "$UPDATE" = "-u" ]; then
      local -r FRASE_CRED="`mocp -V |grep -E "This|Version|Run|Author|Home|Copy|License"`"

      #=== C R E D I T O S =============================================
      if [ "$TALK" = "on" ]; then
         espeak -p0 -ven+f4  "About Player:" &>/dev/null
         echo "$FRASE_CRED"|espeak -p0 -ven+us+m7 &>/dev/null&
         local -i PID_SPK=$!
      fi # =============================================================

      dialog --stdout --no-collapse --cr-wrap \
         --backtitle "Extração de ficheiros de áudios" \
         --title "MocpList - Aguarde! Extraindo arquivos de mídias..." \
         --infobox "About Player:\n\n`echo "$FRASE_CRED"| sed 's/       //'`\n" 0 0

      # Extração de ficheiros ==========================================
      find -L $MUSICA/ -iname "*.mp3"| sed "s;.*${MUSICA}/;;" > $FICHEIROS
      find -L $MUSICA/ -iname "*.ogg"| sed "s;.*${MUSICA}/;;" >> $FICHEIROS
      find -L $MUSICA/ -iname "*.wav"| sed "s;.*${MUSICA}/;;" >> $FICHEIROS
      find -L $MUSICA/ -iname "*.wma"| sed "s;.*${MUSICA}/;;" >> $FICHEIROS
      find -L $MUSICA/ -iname "*.wmv"| sed "s;.*${MUSICA}/;;" >> $FICHEIROS
      find -L $MUSICA/ -iname "*.aac"| sed "s;.*${MUSICA}/;;" >> $FICHEIROS
      find -L $MUSICA/ -iname "*.ac3"| sed "s;.*${MUSICA}/;;" >> $FICHEIROS
      find -L $MUSICA/ -iname "*.mp4"| sed "s;.*${MUSICA}/;;" >> $FICHEIROS
      find -L $MUSICA/ -iname "*.avi"| sed "s;.*${MUSICA}/;;" >> $FICHEIROS
      find -L $MUSICA/ -iname "*.flv"| sed "s;.*${MUSICA}/;;" >> $FICHEIROS
      find -L $MUSICA/ -iname "*.3gp"| sed "s;.*${MUSICA}/;;" >> $FICHEIROS
      find -L $MUSICA/ -iname "*.flac"| sed "s;.*${MUSICA}/;;" >> $FICHEIROS
      # ================================================================      
      report& 2>>$TMP_LOG
      sort $FICHEIROS > $FICHEIROS.tmp
      mv $FICHEIROS.tmp $FICHEIROS
   fi # cria ou atualiza a lista de mídias

   # aguarda finalização do locutor:
   while [ "`ps au| grep $PID_SPK|wc -l`" -gt 1 ]; do sleep 1 ;done
} # atualiza - Atualiza a lista de arquivos de mídias



function check_mail(){
   dialog --stdout --title "MocpList - Fetchmail" \
   --infobox "Checando ${GMAIL:=email}..." \
   3 60

   fetchmail -c > $CHMAIL.1 2>/dev/null
   local -i RETORNO=$?

   grep -q "INBOX" $CHMAIL.1 2>/dev/null
   if [ "$?" = 0 ]; then
      cp $CHMAIL.1 $CHMAIL
      rm $CHMAIL.1
   fi # atualiza arquivo

   # obtém estado da  inbox
   GMAIL="`cut -d' ' -f6 $CHMAIL`"
   TOT_MAIL="`cut -d' ' -f1 $CHMAIL`"
   local -i VISTO="`cut -d' ' -f3 $CHMAIL|sed 's/[()]//g'`"
   NEW_MAIL=$((${TOT_MAIL:=0} - ${VISTO:=-1}))
   if [ "$RETORNO" -eq 11 ]; then
      let NEW_MAIL=-1*$NEW_MAIL
   fi
   
   if [ "$NEW_MAIL" -gt 0 ] && [ "` mocp -Q "%state"`" != "PLAY" ]  && [ "$TALK" = "on" ]; then
      local S=   # plural
      [ "$NEW_MAIL" -gt 1 ] && S="s"
      espeak  -vpt+f4 "Você tem $NEW_MAIL email$S não lido$S." &>/dev/null
   fi # anuncia número de emails não lidos

   return $RETORNO
} # check_mail - faz checagem de email pelo fetchmail, retorna retorno do fetchmail.



function info_mail(){
      local TEXT=$(printf "Checked at `ls -l $CHMAIL|sed 's/  */ /g'|cut -d' ' -f 6-8|sed -r 's/ [0-9][0-9]:/,&/'`" &2>/dev/null)
      dialog   --stdout --title "MocpList - Fetchmail" \
         --backtitle "Informações da caixa de email ($GMAIL)" \
         --msgbox "INBOX ($GMAIL): ${NEW_MAIL/-/!}/$TOT_MAIL\n$TEXT" \
         6 60
} # info_mail - exibe informações da caixa de entrada.



function restart_player(){
   dialog   --stdout --sleep 5 \
      --backtitle "Reiniciando serviço..." \
      --title "Reiniciando o serviço Moc Player..." \
      --infobox "$(printf "`mocp -S`")" 0 0
} # restart_player - reinicia serviço moc player



function setup(){
   local -i RETORNO=3      # retorno do dialog
   local -i LINHAS=0      # número de entradas
   local VALUES=         # entradas do dialog

   # === Alteração do Arquivo de Configuração - Entradas ==================================================
   while [ "$RETORNO" -eq 3 ]; do
      VALUES=$(dialog --stdout --ok-label "Ok" \
            --extra-button --extra-label "File Setup" \
            --backtitle "Configurações - Alteração de parâmetros" \
            --title "MocpList - Configurações" \
            --form "Modifique os campos abaixos conforme a sua escolha:" \
      0 0 0 \
      "Quantidade de mídias (1-9999):"   1 1 "$MAX_FILA"      1 37 45 4 \
      "Mídias com proximidades (1-99):"   2 1 "$VIZINHOS"      2 37 45 2 \
      "Tamanho de cada seção (1-99):"      3 1 "$SECAO"      3 37 45 2 \
      "Locutor (on/off):"         4 1 "$TALK"      4 37 45 3 \
      "Difusão (on/off):"         5 1 "$DIFUSAO"      5 37 45 3 \
      "Checagem de email (on/off):"      6 1 "$CHK_MAIL"      6 37 45 3 \
      "Comando gerador de texto (difusão):"   7 1 "$COMANDO"      7 37 45 60 \
      "Mensagem principal de difusão:"   8 1 "$MENSAGEM"      8 37 45 60)

      RETORNO="$?"

      if [ "$RETORNO" = 3 ]; then
         dialog   --stdout \
            --title "Configurações ($CONF)" \
            --backtitle "Arquivo de configurações" \
            --textbox $CONF \
         0 0
         VALUES=
      fi # exibe arquivo de configuração

      LINHAS="`printf "$VALUES\n"|wc -l`"

      [ -z "$VALUES" ] &&  LINHAS=0
   done # alteração do arquivo de configuração - entradas =================================================

   # === Filtragem e Armazenamento Dos Valores ============================================================
   if [ "$LINHAS" -gt 0 ]; then
      local -a LABELS=("TAM_FILA" "NEIGHBOR" "NEIGHBORHOOD" "TALKER" "BROADCAST" "MAIL" "COMMAND" "MESSAGE")
      local -a VALORES=("$MAX_FILA" "$VIZINHOS" "$SECAO" "$TALK" "$DIFUSAO" "$CHK_MAIL" "$COMANDO" "$MENSAGEM")
      local -i TAM=$(cat $CONF|wc -l)   # número de linhas do arquivo de configuração
      local -i NUMBER_LINE=0      # posição da linha no arquivo


      local SELECT="`printf "$VALUES\n"|head -1|grep "^[0-9]*$"|sed 's/^00*//'`"   # entrada selecionada
      if [ "${SELECT:=0}" -gt 0 ]; then
         MAX_FILA=$SELECT
         VALORES[0]=$SELECT
      fi # set MAX_FILA

      if [ "$LINHAS" -ge 2 ]; then
         SELECT="`printf "$VALUES\n"|head -2|tail -1|grep "^[0-9]*$"|sed 's/^00*//'`"
         if [ "${SELECT:=0}" -gt 0 ]; then
            VIZINHOS=$SELECT
            VALORES[1]=$SELECT
         fi
      fi # set VIZINHOS

      if [ "$LINHAS" -ge 3 ]; then
         SELECT="`printf "$VALUES\n"|head -3|tail -1|grep "^[0-9]*$"|sed 's/^00*//'`"
         if [ "${SELECT:=0}" -gt 0 ]; then
            [ "$SELECT" -lt "$VIZINHOS" ] && SELECT=$VIZINHOS
            SECAO=$SELECT
            VALORES[2]=$SELECT
         fi
      fi # set SECAO

      if [ "$LINHAS" -ge 4 ]; then
         SELECT="`printf "$VALUES\n"|head -4|tail -1`"
         case "$SELECT" in
            on|ON)
               TALK="on"; VOZ="on"
               VALORES[3]="on";;
            off|OFF)
               TALK="off"; VOZ="off"
               VALORES[3]="off";;
         esac
      fi # set TALK on/off

      if [ "$LINHAS" -ge 5 ]; then
         SELECT="`printf "$VALUES\n"|head -5|tail -1`"
         case "$SELECT" in
            on|ON) 
               DIFUSAO="on"
               VALORES[4]="on";;
            off|OFF)
               DIFUSAO="off"
               VALORES[4]="off";;
         esac
      fi # set DIFUSAO on/off

      if [ "$LINHAS" -ge 6 ]; then
         SELECT="`printf "$VALUES\n"|head -6|tail -1`"
         case "$SELECT" in
            on|OFF) 
               CHK_MAIL="on"
               VALORES[5]="on";;
            off|OFF)
               CHK_MAIL="off"
               VALORES[5]="off";;
         esac
      fi # set CHK_MAIL on/off

      if [ "$LINHAS" -ge 7 ]; then
         SELECT="`printf "$VALUES\n"|head -7|tail -1`"
         type "`echo $SELECT|sed "s; .*$;;"`" &>/dev/null
         if [ "$?" = 0 ]; then
            COMANDO=$SELECT
            VALORES[6]=$SELECT
         else   VALORES[6]=
         fi
      fi # set COMANDO

      if [ "$LINHAS" -eq 8 ]; then
         MENSAGEM="`printf "$VALUES\n"|tail -1`"
         VALORES[7]=""$MENSAGEM""
      else   VALORES[7]=
         MENSAGEM=
      fi # set MENSAGEM

      cp $CONF $CONF.1
      for i in $(seq 0 $((${#LABELS[@]}-1))); do
         NUMBER_LINE=$(cat $CONF.1| grep -n "^${LABELS[$i]}[    ]*=.*"|tail -1|cut -f1 -d: 2>>$TMP_LOG)
         if [ -z "$NUMBER_LINE" ] || [ "$NUMBER_LINE" -eq 0 ]; then
            let TAM++
            NUMBER_LINE=$TAM
         fi # add line

         head -$(($NUMBER_LINE - 1)) $CONF.1 >$CONF.2
         if [ "$i" -eq "$((${#LABELS[@]}-1))" ]; then
            printf "${LABELS[$i]} = \"${VALORES[$i]}\"\n" >>$CONF.2
         else   printf "${LABELS[$i]} = ${VALORES[$i]}\n" >>$CONF.2
         fi # insere aspas (") como separador  de texto em BROADCAST
         tail -$(($TAM - $NUMBER_LINE)) $CONF.1 >>$CONF.2
         mv $CONF.2 $CONF.1
      done # edita o arquivo de configuração

      mv $CONF.1 $CONF
   fi # filtragem e armazenamento dos valores =============================================================

   return $RETORNO
} # setup - permite a reconfiguração de parâmetros de busca, retorna retorno do dialog.



function split_std(){
   local TEXT="`echo "$3"|sed "s;|;\n;g"`\n"
   local STRING=
   local -i TAM=`printf "$TEXT"|wc -l`
   local -i i   
        SELECAO=

        for i in `seq 1 $TAM`; do
      STRING="`printf "$TEXT"|head -${i}|tail -1`"
                SELECAO="$SELECAO|$1.*$STRING.*|$2.*$STRING.*"
        done
        SELECAO="`echo "$SELECAO"|sed "s;^|;;"`"
} # split_std - formata padrões de busca de acordo  com os campos a  serem usados



function change_profile(){
   local -i RETORNO=3      # retorno do dialog
   local -i LINHAS=0      # número de entradas
   local ENTRADA=         # entradas do dialog
   local FRAME_ART_CP="$FRAME_ART"   # cópias de restauração de valores
   local FRAME_TIT_CP="$FRAME_TIT"   # //
   local FRAME_ALB_CP="$FRAME_ALB"   # //
   local FRAME_YER_CP="$FRAME_YER"   # //
   local FRAME_CON_CP="$FRAME_CON"   # //
   local FRAME_ALL_CP="$FRAME_ALL" # //


   while [ "$RETORNO" -eq 3 ]; do # ==========================================================
      ENTRADA=$(dialog --stdout --ok-label "Ok" \
            --extra-button --extra-label "Genre List" \
            --title "$1" \
            --backtitle "MocpList - Busca e Enfileiramento" \
            --form "Forneça expressões que combinem com a busca desejada:" \
            0 0 0 \
            "Artista, Banda:"   1 1 "${FRAME_ART:-${DICA[0]}}"   1 18 50 99 \
            "Título:"      2 1 "${FRAME_TIT:-${DICA[1]}}"   2 18 50 99 \
            "Álbum:"      3 1 "${FRAME_ALB:-${DICA[2]}}"   3 18 50 99 \
            "Ano:"         4 1 "${FRAME_YER:-${DICA[3]}}"   4 18 50 99 \
            "Gênero:"      5 1 "${FRAME_CON:-${DICA[4]}}"   5 18 50 99 \
            "Outros:"      6 1 "${FRAME_ALL:-${DICA[5]}}"   6 18 50 99 \
         )

      RETORNO="$?"

      if [ "$RETORNO" = 3 ]; then
         dialog   --stdout \
            --title "Genres List" \
            --backtitle "MocpList - Lista de códigos dos gêneros músicais" \
            --textbox $GENRE_LIST \
            0 0
         ENTRADA=
      fi

      LINHAS="`printf "$ENTRADA\n"|wc -l`"
      [ -z "$ENTRADA" ] &&  LINHAS=0
   done # alteração das variáveis de casamento de padrão ======================================


   # === Filtragem de entradas ================================================================
   if [ "$LINHAS" -gt 0 ]; then
      # seleção de entrada:
      local SELECT="`printf "$ENTRADA\n"|head -1|sed 's/[    ][    ]*/ /g; s/[    ][    ]*$//'`"
      [ "$SELECT" = "${DICA[0]}" ] && SELECT=""
      FRAME_ART="$SELECT"
      if [ -z "$SELECT" ]; then
         PADRAO[0]=
      else   #PADRAO[0]="Artist: .*$SELECT.* |^TPE.*: .*$SELECT.*$"
         split_std "Artist: " "^TPE.*: " "$SELECT"
         PADRAO[0]="$SELECAO"
      fi # formatação 'artista/banda'

      if [ "$LINHAS" -ge 2 ]; then
         SELECT="`printf "$ENTRADA\n"|head -2|tail -1|sed 's/[    ][    ]*/ /g; s/[    ][    ]*$//'`"
         [ "$SELECT" = "${DICA[1]}" ] && SELECT=""
         if [ -z "$SELECT" ]; then
            PARDAO[1]=
         else   split_std "Title: " "^TIT.*: " "$SELECT"
            PADRAO[1]="$SELECAO"
         fi
         FRAME_TIT="$SELECT"
      else   FRAME_TIT=
      fi # formatação 'título'

      if [ "$LINHAS" -ge 3 ]; then
         SELECT="`printf "$ENTRADA\n"|head -3|tail -1|sed 's/[    ][    ]*/ /g; s/[    ][    ]*$//'`"
         [ "$SELECT" = "${DICA[2]}" ] && SELECT="" && FRAME_ALB=""
         if [ -z "$SELECT" ]; then
            PADRAO[2]=
         else   split_std "Album: " "^TALB.*: " "$SELECT"
            PADRAO[2]="$SELECAO"
         fi
         FRAME_ALB="$SELECT"
      else   FRAME_ALB=
      fi # Formatação 'álbum'

      if [ "$LINHAS" -ge 4 ]; then
         SELECT="`printf "$ENTRADA\n"|head -4|tail -1|sed 's/[    ][    ]*/ /g; s/[    ][    ]*$//'`"
         [ "$SELECT" = "${DICA[3]}" ]  && SELECT=""
         if [ -z "$SELECT" ]; then
            PADRAO[3]=
         else   split_std "Year: " "^TYER.*: " "$SELECT"
            PADRAO[3]="$SELECAO"
         fi
         FRAME_YER="$SELECT"
      else   FRAME_YER=
      fi # Formatação 'ano'

      if [ "$LINHAS" -ge 5 ]; then
         SELECT="`printf "$ENTRADA\n"|head -5|tail -1|sed 's/[    ][    ]*/ /g; s/[    ][    ]*$//'`"
         [ "$SELECT" = "${DICA[4]}" ] && SELECT=""
         if [ -z "$SELECT" ]; then
            PADRAO[4]=
         else   split_std "Genre: " "^TCON.*: " "$SELECT"
            PADRAO[4]="$SELECAO"
         fi
         FRAME_CON="$SELECT"
      else   FRAME_CON=
      fi # Formatação 'gênero'

      if [ "$LINHAS" -eq 6 ]; then
         SELECT="`printf "$ENTRADA\n"|tail -1|sed 's/[    ][    ]*/ /g; s/[    ][    ]*$//'`"
         [ "$SELECT" = "${DICA[5]}" ]  && SELECT=""
         if [ -z "$SELECT" ]; then
            PADRAO[5]=
         else   PADRAO[5]="`echo $SELECT|sed 's/^|//g; s/|$//g'`"
         fi
         FRAME_ALL="$SELECT"
      else   FRAME_ALL=
      fi # Formatação 'outros'
   else      FRAME_ART="$FRAME_ART_CP"
         FRAME_TIT="$FRAME_TIT_CP"
         FRAME_ALB="$FRAME_ALB_CP"
         FRAME_YER="$FRAME_YER_CP"
         FRAME_CON="$FRAME_CON_CP"
         FRAME_ALL="$FRAME_ALL_CP"
   fi # filtragem de entradas =================================================================

   return $RETORNO
} # change_profile - permite alterar o perfil do padrão de busca, retorna retorno do dialog.



function set_voice(){
   local TEXT="$1"            # texto a ser analisado
   local -i TAM=`cat $WORDS_ES|wc -l`   # tamanho do arquivo com expressões em alguma língua
   local -i SUM_ES=0         # quantidade de expressões em espanhol encontrada
   local -i SUM_EN=0         # quantidade de expressões em inglês encontrada
          local -i x=0            # aux. de iteração
   local WORD=            # expressão regular de um idioma

   [ -z "$TEXT" ] && return 0

   for x in $(seq 1 $TAM); do
      WORD="`head -$x $WORDS_ES|tail -1`"
      echo "$TEXT"|grep -qiE  "$WORD" && let SUM_ES++
   done # conta ocorrência de expressões em espanhol

   TAM=`cat $WORDS_EN|wc -l`; SUM_EN=0
   for x in $(seq 1 $TAM); do
      WORD="`head -$x $WORDS_EN|tail -1`"
      echo "$TEXT"|grep -qiE  "^$WORD" && let SUM_EN++
   done # conta ocorrência de expressões em inglês

   # ingles=$SUM_EN; espanhol=$SUM_ES ### depurando...

   if [ "$(($SUM_ES + $SUM_EN))" -gt 0 ]; then
      if [ "$SUM_EN" -gt "$SUM_ES" ]; then
         return 2
      else   return 3
      fi
   else   return 1
   fi # elege um dos idiomas ou mantém o default
} # set_voice - elege idioma do locutor



function get_data_and_spk(){
   mocp -i > $DATA_MEDIA 2>/dev/null
   if [ "$?" -eq 0 ]; then
      TRACK="`grep "^File:" $DATA_MEDIA|sed 's/File: *//'`"   # TRACK on play
   else   restart_player
      return 0
   fi # set data or restart moc

   # === Atualiza Tags e Anúncia e Elege Idioma ===============================================================
   if [ "$TRACK1" != "$TRACK" ]; then
      # === Elege Idioma para o Locutor ==================================================================
      if [ "$TALK" = "on" ]; then
         set_voice "$TRACK"
         case "$?" in
            1)   VOZ="pt";;
            2)   VOZ="en-us";;
            3)   VOZ="es-la";;
            *)   VOZ="on";;
         esac
      fi # elege idioma ==================================================================================

      id3v2 -l "${TRACK:=}" 2>>$TMP_LOG|sed '/^PRIV.*:/d'|grep -v "^COMM.*:.*[0-9A-F]\{8,\}" >$DATA_ID3

      ARTIST="`grep "^TPE1.*: " $DATA_ID3|sed "s/^TPE1.*: *//"`"
      SONG_TITLE="`grep "^TIT2.*: " $DATA_ID3|sed "s/^TIT2.*: *//"`"
      YEAR="`grep "^TYER.*: " $DATA_ID3|sed "s/^TYER.*: *//"`"
      ALBUM="`grep "^TALB.*: " $DATA_ID3|sed "s/^TALB.*: *//"`"
      GENRE="`grep "^TCON.*: " $DATA_ID3|sed "s/^TCON.*: *//"`"

      ARTIST="${ARTIST:=$(grep "^Artist:" $DATA_MEDIA|sed 's/^Artist: *//')}"
      SONG_TITLE="${SONG_TITLE:=$(grep "^SongTitle:" $DATA_MEDIA|sed 's/^SongTitle: *//')}"
      ALBUM="${ALBUM:=$(grep "^Album:" $DATA_MEDIA|sed 's/^Album: *//')}"
      YEAR="${YEAR:=$(grep "^.*Year: *" $DATA_ID3|sed "s/^.*Year: *//"|sed "s/,.*$//")}"
      GENRE="${GENRE:=$(grep "^.*Genre: *" $DATA_ID3|sed "s/^.*Genre: *//"|sed "s/[    ]*$//g")}"

      TITLE="$ARTIST - $SONG_TITLE"
      echo $TITLE|grep -qE "[[:alnum:]]" || TITLE="`echo $TRACK|sed 's;^/.*/[ 0-9]*;;'| \
      sed 's/[MmOoFfAa][PpGgLlVv][34GgVvIi]$//'`" # título alternativo

      TRACK1="$TRACK"
   fi # atualiza tags e elege idioma  =========================================================================


   local -i TIME_LEFT="$(grep TimeLeft: $DATA_MEDIA| sed 's/^.* //; s/00*:00/0:01/; s/://; s/^.0//; s/^00*//')"
   # Configura Locutor ========================================================================================
   if  [ "$TIME_LEFT" -gt 3 ] && [ "$TIME_LEFT" -lt 7 ]; then
      # Executa o Locutor ================================================================================
      if [ "$TALK" = "on" ]; then
         local CITE=   # citação do player (mudo por default)
         local -i RND=$RANDOM
         killall -9 espeak &>/dev/null
         if [ $(($RND % 100)) -le 50 ];then
            if [ "$VOZ" = "en-us" ]; then
               CITE="$FRASE_EN"
            else   CITE="$FRASE_PT"
            fi # seleção de pronúncia
         fi # escolhe se anúncia créditos moc

         espeak -p0 -v$VOZ+m1 "$CITE$TITLE..." &>/dev/null

         if [ "$(($RANDOM % 100))" -gt "$PROB" ]; then
            if [ "$DIFUSAO" = "on" ]; then
               local -i PAUSADO=0
               mocp -i|grep -q "State: PLAY" && mocp -P && PAUSADO=1
               if [ "$(($RANDOM % 100))" -gt 80 ]; then
                  local VOICE=
                  TEXTO="`command $COMANDO`"
                  set_voice "$TEXTO"
                  case "$?" in
                  1)   VOICE="pt";;
                  2)   VOICE="en-us";;
                  3)   VOICE="es-la";;
                  *)   VOICE="pt";;
                  esac
                  echo "$TEXTO"|espeak -v${VOICE}+m4 &>/dev/null
               else   espeak -vpt+f4 "$MENSAGEM" &>/dev/null
               fi # escolhe aleatóriamente a frase de difusão
               [ "$PAUSADO" -eq 1 ] && mocp -U
            fi # difusão de mensagens
         else   CITE="`date "+%H horas, %M minutos"|sed 's/^0//'|sed -r 's/(.*, )0(.*)/\1\2/'`"
            espeak  -vpt+f4 "$HOSTNAME: $CITE" &>/dev/null
            if [ "$NEW_MAIL" -gt 0 ]; then
               local S=   # plural
               [ "$NEW_MAIL" -gt 1 ] && S="s"
               espeak  -vpt+m4 "Você tem $NEW_MAIL email$S não lido$S." &>/dev/null
            fi # anuncia número de emails não lidos
         fi # elege anúncio de horas, ou difusão/citação
      fi # TALK TRACK in playing =========================================================================
   fi # configura saída de voz sintetizada ====================================================================

   if [ "$TRACK0" != "$TRACK" ]; then
      TRACK0=$TRACK
      return 0
   else   return 1
   fi # verifica troca da mídia em execução
} # get_data_and_spk - obtém dados da mídia em reprodução e anuncia titulo em voz sintetizada



function enfileirar(){
   local -i PERCENTUAL=$2               # limitador da partição (com uma casa decimal)
   local -i TT_VAR=`cat $TT_VARRIDOS`         # total acumulado de ficheiros pesquisados
   local -i TT_INDEX="`cat $INDEX 2>>$TMP_LOG|wc -l`"   # total de índices a serem pesquisados
   local -i PONTEIRO=0         # ponteiro inicial do segmento
   local -i LINE_SELECT=0         # índice contido no segmento
   local -i PROXIMO=0         # contador de vizinhos enfileirados
   local -i CONTADOR=0         # ponteiro do segmento em varrimento
   local -i VARRIDOS=0         # contador de índices pesquisados da partição
   local -i PERC_BUSCA=0         # estado da busca e limitador de partição
   local MEDIA_SELECTED=         # mídia selecionada
   local ID3=            # armazena dados id3v2 


   if [ "$1" != "no" ]; then
      local -i TT_FILA=0            # reinicia &#324;umero de enfileirados
   else
      local -i TT_FILA=$(cat $TOT_FILA)      # restaura número de enfileirados
   fi # número de enfileirados

   printf "" > $CHECKEDS               # limpa lista auxiliar

   # === V A R R E D U R A   D A   P A R T I Ç A O ============================================================================
   while [ "$PERC_BUSCA" -le "$PERCENTUAL" ] && [ "$VARRIDOS" -lt "$TT_INDEX" ]; do
      PONTEIRO=$((1 + (($RANDOM + `date +%N|sed -e 's/^00*//g'`) % $TT_INDEX)))   # ponteiro randomizado
      PROXIMO=0; CONTADOR=0

      # === V A R R E D U R A   D O   S E G M E N T O ====================================================================
      while [ "$CONTADOR" -lt "$SECAO" ] && [ "$PONTEIRO" -le "$TT_INDEX" ]; do
         [ "`cat $SINAL`" -eq 0 ] && return 2 # interrupção por sinal
         LINE_SELECT="`head -$PONTEIRO $INDEX|tail -1`"   # seleciona índice a pesquisar

         # === C H E C A G E M   D E   I N D I C E S ================================================================
         grep -q "^$LINE_SELECT$" $CHECKEDS   # checa se índice já foi  pesquisado
         if [ "$?" -ne 0 ]; then
            MEDIA_SELECTED="`head -$LINE_SELECT $FICHEIROS|tail -1`" # seleciona mídia apontada pelo índice
            ID3="`id3v2 -l "$MUSICA/$MEDIA_SELECTED"|grep -E "$FILTRO"`" # obtém tags id3 da mídia

            # === V E R I F I C A   C A S A M E N T O   D E   P A D R O E S ====================================
            echo "$ID3"|grep -qiE "${PADRAO[0]}"
            if [ "$?" -eq 0 ] || [ "${PADRAO[0]}" = "" ]; then
               echo "$ID3"|grep -qiE "${PADRAO[1]}"
               if [ "$?" -eq 0 ] || [ "${PADRAO[1]}" = "" ]; then
                  echo "$ID3"|grep -qiE "${PADRAO[2]}"
                  if [ "$?" -eq 0 ] || [ "${PADRAO[2]}" = "" ]; then
                     echo "$ID3"|grep -qiE "${PADRAO[3]}"
                     if [ "$?" -eq 0 ] || [ "${PADRAO[3]}" = "" ]; then
                        echo "$ID3"|grep -qiE "${PADRAO[4]}"
                        if [ "$?" -eq 0 ] || [ "${PADRAO[4]}" = "" ]; then
                           echo "$ID3"|grep -qiE "${PADRAO[5]}"
                           if [ "$?" -eq 0 ] || [ "${PADRAO[5]}" = "" ]; then

                              # === E N F I L E I R A   D E   M I D I A ==========
                              if [ "$TT_FILA" -lt "$MAX_FILA" ]; then
                                 mocp -a "$MUSICA/$MEDIA_SELECTED" || restart_player &>/dev/null
                                 if [ "`mocp -Q %state  2>/dev/null`" = "STOP" ]; then
                                    [ "$TALK" = "on" ] && espeak -p0 -vpt+f4 "Reproduzindo..." &>/dev/null
                                    mocp -p 2>/dev/null
                                    sleep .5
                                 fi # inicia a reprodução
                                 let TT_FILA++; let PROXIMO++
                                 echo $TT_FILA > $TOT_FILA
                                 [ "$PROXIMO" -ge "$VIZINHOS" ] && CONTADOR=$SECAO
                              else return 1   # conclusão do enfileiramento
                              fi # enfileiramento de mídia =======================

                           fi # other
                        fi # genre
                     fi # year
                  fi # album
               fi # title
            fi # artist/band ===================================================================================

            echo "$LINE_SELECT" >> $CHECKEDS
         fi # checagem ==============================================================================================

         let PONTEIRO++ # move ponteiro do segmento
         let CONTADOR++
      done # varredura do seguimento =====================================================================================

      VARRIDOS="`cat $CHECKEDS|wc -l`" || exit 1
      PERC_BUSCA=$((($VARRIDOS + $TT_VAR)*1000/$TT_FICHEIROS))
      echo $PERC_BUSCA >$PERC_OUT   # (exibido na tela principal)
   done # varredura da partição ===============================================================================================
   echo "$(($TT_VAR + $VARRIDOS))" > $TT_VARRIDOS   # variável restaurável

   test "`cat $TT_VARRIDOS`" -lt "$TT_FICHEIROS"
   return $? # retorna 1 se concluído, 2 se interrompido e 0 se não concluído
} # enfileira - pesquisa na partição em construção e enfileira mídias



function auto_enqueueur(){
   if [ "$AUTO" != "auto" ];then
      estado_sub_pid
      change_profile "AUTO ENFILEIRAR $MAX_FILA mídias ao 'playlist'..."
      if [ "$?" -eq 0 ]; then
         AUTO="auto"
      else   AUTO="no-auto"
      fi # ativa o modo auto se confirmado
   else   AUTO="no-auto"
   fi # alterna modo automático
} # auto_enqueueur - toggle auto/no-auto



function hash_list(){
   local LIMPAR="$1"         # limpar fila (yes/no)
   seq 1 $TT_FICHEIROS > $INDEX || exit 1   # lista de índices a serem varridos
   local -ai PARTICAO=(`seq 50 50 950` 999 1000) # limitadores de partições (percentuais com uma casa decimal)
   local -i LEN=${#PARTICAO[@]}      # número de partições (20 + 1 partições)
   local -i i=0            # variável de incremento
   echo 0 > $TT_VARRIDOS         # total geral de índices pesquisados
   echo 0 > $PERC_OUT         # percentual da varrredura
   echo 1 > $SINAL            # flag de interrupção de busca e enfileiramento
   echo 0 > $TOT_FILA         # número de enfileirados


   if [ "$TALK" = "on" ]; then
      espeak -p0 -vpt+f4 "$HOSTNAME: Enfileirando $MAX_FILA mídias.: "   &>/dev/null
      test -n "$FRAME_ART" && espeak -p0 -vpt+f4 "Artista: $FRAME_ART"   &>/dev/null
      test -n "$FRAME_TIT" &&   espeak -p0 -vpt+f4 "Título: $FRAME_TIT"      &>/dev/null
      test -n "$FRAME_ALB" &&   espeak -p0 -vpt+f4 "Álbum: $FRAME_ALB"      &>/dev/null
      test -n "$FRAME_YER" &&   espeak -p0 -vpt+f4 "Ano: $FRAME_YER"      &>/dev/null
      test -n "$FRAME_CON" &&   espeak -p0 -vpt+f4 "Gênero: $FRAME_CON"      &>/dev/null
      test -n "$FRAME_ALL" &&   espeak -p0 -vpt+f4 "Outros: $FRAME_ALL"      &>/dev/null
   fi # anuncia enfileiramento

   for ((i;i<$LEN;i++)); do
      # === BEFORE =============================================================
      [ "$i" -gt 0 ] && LIMPAR="no" # mantém playlist após primeira iteração

      # === ENFILEIRA  enfileirar <yes|no|auto> <partição> =====================
      enfileirar "$LIMPAR" ${PARTICAO[$i]}

      # === AFTER ==============================================================
      if [ "$?" -eq 0 ]; then
         sed 's/^/\^/' $CHECKEDS|sed 's/$/\$/' > $CHECKEDS.1
         grep -vf $CHECKEDS.1 $INDEX > $INDEX.1
         mv $INDEX.1 $INDEX
      else break # termina se concluído ou interrompido por sinal
      fi # elimina partição pesquisada do vetor de índices
   done # pesquisa em cada partição construída em tempo de busca e enfileiramento
   echo -1 > $SUB_PID
   [ "$TALK" = "on" ] && espeak -p0 -vpt+f4  "Busca encerrada." &>/dev/null
} # hash_list - faz o particionamento dos índices e enfileira mídias casadas



function set_list(){
# Parâmetros:
#   1) limpar? <yes|no|auto>
#   2) frase do dialog
   local -i RET=1   # retorno

   TT_FICHEIROS="`cat $FICHEIROS|wc -l`"

   if [ "$1" = "auto" ]; then
      [ "`cat $SUB_PID`" -le 0 ] && RET=0
   else   estado_sub_pid && change_profile "$2" && RET=0
   fi # permite interromper e reiniciar o enfileiramento
   
   if [ "$RET" -eq 0 ]; then
      if [ "$1" != "no" ]; then
         mocp -s &>/dev/null
         mocp -c   &>/dev/null
      fi # interrompe e limpa playlist
      hash_list $1& 2>>$TMP_LOG
      echo $! > $SUB_PID
   fi # enfileira
} # set_list - permite reconfiguração da forma de busca e enfileira arquivos



function estado_sub_pid(){
   local -i RET=0
   if [ "`cat $SUB_PID`" -gt 0 ]; then
      dialog   --stdout \
         --title "Atenção!" --defaultno \
         --yesno "Existi um processo de enfileiramento aberto. A conclusão do mesmo pode demorar alguns minutos. \
         \n\nVocê deseja terminá-lo?" \
         12 60
      if [ "$?" -eq 0 ]; then
         dialog --stdout \
         --title "MocpList: Encerrando busca..." \
         --infobox "\nAguarde! Encerrando procedimento..." \
         7 40
         echo "0" > $SINAL
         local -i DEAD="`cat $SUB_PID`"
         while [ "${DEAD:=0}" -gt 0 ]; do sleep 1; DEAD="`cat $SUB_PID`" ;done
      else   RET=1
      fi # modifica sinal e  aguarda encerramento
   fi # verifica se procedimento está em execução
   return $RET
} # estado_sub_pid - verifica e permite encerrar processo de busca em execução



function display_info(){
   # parâmetro 1: refresh
   get_data_and_spk 2>> $TMP_LOG

   if [ "$?" -eq 0 ] || [ "$1" -eq 0 ]; then
      local STATUS="ocioso"

      local FILE="`echo $TRACK|sed 's;.*/M[úu]sica/;../;'`"

      [ "`cat $SUB_PID`" -gt 0 ] && STATUS="`cat $PERC_OUT`% concluído."
      if [ -z "$TITLE" ]; then
         MODO="Waiting"
         TEXTO="Aguardando"
      else   MODO="Playing -"
         TEXTO="Reproduzindo $TITLE"
      fi # textos da sobre  o estado do tocador
      # TEXTO="[$espanhol|$ingles] $TEXTO" ### depurando...
      TEXTO="$TEXTO...\n\nArtista: ${ARTIST}\nTítulo:  ${SONG_TITLE}\nÁlbum:   ${ALBUM}\nAno:     ${YEAR}"
      TEXTO="$TEXTO\nGênero:  ${GENRE}\nArquivo: ${FILE:=}"
      TEXTO="$TEXTO\n\nEstado da pesquisa: $(echo $STATUS|sed -r "s/(.*)(.\%).*/\1,\2/"|sed "s/^,/0,/")\nEnfileiramento:     `cat $TOT_FILA`/$MAX_FILA"
      TEXTO="$TEXTO\nPalavras chaves:    {`echo "(${FRAME_ART:-${DICA[0]}}) & (${FRAME_TIT:-${DICA[1]}}) & (${FRAME_ALB:-${DICA[2]}}) & (${FRAME_YER:-${DICA[3]}}) & (${FRAME_CON:-${DICA[4]}}) & (${FRAME_ALL:-${DICA[5]}})"`}"

      dialog   --stdout --no-collapse --trim --tab-correct \
         --backtitle " .::: <s>et :: <l>ist :: <i>nfo :: <b>ack :: <n>ext :: <p>ause :: <h>elp :: <q>uit :::" \
         --title "MocpList - Talk

Scripts recomendados

KSH-93 orientado a objetos... SQN :P

cdmp3.sh

firewall

Monitoramento da bateria

Agenda de telefone em Shell usando Dialog


  

Comentários
[1] Comentário enviado por aleniac em 26/06/2018 - 18:06h

;) Mais detalhes ou atualizações podem ser obtidas em:
https://drive.google.com/drive/folders/1aTy4uEaCt5GVof9-P3HJEmX9tVv4t7gE

Khayla Elias dos Santos


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner
Linux banner
Linux banner

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts