瀏覽代碼

No more celery, audiogen used for continous, too

readme is now rst, and included in setup.py
boyska 9 年之前
父節點
當前提交
241eb30c7c
共有 7 個文件被更改,包括 67 次插入63 次删除
  1. 17 8
      README.rst
  2. 24 0
      larigira/audiogen_mpdrandom.py
  3. 0 2
      larigira/celeryconfig.py
  4. 2 0
      larigira/eventutils.py
  5. 15 9
      larigira/mpc.py
  6. 0 41
      larigira/task.py
  7. 9 3
      setup.py

+ 17 - 8
README.mdwn → README.rst

@@ -1,6 +1,10 @@
+=========
 larigira
 larigira
 =========
 =========
 
 
+About
+-------
+
 A radio automation based on MPD. Larigira will sit right to your mpd player and
 A radio automation based on MPD. Larigira will sit right to your mpd player and
 will keep your playlist never empty. It will also manage a db of "events", so
 will keep your playlist never empty. It will also manage a db of "events", so
 that you can schedule shows, play jingles every X minutes, etc.
 that you can schedule shows, play jingles every X minutes, etc.
@@ -12,31 +16,36 @@ Software stack
 * python2
 * python2
   * gevent as an async framework
   * gevent as an async framework
   * flask to provide web interface and rpc
   * flask to provide web interface and rpc
-  * celery for task dispatching
 * ejdb as an embedded database
 * ejdb as an embedded database
 
 
 Why? (aka design features)
 Why? (aka design features)
------
+--------------------------
 
 
 Reinventing a player is a bad idea. MPD provides an eccellent base.
 Reinventing a player is a bad idea. MPD provides an eccellent base.
 
 
 Separating the player from "action loops" makes it easy to work on this. For
 Separating the player from "action loops" makes it easy to work on this. For
 example, you can stop larigira for some minutes, and the audio will keep
 example, you can stop larigira for some minutes, and the audio will keep
-playing. Also, you can replace it.
+playing. It also means that you can easily replace specific parts of your radio
+automation.
 
 
-The "continous playing" part needs to be separated from the "events" part.
-`larigira` can be run to perform one, the other, or both the duties.
+The "continous playing" part is separated from the "events" part.  ``larigira``
+can be run to perform one, the other, or both.
 
 
 The "audio generation" part can be used separately by any script that you like.
 The "audio generation" part can be used separately by any script that you like.
 
 
 Installation
 Installation
 -------------
 -------------
 
 
-Just run `python setup.py install`. It will, of course, also work in a
-virtualenv.
+Just run ``python setup.py install``. It will, of course, also work in a
+virtualenv. Apart from running an MPD server, there is no additional setup.
+
+You will find some command in your PATH now; they all begin with ``larigira``,
+so the usual ``<TAB><TAB>`` is a good way to explore them ;)
 
 
 The name
 The name
 ---------
 ---------
 
 
-> larigira mai la sbaglia
+    larigira mai la sbaglia...
+    
+    -- https://www.youtube.com/watch?v=K9XJkOSSdEA
 
 

+ 24 - 0
larigira/audiogen_mpdrandom.py

@@ -0,0 +1,24 @@
+import logging
+log = logging.getLogger('mpdrandom')
+import random
+
+from mpd import MPDClient
+
+
+def generate_by_artist(spec):
+    '''choose HOWMANY random artists, and for each one choose a random song'''
+    for attr in ('howmany',):
+        if attr not in spec:
+            raise ValueError("Malformed audiospec: missing '%s'" % attr)
+
+    log.info('generating')
+    c = MPDClient()
+    c.connect('localhost', 6600)  # TODO: read global options somehow
+
+    artists = c.list('artist')
+    log.debug("got %d artists" % len(artists))
+    if not artists:
+        raise ValueError("no artists in your mpd database")
+    for _ in xrange(spec['howmany']):
+        artist = random.choice(artists)
+        yield random.choice(c.find('artist', artist))['file']

+ 0 - 2
larigira/celeryconfig.py

