forked from rc/aircox
		
	lot of fixes and updates, add diffusion monitor and so on
This commit is contained in:
		
							
								
								
									
										91
									
								
								programs/management/commands/diffusions_monitor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								programs/management/commands/diffusions_monitor.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,91 @@
 | 
				
			|||||||
 | 
					from django.core.management.base    import BaseCommand, CommandError
 | 
				
			||||||
 | 
					from django.utils                   import timezone as tz
 | 
				
			||||||
 | 
					from programs.models                import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Actions:
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def update (date):
 | 
				
			||||||
 | 
					        items = []
 | 
				
			||||||
 | 
					        for schedule in Schedule.objects.filter(parent__active = True):
 | 
				
			||||||
 | 
					            items += schedule.diffusions_of_month(date, exclude_saved = True)
 | 
				
			||||||
 | 
					            print('> {} new diffusions for schedule #{} ({})'.format(
 | 
				
			||||||
 | 
					                    len(items), schedule.id, str(schedule)
 | 
				
			||||||
 | 
					                  ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        print('total of {} diffusions will be created. To be used, they need '
 | 
				
			||||||
 | 
					              'manual approval.'.format(len(items)))
 | 
				
			||||||
 | 
					        print(Diffusion.objects.bulk_create(items))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def clean (date):
 | 
				
			||||||
 | 
					        qs = Diffusion.objects.filter(type = Diffusion.Type['unconfirmed'],
 | 
				
			||||||
 | 
					                                      date__lt = date)
 | 
				
			||||||
 | 
					        print('{} diffusions will be removed'.format(qs.count()))
 | 
				
			||||||
 | 
					        qs.delete()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def check (date):
 | 
				
			||||||
 | 
					        qs = Diffusion.objects.filter(type = Diffusion.Type['unconfirmed'],
 | 
				
			||||||
 | 
					                                      date__gt = date)
 | 
				
			||||||
 | 
					        items = []
 | 
				
			||||||
 | 
					        for diffusion in qs:
 | 
				
			||||||
 | 
					            schedules = Schedule.objects.filter(parent = diffusion.program)
 | 
				
			||||||
 | 
					            for schedule in schedules:
 | 
				
			||||||
 | 
					                if schedule.match(diffusion.date):
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                print('> #{}: {}'.format(diffusion.date, str(diffusion)))
 | 
				
			||||||
 | 
					                items.append(diffusion.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        print('{} diffusions will be removed'.format(len(items)))
 | 
				
			||||||
 | 
					        if len(items):
 | 
				
			||||||
 | 
					            Diffusion.objects.filter(id__in = items).delete()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Command (BaseCommand):
 | 
				
			||||||
 | 
					    help= 'Monitor diffusions'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add_arguments (self, parser):
 | 
				
			||||||
 | 
					        now = tz.datetime.today()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        group = parser.add_argument_group('action')
 | 
				
			||||||
 | 
					        group.add_argument(
 | 
				
			||||||
 | 
					            '--update', action='store_true',
 | 
				
			||||||
 | 
					            help = 'generate (unconfirmed) diffusions for the given month. '
 | 
				
			||||||
 | 
					                   'These diffusions must be confirmed manually by changing '
 | 
				
			||||||
 | 
					                   'their type to "normal"')
 | 
				
			||||||
 | 
					        group.add_argument(
 | 
				
			||||||
 | 
					            '--clean', action='store_true',
 | 
				
			||||||
 | 
					            help = 'remove unconfirmed diffusions older than the given month')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        group.add_argument(
 | 
				
			||||||
 | 
					            '--check', action='store_true',
 | 
				
			||||||
 | 
					            help = 'check future unconfirmed diffusions from the given date '
 | 
				
			||||||
 | 
					                   'agains\'t schedules and remove it if that do not match any '
 | 
				
			||||||
 | 
					                   'schedule')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        group = parser.add_argument_group(
 | 
				
			||||||
 | 
					            '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,
 | 
				
			||||||
 | 
					                            help='used by update, default is today\'s year')
 | 
				
			||||||
 | 
					        group.add_argument('--month', type=int, default=now.month,
 | 
				
			||||||
 | 
					                            help='used by update, default is today\'s month')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def handle (self, *args, **options):
 | 
				
			||||||
 | 
					        date = tz.datetime(year = options.get('year'),
 | 
				
			||||||
 | 
					                                 month = options.get('month'),
 | 
				
			||||||
 | 
					                                 day = 1)
 | 
				
			||||||
 | 
					        date = tz.make_aware(date)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if options.get('update'):
 | 
				
			||||||
 | 
					            Actions.update(date)
 | 
				
			||||||
 | 
					        elif options.get('clean'):
 | 
				
			||||||
 | 
					            Actions.clean(date)
 | 
				
			||||||
 | 
					        elif options.get('check'):
 | 
				
			||||||
 | 
					            Actions.check(date)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            raise CommandError('no action has been given')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										136
									
								
								programs/management/commands/sounds_monitor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								programs/management/commands/sounds_monitor.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,136 @@
 | 
				
			|||||||
 | 
					import os
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.core.management.base    import BaseCommand, CommandError
 | 
				
			||||||
 | 
					from django.utils                   import timezone
 | 
				
			||||||
 | 
					from programs.models                import *
 | 
				
			||||||
 | 
					import programs.settings            as settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Command (BaseCommand):
 | 
				
			||||||
 | 
					    help= "Take a look at the programs directory to check on new podcasts"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def report (self, program = None, component = None, *content):
 | 
				
			||||||
 | 
					        if not component:
 | 
				
			||||||
 | 
					            print('{}: '.format(program), *content)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            print('{}, {}: '.format(program, component), *content)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def handle (self, *args, **options):
 | 
				
			||||||
 | 
					        programs = Program.objects.filter()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for program in programs:
 | 
				
			||||||
 | 
					            self.scan_dir(program, program.path + '/public', public = True)
 | 
				
			||||||
 | 
					            self.scan_dir(program, program.path + '/podcasts', embed = True)
 | 
				
			||||||
 | 
					            self.scan_dir(program, program.path + '/private')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ensure_episode (self, program, sound):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        For a given program, check if there is an episode to associate to.
 | 
				
			||||||
 | 
					        This makes the assumption that the name of the file has 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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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})'
 | 
				
			||||||
 | 
					                       '(?P<month>[0-9]{2})'
 | 
				
			||||||
 | 
					                       '(?P<day>[0-9]{2})'
 | 
				
			||||||
 | 
					                       '(_(?P<n>[0-9]+))?'
 | 
				
			||||||
 | 
					                       '_?(?P<name>.*)\.\w+$'
 | 
				
			||||||
 | 
					                     , path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not r:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        r = r.groupdict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # check on episodes
 | 
				
			||||||
 | 
					        diffusion = Diffusion.objects.filter( program = program
 | 
				
			||||||
 | 
					                                            , date__year = int(r['year'])
 | 
				
			||||||
 | 
					                                            , date__month = int(r['month'])
 | 
				
			||||||
 | 
					                                            , date__day = int(r['day'])
 | 
				
			||||||
 | 
					                                            )
 | 
				
			||||||
 | 
					        if not diffusion.count():
 | 
				
			||||||
 | 
					            self.report(program, path, 'no diffusion found for the given date')
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        diffusion = diffusion[0]
 | 
				
			||||||
 | 
					        if diffusion.episode:
 | 
				
			||||||
 | 
					            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):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Scan a given directory that is associated to the given program, and
 | 
				
			||||||
 | 
					        update sounds information
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Return a list of scanned sounds
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if not os.path.exists(dir_path):
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        paths = []
 | 
				
			||||||
 | 
					        for path in os.listdir(dir_path):
 | 
				
			||||||
 | 
					            path = dir_path + '/' + path
 | 
				
			||||||
 | 
					            if not path.endswith(settings.AIRCOX_SOUNDFILE_EXT):
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            paths.append(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # check for new sound files or update
 | 
				
			||||||
 | 
					            sound = Sound.objects.filter(path = path)
 | 
				
			||||||
 | 
					            if sound.count():
 | 
				
			||||||
 | 
					                sound = sound[0]
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                sound = Sound(path = path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # check for the corresponding episode:
 | 
				
			||||||
 | 
					            episode = self.ensure_episode(program, sound)
 | 
				
			||||||
 | 
					            if not episode:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            sound.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for sound_ in episode.sounds.get_queryset():
 | 
				
			||||||
 | 
					                if sound_.path == sound.path:
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.report(program, path, 'associate sound to episode '
 | 
				
			||||||
 | 
					                       , episode.id)
 | 
				
			||||||
 | 
					            episode.sounds.add(sound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return paths
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Reference in New Issue
	
	Block a user