[PYTHON] Créez votre propre lecteur de musique avec Bottle0.13 + jPlayer2.5!

introduction

Le framework léger Bottle semble être populaire, donc je vais créer un lecteur de musique cloud pour la pratique. Le produit fini est répertorié dans Bitbucket, donc seuls les principaux points seront expliqués. L'exemple d'opération est disponible sur ici. Au fait, j'ai confirmé l'opération avec Python 2.6.

Qu'est-ce qu'un lecteur de musique cloud?

Il est pratique de pouvoir télécharger et lire à partir de n'importe quel appareil une fois que vous l'achetez, comme iTunes ou Amazon Cloud Player. Cependant, en tant que cuisine d'achat de CD, je souhaite toujours le lire avec le fichier source sonore à portée de main. Google Music vous permet de télécharger des fichiers vous-même, mais l'industrie de la musique japonaise est inflexible Par conséquent, il sera difficile d'exploiter un service similaire au Japon pour le moment. Par conséquent, j'ai toujours voulu créer mon propre lecteur de musique dans le cloud, je vais donc profiter de l'occasion pour le mettre en œuvre.

Réfléchissez à son fonctionnement

Une autre option consiste à créer un serveur de streaming en utilisant Subsonic ou Icecast. Bien que cela soit facile et que de nombreux joueurs puissent y jouer, cela présente l'inconvénient de subir une charge de traitement car la source sonore est encodée côté serveur. (En fait, j'avais l'habitude d'utiliser cette méthode jusqu'à présent, mais il y a un problème avec l'opération de sélection de morceau.) Cette fois, la plupart de la lecture sera laissée au plug-in jQuery jPlayer, un lecteur multimédia basé sur HTML5. Je ne sais pas si le framework léger Bottle entre en jeu car la partie traitement de Python émoussé consiste simplement à lister la liste de lecture, mais je pense que c'est juste pour étudier.

Les bases de la bouteille

Bottle vous permet de créer des applications Web avec une syntaxe très simple.

au.py


# -*- coding: utf-8 -*-
from bottle import route, run #Il semble courant de ne récupérer que les méthodes nécessaires (?)

@route('/hello') #Spécifiez le chemin cible pour exécuter la fonction suivante
def hello(): #Le nom de la fonction peut être n'importe quoi
    return 'Hello World!' #Contenu à afficher dans le navigateur

if __name__ == "__main__": #Notez que si vous ne le bloquez pas, une erreur se produira lorsque vous l'exécuterez à partir d'Apache décrit plus loin.
    run(host='0.0.0.0', port=8080, debug=True, reloader=True)

Pour l'argument de run ()

Exécutez le script ci-dessus à partir de la ligne de commande.

python au.py

Si vous accédez à l'adresse du serveur http: //: 8080 / hello depuis votre navigateur, vous devriez voir "Hello World!".

Utilisez un modèle

Maintenant, implémentons le lecteur de musique cloud souhaité à partir d'ici. Le moteur de template de Bottle peut être utilisé comme Django, donc les utilisateurs expérimentés de Django devraient être heureux de l'utiliser facilement. Les spécifications détaillées peuvent être trouvées dans le Document original.

au.py


from bottle import route, template, TEMPLATE_PATH
import os

ROOT_PATH = os.path.dirname(os.path.abspath(__file__)) #Chemin absolu vers le dossier où se trouve ce script
TEMPLATE_PATH.insert(0, ROOT_PATH+'/templates') #Spécifiez le dossier pour stocker le fichier de modèle

@route('/')
def index():
    return template('player.html') #Vous pouvez également passer des paramètres à la suite du fichier modèle

