2 # This file is part of my.gpodder.org.
4 # my.gpodder.org is free software: you can redistribute it and/or modify it
5 # under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or (at your
7 # option) any later version.
9 # my.gpodder.org is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
12 # License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with my.gpodder.org. If not, see <http://www.gnu.org/licenses/>.
18 from mygpo
.api
.models
import ToplistEntry
, Podcast
, Subscription
, EpisodeToplistEntry
19 from mygpo
.data
.mimetype
import get_type
, CONTENT_TYPES
20 from datetime
import timedelta
25 # Python 2.5 seems to have a different json module
26 if not 'dumps' in dir(json
):
33 def get_podcasts_for_languages(languages
=None, podcast_query
=Podcast
.objects
.all()):
35 return Podcast
.objects
.all()
37 regex
= '^(' + '|'.join(languages
) + ')'
38 return podcast_query
.filter(language__regex
=regex
)
41 def get_toplist(count
, languages
=None, types
=None):
43 Returns count podcasts with the most subscribers (individual users)
44 If languages is given as an array of 2-character languages codes, only
45 podcasts with the given languages are considered
47 For language-specific lists the entries' oldplace attribute is calculated
48 based on the same language list
51 # if we include all "known" types, ignore this criteria
52 # this will then include all types, also unknown ones
53 if types
and len(types
) == len(CONTENT_TYPES
):
56 if not languages
and not types
:
57 return ToplistEntry
.objects
.all()[:count
]
59 podcast_entries_base
= ToplistEntry
.objects
.all()
60 group_entries_base
= ToplistEntry
.objects
.all()
63 lang_regex
= '^(' + '|'.join(languages
) + ')'
64 podcast_entries_base
= podcast_entries_base
.filter(podcast__language__regex
=lang_regex
)
65 group_entries_base
= group_entries_base
.filter(podcast_group__podcast__language__regex
=lang_regex
).distinct()
68 type_regex
= '.*(' + '|'.join(types
) + ').*'
69 podcast_entries_base
= podcast_entries_base
.filter(podcast__content_types__regex
=type_regex
)
70 group_entries_base
= group_entries_base
.filter(podcast_group__podcast__content_types__regex
=type_regex
).distinct()
73 old_podcast_entries
= list(podcast_entries_base
.exclude(oldplace
=0).order_by('oldplace')[:count
])
74 old_group_entries
= list(group_entries_base
.exclude(oldplace
=0).order_by('oldplace')[:count
])
75 old_list
= merge_toplists(old_podcast_entries
, old_group_entries
, lambda x
: x
.oldplace
, reverse
=False)
76 old_items
= [e
.get_item() for e
in old_list
]
78 podcast_entries
= podcast_entries_base
.order_by('-subscriptions')[:count
]
79 group_entries
= group_entries_base
.order_by('-subscriptions')[:count
]
80 cur_list
= merge_toplists(podcast_entries
, group_entries
, lambda x
: x
.subscriptions
, reverse
=True, count
=count
)
83 x
.oldplace
= old_items
.index(x
.get_item())+1 if x
.get_item() in old_items
else 0
87 def get_episode_toplist(count
, languages
=None, types
=None):
88 """Returns the first num entries of the episode toplist with the given search criteria"""
90 # if we include all "known" types, ignore this criteria
91 # this will then include all types, also unknown ones
92 if types
and len(types
) == len(CONTENT_TYPES
):
95 entries
= EpisodeToplistEntry
.objects
.all()
98 regex
= '^(' + '|'.join(languages
) + ')'
99 entries
= entries
.filter(episode__podcast__language__regex
=regex
)
102 # we can just use a regex here, because searching for the right "type" of an
103 # episode is more complex; we first look for all podcasts with the right type
104 # and then look through their episodes
105 type_regex
= '.*(' + '|'.join(types
) + ').*'
106 entries
= entries
.filter(episode__podcast__content_types__regex
=type_regex
)
109 if e
.episode
.mimetype
and get_type(e
.episode
.mimetype
) in types
:
112 if len(entry_list
) >= count
:
115 return entries
[:count
]
118 def merge_toplists(podcast_entries
, group_entries
, sortkey
, reverse
, count
=None):
120 merges a podcast- and a group toplist based on the given sortkey
122 entries
= list(podcast_entries
)
123 entries
.extend(group_entries
)
124 entries
.sort(key
=sortkey
, reverse
=reverse
)
126 entries
= entries
[:count
]
130 def get_random_picks(languages
=None, recent_days
=timedelta(days
=7)):
131 # threshold = datetime.today() - recent_days
133 all_podcasts
= Podcast
.objects
.all().exclude(title
='').order_by('?')
134 lang_podcasts
= get_podcasts_for_languages(languages
, all_podcasts
)
135 # recent_podcasts = lang_podcasts.annotate(latest_release=Max('episode__timestamp')).filter(latest_release__gt=threshold)
137 # if recent_podcasts.count() > 0:
138 # return recent_podcasts
140 if lang_podcasts
.count() > 0:
146 def get_all_subscriptions(user
):
147 return set([s
.podcast
for s
in Subscription
.objects
.filter(user
=user
)])
149 def get_public_subscriptions(user
):
150 subscriptions
= [s
for s
in Subscription
.objects
.filter(user
=user
)]
151 public_subscriptions
= set([s
.podcast
for s
in subscriptions
if s
.get_meta().public
])
152 return public_subscriptions