General A/B testing.
[wolnelektury.git] / src / catalogue / helpers.py
index b48c483..796ed04 100644 (file)
@@ -1,22 +1,22 @@
-# -*- coding: utf-8 -*-
 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
 from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
 from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
-from django.db.models import Count
+from django.core.cache import cache
+
 from .models import Tag, Book
 from os.path import getmtime
 from .models import Tag, Book
 from os.path import getmtime
-import cPickle
+import pickle
 from collections import defaultdict
 
 
 from collections import defaultdict
 
 
-
 BOOK_CATEGORIES = ('author', 'epoch', 'genre', 'kind')
 
 BOOK_CATEGORIES = ('author', 'epoch', 'genre', 'kind')
 
-
 _COUNTERS = None
 _COUNTERS = None
-_COUNTER_TIME = None
+_COUNTER_TIME = 0
+
+
 def get_top_level_related_tags(tags, categories=None):
     """
     Finds tags related to given tags through books, and counts their usage.
 def get_top_level_related_tags(tags, categories=None):
     """
     Finds tags related to given tags through books, and counts their usage.
@@ -27,8 +27,17 @@ def get_top_level_related_tags(tags, categories=None):
     global _COUNTERS, _COUNTER_TIME
     # First, check that we have a valid and recent version of the counters.
     if getmtime(settings.CATALOGUE_COUNTERS_FILE) > _COUNTER_TIME:
     global _COUNTERS, _COUNTER_TIME
     # First, check that we have a valid and recent version of the counters.
     if getmtime(settings.CATALOGUE_COUNTERS_FILE) > _COUNTER_TIME:
-        with open(settings.CATALOGUE_COUNTERS_FILE) as f:
-            _COUNTERS = cPickle.load(f)
+        for i in range(10):
+            try:
+                with open(settings.CATALOGUE_COUNTERS_FILE, 'rb') as f:
+                    _COUNTERS = pickle.load(f)
+            except (EOFError, ValueError):
+                if i < 9:
+                    continue
+                else:
+                    raise
+            else:
+                break
 
     tagids = tuple(sorted(t.pk for t in tags))
     try:
 
     tagids = tuple(sorted(t.pk for t in tags))
     try:
@@ -38,7 +47,6 @@ def get_top_level_related_tags(tags, categories=None):
 
     related = Tag.objects.filter(pk__in=related_ids)
 
 
     related = Tag.objects.filter(pk__in=related_ids)
 
-    # TODO: do we really need that?
     if categories is not None:
         related = related.filter(category__in=categories)
 
     if categories is not None:
         related = related.filter(category__in=categories)
 
@@ -46,8 +54,6 @@ def get_top_level_related_tags(tags, categories=None):
         tag.count = _COUNTERS['count'][tuple(sorted(tagids + (tag.pk,)))]
         yield tag
 
         tag.count = _COUNTERS['count'][tuple(sorted(tagids + (tag.pk,)))]
         yield tag
 
-    #~ return related
-
 
 def update_counters():
     def combinations(things):
 
 def update_counters():
     def combinations(things):
@@ -61,7 +67,7 @@ def update_counters():
     def count_for_book(book, count_by_combination=None, parent_combinations=None):
         if not parent_combinations:
             parent_combinations = set()
     def count_for_book(book, count_by_combination=None, parent_combinations=None):
         if not parent_combinations:
             parent_combinations = set()
-        tags = sorted(tuple(t.pk for t in book.tags.filter(category__in=('author', 'genre', 'epoch', 'kind'))))
+        tags = sorted(book.tags.filter(category__in=('author', 'genre', 'epoch', 'kind')).values_list('pk', flat=True))
         combs = list(combinations(tags))
         for c in combs:
             if c not in parent_combinations:
         combs = list(combinations(tags))
         for c in combs:
             if c not in parent_combinations:
@@ -88,5 +94,18 @@ def update_counters():
         "next": dict(next_combinations),
     }
 
         "next": dict(next_combinations),
     }
 
-    with open(settings.CATALOGUE_COUNTERS_FILE, 'w') as f:
-        cPickle.dump(counters, f)
+    with open(settings.CATALOGUE_COUNTERS_FILE, 'wb') as f:
+        pickle.dump(counters, f)
+
+
+def get_audiobook_tags():
+    audiobook_tag_ids = cache.get('audiobook_tags')
+    if audiobook_tag_ids is None:
+        books_with_audiobook = Book.objects.filter(media__type__in=('mp3', 'ogg'))\
+            .distinct().values_list('pk', flat=True)
+        audiobook_tag_ids = Tag.objects.filter(
+            items__content_type=ContentType.objects.get_for_model(Book),
+            items__object_id__in=list(books_with_audiobook)).distinct().values_list('pk', flat=True)
+        audiobook_tag_ids = list(audiobook_tag_ids)
+        cache.set('audiobook_tags', audiobook_tag_ids)
+    return audiobook_tag_ids