Un pequeño script para tener un Jukebox de Modarchive.org

shell

Como algunos que me conocen saben, soy seguidor de la scene desde hace muchísimos años. Quizá últimamente no tengo tiempo de estar al día, pero me sigue gustando escuchar la música que sale de ese mundillo. Para los que lo conocen, el sitio http://modarchive.org es un buen punto donde descargar “mods” de todas las épocas.

Tengo una buena colección de mods pero está un poco gastada de tanto escucharla, así que ante la inmensidad de modarchive, busqué la manera de reproducir los archivos de esa página de una forma continua sin tener que descargarlos uno por uno, por eso me puse manos a la obra para hacer un script que hiciese el trabajo sucio por mi.

Al principio era algo muy sencillo pero poco a poco ha ido creciendo y ahora creo que ya puedo enseñarlo. No esperéis nada espectacular, ya que está hecho en bash usando las herramientas de procesamiento sed, grep, cut, etc.

Para reproducir los ficheros utilizo el programa de consola “mikmod” para que todo quede ahí, en la consola, pero cualquiera es libre de modificar el script para lo haga con lo que mas le guste.

Actualización:
Para reproducir los archivos uso audacious, que permite encolarlos conforme son descargados. El único requisito es tener el programa iniciado antes de lanzar el script.

¿Cómo se usa el script?

Si atendemos a la ayuda incluida es bastante sencillo:

usage: ./modarchive.sh [options]
 
Modarchive Jukebox can be used with one of the following options:
   -h : Show this help message
 
   -s <section> Play from selected section: Can be one of this 
          uploads     This is a list of the recent member upload activity
          featured    These modules have been nominated by the crew for either outstanding quality, technique or creativity (or combination of).
          favourites  These modules have been nominated by the members via their favourites. 
          downloads   The top 1000 most downloaded modules, recorded since circa 2002. 
          topscore    This chart lists the most revered modules on the archive.
          new         Same than uploads but using search engine
          random      Ramdom module from entire archive
   -a <artist>  Search in artist database
   -m <module>  Search in module database (Title and Filename)
 
   -n <number>  Number of tracks to play
   -r           Shuffle playlist
 
Hint: Use + symbol instead blankspaces in search strings.

El script necesita que le digamos de qué sección descargar, una vez seleccionada descargará un fichero y los encolará en audacious. El script se ejecutará hasta recuperar todos los elementos de la búsqueda o hasta llegar al número de ficheros especificado con la opción -n. Si se escoge la seción “random” y no se especifica un número de ficheros el programa se ejecutará indefinidamente, o bien hasta que pulsemos Ctrl-C o se nos llene el disco duro Eye-wink

Y por fin el script. Gracias a David que me ha dado un espacio en el repositorio subversion público de Arco. Lo puedes descargar de aquí

https://arco.esi.uclm.es/svn/public/prj/modarchive/modarchive.sh

Tan solo tienes que darle atributos de ejecución.

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de brue

Qué pasada...

... esto sí que es un buen background musical.

brue

Imagen de shakaran

My 2 cent's

Bueno, mis dos céntimos, ya que al menos lo has liberado como software libre.

He portado el script bash de fsancho a python. Creo que requiere al menos python 2.7 ya que utiliza el módulo optparse.

Se puede descargar de:
http://www.shakaran.net/blog/wp-content/modarchive/modarchive.py

Os lo pongo al final de mi comentario también.

Ejemplo de ejecución:
python modarchive.py -s random -d

Resto de ejemplos en la ayuda (intentando mantener las opciones originales):
python modarchive.py -h

Supongo que es mejorable, no esta muy pythonico y tendrá algun bug (no he probado todas las acciones), pero es lo que he podido hacer en una horilla libre de la siesta.

Saludos

#!/bin/env python
#*-* coding: utf-8 *-*
 
"""
###############################################################################
#                        MODARCHIVE JUKEBOX SCRIPT
#   
#  Made by: Fernando Sancho AKA ‘toptnc’
#  email: toptnc@gmail.com
#
#  This script plays mods from <a href="http://modarchive.org" title="http://modarchive.org">http://modarchive.org</a> in random order
#  It can fetch files from various categories
#
#   This scripts needs the program mikmod installed under $PATH
#
#  This script is released under the terms of GNU GPL License 
#
###############################################################################
 
GPLv3 03-18-2011 
Port to python by: Ángel Guzmán Maeso (shakaran at gmail dot com) <a href="http://shakaran.net/blog/wp-content/modarchive/modarchive.py
" title="http://shakaran.net/blog/wp-content/modarchive/modarchive.py
">http://shakaran.net/blog/wp-content/modarchive/modarchive.py
</a> 
"""
from sys import exit
from os import path, makedirs, mkdir, remove, system
from urllib import urlopen
import re
import zipfile
 
VERSION = '1.0'
DEBUG = False
MODPATH = '/tmp/modarchive'
RANDOMSONG = None
MIKMOD = '/usr/bin/mikmod'
MODURL = None
 