Dans le modèle, nous préparerons immédiatement jPlayer. Puisque l'apparence est secondaire, CSS utilise [Blue Monday] qui vient avec jPlayer, et la partie HTML est un lecteur vocal avec une liste de lecture de ce site. J'étais autorisé à me référer! De plus, les parties communes de chaque modèle sont rassemblées dans un fichier modèle séparé avec % rebase () '' ''. Notez que cela a un format différent de Django. Veuillez noter que les `` jplayer.m3u.js``` et `ʻinit.js``` passés dans les paramètres sont des scripts que vous créerez plus tard.

templates/player.html


% rebase('base.html', css=['jplayer.blue.monday.css'], js=['jquery.jplayer.min.js', 'jplayer.playlist.min.js', 'jplayer.m3u.js', 'init.js']) <!--Étant donné que les paramètres peuvent être passés après le fichier modèle, spécifiez les fichiers CSS et JS à lire en plus.-->
<div id="jquery_jplayer_N" class="jp-jplayer"></div>
<div id="jp_container_N" class="jp-audio">
    <div class="jp-type-playlist">
        <div class="jp-gui jp-interface">
            <ul class="jp-controls">
                <li><a href="javascript:;" class="jp-previous" tabindex="1">previous</a></li>
                <li><a href="javascript:;" class="jp-play" tabindex="1">play</a></li>
                <li><a href="javascript:;" class="jp-pause" tabindex="1">pause</a></li>
                <li><a href="javascript:;" class="jp-next" tabindex="1">next</a></li>
                <li><a href="javascript:;" class="jp-stop" tabindex="1">stop</a></li>
                <li><a href="javascript:;" class="jp-mute" tabindex="1" title="mute">mute</a></li>
                <li><a href="javascript:;" class="jp-unmute" tabindex="1" title="unmute">unmute</a></li>
                <li><a href="javascript:;" class="jp-volume-max" tabindex="1" title="max volume">max volume</a></li>
            </ul>
            <div class="jp-progress">
                <div class="jp-seek-bar">
                    <div class="jp-play-bar"></div>
                </div>
            </div>
            <div class="jp-volume-bar">
                <div class="jp-volume-bar-value"></div>
            </div>
            <div class="jp-time-holder">
                <div class="jp-current-time"></div>
                <div class="jp-duration"></div>
            </div>
            <ul class="jp-toggles">
                <li><a href="javascript:;" class="jp-shuffle" tabindex="1" title="shuffle">shuffle</a></li>
                <li><a href="javascript:;" class="jp-shuffle-off" tabindex="1" title="shuffle off">shuffle off</a></li>
                <li><a href="javascript:;" class="jp-repeat" tabindex="1" title="repeat">repeat</a></li>
                <li><a href="javascript:;" class="jp-repeat-off" tabindex="1" title="repeat off">repeat off</a></li>
            </ul>
        </div>
        <div class="jp-playlist">
            <ul>
                <li></li>
            </ul>
        </div>
    </div>
</div>
<div id="m3u_list"></div>

Ensuite, écrivez le fichier modèle pour la partie commune.

templates/base.html


<!DOCTYPE html>
<html>
<head>
    <title>AuPy - Croud Music Player</title>
    <script type="text/javascript" src="js/jquery.min.js"></script>
% for item in css: <!--Lire le fichier CSS passé en paramètre-->
    <link rel="stylesheet" type="text/css" href="css/{{item}}"> 
% end
% for item in js: <!--Lire le fichier JS également passé en paramètre-->
    <script type="text/javascript" src="js/{{item}}"></script>
% end
</head>
<body>
{{!base}} <!--Voici le contenu du fichier modèle appelant-->
</body>
</html>

À ce stade, je ne peux pas encore exécuter jPlayer.

Créer un plug-in jQuery qui lit les fichiers m3u

Implémentez un plug-in qui définira le fichier m3u / m3u8 sur la liste de lecture jPlayer. Il peut être implémenté en tant que plug-in jQuery en l'écrivant dans le format ci-dessous.

;(function($) {
    $.fn.loadm3u = function (){
        //Traitement du contenu
    }
})(jQuery);

Cette fois, nous allons créer un plug-in qui suppose l'utilisation suivante.

$().loadm3u(chemin du fichier m3u,Chemin du dossier de musique côté serveur,Chemin à remplacer(option))


 Le plug-in a une fonction pour remplacer automatiquement le chemin spécifié à l'avance. En conséquence, les fichiers m3u / m3u8 crachés par foobar2000 etc. peuvent être utilisés tels quels dans le lecteur de musique cloud.


#### **`js/jplayer.m3u.js`**

;(function($) { $.fn.loadm3u = function (filepath, server_music_dir, local_music_dir){ $.get(filepath, function(data){ //Obtenez le fichier m3u passé en argument var data_array = data.split(/\r\n|\r|\n/); //Split à la pause var playlists = []; for (var i = 0; i < data_array.length; i++){ //Traiter ligne par ligne if(data_array[i] != ""){ if (typeof local_music_dir != "undefined") { data_array[i] = data_array[i].replace(local_music_dir+"\", "") //Supprimer le chemin à remplacer } unix_dir_path = data_array[i].replace(/\/g, "/") //Corriger la barre oblique inverse en barre oblique title = unix_dir_path.split("/"); //Fractionner avec barre oblique playlists.push({"title":title[title.length-1], "free":true, "mp3":server_music_dir+"/"+unix_dir_path}); //Stockez le nom de fichier et le chemin du fichier de la source sonore dans la liste } }

        $("#jquery_jplayer_N").jPlayer("destroy"); //Initialiser jPlayer

        var Playlist = new jPlayerPlaylist( //Listes de lecture et options à charger dans jPlayer
            {
                jPlayer: "#jquery_jplayer_N",
                cssSelectorAncestor: "#jp_container_N"
            }, playlists, {
                supplied: "mp3" //Formats de fichiers audio pris en charge
            }
        );
    });
}

})(jQuery);


 De plus, bien que seul le mp3 soit spécifié dans le script ci-dessus, il semble qu'il sera lu sans problème même si vous passez un fichier de musique tel que ogg juste pour le chemin du fichier. flac n'a pas fonctionné car le navigateur ne prend pas en charge la lecture.

## Générer un fichier JS pour l'initialisation en Python

 Tout d'abord, préparez un script pour décrire les paramètres ensemble.


#### **`setting.py`**
```py