@@ -1,2 +0,0 @@
-CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
-CELERYD_POOL_RESTARTS = True

+ 2 - 0
larigira/eventutils.py

@@ -12,11 +12,13 @@ class ParentedLet(gevent.Greenlet):
     def __init__(self, queue):
     def __init__(self, queue):
         gevent.Greenlet.__init__(self)
         gevent.Greenlet.__init__(self)
         self.parent_queue = queue
         self.parent_queue = queue
+        self.tracker = None  # set this to recognize easily
 
 
     def parent_msg(self, kind, *args):
     def parent_msg(self, kind, *args):
         return {
         return {
             'emitter': self,
             'emitter': self,
             'class': self.__class__.__name__,
             'class': self.__class__.__name__,
+            'tracker': self.tracker,
             'kind': kind,
             'kind': kind,
             'args': args
             'args': args
         }
         }

+ 15 - 9
larigira/mpc.py

@@ -1,10 +1,12 @@
 from __future__ import print_function
 from __future__ import print_function
 from gevent import monkey
 from gevent import monkey
 monkey.patch_all(subprocess=True)
 monkey.patch_all(subprocess=True)
+import os
 
 
 import logging
 import logging
+FORMAT = '%(asctime)s|%(levelname)s[%(name)s:%(lineno)d] %(message)s'
 logging.basicConfig(level=logging.INFO,
 logging.basicConfig(level=logging.INFO,
-                    format='%(asctime)s %(message)s',
+                    format=FORMAT,
                     datefmt='%H:%M:%S')
                     datefmt='%H:%M:%S')
 import signal
 import signal
 
 
@@ -13,9 +15,13 @@ from gevent.queue import Queue
 from gevent.wsgi import WSGIServer
 from gevent.wsgi import WSGIServer
 from mpd import MPDClient
 from mpd import MPDClient
 
 
-from eventutils import ParentedLet, CeleryTask, Timer
-from task import create as create_continous
+from eventutils import ParentedLet, Timer
 import rpc
 import rpc
+from audiogen import generate
+
+CONTINOUS_AUDIODESC = dict(kind='mpd', howmany=1)
+MPD_HOST = os.getenv('MPD_HOST', 'localhost')
+MPD_PORT = int(os.getenv('MPD_PORT', '6600'))
 
 
 
 
 class MpcWatcher(ParentedLet):
 class MpcWatcher(ParentedLet):
@@ -24,13 +30,12 @@ class MpcWatcher(ParentedLet):
         if client is None:
         if client is None:
             self.client = MPDClient()
             self.client = MPDClient()
             # TODO: use config values
             # TODO: use config values
-            self.client.connect("localhost", 6600)
+            self.client.connect(MPD_HOST, MPD_PORT)
         else:
         else:
             self.client = client  # assume it is already connected
             self.client = client  # assume it is already connected
 
 
     def do_business(self):
     def do_business(self):
         while True:
         while True:
-            # status = check_output(['mpc', 'idle']).decode('utf-8').strip()
             status = self.client.idle()[0]
             status = self.client.idle()[0]
             logging.info(status)
             logging.info(status)
             yield ('mpc', status)
             yield ('mpc', status)
@@ -50,8 +55,9 @@ class Player(gevent.Greenlet):
         if(len(songs) >= self.min_playlist_length):
         if(len(songs) >= self.min_playlist_length):
             return
             return
         logging.info('need to add new songs')
         logging.info('need to add new songs')
-        CeleryTask(create_continous, self.q).start()
-        CeleryTask(create_continous, self.q).start()
+        picker = gevent.Greenlet(generate, CONTINOUS_AUDIODESC)
+        picker.link_value(lambda g: mpd_client.add(next(g.value).strip()))
+        picker.start()
 
 
     def _run(self):
     def _run(self):
         MpcWatcher(self.q, client=None).start()
         MpcWatcher(self.q, client=None).start()
