He estado un poco ocioso y me puse a trabajar en un script en bash para crear las listas de reproducción para mi mp4, un iriver E100. Me puse picar código, pues a pesar de que encontré algunas soluciones la verdad nada supera a la herramienta que uno mismo construyó.
Una pequeña introducción. Los reproductores iriver usan un extraño formato (.PLA) para sus listas de reproducción, que hasta lo que tengo entendido solo la usan ellos. El script toma una lista de reproducción en formato m3u y la procesa para convertirla en una lista .pla
Sin más palabras, el script:
#! /bin/bash
################################################################################
# Este script transforma una lista de música de formato m3u a pla. El formato #
# pla es usado exclusivamente (hasta lo que yo sé) por los reproductores #
# portátiles fabricados por iRiver. Por esta razón el script filtrará los #
# tracks, incluyendo en el archivo de salida solo los que se encuentran en el #
# dispositivo. Además, la lista pla se guardará siempre en el directorio #
# ${iriver_mount_dir}/${Plist_Dir}. Por defecto ${Plist_Dir}="Playlist" que es #
# donde el iRiver e100 busca los playlists. Si tu reproductor ocupa otra ruta #
# cambia el valor de ${Plist_Dir} al correcto. #
# #
# Diseñado para crear listas de música para mi iRiver E100. He de suponer que #
# servirá en otros... #
# #
# Licencia: GPLv2 #
# Autor: Marcelo (sd0625) Vergara #
# e-mail: sd0625@gmail.com #
# última modificación: lun 8 feb 2010 #
################################################################################
Plist_Dir="Playlists"
Version="0.9"
################################################################################
# Verifica las opciones auxiliares, y efectúa las acciones correspondientes
while getopts ":Vho:fv" opt; do
case $opt in
V) #--> Version
#${0##*/} muestra el nombre del script eliminando la ruta a éste
echo "${0##*/} Versión $Version: El convertidor de listas de música para los"\
"reproductores iRiver."
exit 0
;;
h ) #--> Ayuda
echo -e "modo de uso: ${0##*/} [-Vhvf] [-o file] m3u_list iRiver_mount_point"\
"\n\n${0##*/} convierte listas de reproducción m3u al formato pla usado en los"\
"reproductores iRiver.\n\nOpciones:\n\n\t-V\tMuestra la versión del script y"\
"termina.\n\t-h\tMuestra esta ayuda y termina.\n\t-v\tMuestra información"\
"mientras se ejecuta.\n\t-o file\tNombre del archivo de salida. Si no se"\
"especifica se ocupa el nombre del archivo de entrada como patrón.\n\t-f\tSe"\
"sobreescribe el archivo de salida.\n\nObservaciones:\n\n\t- El script supone que"\
"ruta_reproductor es efectivamente donde está montado el dispositivo. La única"\
"revisión es verificar que en ese directorio está montado un disco vfat.\n\t- El"\
"script no agrega a la lista aquellos tracks que no se encuentren en el"\
"reproductor.\n\t- La lista se escribirá en la carpeta $Plist_Dir del Reproductor."\
"Si el tuyo ocupa otra, edita el valor de $Plist_Dir en el script\n\nBugs y"\
"mejoras reportarlas a sd0625@gmail.com."
exit 0
;;
o ) #--> Nombre del archivo de salida. Si se omite, se ocupa el nombre del archivo de
#--> entrada cambiando la extensión a .pla. Error si se ingresa más de uno o una ruta
#--> a éste
if [[ -n $pla_list ]]; then
echo "ERROR: ingresaste más de un archivo de salida." >&2
exit 1
fi
pla_list=$OPTARG
if [[ $pla_list != ${pla_list##*/} ]]; then
echo "ERROR: Debes ingresar solo el nombre del archivo."\
"de salida; éste se guarda automáticamente en el"\
"directorio $Plist_Dir de tu reproductor" >&2
exit 1
fi
# Si $pla_list no termina en .pla se le añade
ext=${pla_list##*.}
[[ ${#ext} != 3 || `expr $ext : [pP][lL][aA]` != 3 ]] && pla_list=$pla_list.pla
;;
f) #--> Sobreescribir el archivo si existe
force=" "
;;
v) #--> mostrar información
verbose=" "
;;
:) #--> falta argumento para -o
echo -e "Error\n-o: No indicaste archivo de salida." >&2
exit 1
;;
?) #--> Opción desconocida
echo -e "ERROR:\nOpción -$OPTARG desconocida. Consulta $0"\
"-h para ver la ayuda" >&2
exit 1
;;
esac
done
shift $(($OPTIND- 1))
# fin procesamiento de opciones
################################################################################
################################################################################
# procesamiento y verficación de argumentos
m3u_list=$1
iRiver_mount_point=$2
if [[ $# != 2 ]]; then
echo -e "ERROR:\nNo indicaste correctamente el archivo de entrada y el"\
"directorio de montaje del reproductor." >&2
exit 1
fi
if ! [[ -f "$m3u_list" && -d "$iRiver_mount_point" ]]; then
echo -e "ERROR:\n\"$m3u_list\" no es un fichero y/o \"$iRiver_mount_point\" no"\
"es un directorio." >&2
exit 1;
fi
ext=${m3u_list##*.}
if [[ ${#ext} != 3 || $(expr $ext : [mM]3[uU]) != 3 ]]; then
echo -e "ERROR:\n\"$m3u_list\" no es una lista de reproducción m3u." >&2
exit 1;
fi
# usado para transformar una ruta relativa a una absoluta sin / al final
cd "$iRiver_mount_point"
iRiver_mount_point="$PWD"
cd "$OLDPWD"
mount -t vfat | grep -q " $iRiver_mount_point "
if [[ $? != 0 ]]; then
echo -e "ERROR:\n\"$iRiver_mount_point\" no es un punto de montaje de un disco vfat." >&2
exit 1
fi
# fin argumentos
####################################################################################################
####################################################################################################
# comienzo del procesamiento
if [[ -z "$pla_list" ]]; then # si no se especificó archivo de salida
pla_list=${m3u_list##*/}
pla_list=${pla_list%.*}.pla
fi
pla_list="$iRiver_mount_point/$Plist_Dir/$pla_list"
m3u_list_dir="${m3u_list%/*}"
[[ "$m3u_list" == "$m3u_list_dir" ]] && m3u_list_dir=.
cd "$m3u_list_dir"
m3u_list_dir=$PWD
cd "$OLDPWD"
if [[ -f "$pla_list" && -z $force ]]; then
echo -e "ERROR:\nYa existe un archivo llamado \"$pla_list\". Usa -f para sobreescribirlo." >&2
exit 1
fi
( : > "$pla_list" ) 2> /dev/null
if [[ $? != 0 ]]; then
echo -e "ERROR:\nNo se pudo crear el archivo \"$pla_list\"." >&2
exit 1;
fi
#filtra la lista m3u quedándose solo con la ruta de los tracks y eliminando lo demás
tracks=$(grep -E "^/|^.[./]" "$m3u_list")
IFS=$'\x0d\x0a'
tmp_file_head=$(mktemp -p /tmp iriverlist.XXXXXX)
tmp_file_body=$(mktemp -p /tmp iriverlist.XXXXXX)
declare -i j=0 track_ok=0 intaux=0 offset_mount=${#iRiver_mount_point}
(( offset_mount-- ))
for i in $tracks; do
cd "$m3u_list_dir" # util solo para determinar si la pista está en el reproductor
# en listas con rutas relativas
if ! [[ -f "$i" ]]; then
[[ -n $verbose ]] && echo "\"$i\" no existe" >&2
continue
fi
cd "${i%/*}"
track_path="$PWD/"
if [[ $track_path == ${track_path#$iRiver_mount_point/} ]]; then
[[ -n $verbose ]] && echo -e "\"$i\" no está en el reproductor." >&2
continue
fi
win_path=${track_path#$iRiver_mount_point}${i##*/}
# cambia los separadores de directorio usados en Unix (/) por los de Windows (\)
win_path=${win_path//\//\\}
#convierte desde la codificación UTF-8 a latin1 para nombres de archivo con letras acentuadas, eñes, etc
win_path=$( echo $win_path | iconv --from UTF-8 --to ISO_8859-1 )
j=1
#por la estructura de los archivos *.pla, parece que no soportan rutas de mas de 255 caracteres.
#PD: las rutas siempre son relativas al directorio raiz del reproductor
if (( ${#win_path} > 255 )); then
[[ -n $verbose ]] && echo "\"$win_path\" tiene más de 255 carácteres." >&2
continue
fi
offset=${#track_path}
(( offset=offset-offset_mount ))
printf -v offset "%02x" $offset
printf "%b%b" "\x00" "\x$offset" >> "$tmp_file_body"
#en cada ciclo añade al final del archivo $tmp_file_body un byte 0x00 y la primera letra de la
#variable $win_path para luego eliminarla de la cadena
while [[ -n $win_path ]]; do
printf "%b%c" '\x00' $win_path >> "$tmp_file_body"
win_path=${win_path:1}
((j++))
done
while (( $j < 256 )); do
printf "%b%b" '\x00' '\x00' >> "$tmp_file_body"
((j++))
done
((track_ok++))
done
if (( track_ok == 0 )); then
echo "No se encontraron tracks validos..." >&2
rm "$tmp_file_head" "$tmp_file_body" "$pla_list"
exit 1
fi
#mask se usa para convertir el número $track_ok en su representacion binaria de bytes little endian
declare -i mask=16777216
j=0;
while (( j < 4 )); do
((intaux = track_ok / mask))
((track_ok = track_ok % mask))
((mask = mask / 256))
printf -v aux "%02X" $intaux
printf "%b" "\x$aux" >> "$tmp_file_head"
((j++))
done
echo "iriver UMS PLA" >> "$tmp_file_head"
j=19
while (( $j < 512 )); do
printf "%b" '\x00' >> "$tmp_file_head"
((j++))
done
cat "$tmp_file_head" "$tmp_file_body" > "$pla_list"
rm "$tmp_file_head" "$tmp_file_body"
exit 0
El script trabaja de la siguiente manera:
irivelist [-vVhf] [-o output_file] mi_lista.m3u punto_de_montaje_reproductordonde:
- -V
- -v
- -h
- -f
- -o file
- mi_lista.m3u
- punto de montaje_reproductor
muestra la versión y termina
muestra los mensajes de error
muestra la ayuda y termina
fuerza la sobreescritura del fichero de salida
indica el nombre del fichero de salida. Es necesario solo el nombre, pues el script guardará la lista en la carpeta Playlists del reproductor. Si no se indica, el nombre del archivo de salida será el mismo que el de entrada, cambiando solo la extensión a .pla
la lista de entrada la cual se convertirá a PLA. Puede tener tanto listas con rutas relativas (que empiezen con ./) o absolutas (empiezan con /)
es el directorio donde está montado el reproductor.
Como ya se mencionó antes, como la el formato parece ser usado exclusivamete por iriver .Inc, el script se encargará de verificar si cada track se encuentra efectivamente en el reproductor. También se encarga de guardar las listas de salida en el directorio usado por el reproductor para este fin.
Traté de que el script verificará automáticamente si había un reproductor iriver y donde estaba montado. Lo primero lo pude hacer usando lsusb -d 4102: (4102 es el ID de la compañía que manufactura los reproductores), pero no encontré la manera de saber en qué carpeta está montado, y si es que está montado. Es por eso que me vi en la obligación de que se le indique al script la carpeta donde se monta el dispositivo. Si alguien sabe como hacer esto último que me ayude...
Cualquier duda, ayuda o lo que sea relevante en la mejora del iriverlist es bienvenida
EDITO: para quien lo necesite, solo tiene que hacer un copy-paste del script y guardarlo como iriverlist (o como se les de la gana). Despues tienen que darle permisos de ejecución, moverlo a alguna de las carpetas de $PATH para llamarlo como cualquier comando (yo me creee mi ~/.bin para esos casos) y listo

Buen script!
para mirar en que directorio está montado talvez puedes hacerlo con el archivo /etc/mtab.
el problema es que no me sé el dispositivo, recuerda que es plug & play. Además a mi reproductor se le puede agregar una tarjeta microSD, aunque no esté instalada, el SO detecta tanto la memoria interna (gralmnete /dev/sdb) y la externa (generlamente /dev/sdc)... igual vamos a chequear
se me ocurre una posibilidad. Lanzar el script antes de conectarlo. El script lee el mtab, pide que conectes el dispositivo, vuelve a leer el mtab y compara. Si compruebas que siempre conecta antes la memoria interna que la sd (por ejemplo) supongo que las dos ultimas lineas en orden serán los puntos de montaje para cada cosa.
No sé... como no tengo ningún aparatito de esos no puedo comprobarlo ahora.
Otra opción, podría ser ponerle una etiqueta (label) a las particiones del dispositivo.
Por ejemplo DISPOSITIVO para la memoria interna y SD para la externa. Siendo así, el sistema montará siempre en /media/DISPOSITIVO y en /media/SD.
Al menos mis usb los tengo con etiquetas y siempre los montan en esos puntos de montaje.
se me olvidaba decirte... el script solo ve los tracks en la memoria interna... la externa no la he probado porque no he deshuesado listas que contengan tracks en la otra memoria, asi que no se como funciona en ese caso. ademas lo estoy tratando de hacer lo mas portable que pueda ... supongo que para mi uso personal lo modificaré un poco para que si no le indico la ruta, use por defecto /media/e100.. no se me habia ocurrido... gracias