forked from rc/aircox
		
	fix stuffs, documentation
This commit is contained in:
		@ -1,3 +1,20 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					Manage diffusions using schedules, to update, clean up or check diffusions.
 | 
				
			||||||
 | 
					A diffusion generated using this utility is considered has type "unconfirmed",
 | 
				
			||||||
 | 
					and is not considered as ready for diffusion; To do so, users must confirm the
 | 
				
			||||||
 | 
					diffusion case by changing it's type to "default".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Different actions are available:
 | 
				
			||||||
 | 
					- "update" is the process that is used to generated them using programs
 | 
				
			||||||
 | 
					schedules for the (given) month.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "clean" will remove all diffusions that are still unconfirmed and have been
 | 
				
			||||||
 | 
					planified before the (given) month.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "check" will remove all diffusions that are unconfirmed and have been planified
 | 
				
			||||||
 | 
					from the (given) month and later.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					from argparse                       import RawTextHelpFormatter
 | 
				
			||||||
from django.core.management.base    import BaseCommand, CommandError
 | 
					from django.core.management.base    import BaseCommand, CommandError
 | 
				
			||||||
from django.utils                   import timezone as tz
 | 
					from django.utils                   import timezone as tz
 | 
				
			||||||
from programs.models                import *
 | 
					from programs.models                import *
 | 
				
			||||||
@ -44,9 +61,11 @@ class Actions:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Command (BaseCommand):
 | 
					class Command (BaseCommand):
 | 
				
			||||||
    help= 'Monitor diffusions'
 | 
					    help= __doc__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def add_arguments (self, parser):
 | 
					    def add_arguments (self, parser):
 | 
				
			||||||
 | 
					        parser.formatter_class=RawTextHelpFormatter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        now = tz.datetime.today()
 | 
					        now = tz.datetime.today()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        group = parser.add_argument_group('action')
 | 
					        group = parser.add_argument_group('action')
 | 
				
			||||||