@@ -67,8 +73,8 @@ class Player(gevent.Greenlet):
                 logging.info('CLOCK')
                 logging.info('CLOCK')
             if kind == 'timer' or (kind == 'mpc' and args[0] == 'playlist'):
             if kind == 'timer' or (kind == 'mpc' and args[0] == 'playlist'):
                 gevent.Greenlet.spawn(self.check_playlist)
                 gevent.Greenlet.spawn(self.check_playlist)
-            elif kind == 'celery':
-                logging.info("celery: %s" % str(args))
+            elif value['tracker'] == 'mpd_generate':
+                logging.info("generated! %s" % tuple(args[0]))
             else:
             else:
                 logging.warning("Unknown message: %s" % str(value))
                 logging.warning("Unknown message: %s" % str(value))
             logging.info(str(value))
             logging.info(str(value))

+ 0 - 41
larigira/task.py

@@ -1,41 +0,0 @@
-import time
-import logging
-import random
-logging.basicConfig(level=logging.DEBUG,
-                    format='%(asctime)s %(message)s',
-                    datefmt='%H:%M:%S')
-
-from celery import Celery
-
-celery = Celery('hello', backend='redis://localhost',
-                broker='redis://localhost:6379/0')
-
-
-@celery.task(name='create_continous')
-def create():
-    sec = random.uniform(2, 5)
-    time.sleep(sec)
-    logging.info('hello world')
-    return 'slept! %.2f' % sec
-
-if __name__ == '__main__':
-    celery.control.broadcast('pool_restart',
-                             arguments={'reload': True})
-    res = []
-    N = 14
-
-    def callback(*args, **kwargs):
-        print(args)
-        print(kwargs)
-        print('---')
-
-    for i in xrange(N):
-        print('append', i)
-        res.append(create.apply_async(expires=2))
-
-    for i in xrange(N):
-        logging.info('wait %d' % i)
-        val = res[i].get()
-        logging.info('got %s' % str(val))
-
-    time.sleep(30)

+ 9 - 3
setup.py

@@ -1,9 +1,15 @@
 import sys
 import sys
+import os
 
 
 from setuptools import setup
 from setuptools import setup
 from setuptools.command.test import test as TestCommand
 from setuptools.command.test import test as TestCommand
 
 
 
 
+def read(fname):
+    with open(os.path.join(os.path.dirname(__file__), fname)) as buf:
+        return buf.read()
+
+
 class PyTest(TestCommand):
 class PyTest(TestCommand):
     user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")]
     user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")]
 
 
@@ -25,6 +31,7 @@ class PyTest(TestCommand):
 setup(name='larigira',
 setup(name='larigira',
       version='0.1',
       version='0.1',
       description='A radio automation based on MPD',
       description='A radio automation based on MPD',
+      long_description=read('README.rst'),
       author='boyska',
       author='boyska',
       author_email='piuttosto@logorroici.org',
       author_email='piuttosto@logorroici.org',
       license='AGPL',
       license='AGPL',
@@ -32,9 +39,7 @@ setup(name='larigira',
       install_requires=[
       install_requires=[
           'gevent',
           'gevent',
           'flask',
           'flask',
-          'python-mpd2',
-          'redis',
-          'celery'
+          'python-mpd2'
       ],
       ],
       tests_require=['pytest'],
       tests_require=['pytest'],
       cmdclass={'test': PyTest},
       cmdclass={'test': PyTest},
@@ -43,6 +48,7 @@ setup(name='larigira',
           'console_scripts': ['larigira=larigira.mpc:main',
           'console_scripts': ['larigira=larigira.mpc:main',
                               'larigira-audiogen=larigira.audiogen:main'],
                               'larigira-audiogen=larigira.audiogen:main'],
           'larigira.audiogenerators': [
           'larigira.audiogenerators': [
+              'mpd = larigira.audiogen_mpdrandom:generate_by_artist',
               'static = larigira.audiogen_static:generate',
               'static = larigira.audiogen_static:generate',
               'randomdir = larigira.audiogen_randomdir:generate'
               'randomdir = larigira.audiogen_randomdir:generate'
           ]
           ]