#! -*- coding: utf-8 -*-
import os

SERVER_MUSIC_ADDR = os.path.expandvars('audio') #Par rapport aux dossiers de musique/URL absolue
SERVER_PLAYLIST_ADDR = os.path.expandvars('playlist') #Par rapport aux dossiers de playlist/URL absolue
SERVER_PLAYLIST_DIR = os.path.expandvars('/home/example/aupy/playlist') #Chemin absolu du dossier de la playlist
LOCAL_MUSIC_DIR = os.path.expandvars('C:\Users\example\Music') #Chemin absolu du dossier de musique local à remplacer

Ensuite, listez les fichiers dans le dossier playlist sur le serveur, ajoutez-les à

</ div> ``, et chargez-les dans le plugin que vous venez de créer lorsque l'utilisateur clique sur un élément. Sortez le fichier JS à afficher en Python.

au.py


from bottle import route, response
from setting import * #Lisez le fichier de paramètres

@route('/js/init.js') #Détourner une demande pour ce fichier JS
def initjs():
    if LOCAL_MUSIC_DIR:
        local_music_dir = ', "'+LOCAL_MUSIC_DIR.replace('\\', '\\\\')+'"' #Définissez le chemin à remplacer
    else:
        local_music_dir = ''
    
    output = '$(function(){\n' #Commencer à écrire le contenu de sortie
    files = os.listdir(SERVER_PLAYLIST_DIR) #Lister les fichiers dans le dossier de la playlist
    files.sort()
    flg = True
    for file in files:
        if file.startswith('.'): #.Pour sauter htaccess, etc.
            continue
        id = file.translate(None, '.')
        output += '$("#m3u_list").append("<a href=\\"#\\" id=\\"m3u_file_'+id+'\\" class=\\"list-group-item\\">'+file+'</a>");\n' #Fichier de liste de lecture ajouté au HTML
        output += '$("#m3u_file_'+id+'").click(function(){ $().loadm3u("'+SERVER_PLAYLIST_ADDR+'/'+file+'", "'+SERVER_MUSIC_ADDR+'"'+local_music_dir+'); });\n' #Cliquez sur le déclencheur pour transmettre le fichier m3u au plug-in
        if flg:
            output += '$().loadm3u("'+SERVER_PLAYLIST_ADDR+'/'+file+'", "'+SERVER_MUSIC_ADDR+'"'+local_music_dir+');\n' #Charger automatiquement la première playlist
            flg = False
    output += '\n});'

    response.content_type = 'text/javascript' #Définir le type MIME sur JS
    return output

Est-ce seulement moi que le code devient obscurci à la fois lorsque l'opération #string est implémentée?

Comment gérer les fichiers statiques

Enfin, téléchargez le fichier musical et la liste de lecture sur le serveur et le lecteur est terminé. Les demandes pour ces fichiers statiques peuvent être acceptées par Bottle comme indiqué ci-dessous, mais il est plus stable s'ils sont correctement acceptés par Apache, ce qui sera décrit plus loin.

