refactor(airtime_analyzer): rename to libretime-analyzer and make entrypoint pythonic
This commit is contained in:
parent
b6d22c94a1
commit
e21abf1bf1
|
@ -916,14 +916,14 @@ SQL;
|
||||||
* on the local disk (like /tmp) over to Airtime's "stor" directory,
|
* on the local disk (like /tmp) over to Airtime's "stor" directory,
|
||||||
* which is where all ingested music/media live.
|
* which is where all ingested music/media live.
|
||||||
*
|
*
|
||||||
* This is done in PHP here on the web server rather than in airtime_analyzer because
|
* This is done in PHP here on the web server rather than in libretime-analyzer because
|
||||||
* the airtime_analyzer might be running on a different physical computer than the web server,
|
* the libretime-analyzer might be running on a different physical computer than the web server,
|
||||||
* and it probably won't have access to the web server's /tmp folder. The stor/organize directory
|
* and it probably won't have access to the web server's /tmp folder. The stor/organize directory
|
||||||
* is, however, both accessible to the machines running airtime_analyzer and the web server
|
* is, however, both accessible to the machines running libretime-analyzer and the web server
|
||||||
* on Airtime Pro.
|
* on Airtime Pro.
|
||||||
*
|
*
|
||||||
* The file is actually copied to "stor/organize", which is a staging directory where files go
|
* The file is actually copied to "stor/organize", which is a staging directory where files go
|
||||||
* before they're processed by airtime_analyzer, which then moves them to "stor/imported" in the final
|
* before they're processed by libretime-analyzer, which then moves them to "stor/imported" in the final
|
||||||
* step.
|
* step.
|
||||||
*
|
*
|
||||||
* @param string $tempFilePath
|
* @param string $tempFilePath
|
||||||
|
|
|
@ -33,10 +33,10 @@ class Application_Service_MediaService
|
||||||
}
|
}
|
||||||
|
|
||||||
//Copy the temporary file over to the "organize" folder so that it's off our webserver
|
//Copy the temporary file over to the "organize" folder so that it's off our webserver
|
||||||
//and accessible by airtime_analyzer which could be running on a different machine.
|
//and accessible by libretime-analyzer which could be running on a different machine.
|
||||||
$newTempFilePath = Application_Model_StoredFile::moveFileToStor($filePath, $originalFilename, $copyFile);
|
$newTempFilePath = Application_Model_StoredFile::moveFileToStor($filePath, $originalFilename, $copyFile);
|
||||||
|
|
||||||
//Dispatch a message to airtime_analyzer through RabbitMQ,
|
//Dispatch a message to libretime-analyzer through RabbitMQ,
|
||||||
//notifying it that there's a new upload to process!
|
//notifying it that there's a new upload to process!
|
||||||
$storageBackend = new ProxyStorageBackend($CC_CONFIG["current_backend"]);
|
$storageBackend = new ProxyStorageBackend($CC_CONFIG["current_backend"]);
|
||||||
Application_Model_RabbitMq::SendMessageToAnalyzer($newTempFilePath,
|
Application_Model_RabbitMq::SendMessageToAnalyzer($newTempFilePath,
|
||||||
|
|
|
@ -113,7 +113,7 @@ function checkRMQConnection() {
|
||||||
* @return boolean true if airtime-analyzer is running
|
* @return boolean true if airtime-analyzer is running
|
||||||
*/
|
*/
|
||||||
function checkAnalyzerService() {
|
function checkAnalyzerService() {
|
||||||
exec("pgrep -f airtime_analyzer", $out, $status);
|
exec("pgrep -f libretime-analyzer", $out, $status);
|
||||||
if (($out > 0) && $status == 0) {
|
if (($out > 0) && $status == 0) {
|
||||||
return posix_kill(rtrim($out[0]), 0);
|
return posix_kill(rtrim($out[0]), 0);
|
||||||
}
|
}
|
||||||
|
|
4
install
4
install
|
@ -1014,8 +1014,8 @@ loudCmd "usermod -G ${web_user} -a celery"
|
||||||
systemInitInstall libretime-celery
|
systemInitInstall libretime-celery
|
||||||
verbose "...Done"
|
verbose "...Done"
|
||||||
|
|
||||||
verbose "\n * Installing airtime_analyzer..."
|
verbose "\n * Installing libretime-analyzer..."
|
||||||
loudCmd "$python_bin ${AIRTIMEROOT}/python_apps/airtime_analyzer/setup.py install --install-scripts=/usr/bin --no-init-script"
|
loudCmd "$python_bin ${AIRTIMEROOT}/python_apps/airtime_analyzer/setup.py install --install-scripts=/usr/bin"
|
||||||
systemInitInstall libretime-analyzer $web_user
|
systemInitInstall libretime-analyzer $web_user
|
||||||
verbose "...Done"
|
verbose "...Done"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
# libretime-analyzer
|
||||||
|
|
||||||
|
libretime-analyzer is a daemon that processes LibreTime file uploads as background jobs.
|
||||||
|
|
||||||
|
It performs metadata extraction using Mutagen and moves uploads into LibreTime's
|
||||||
|
music library directory (stor/imported).
|
||||||
|
|
||||||
|
libretime-analyzer uses process isolation to make it resilient to crashes and runs in
|
||||||
|
a multi-tenant environment with no modifications.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python setup.py install
|
||||||
|
```
|
||||||
|
|
||||||
|
You will need to allow the "airtime" RabbitMQ user to access all exchanges and queues within the /airtime vhost:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rabbitmqctl set_permissions -p /airtime airtime .\* .\* .\*
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
This program must run as a user with permissions to write to your Airtime music library
|
||||||
|
directory. For standard Airtime installations, run it as the www-data user:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo -u www-data libretime-analyzer --daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
Or during development, add the --debug flag for more verbose output:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo -u www-data libretime-analyzer --debug
|
||||||
|
```
|
||||||
|
|
||||||
|
To print usage instructions, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
libretime-analyzer --help
|
||||||
|
```
|
||||||
|
|
||||||
|
This application can be run as a daemon by running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
libretime-analyzer -d
|
||||||
|
```
|
||||||
|
|
||||||
|
# Developers
|
||||||
|
|
||||||
|
For development, you want to install libretime-analyzer system-wide but with everything symlinked back to the source
|
||||||
|
directory for convenience. This is super easy to do, just run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r requirements-dev.txt
|
||||||
|
pip install --editable .
|
||||||
|
```
|
||||||
|
|
||||||
|
To send an test message to libretime-analyzer, you can use the message_sender.php script in the tools directory.
|
||||||
|
For example, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php tools/message_sender.php '{ "tmp_file_path" : "foo.mp3", "final_directory" : ".", "callback_url" : "http://airtime.localhost/rest/media/1", "api_key" : "YOUR_API_KEY" }'
|
||||||
|
|
||||||
|
php tools/message_sender.php '{"tmp_file_path":"foo.mp3", "import_directory":"/srv/airtime/stor/imported/1","original_filename":"foo.mp3","callback_url": "http://airtime.localhost/rest/media/1", "api_key":"YOUR_API_KEY"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
By default, logs are saved to:
|
||||||
|
|
||||||
|
```
|
||||||
|
/var/log/airtime/airtime_analyzer.log
|
||||||
|
```
|
||||||
|
|
||||||
|
This application takes care of rotating logs for you.
|
||||||
|
|
||||||
|
## Unit Tests
|
||||||
|
|
||||||
|
To run the unit tests, execute:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nosetests
|
||||||
|
```
|
||||||
|
|
||||||
|
If you care about seeing console output (stdout), like when you're debugging or developing
|
||||||
|
a test, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nosetests -s
|
||||||
|
```
|
||||||
|
|
||||||
|
To run the unit tests and generate a code coverage report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nosetests --with-coverage --cover-package=airtime_analyzer
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running in a Multi-Tenant Environment
|
||||||
|
|
||||||
|
## History and Design Motivation
|
|
@ -1,95 +0,0 @@
|
||||||
airtime_analyzer
|
|
||||||
==========
|
|
||||||
|
|
||||||
airtime_analyzer is a daemon that processes Airtime file uploads as background jobs.
|
|
||||||
It performs metadata extraction using Mutagen and moves uploads into Airtime's
|
|
||||||
music library directory (stor/imported).
|
|
||||||
|
|
||||||
airtime_analyzer uses process isolation to make it resilient to crashes and runs in
|
|
||||||
a multi-tenant environment with no modifications.
|
|
||||||
|
|
||||||
Installation
|
|
||||||
==========
|
|
||||||
|
|
||||||
$ sudo python setup.py install
|
|
||||||
|
|
||||||
You will need to allow the "airtime" RabbitMQ user to access all exchanges and queues within the /airtime vhost:
|
|
||||||
|
|
||||||
sudo rabbitmqctl set_permissions -p /airtime airtime .\* .\* .\*
|
|
||||||
|
|
||||||
|
|
||||||
Usage
|
|
||||||
==========
|
|
||||||
|
|
||||||
This program must run as a user with permissions to write to your Airtime music library
|
|
||||||
directory. For standard Airtime installations, run it as the www-data user:
|
|
||||||
|
|
||||||
$ sudo -u www-data airtime_analyzer --daemon
|
|
||||||
|
|
||||||
Or during development, add the --debug flag for more verbose output:
|
|
||||||
|
|
||||||
$ sudo -u www-data airtime_analyzer --debug
|
|
||||||
|
|
||||||
To print usage instructions, run:
|
|
||||||
|
|
||||||
$ airtime_analyzer --help
|
|
||||||
|
|
||||||
This application can be run as a daemon by running:
|
|
||||||
|
|
||||||
$ airtime_analyzer -d
|
|
||||||
|
|
||||||
Other runtime flags can be listed by running:
|
|
||||||
|
|
||||||
$ airtime_analyzer --help
|
|
||||||
|
|
||||||
|
|
||||||
Developers
|
|
||||||
==========
|
|
||||||
|
|
||||||
For development, you want to install airtime_analyzer system-wide but with everything symlinked back to the source
|
|
||||||
directory for convenience. This is super easy to do, just run:
|
|
||||||
|
|
||||||
$ sudo python setup.py develop
|
|
||||||
|
|
||||||
To send an test message to airtime_analyzer, you can use the message_sender.php script in the tools directory.
|
|
||||||
For example, run:
|
|
||||||
|
|
||||||
$ php tools/message_sender.php '{ "tmp_file_path" : "foo.mp3", "final_directory" : ".", "callback_url" : "http://airtime.localhost/rest/media/1", "api_key" : "YOUR_API_KEY" }'
|
|
||||||
|
|
||||||
$ php tools/message_sender.php '{"tmp_file_path":"foo.mp3", "import_directory":"/srv/airtime/stor/imported/1","original_filename":"foo.mp3","callback_url": "http://airtime.localhost/rest/media/1", "api_key":"YOUR_API_KEY"}'
|
|
||||||
|
|
||||||
Logging
|
|
||||||
=========
|
|
||||||
|
|
||||||
By default, logs are saved to:
|
|
||||||
|
|
||||||
/var/log/airtime/airtime_analyzer.log
|
|
||||||
|
|
||||||
This application takes care of rotating logs for you.
|
|
||||||
|
|
||||||
|
|
||||||
Unit Tests
|
|
||||||
==========
|
|
||||||
|
|
||||||
To run the unit tests, execute:
|
|
||||||
|
|
||||||
$ nosetests
|
|
||||||
|
|
||||||
If you care about seeing console output (stdout), like when you're debugging or developing
|
|
||||||
a test, run:
|
|
||||||
|
|
||||||
$ nosetests -s
|
|
||||||
|
|
||||||
To run the unit tests and generate a code coverage report, run:
|
|
||||||
|
|
||||||
$ nosetests --with-coverage --cover-package=airtime_analyzer
|
|
||||||
|
|
||||||
|
|
||||||
Running in a Multi-Tenant Environment
|
|
||||||
===========
|
|
||||||
|
|
||||||
|
|
||||||
History and Design Motivation
|
|
||||||
===========
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
"""Runs the airtime_analyzer application.
|
|
||||||
"""
|
"""
|
||||||
|
Main CLI entrypoint for the libretime-analyzer app.
|
||||||
|
"""
|
||||||
|
|
||||||
import daemon
|
import daemon
|
||||||
import argparse
|
import argparse
|
||||||
|
@ -13,9 +12,9 @@ LIBRETIME_CONF_DIR = os.getenv('LIBRETIME_CONF_DIR', '/etc/airtime')
|
||||||
DEFAULT_RMQ_CONFIG_PATH = os.path.join(LIBRETIME_CONF_DIR, 'airtime.conf')
|
DEFAULT_RMQ_CONFIG_PATH = os.path.join(LIBRETIME_CONF_DIR, 'airtime.conf')
|
||||||
DEFAULT_HTTP_RETRY_PATH = '/tmp/airtime_analyzer_http_retries'
|
DEFAULT_HTTP_RETRY_PATH = '/tmp/airtime_analyzer_http_retries'
|
||||||
|
|
||||||
def run():
|
def main():
|
||||||
'''Entry-point for this application'''
|
'''Entry-point for this application'''
|
||||||
print("Airtime Analyzer {}".format(VERSION))
|
print("LibreTime Analyzer {}".format(VERSION))
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("-d", "--daemon", help="run as a daemon", action="store_true")
|
parser.add_argument("-d", "--daemon", help="run as a daemon", action="store_true")
|
||||||
parser.add_argument("--debug", help="log full debugging output", action="store_true")
|
parser.add_argument("--debug", help="log full debugging output", action="store_true")
|
||||||
|
@ -42,4 +41,5 @@ def run():
|
||||||
http_retry_queue_path=http_retry_queue_path,
|
http_retry_queue_path=http_retry_queue_path,
|
||||||
debug=args.debug)
|
debug=args.debug)
|
||||||
|
|
||||||
run()
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -2,7 +2,7 @@
|
||||||
Description=LibreTime Media Analyzer Service
|
Description=LibreTime Media Analyzer Service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/usr/bin/airtime_analyzer
|
ExecStart=/usr/bin/libretime-analyzer
|
||||||
User=libretime-analyzer
|
User=libretime-analyzer
|
||||||
Group=libretime-analyzer
|
Group=libretime-analyzer
|
||||||
Restart=always
|
Restart=always
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
### BEGIN INIT INFO
|
### BEGIN INIT INFO
|
||||||
# Provides: airtime_analyzer
|
# Provides: libretime-analyzer
|
||||||
# Required-Start: $local_fs $remote_fs $network $syslog $all
|
# Required-Start: $local_fs $remote_fs $network $syslog $all
|
||||||
# Required-Stop: $local_fs $remote_fs $network $syslog
|
# Required-Stop: $local_fs $remote_fs $network $syslog
|
||||||
# Default-Start: 2 3 4 5
|
# Default-Start: 2 3 4 5
|
||||||
# Default-Stop: 0 1 6
|
# Default-Stop: 0 1 6
|
||||||
# Short-Description: Manage airtime_analyzer daemon
|
# Short-Description: Manage libretime-analyzer daemon
|
||||||
### END INIT INFO
|
### END INIT INFO
|
||||||
|
|
||||||
USERID=www-data
|
USERID=www-data
|
||||||
GROUPID=www-data
|
GROUPID=www-data
|
||||||
NAME=airtime_analyzer
|
NAME=libretime-analyzer
|
||||||
|
|
||||||
DAEMON=/usr/bin/$NAME
|
DAEMON=/usr/bin/$NAME
|
||||||
PIDFILE=/var/run/$NAME.pid
|
PIDFILE=/var/run/$NAME.pid
|
||||||
|
|
|
@ -15,10 +15,10 @@ env LANG='en_US.UTF-8'
|
||||||
env LC_ALL='en_US.UTF-8'
|
env LC_ALL='en_US.UTF-8'
|
||||||
|
|
||||||
#script
|
#script
|
||||||
# airtime_analyzer
|
# libretime-analyzer
|
||||||
#end script
|
#end script
|
||||||
|
|
||||||
exec airtime_analyzer
|
exec libretime-analyzer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
coverage
|
||||||
|
mock
|
||||||
|
nose
|
|
@ -1,58 +1,31 @@
|
||||||
from __future__ import print_function
|
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
from subprocess import call
|
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# Change directory since setuptools uses relative paths
|
# Change directory since setuptools uses relative paths
|
||||||
script_path = os.path.dirname(os.path.realpath(__file__))
|
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
||||||
print(script_path)
|
|
||||||
os.chdir(script_path)
|
|
||||||
|
|
||||||
# Allows us to avoid installing the upstart init script when deploying airtime_analyzer
|
setup(
|
||||||
# on Airtime Pro:
|
name="libretime-analyzer",
|
||||||
if '--no-init-script' in sys.argv:
|
version="0.1",
|
||||||
data_files = []
|
description="Libretime Analyzer Worker and File Importer",
|
||||||
sys.argv.remove('--no-init-script') # super hax
|
url="https://libretime.org",
|
||||||
else:
|
author="LibreTime Contributors",
|
||||||
data_files = [('/etc/init', ['install/upstart/airtime_analyzer.conf']),
|
license="AGPLv3",
|
||||||
('/etc/init.d', ['install/sysvinit/airtime_analyzer'])]
|
packages=["airtime_analyzer"],
|
||||||
print(data_files)
|
entry_points={
|
||||||
|
"console_scripts": [
|
||||||
setup(name='airtime_analyzer',
|
"libretime-analyzer=airtime_analyzer.cli:main",
|
||||||
version='0.1',
|
]
|
||||||
description='Airtime Analyzer Worker and File Importer',
|
},
|
||||||
url='http://github.com/sourcefabric/Airtime',
|
install_requires=[
|
||||||
author='Albert Santoni',
|
"mutagen==1.42.0",
|
||||||
author_email='albert.santoni@sourcefabric.org',
|
"pika~=1.1.0",
|
||||||
license='MIT',
|
"file-magic",
|
||||||
packages=['airtime_analyzer'],
|
"python-daemon",
|
||||||
scripts=['bin/airtime_analyzer'],
|
"requests>=2.7.0",
|
||||||
install_requires=[
|
"rgain3==1.0.0",
|
||||||
'mutagen==1.42.0',
|
"pycairo==1.19.1",
|
||||||
'pika~=1.1.0',
|
"PyGObject<=3.36.1",
|
||||||
'file-magic',
|
],
|
||||||
'nose',
|
zip_safe=False,
|
||||||
'coverage',
|
)
|
||||||
'mock',
|
|
||||||
'python-daemon',
|
|
||||||
'requests>=2.7.0',
|
|
||||||
'rgain3==1.0.0',
|
|
||||||
'pycairo==1.19.1',
|
|
||||||
'PyGObject<=3.36.1',
|
|
||||||
# These next 3 are required for requests to support SSL with SNI. Learned this the hard way...
|
|
||||||
# What sucks is that GCC is required to pip install these.
|
|
||||||
#'ndg-httpsclient',
|
|
||||||
#'pyasn1',
|
|
||||||
#'pyopenssl'
|
|
||||||
],
|
|
||||||
zip_safe=False,
|
|
||||||
data_files=data_files)
|
|
||||||
|
|
||||||
# Remind users to reload the initctl config so that "service start airtime_analyzer" works
|
|
||||||
if data_files:
|
|
||||||
print("Remember to reload the initctl configuration")
|
|
||||||
print("Run \"sudo initctl reload-configuration; sudo service airtime_analyzer restart\" now.")
|
|
||||||
print("Or on Ubuntu Xenial (16.04)")
|
|
||||||
print("Remember to reload the systemd configuration")
|
|
||||||
print("Run \"sudo systemctl daemon-reload; sudo service airtime_analyzer restart\" now.")
|
|
||||||
|
|
|
@ -162,4 +162,4 @@ def test_mp3_bad_channels():
|
||||||
#Mutagen doesn't extract comments from mp3s it seems
|
#Mutagen doesn't extract comments from mp3s it seems
|
||||||
|
|
||||||
def test_unparsable_file():
|
def test_unparsable_file():
|
||||||
MetadataAnalyzer.analyze('README.rst', dict())
|
MetadataAnalyzer.analyze('tests/test_data/unparsable.txt', dict())
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
test-file
|
|
@ -7,6 +7,7 @@ if [[ -n "$TRAVIS_PHP_VERSION" ]]; then
|
||||||
fi
|
fi
|
||||||
if [[ -n "$TRAVIS_PYTHON_VERSION" ]]; then
|
if [[ -n "$TRAVIS_PYTHON_VERSION" ]]; then
|
||||||
pushd python_apps/airtime_analyzer
|
pushd python_apps/airtime_analyzer
|
||||||
|
pip3 install -r requirements-dev.txt
|
||||||
pip3 install -e .
|
pip3 install -e .
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue