class VodListSerializer(ModelSerializer):
    image = SerializerMethodField()
    category = SerializerMethodField()
    definition = SerializerMethodField()

    class Meta:
        model = Vod
        fields = [
            'id',
            'title',
            'image',
            'category',
            'definition',
            'duration',
            'slug',
        ]

    @try_or_error
    def get_definition(self, obj):
        return obj.get_definition_display()

    @try_or_error
    def get_category(self, obj):
        return obj.category.name

    @try_or_error
    def get_image(self, obj):
        thumb_url = get_thumbnailer(obj.image)['avatar'].url
        return thumb_url class VodDetailSerializer(ModelSerializer):
    """
    VodDetailSerializer doc

    """
    definition = SerializerMethodField()
    category = serializers.SlugRelatedField(
        read_only=True,
        slug_field='name'
    )
    video_list = VodDetailSubSetSerializer(many=True)

    class Meta:
        model = Vod
        fields = [
            'title',
            'image',
            'video',
            'category',
            'description',
            'definition',
            'video_list'
        ]

    def get_category(self, obj):
        return str(obj.category)

    def get_definition(self, obj):
        return obj.get_definition_display() class CategoryListSerializer(ModelSerializer):
    class Meta:
        model = VideoCategory
        fields = ['name'] class RegionListSerializer(ModelSerializer):
    class Meta:
        model = VideoRegion
        fields = ['name'] class VodHomeListSerializer(ModelSerializer):
    image = SerializerMethodField()
    category = SerializerMethodField()
    definition = SerializerMethodField()

    class Meta:
        model = Vod
        fields = [
            'id',
            'title',
            'image',
            'category',
            'definition',
            'duration',
            'slug',
        ]

    @try_or_error
    def get_definition(self, obj):
        return obj.get_definition_display()

    @try_or_error
    def get_category(self, obj):
        return obj.category.name

    @try_or_error
    def get_image(self, obj):
        thumb_url = get_thumbnailer(obj.image)['big_avatar'].url
        return thumb_url class Vod(models.Model):
    title = models.CharField(max_length=120, verbose_name='标题')
    # image = models.ImageField(upload_to=upload_image_location, null=True, blank=True)
    # video = models.FileField(null=True,blank=True,storage=VodStorage())
    image = ModelAdminResumableImageField(null=True, blank=True, storage=VodStorage(), max_length=1000,
                                          verbose_name='缩略图')
    video = ModelAdminResumableFileField(null=True, blank=True, storage=VodStorage(), max_length=1000,
                                         verbose_name='视频')
    duration = models.CharField(max_length=50, blank=True, null=True, verbose_name='时长')
    local_video = models.FilePathField(path=settings.LOCAL_MEDIA_ROOT, blank=True, recursive=True)
    definition = models.CharField(max_length=10, choices=VIDEO_QUALITY, blank=False, default='H', verbose_name='清晰度')
    category = models.ForeignKey(VideoCategory, null=True, blank=True, verbose_name='分类')
    save_path = models.CharField(max_length=128, blank=False, null=True, default='default', verbose_name='保存路径')  # ,default=FileDirectory.objects.first())
    year = models.CharField(max_length=10, blank=False, null=True, default=datetime.datetime.now().year, verbose_name='年份')
    region = models.ForeignKey(VideoRegion, to_field='name', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='地区')
    file_size = models.CharField(max_length=128, default='0B', editable=False, verbose_name='文件大小')
    view_count = models.IntegerField(default=0, verbose_name='观看次数')
    view_count_temp = 0
    creator = models.ForeignKey(User, null=True, blank=False, editable=False)
    description = models.TextField(blank=True, verbose_name='简介')
    select_name = models.CharField(max_length=100, blank=False, verbose_name='选集名称', default='1')
    updated = models.DateTimeField(auto_now=True, auto_now_add=False)
    timestamp = models.DateTimeField(auto_now=False, auto_now_add=True, verbose_name='创建时间')  # The first time added
    slug = models.SlugField(unique=True, blank=True)
    search_word = models.CharField(max_length=10000, null=True, blank=True)
    # tags = models.ManyToManyField(VideoTag, blank=True)
    video_list = SortedManyToManyField('self', blank=True)
    # video_list = models.ManyToManyField('self', blank=True, symmetrical=False)
    active = models.IntegerField(null=True, blank=False, default=0, choices=((1, 'Yes'), (0, 'No')))
    progress = models.IntegerField(null=True, blank=True, default=0)
    objects = VodManager()

    class Meta:
        verbose_name = '视频'
        verbose_name_plural = '视频列表'
        ordering = ["-timestamp", "-updated"]

    def save(self, without_valid=False, *args, **kwargs):
        logging.debug('==== 保存点播节目 %s ====' % self.title)
        p = Pinyin()
        full_pinyin = p.get_pinyin(smart_str(self.title), '')
        first_pinyin = p.get_initials(smart_str(self.title), '').lower()
        self.search_word = " ".join([full_pinyin, first_pinyin])
        logging.debug("video path:", self.video)

        if self.description is None or self.description == "":
            self.description = default_description(self)

        if self.local_video != '' and self.local_video is not None:
            basename = Path(self.local_video).relative_to(Path(settings.LOCAL_MEDIA_ROOT))
            self.video.name = str(Path(settings.LOCAL_MEDIA_URL) / basename)
            logging.debug("save local_video to filefield done")

        if without_valid:
            ret = super(Vod, self).save(*args, **kwargs)
            return ret
        super(Vod, self).save(*args, **kwargs)
        try:
            if self.video != None and self.video != '':
                relative_path = Path(self.video.name).relative_to(settings.MEDIA_URL)  # Djan%20go.mp4
                rel_name = uri_to_iri(relative_path)  # Djan go.mp4

                #  Make sure the self.video.name is not in the LOCAL_FOLDER
                if not self.video.name.startswith(settings.LOCAL_FOLDER_NAME) and \
                        not self.video.name.startswith(settings.RECORD_MEDIA_FOLDER):
                    self.video.name = str(rel_name)
                logging.debug('save_path:', self.save_path)
                logging.debug('video.name:', self.video.name)
                logging.debug('size:', self.video.file.size)
                self.file_size = humanfriendly.format_size(self.video.file.size)
                # duration = VideoFileClip(self.video.path).duration
                # self.duration = time_formate(duration)
            else:
                print("video file is None")
        except:
            pass

        try:
            if self.image:
                self.image.name = str(uri_to_iri(Path(self.image.name).relative_to(settings.MEDIA_URL)))
        except:
            pass
        return super(Vod, self).save(*args, **kwargs)

    def __unicode__(self):
        return self.title

    def __str__(self):
        return self.title

    def image_tag(self):
        if self.image is not None and str(self.image) != "":
            if os.path.exists(self.image.path):
                return mark_safe('<img src="%s" width="160" height="90" />' % (self.image.url))
            else:
                return mark_safe('<img src="#" width="160" height="90" />')
        else:
            return mark_safe('<img src="%s" width="160" height="90" />' % (settings.DEFAULT_IMAGE_SRC))

    image_tag.short_description = '缩略图'

    def get_absolute_url(self):
        # print("get absolute url:",self.slug)
        return reverse("vod:vod-detail", kwargs={"slug": self.slug})

    def add_view_count(self):
        self.view_count_temp += 1

    def colored_active(self):
        color_code = 'red' if self.active == 0 else 'green'
        return format_html(
            '<span style="color:{};">{}</span>',
            color_code,
            self.get_active_display()
        )

    colored_active.short_description = '是否激活'

    def video_format(self):
        suffix = Path(self.video.name).suffix
        color_code = 'green' if suffix in ['.mp4', '.m3u8'] else 'red'
        return format_html(
            '<span style="color:{};">{}</span>',
            color_code,
            suffix
        )

    video_format.short_description = '视频文件格式' class VideoCategory(models.Model):
    name = models.CharField(max_length=128, verbose_name='分类名称')
    type = models.CharField(max_length=128, choices=TYPES, default='common', verbose_name='类型')
    isSecret = models.BooleanField(default=False, verbose_name='是否加密')
    level = models.IntegerField(null=False, blank=False, default=1, choices=((1, '一级分类'), (2, '二级分类')),
                                verbose_name='分类等级')
    subset = models.ManyToManyField('self', blank=True, verbose_name='分类关系')

    class Meta:
        verbose_name = '视频分类'
        verbose_name_plural = '视频分类管理'

    def __str__(self):
        base_name = self.name + str('  (level %d)' % (self.level))
        if self.subset.first() and self.level == 2:
            return '--'.join([self.subset.first().name, base_name])
        else:
            return base_name

    def save(self, *args, **kwargs):
        super(VideoCategory, self).save(*args, **kwargs)

    def colored_level(self):
        color_code = 'red' if self.level == 1 else 'green'
        return format_html(
            '<span style="color:{};">{}</span>',
            color_code,
            self.get_level_display()
        )

    colored_level.short_description = '分级' class VideoRegion(models.Model):
    name = models.CharField(max_length=200, verbose_name='地区', unique=True)

    class Meta:
        verbose_name = '视频地区管理'
        verbose_name_plural = '视频地区'

    def __str__(self):
        return self.name def get_years(category):
    category = None if category == '全部' or category == '' else category
    _years = get_vod_field_list(Vod, 'year', category)
    years = []
    for year in _years:
        years.append(year[0])
    return years class VodPageNumberPagination(PageNumberPagination):
    page_size = 12

    def get_paginated_response(self, data):
        year = self.request.query_params.get('year')
        return Response(OrderedDict([
            ('count', self.page.paginator.count),
            ('next', self.get_next_link()),
            ('previous', self.get_previous_link()),
            ('cur_page', self.page.number),
            ('num_pages', self.paginator.num_pages),
            ('page_range', self.paginator.pager_num_range()),
            ('year', year),
            ('results', data)
        ]))

    def paginate_queryset(self, queryset, request, view=None):
        """
        Paginate a queryset if required, either returning a
        page object, or `None` if pagination is not configured for this view.
        """

        page_size = self.get_page_size(request)
        if not page_size:
            return None
        cur_page = request.query_params.get(self.page_query_param)
        if not cur_page:
            cur_page = 1
        # paginator = self.django_paginator_class(queryset, page_size)
        self.paginator = CustomPaginator(cur_page, 5, queryset, page_size)
        page_number = request.query_params.get(self.page_query_param, 1)
        if page_number in self.last_page_strings:
            page_number = self.paginator.num_pages

        try:
            self.page = self.paginator.page(page_number)
        except InvalidPage as exc:
            msg = self.invalid_page_message.format(
                page_number=page_number, message=six.text_type(exc)
            )
            raise NotFound(msg)

        if self.paginator.num_pages > 1 and self.template is not None:
            # The browsable API should display pagination controls.
            self.display_page_controls = True

        self.request = request
        return list(self.page) class HasPermission(BasePermission):
    message = 'You must have permission of this video.'

    def has_object_permission(self, request, view, obj):
        return True
        permission = False
        if request.user.is_authenticated:
            try:
                permission = request.user.userpermission.has_permision()
            except:
                pass
        return permission
