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 django
.db
.models
import Max
21 from datetime
import datetime
, timedelta
27 # Python 2.5 seems to have a different json module
28 if not 'dumps' in dir(json
):
35 def get_podcasts_for_languages(languages
=None, podcast_query
=Podcast
.objects
.all()):
37 return Podcast
.objects
.all()
39 regex
= '^(' + '|'.join(languages
) + ')'
40 return podcast_query
.filter(language__regex
=regex
)
43 def get_toplist(count
, languages
=None, types
=None):
45 Returns count podcasts with the most subscribers (individual users)
46 If languages is given as an array of 2-character languages codes, only
47 podcasts with the given languages are considered
49 For language-specific lists the entries' oldplace attribute is calculated
50 based on the same language list
53 # if we include all "known" types, ignore this criteria
54 # this will then include all types, also unknown ones
55 if types
and len(types
) == len(CONTENT_TYPES
):
58 if not languages
and not types
:
59 return ToplistEntry
.objects
.all()[:count
]
61 podcast_entries_base
= ToplistEntry
.objects
.all()
62 group_entries_base
= ToplistEntry
.objects
.all()
65 lang_regex
= '^(' + '|'.join(languages
) + ')'
66 podcast_entries_base
= podcast_entries_base
.filter(podcast__language__regex
=lang_regex
)
67 group_entries_base
= group_entries_base
.filter(podcast_group__podcast__language__regex
=lang_regex
).distinct()
70 type_regex
= '.*(' + '|'.join(types
) + ').*'
71 podcast_entries_base
= podcast_entries_base
.filter(podcast__content_types__regex
=type_regex
)
72 group_entries_base
= group_entries_base
.filter(podcast_group__podcast__content_types__regex
=type_regex
).distinct()
75 old_podcast_entries
= list(podcast_entries_base
.exclude(oldplace
=0).order_by('oldplace')[:count
])
76 old_group_entries
= list(group_entries_base
.exclude(oldplace
=0).order_by('oldplace')[:count
])
77 old_list
= merge_toplists(old_podcast_entries
, old_group_entries
, lambda x
: x
.oldplace
, reverse
=False)
78 old_items
= [e
.get_item() for e
in old_list
]
80 podcast_entries
= podcast_entries_base
.order_by('-subscriptions')[:count
]
81 group_entries
= group_entries_base
.order_by('-subscriptions')[:count
]
82 cur_list
= merge_toplists(podcast_entries
, group_entries
, lambda x
: x
.subscriptions
, reverse
=True, count
=count
)
85 x
.oldplace
= old_items
.index(x
.get_item())+1 if x
.get_item() in old_items
else 0
89 def get_episode_toplist(count
, languages
=None, types
=None):
90 """Returns the first num entries of the episode toplist with the given search criteria"""
92 # if we include all "known" types, ignore this criteria
93 # this will then include all types, also unknown ones
94 if types
and len(types
) == len(CONTENT_TYPES
):
97 entries
= EpisodeToplistEntry
.objects
.all()
100 regex
= '^(' + '|'.join(languages
) + ')'
101 entries
= entries
.filter(episode__podcast__language__regex
=regex
)
104 # we can just use a regex here, because searching for the right "type" of an
105 # episode is more complex; we first look for all podcasts with the right type
106 # and then look through their episodes
107 type_regex
= '.*(' + '|'.join(types
) + ').*'
108 entries
= entries
.filter(episode__podcast__content_types__regex
=type_regex
)
111 if e
.episode
.mimetype
and get_type(e
.episode
.mimetype
) in types
:
114 if len(entry_list
) >= count
:
117 return entries
[:count
]
120 def merge_toplists(podcast_entries
, group_entries
, sortkey
, reverse
, count
=None):
122 merges a podcast- and a group toplist based on the given sortkey
124 entries
= list(podcast_entries
)
125 entries
.extend(group_entries
)
126 entries
.sort(key
=sortkey
, reverse
=reverse
)
128 entries
= entries
[:count
]
132 def get_random_picks(languages
=None, recent_days
=timedelta(days
=7)):
133 # threshold = datetime.today() - recent_days
135 all_podcasts
= Podcast
.objects
.all().exclude(title
='').order_by('?')
136 lang_podcasts
= get_podcasts_for_languages(languages
, all_podcasts
)
137 # recent_podcasts = lang_podcasts.annotate(latest_release=Max('episode__timestamp')).filter(latest_release__gt=threshold)
139 # if recent_podcasts.count() > 0:
140 # return recent_podcasts
142 if lang_podcasts
.count() > 0:
148 def get_all_subscriptions(user
):
149 return set([s
.podcast
for s
in Subscription
.objects
.filter(user
=user
)])
151 def get_public_subscriptions(user
):
152 subscriptions
= [s
for s
in Subscription
.objects
.filter(user
=user
)]
153 public_subscriptions
= set([s
.podcast
for s
in subscriptions
if s
.get_meta().public
])
154 return public_subscriptions