1 from collections
import defaultdict
3 from itertools
import count
5 from couchdbkit
.ext
.django
.schema
import *
7 from django
.utils
.text
import slugify
9 from mygpo
.podcasts
.models
import Slug
10 from mygpo
.decorators
import repeat_on_conflict
11 from mygpo
.utils
import partition
14 # TODO: move to feed-downloader?
15 def assign_missing_episode_slugs(podcast
):
16 common_title
= podcast
.get_common_episode_title()
18 episodes
= Episode
.objects
.filter(podcast
=podcast
, slug__isnull
=True)
20 for episode
in episodes
:
21 slug
= EpisodeSlug(episode
, common_title
).get_slug()
22 episode
.set_slug(slug
)
25 class SlugGenerator(object):
26 """ Generates a unique slug for an object """
29 def __init__(self
, obj
, override_existing
=False):
30 if obj
.slug
and not override_existing
:
31 raise ValueError('%(obj)s already has slug %(slug)s' % \
32 dict(obj
=obj
, slug
=obj
.slug
))
34 self
.base_slug
= self
._get
_base
_slug
(obj
)
38 def _get_base_slug(obj
):
41 base_slug
= slugify(obj
.title
)
46 def _get_existing_slugs():
51 """ Gets existing slugs and appends numbers until slug is unique """
52 if not self
.base_slug
:
55 existing_slugs
= self
._get
_existing
_slugs
()
57 if not self
.base_slug
in existing_slugs
:
58 return str(self
.base_slug
)
61 tmp_slug
= '%s-%d' % (self
.base_slug
, n
)
62 if not tmp_slug
in existing_slugs
:
63 # slugify returns SafeUnicode, we need a plain string
68 class PodcastGroupSlug(SlugGenerator
):
69 """ Generates slugs for Podcast Groups """
71 def _get_existing_slugs(self
):
72 query
= Slug
.objects
.filter(scope__isnull
=True,
73 slug__startswith
=self
.base_slug
)
74 return [s
['slug'] for s
in query
]
78 class PodcastSlug(PodcastGroupSlug
):
79 """ Generates slugs for Podcasts """
82 def _get_base_slug(podcast
):
83 base_slug
= SlugGenerator
._get
_base
_slug
(podcast
)
88 # append group_member_name to slug
89 if podcast
.group_member_name
:
90 member_slug
= slugify(podcast
.group_member_name
)
91 if member_slug
and not member_slug
in base_slug
:
92 base_slug
= '%s-%s' % (base_slug
, member_slug
)
98 class EpisodeSlug(SlugGenerator
):
99 """ Generates slugs for Episodes """
101 def __init__(self
, episode
, common_title
, override_existing
=False):
102 self
.common_title
= common_title
103 super(EpisodeSlug
, self
).__init
__(episode
, override_existing
)
104 self
.podcast_id
= episode
.podcast
107 def _get_base_slug(self
, obj
):
109 number
= obj
.get_episode_number(self
.common_title
)
113 short_title
= obj
.get_short_title(self
.common_title
)
115 return slugify(short_title
)
118 return slugify(obj
.title
)
123 def _get_existing_slugs(self
):
124 """ Episode slugs have to be unique within the Podcast """
125 query
= Slug
.objects
.filter(scope
=self
.podcast_id
,
126 slug__startswith
=self
.base_slug
)
127 return [s
['slug'] for s
in query
]
130 class SlugMixin(DocumentSchema
):
131 slug
= StringProperty()
132 merged_slugs
= StringListProperty()
134 def set_slug(self
, slug
):
135 """ Set the main slug of the object """
138 self
.merged_slugs
.append(self
.slug
)
140 self
.merged_slugs
= list(set(self
.merged_slugs
) - set([slug
]))
145 def remove_slug(self
, slug
):
146 """ Removes the slug from the object """
149 if self
.slug
== slug
:
152 # remove from merged slugs
153 self
.merged_slugs
= list(set(self
.merged_slugs
) - set([slug
]))