import random
from wrapcache import wrapcache
from django.db.models import Q
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.generics import (
    CreateAPIView,
    DestroyAPIView,
    ListAPIView,
    UpdateAPIView,
    RetrieveAPIView,
    RetrieveUpdateAPIView
)
from rest_framework.permissions import (
    AllowAny,
    IsAuthenticated,
    IsAdminUser,
    IsAuthenticatedOrReadOnly,
)
from .serializers import (
    VodListSerializer, VodDetailSerializer, CategoryListSerializer,
    RegionListSerializer, VodHomeListSerializer
)
from vodmanagement.models import Vod, VideoCategory, VideoRegion
from vodmanagement.views import get_years
from .pagination import VodPageNumberPagination
from .permissions import HasPermission



@wrapcache(60)
def get_all_videos(main_category):
    query_set = Vod.objects.filter(active=1)
    if main_category:
        result = query_set.filter(category__subset__name=main_category)
        result |= query_set.filter(category__name=main_category)
        return result.distinct()
    return query_set


@wrapcache(60)
def get_filter_videos(query_set, category=None, year=None, region=None):
    if category:
        query_set = query_set.filter(category__name=category)
    if year:
        query_set = query_set.filter(year=year)
    if region:
        query_set = query_set.filter(region__name=region)
    return query_set