def get_mikmod_bin():
    return MIKMOD
 
def check_mikmod():
    from os.path import exists as e
    return e(get_mikmod_bin())
 
if not check_mikmod():
    print 'This scripts needs the binary MIKMOD to run. Please install it or change the script'
    exit(1)
 
def get_url(url = None):
    try:
        return urlopen(url).read()
    except IOError, e:
        print _('Error: could not connect to the url' % url)
        return None
 
def get_data(url = None, uregex = None):
    data = get_url(url)
    #print data
    data.replace('<>', '\n')
    if uregex:
        p = re.compile(r'(%s)' % uregex)
        m = p.search(data)
 
        if m:
            return m.group()
        else:
            print 'No se encontraron resultados'
            return None
    else:
        return data
 
def get_mod_file(modurl, page):
    data = get_url('%s&page=%s' %(modurl, page))
    data.replace('href=', '\n')
    data.replace('>', '\n')
 
    p = re.compile(r'(http://modarchive.org/data/downloads.php\?moduleid=(.*)\#)')
    m = p.search(data)
 
    if m:
        module = m.group()[50 : -150]
        module = module[0:- (len(module) - module.find('#')) ]
        debug(module)
        return ('http://modarchive.org/data/downloads.php?moduleid=%s' % module, module)
    else:
        print 'No se encontraron resultados'
        return (None, None)
 
def unzip_file_into_dir(file, modID, dir):
    if not path.exists(dir + '/' + modID):
        mkdir(dir + '/' + modID, 0777)
    zfobj = zipfile.ZipFile(file)
    for name in zfobj.namelist():
        if name.endswith('/'):
            if not path.exists(path.join(dir, name)):
                mkdir(path.join(dir, name))
        else:
            outfile = open(path.join(dir + '/' + modID, name), 'wb')
            outfile.write(zfobj.read(name))
            outfile.close()
 
def debug(string = None):
    if DEBUG:
        print 'DEBUG:', string
 
def usage():
    return """
Modarchive Jukebox can be used with one of the following options:
\n\n
Hint: Use + symbol instead blankspaces in search strings."""
 
from argparse import ArgumentParser, RawTextHelpFormatter
 
parser = ArgumentParser(prog='modarchive', formatter_class=RawTextHelpFormatter, add_help=True, description=usage(), version=VERSION)
parser.add_argument('-d', '--debug', action='store_true', dest='debug', help='Enable debug mode')
 
parser.add_argument('-s', dest='section', nargs=1, type=str, choices=('uploads', 'featured', 'favourites', 'downloads', 'topscore', 'new', 'random'),
          help="""Play from selected section: Can be one of this
uploads     This is a list of the recent member upload activity.
featured    These modules have been nominated by the crew for either \n\t    outstanding quality, technique or creativity (or combination of).
favourites  These modules have been nominated by the members via their favourites.
downloads   The top 1000 most downloaded modules, recorded since circa 2002.
topscore    This chart lists the most revered modules on the archive.
new         Same than uploads but using search engine.
random      Ramdom module from entire archive.""")
 
search_group = parser.add_argument_group('Searching')
search_group.add_argument('-a', dest='artist', nargs=1, type=str, help='Search in artist database')        
search_group.add_argument('-m', dest='module', nargs=1, type=str, help="Search in module database (Title and Filename)")
 
try:
    results = parser.parse_args()
except IOError, msg:
    parser.error(str(msg))
 
if results.debug:
    DEBUG = True
 
debug(results)
 
pages = None
if results.section:
    if results.section[0] == 'uploads':
        MODURL = 'http://modarchive.org/index.php?request=view_actions_uploads'
        pages = None
    elif results.section[0] == 'featured':
        MODURL = 'http://modarchive.org/index.php?request=view_chart&query=featured'
        pages = get_data(MODURL, 'page=(\w)#mods')[5:-5]
    elif results.section[0] == 'favourites':
        MODURL = 'http://modarchive.org/index.php?request=view_top_favourites'
        pages = get_data(MODURL, 'page=(\w)#mods')[5:-5]
    elif results.section[0] == 'downloads':
        MODURL = 'http://modarchive.org/index.php?request=view_chart&query=tophits'
        pages = get_data(MODURL, 'page=(\w)#mods')[5:-5]
    elif results.section[0] == 'topscore':
        MODURL = 'http://modarchive.org/index.php?request=view_chart&query=topscore'
        pages = get_data(MODURL, 'page=(\w)#mods')[5:-5]
    elif results.section[0] == 'new':
        MODURL = 'http://modarchive.org/index.php?request=search&search_type=new_additions'
        pages = get_data(MODURL, 'page=(\w)#mods')[5:-5]
    elif results.section[0] == 'random':
        MODURL = 'http://modarchive.org/index.php?request=view_random'
        pages = 0
