1 from datetime
import datetime
2 from optparse
import make_option
3 from collections
import Counter
5 from django
.core
.management
.base
import BaseCommand
7 from couchdbkit
.exceptions
import ResourceNotFound
8 from couchdbkit
import Consumer
10 from mygpo
.core
.models
import Podcast
, PodcastGroup
, Episode
11 from mygpo
.core
.slugs
import EpisodeSlug
, EpisodesMissingSlugs
12 from mygpo
.decorators
import repeat_on_conflict
13 from mygpo
.utils
import progress
14 from mygpo
.db
.couchdb
import get_main_database
15 from mygpo
.maintenance
.models
import CommandStatus
, CommandRunStatus
16 from mygpo
.db
.couchdb
.podcast
import podcast_by_id
19 class Command(BaseCommand
):
21 option_list
= BaseCommand
.option_list
+ (
22 make_option('--since', action
='store', type=int, dest
='since',
23 default
=0, help="Where to start the operation"),
25 make_option('--continue', action
='store_true', dest
='continue',
26 default
=False, help="Continue from last sequence number"),
28 make_option('--silent', action
='store_true', dest
='silent',
29 default
=False, help="Don't display any progress output"),
33 def handle(self
, *args
, **options
):
35 db
= get_main_database()
36 status
= self
.get_cmd_status()
37 since
= self
.get_since(status
, options
)
38 objects
= self
.get_objects(db
, since
)
42 # create unfinished command run status
43 run_status
= CommandRunStatus()
44 run_status
.timestamp_started
= datetime
.utcnow()
45 run_status
.start_seq
= since
46 # add it to existing one (if any)
47 status
.runs
.append(run_status
)
50 total
= db
.info()['update_seq']
52 has_slug
= lambda x
: bool(x
.slug
)
54 for seq
, obj
in objects
:
55 total
= db
.info()['update_seq']
57 if isinstance(obj
, PodcastGroup
):
58 podcasts
= filter(has_slug
, obj
.podcasts
)
60 if isinstance(obj
, Podcast
):
61 podcasts
= filter(has_slug
, [obj
])
63 elif isinstance(obj
, Episode
):
67 podcast
= podcast_by_id(obj
.podcast
)
70 podcasts
= filter(has_slug
, [podcast
])
72 updated
= self
.handle_podcasts(podcasts
)
73 actions
['updated'] += updated
75 if not options
['silent']:
76 status_str
= ', '.join('%s: %d' % x
for x
in actions
.items())
77 progress(seq
, total
, status_str
)
80 # finish command run status
81 run_status
.timestamp_finished
= datetime
.utcnow()
82 run_status
.end_seq
= total
83 run_status
.status_counter
= dict(actions
)
84 # and overwrite existing one (we could keep a longer log here)
85 status
.runs
= [run_status
]
90 def handle_podcasts(self
, podcasts
):
93 for podcast
in podcasts
:
94 common_title
= podcast
.get_common_episode_title()
95 episodes
= EpisodesMissingSlugs(podcast
.get_id())
97 for episode
in episodes
:
98 slug
= EpisodeSlug(episode
, common_title
).get_slug()
101 self
.update_obj(obj
=episode
, slug
=slug
)
106 @repeat_on_conflict(['obj'])
107 def update_obj(self
, obj
, slug
):
113 def get_objects(db
, since
=0, limit
=1, timeout
=1000):
114 consumer
= Consumer(db
)
117 resp
= consumer
.wait_once(since
=since
, limit
=limit
, timeout
=timeout
,
118 include_docs
=True, filter='slugs/slug_objects')
119 results
= resp
['results']
125 cls
= (PodcastGroup
, Podcast
, Episode
)
126 classes
= dict( (c
._doc
_type
, c
) for c
in cls
)
129 doc_type
= doc
['doc_type']
131 c
= classes
[doc_type
]
132 yield seq
, c
.wrap(doc
)
134 since
= resp
['last_seq']
138 def get_cmd_status():
140 status
= CommandStatus
.get('episode-slug-status')
141 except ResourceNotFound
:
142 status
= CommandStatus()
143 status
.command
= 'Episode-Slug-Update'
144 status
._id
= 'episode-slug-status'
150 def get_since(status
, options
):
151 if options
['continue']:
152 return status
.last_seq
154 return options
['since']