def checked_query_param(param: str):
    return param if (param != '全部' and param != '') else None


class VodListAPIView(ListAPIView):
    """
    VodListAPIView doc
    """
    serializer_class = VodListSerializer
    permission_classes = [AllowAny]
    pagination_class = VodPageNumberPagination  # PageNumberPagination

    def get_queryset(self, *args, **kwargs):
        main_category = self.request.query_params.get('main_category')
        queryset_list = get_all_videos(main_category)
        category = checked_query_param(self.request.query_params.get('category'))
        year = checked_query_param(self.request.query_params.get('year'))
        region = checked_query_param(self.request.query_params.get('region'))
        queryset_list = get_filter_videos(queryset_list, category=category, year=year, region=region)
        search = self.request.GET.get("search")
        if search is not None and search != '':
            queryset_list = queryset_list.filter(
                Q(title__icontains=search) |
                Q(description__icontains=search)
            )
        return queryset_list


class VodDetailAPIView(RetrieveAPIView):
    """
    VodDetailAPIView doc

    """
    lookup_field = 'id'
    serializer_class = VodDetailSerializer
    permission_classes = [HasPermission]

    def get_queryset(self, *args, **kwargs):
        query_set = Vod.objects.filter(active=1)
        return query_set


@wrapcache(60)
def gen_categories():
    categories = {}
    for level_1 in VideoCategory.objects.filter(level=1):
        children = level_1.subset.all()
        categories[level_1.name] = CategoryListSerializer(children, many=True).data
    return categories


class CategoryListAPIView(APIView):
    """
    CategoryListAPIView doc
    """
    serializer_class = CategoryListSerializer
    permission_classes = [AllowAny]
    queryset = VideoCategory.objects.all()

    def get(self, request, format=None):
        return Response(gen_categories())


class YearListAPIView(APIView):
    permission_classes = [AllowAny]

    def get(self, *args, **kwargs):
        main_category = self.request.query_params.get('category')
        if main_category is None:
            Response('Error, the year list request must contain 1 first level category parameter.')

        year_list = get_years(main_category)