elif results.artist:
    MODURL = 'http://modarchive.org/index.php?query=%s&submit=Find&request=search&search_type=guessed_artist' % results.artist[0]
    pages = get_data(MODURL, 'page=(\w)#mods')[5:-5]
elif results.module:
    MODURL = 'http://modarchive.org/index.php?request=search&query=%s&submit=Find&search_type=filename_or_songtitle' % results.module[0]
    res = get_data(MODURL, 'page=(\w)#mods')[5:-5]
 
print "Starting Modarchive JukeBox Player"
debug("Pages: %s" % pages)
 
if not path.exists(MODPATH):
    debug('Creating dir %s' % MODPATH)
    makedirs(MODPATH)
 
while 1:
    print 'Press Ctrl-C twice to stop'
 
    (modfile, modID) = get_mod_file(MODURL, pages)
 
    if modfile:
        zip_file = '%s/%s.zip' %(MODPATH, modID)
        print "Downloading %s to %s" %(modfile, zip_file)
        f = open(zip_file, 'w')
        f.write(get_url(modfile))
        f.close()
        unzip_file_into_dir(zip_file, modID, MODPATH)
        remove(zip_file)
 
#   if [ ! -z $(pgrep pidgin) ];
#   then
#       purple-remote "setstatus?status=available&message=Modarchive JukeBox:  ${MODFILE}"
#   fi;
	print 'mikmod i -hqmixer --surrond X -noloops %s/%s/*' % (MODPATH, modID)
    print system('mikmod i -hqmixer --surrond X -noloops %s/%s/*' % (MODPATH, modID))
#   if [ ! -z $(pgrep pidgin) ];
#   then
#       purple-remote "setstatus?status=available&message="
#   fi;

Today is a good day. Would you be tomorrow?

Imagen de fsancho

Jo!

Así da gusto.

Mi idea inicial era hacerlo en python pero llevo tanto tiempo diciendo que voy a aprender Python que ya ni me acuerdo. Y al final bash me resuelve siempre la papeleta de una u otra forma.

Lo bueno de que funcione en python es que no se dependería de ningún programa externo. Simplemente habría que utilizar los bindings de Gstreamer y lanzar desde ahí la reproducción, ya que Gstreamer utiliza modplug para reproducir los mod.

De todas formas, si os fijáis le he hecho unos cuantos cambios al código. Ahora ya no uso mikmod, he pasado a audacious, aunque cambiar a mikmod es relativamente simple, con poner

PLAYER=/usr/bin/mikmod
PLAYEROPTS="-i -hqmixer --surrond -X -noloops"

y eliminar la comprobación de que el player esté ejecutandose.

Ahora tarda mas al arrancar ya que recupera la búsqueda completa y de ahí crea una playlist, así nos evitamos que en una misma sesión se repitan pistas. Pero en cuanto se descarga el primer fichero ya se puede dar al play del audacious y empezar a escuchar, que el resto se van añadiendo a la cola conforme se descargan.

Imagen de brue

lo he ...

... editado para que se vea como código.

brue

Imagen de shakaran

gracias

gracias Eye-wink probe con <*code><*/code> pero no lo resaltaba, ¿cual era la etiqueta correcta?

Today is a good day. Would you be tomorrow?

Imagen de david.villa

Listados de código en CRySoL

Listados de código en CRySoL

No soy portavoz de ningún colectivo, grupo o facción. Mi opinión es personal e intransferible.

Imagen de int-0

Wuoa!

...pero que guay!

------------------------------------------------------------
$ python -c "print 'VG9udG8gZWwgcXVlIGxvIGxlYSA6KQ==\n'.decode('base64')"
------------------------------------------------------------

Imagen de fsancho

Bah!

Adulador. Si en realidad lo he puesto para que empecéis a meterle mas cosas o traducirlo a mas lenguajes.

Imagen de int-0

Pues anda...

...si quieres q sea más fácil ponerle tontunitas... github o algo así porque editarlo desde crysol se me hace "pesaíto"...

------------------------------------------------------------
$ python -c "print 'VG9udG8gZWwgcXVlIGxvIGxlYSA6KQ==\n'.decode('base64')"
------------------------------------------------------------

Imagen de fsancho

Subversion

Estoy en arduas negociaciones con David Sticking out tongue para que me abra una ramita en el SVN de Arco. Si no, pues github y a correr, pero como nunca me he dado de alta ahí, me da pereza para una cosilla tan nimia.

Imagen de int-0

Pues chico...

....yo tengo una cuenta y tengo subidas 4 tontunas, pero hay un montón de proyectos muy interesantes y hacerles seguimiento es realmente fácil... es una especie de facebook para programadores... joer, este comentario casi parece SPAM!

------------------------------------------------------------
$ python -c "print 'VG9udG8gZWwgcXVlIGxvIGxlYSA6KQ==\n'.decode('base64')"
------------------------------------------------------------

Imagen de fsancho

Ya está en el subversion

Gracias David.

Tu concepto de tontuna y el mío están muy alejados Eye-wink