@ -66,9 +85,7 @@ class Command (BaseCommand):
 | 
				
			|||||||
                   'schedule')
 | 
					                   'schedule')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        group = parser.add_argument_group(
 | 
					        group = parser.add_argument_group(
 | 
				
			||||||
            'date',
 | 
					            'date')
 | 
				
			||||||
            'this information is used by the action, starting at the first (!) '
 | 
					 | 
				
			||||||
                'of the given month')
 | 
					 | 
				
			||||||
        group.add_argument('--year', type=int, default=now.year,
 | 
					        group.add_argument('--year', type=int, default=now.year,
 | 
				
			||||||
                            help='used by update, default is today\'s year')
 | 
					                            help='used by update, default is today\'s year')
 | 
				
			||||||
        group.add_argument('--month', type=int, default=now.month,
 | 
					        group.add_argument('--month', type=int, default=now.month,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,22 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					Check over programs' sound files, scan them, and add them to the
 | 
				
			||||||
 | 
					database if they are not there yet.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It tries to parse the file name to get the date of the diffusion of an
 | 
				
			||||||
 | 
					episode and associate the file with it; We use the following format:
 | 
				
			||||||
 | 
					    yyyymmdd[_n][_][title]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Where:
 | 
				
			||||||
 | 
					    'yyyy' is the year of the episode's diffusion;
 | 
				
			||||||
 | 
					    'mm' is the month of the episode's diffusion;
 | 
				
			||||||
 | 
					    'dd' is the day of the episode's diffusion;
 | 
				
			||||||
 | 
					    'n' is the number of the episode (if multiple episodes);
 | 
				
			||||||
 | 
					    'title' the title of the sound;
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
 | 
					from argparse import RawTextHelpFormatter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.core.management.base    import BaseCommand, CommandError
 | 
					from django.core.management.base    import BaseCommand, CommandError
 | 
				
			||||||
from django.utils                   import timezone
 | 
					from django.utils                   import timezone
 | 
				
			||||||
@ -8,8 +25,7 @@ import programs.settings            as settings
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Command (BaseCommand):
 | 
					class Command (BaseCommand):
 | 
				
			||||||
    help= "Take a look at the programs directory to check on new podcasts"
 | 
					    help= __doc__
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def report (self, program = None, component = None, *content):
 | 
					    def report (self, program = None, component = None, *content):
 | 
				
			||||||
        if not component:
 | 
					        if not component:
 | 
				
			||||||
@ -17,82 +33,71 @@ class Command (BaseCommand):
 | 
				
			|||||||
        else:
 | 
					        else:
 | 
				
			||||||
            print('{}, {}: '.format(program, component), *content)
 | 
					            print('{}, {}: '.format(program, component), *content)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add_arguments (self, parser):
 | 
				
			||||||
 | 
					        parser.formatter_class=RawTextHelpFormatter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def handle (self, *args, **options):
 | 
					    def handle (self, *args, **options):
 | 
				
			||||||
        programs = Program.objects.filter()
 | 
					        programs = Program.objects.filter()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for program in programs:
 | 
					        for program in programs:
 | 
				
			||||||
            self.scan_dir(program, program.path + '/public', public = True)
 | 
					            self.check(program, program.path + '/public', public = True)
 | 
				
			||||||
            self.scan_dir(program, program.path + '/podcasts', embed = True)
 | 
					            self.check(program, program.path + '/podcasts', embed = True)
 | 
				
			||||||
            self.scan_dir(program, program.path + '/private')
 | 
					            self.check(program, program.path + '/private')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_sound_info (self, path):
 | 
				
			||||||
    def ensure_episode (self, program, sound):
 | 
					 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        For a given program, check if there is an episode to associate to.
 | 
					        Parse file name to get info on the assumption it has the correct
 | 
				
			||||||
        This makes the assumption that the name of the file has the following
 | 
					        format (given in Command.help)
 | 
				
			||||||
        format:
 | 
					 | 
				
			||||||
            yyyymmdd[_n][_][title]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Where:
 | 
					 | 
				
			||||||
            yyyy: is the year of the episode's diffusion
 | 
					 | 
				
			||||||
            mm: is the month of the episode's diffusion
 | 
					 | 
				
			||||||
            dd: is the day of the episode's diffusion
 | 
					 | 
				
			||||||
            n: is the number of the episode (if multiple episodes)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        We check against the diffusion rather than the episode's date, because
 | 
					 | 
				
			||||||
        this is the diffusion that defines when the sound will be podcasted for
 | 
					 | 
				
			||||||
        the first time.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        We create the episode if it does not exists only if there is a diffusion
 | 
					 | 
				
			||||||
        matching the date of the sound, in order to respect the hierarchy of
 | 
					 | 
				
			||||||
        episode creation.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        We dont create episode if it does not exists, because only episodes must
 | 
					 | 
				
			||||||
        be created through diffusions
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        TODO: multiple diffusions at the same date
 | 
					 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        path = os.path.basename(sound.path)
 | 
					 | 
				
			||||||
        r = re.search('^(?P<year>[0-9]{4})'
 | 
					        r = re.search('^(?P<year>[0-9]{4})'
 | 
				
			||||||
                      '(?P<month>[0-9]{2})'
 | 
					                      '(?P<month>[0-9]{2})'
 | 
				
			||||||
                      '(?P<day>[0-9]{2})'
 | 
					                      '(?P<day>[0-9]{2})'
 | 
				
			||||||
                      '(_(?P<n>[0-9]+))?'
 | 
					                      '(_(?P<n>[0-9]+))?'
 | 
				
			||||||
                       '_?(?P<name>.*)\.\w+$'
 | 
					                      '_?(?P<name>.*)\.\w+$',
 | 
				
			||||||
                     , path)
 | 
					                      os.path.basename(path))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not r:
 | 
					        if not (r and r.groupdict()):
 | 
				
			||||||
            return
 | 
					            self.report(program, path, "file path is not correct, use defaults")
 | 
				
			||||||
        r = r.groupdict()
 | 
					            r = {
 | 
				
			||||||
 | 
					                'name': os.path.splitext(path)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        r['path'] = path
 | 
				
			||||||
 | 
					        return r
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ensure_sound (self, sound_info):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Return the Sound for the given sound_info; If not found, create it
 | 
				
			||||||
 | 
					        without saving it.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        sound = Sound.objects.filter(path = path)
 | 
				
			||||||
 | 
					        if sound:
 | 
				
			||||||
 | 
					            sound = sound[0]
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            sound = Sound(path = path, title = sound_info['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def find_episode (self, program, sound_info):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        For a given program, and sound path check if there is an episode to
 | 
				
			||||||
 | 
					        associate to, using the diffusion's date.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If there is no matching episode, return None.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
        # check on episodes
 | 
					        # check on episodes
 | 
				
			||||||
        diffusion = Diffusion.objects.filter( program = program
 | 
					        diffusion = Diffusion.objects.filter(
 | 
				
			||||||
                                            , date__year = int(r['year'])
 | 
					            program = program,
 | 
				
			||||||
                                            , date__month = int(r['month'])
 | 
					            date__year = int(sound_info['year']),
 | 
				
			||||||
                                            , date__day = int(r['day'])
 | 
					            date__month = int(sound_info['month']),
 | 
				
			||||||
 | 
					            date__day = int(sound_info['day'])
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not diffusion.count():
 | 
					        if not diffusion.count():
 | 
				
			||||||
            self.report(program, path, 'no diffusion found for the given date')
 | 
					            self.report(program, path, 'no diffusion found for the given date')
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					 | 
				
			||||||
        diffusion = diffusion[0]
 | 
					        diffusion = diffusion[0]
 | 
				
			||||||
        if diffusion.episode:
 | 
					        return diffusion.episode or None
 | 
				
			||||||
            return diffusion.episode
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        episode = Episode( parent = program
 | 
					 | 
				
			||||||
                         , title = r.get('name') \
 | 
					 | 
				
			||||||
                                    .replace('_', ' ') \
 | 
					 | 
				
			||||||
                                    .capitalize()
 | 
					 | 
				
			||||||
                         , date = diffusion.date
 | 
					 | 
				
			||||||
                         )
 | 
					 | 
				
			||||||
        episode.save()
 | 
					 | 
				
			||||||
        if program.tags.all():
 | 
					 | 
				
			||||||
            episode.tags.add(program.tags.all())
 | 
					 | 
				
			||||||
        self.report(program, path, 'episode does not exist, create')
 | 
					 | 
				
			||||||
        return episode
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def scan_dir (self, program, dir_path, public = False, embed = False):
 | 
					    def check (self, program, dir_path, public = False, embed = False):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Scan a given directory that is associated to the given program, and
 | 
					        Scan a given directory that is associated to the given program, and
 | 
				
			||||||
        update sounds information
 | 
					        update sounds information
 | 
				
			||||||
@ -110,27 +115,22 @@ class Command (BaseCommand):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            paths.append(path)
 | 
					            paths.append(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # check for new sound files or update
 | 
					            sound_info = self.get_sound_info(path)
 | 
				
			||||||
            sound = Sound.objects.filter(path = path)
 | 
					            sound = self.ensure_sound(sound_info)
 | 
				
			||||||
            if sound.count():
 | 
					 | 
				
			||||||
                sound = sound[0]
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                sound = Sound(path = path)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # check for the corresponding episode:
 | 
					            sound.public = public
 | 
				
			||||||
            episode = self.ensure_episode(program, sound)
 | 
					 | 
				
			||||||
            if not episode:
 | 
					 | 
				
			||||||
                continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            sound.save()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # episode and relation
 | 
				
			||||||
 | 
					            if 'year' in sound_info:
 | 
				
			||||||
 | 
					                episode = self.find_episode(program, sound_info)
 | 
				
			||||||
 | 
					                if episode:
 | 
				
			||||||
                    for sound_ in episode.sounds.get_queryset():
 | 
					                    for sound_ in episode.sounds.get_queryset():
 | 
				
			||||||
                        if sound_.path == sound.path:
 | 
					                        if sound_.path == sound.path:
 | 
				
			||||||
                    continue
 | 
					                            break
 | 
				
			||||||
 | 
					                    else:
 | 
				
			||||||
            self.report(program, path, 'associate sound to episode '
 | 
					                        self.report(program, path, 'associate sound to episode ',
 | 
				
			||||||
                       , episode.id)
 | 
					                                    episode.id)
 | 
				
			||||||
                        episode.sounds.add(sound)
 | 
					                        episode.sounds.add(sound)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        return paths
 | 
					        return paths
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user