au.py


from bottle import route, static_file

@route('/css/<filename>')
def css(filename):
    return static_file(filename, root=ROOT_PATH+'/css')

@route('/js/<filename>')
def js(filename):
    return static_file(filename, root=ROOT_PATH+'/js')

@route('/audio/<filepath:path>')
def audio(filepath):
    return static_file(filepath, root=ROOT_PATH+'/audio')

@route('/playlist/<filename>')
def playlist(filename):
    return static_file(filename, root=ROOT_PATH+'/playlist'

Authentification de base

Il est respectueux des droits d'auteur de rendre les fichiers musicaux accessibles à tous, alors définissez un mot de passe. L'authentification de base peut également être appliquée à Bottle. Cette fois, nous obtiendrons les informations d'authentification de .htpasswd``` qui est le fichier de mot de passe pour l'authentification de base d'Apache. Cependant, si vous activez à la fois l'authentification de base d'Apache, cela ne fonctionnera pas correctement, alors assurez-vous de désactiver l'un ou l'autre.

au.py


from bottle import route, auth_basic
from crypt import crypt

def check(user, passwd): #Créez votre propre fonction de vérification de mot de passe(En d'autres termes, il peut également s'agir d'une authentification de passoire)
    for line in open(ROOT_PATH+'/.htpasswd', 'r'): #.Obtenir ligne par ligne de htpasswd
        htpasswd = line[:-1].split(':') #Nom d'utilisateur et mot de passe cryptés séparés
        if user is not None and htpasswd[1] is None: #.Activer l'authentification même si seul le nom d'utilisateur est défini
            if user == htpasswd[0]:
                return True
        elif user is not None and passwd is not None:
            if user == htpasswd[0] and crypt(passwd, htpasswd[1][0:2]) == htpasswd[1]: #Faites correspondre le nom d'utilisateur et le mot de passe crypté
                return True
    return False

@route('/')
@auth_basic(check) #Ajouter à la demande d'authentification
def index():
    return template('player.html')

Exécuter à partir d'Apache + WSGI

La fonction serveur de Bottle n'est pas stable, il est donc préférable de la limiter au développement. Cette fois, je vais vous présenter un exemple d'appel depuis Apache, mais cela dépend grandement de l'environnement, alors veuillez l'utiliser comme référence. Tout d'abord, créez un adaptateur dans le fichier WSGI qui sera appelé à partir d'Apache et transmis à Bottle.

adapter.wsgi


import sys, os
sys.path.append(os.path.dirname(os.path.abspath(__file__))) #Passez le chemin du dossier où se trouve le script
import bottle, au #Chargez la bouteille elle-même et l'application
application = bottle.default_app()

Ensuite, écrivez ce qui suit dans un fichier approprié en fonction de l'environnement, tel que httpd.conf '' ou wsgi.conf '' d'Apache, ou un autre fichier de configuration d'hôte virtuel.

httpd.conf


WSGIScriptAlias /aupy /home/example/aupy/adapter.wsgi #Spécifiez l'adaptateur
<Directory "/home/example/aupy/">
   Options ExecCGI Indexes FollowSymlinks
   AllowOverride All #.Activer htaccess
   Order deny,allow
   Allow from all
</Directory>

Alias /aupy/audio /home/example/aupy/audio
<Directory "/home/example/aupy/audio">
   AllowOverride All
   Order deny,allow
   Allow from all
</Directory>

Alias /aupy/playlist /home/example/aupy/playlist
<Directory "/home/example/aupy/playlist">
   AllowOverride All
   Order deny,allow
   Allow from all
</Directory>

De plus, si vous appliquez l'authentification de base au dossier de musique, il semble que la lecture ne démarre pas correctement sur Android Chrome, donc comme contre-mesure pour un accès direct, j'ai compromis avec les restrictions par les référents ou les agents utilisateurs (en spécifiant un modèle spécifique).

.htaccess


SetEnvIf Referer "^http://example.com.*" allowReferer #Autoriser l'accès à partir du lecteur de musique cloud
SetEnvIf User-Agent "example" allowReferer #Autorisé pour certains UA
order deny,allow
deny from all
allow from env=allowReferer

Prend en charge les noms de fichiers japonais

J'ai oublié d'écrire la chose importante. Puisque je suis une cuisine HM de musique occidentale, il n'y a pas de problème, mais je pense que le grand public voudra jouer de la musique avec des noms de fichiers japonais. Malheureusement, je ne savais pas comment acheminer des URL multi-octets dans Bottle, alors faites-le moi savoir si vous le pouvez. Apache peut gérer les URL multi-octets en introduisant mod_encoding.

Présentation des commandes exécutées dans CentOS 6.2. Veuillez noter que le chemin, etc. diffère selon la distribution. Tout d'abord, téléchargez les fichiers requis à partir de la console.

wget http://webdav.todo.gr.jp/download/mod_encoding-20021209.tar.gz
wget http://iij.dl.sourceforge.jp/webdav/13905/mod_encoding.c.apache2.20040616
wget http://www.aconus.com/~oyaji/faq/mod_encoding.c-apache2.2-20060520.patch

Extrayez le fichier téléchargé et appliquez le correctif.

tar zxvf mod_encoding-20021209.tar.gz
cd mod_encoding-20021209/
./configure --with-apxs=/usr/sbin/apxs
cp ../mod_encoding.c.apache2.20040616 mod_encoding.c
patch -p0 < ../mod_encoding.c-apache2.2-20060520.patch

Installez la bibliothèque iconv_hook incluse.

cd lib
./configure
make
sudo make install
sudo vi /etc/ld.so.conf
/usr/local/Ajouter une bibliothèque
ldconfig

Enfin, installez mod_encoding.

cd ../
make
gcc -shared -o mod_encoding.so mod_encoding.o -Wc,-Wall -L/usr/local/lib -Llib -liconv_hook
sudo make install

Ajoutez ce qui suit au fichier de configuration Apache.

httpd.conf


<IfModule mod_encoding.c>
EncodingEngine On
SetServerEncoding UTF-8
DefaultClientEncoding UTF-8 CP932 EUCJP-MS

AddClientEncoding "RMA/*" CP932
AddClientEncoding "xdwin9x/" CP932
AddClientEncoding "cadaver/" UTF-8 EUCJP-MS
AddClientEncoding "Mozilla/" EUCJP-MS
</IfModule>

Enfin, redémarrez Apache avec sudo service httpd restart '' et vous devriez pouvoir accéder correctement à l'URL contenant des multi-octets.

en conclusion

Comment s'est passée l'introduction de Bottle? Bien sûr, même si vous êtes un geek, essayez de créer un lecteur de musique cloud pour votre famille!

Recommended Posts

Créez votre propre lecteur de musique avec Bottle0.13 + jPlayer2.5!
Essayez de créer votre propre AWS-SDK avec bash
Créez rapidement votre propre module avec setuptools (python)
[Python] Créez votre propre bot LINE
Créez votre propre manuel. [Linux] [homme]
Résolvez votre propre labyrinthe avec Q Learning
Entraînez UGATIT avec votre propre jeu de données
Créez votre propre VPC avec un seul sous-réseau public uniquement avec boto
Comment créer votre propre site de domaine avec heroku (plan gratuit)
Créer un lecteur vidéo avec PySimpleGUI + OpenCV
[Renforcer l'apprentissage] DQN avec votre propre bibliothèque
Créez votre propre serveur DNS avec Twisted
Créez votre propre valeur composite avec SQLAlchemy
Créez votre propre PC pour un apprentissage en profondeur
Pour importer votre propre module avec jupyter
Publiez votre propre bibliothèque Python sur Homebrew
Rendez vos photos illustrées avec le filtre de mode d'oreiller
Étapes pour installer votre propre bibliothèque avec pip
Flux de création de votre propre package avec setup.py avec python
Mémo pour créer votre propre Box avec le Python de Pepper
Appelez votre propre bibliothèque de langage C avec Go en utilisant cgo
Écrivez votre propre fonction d'activation avec Pytorch (sigmoïde dur)
Appelons votre propre bibliothèque C ++ avec Python (Préférences)
[# 2] Créez Minecraft avec Python. ~ Dessin du modèle et implémentation du lecteur ~
Définissez votre propre fonction de distance avec k-means de scikit-learn
Personnalisez Jupyter Notebook: modifiez l'arrière-plan et les icônes