class RestoreForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(RestoreForm, self).__init__(*args, **kwargs)
        self.fields['save_path'] = forms.ChoiceField(choices=save_path_choices(), label=self.fields['save_path'].label)

    class Meta:
        model = Restore
        fields = '__all__' class CategoryAdminForm(forms.ModelForm):
    class Meta:
        model = VideoCategory
        widgets = {
            'type': forms.RadioSelect,
        }
        fields = '__all__' class VodForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(VodForm, self).__init__(*args, **kwargs)
        if self.instance.image.name and self.instance.video.name:
            self.fields['save_path'] = forms.ChoiceField(choices=get_save_path_choice(self.instance.save_path), label=self.fields['save_path'].label)
        else:
            self.fields['save_path'] = forms.ChoiceField(choices=save_path_choices(), label=self.fields['save_path'].label)
            # self.fields['save_path'].widget.attrs['disabled='disabled''] = True
        create_storage_paths()

    def clean_title(self):
        data = self.cleaned_data['title']
        return data

    def clean(self):
        return super(VodForm, self).clean()

    class Meta:
        model = Vod
        fields = (
            'category',
            'save_path',
            'video',
            'title',
            'image',
            'year',
            'description',
            'slug',
            'search_word',
        )
        widgets = {
            'description': KindEditor(),
        } class MultipleUploadForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(MultipleUploadForm, self).__init__(*args, **kwargs)
        self.fields['save_path'] = forms.ChoiceField(choices=save_path_choices(), label=self.fields['save_path'].label)

    class Meta:
        model = MultipleUpload
        fields = '__all__' 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 MultipleUpload(models.Model):
    files = ModelAdminResumableMultiFileField(null=True, blank=True, storage=VodStorage(), verbose_name='文件')
    save_path = models.CharField(max_length=128, blank=False, null=True, verbose_name='保存路径')
    category = models.ForeignKey(VideoCategory, null=True, verbose_name='分类')

    class Meta:
        verbose_name = '批量上传'
        verbose_name_plural = '批量上传管理' class Restore(models.Model):
    txt_file = models.FileField(blank=True, null=True, verbose_name='备份配置文件')
    zip_file = ModelAdminResumableRestoreFileField(null=True, blank=True, storage=VodStorage(), verbose_name='压缩包')
    save_path = models.CharField(max_length=128, blank=False, null=True)  # ,default=FileDirectory.objects.first())

    class Meta:
        verbose_name = '视频导入'
        verbose_name_plural = '视频导入'

    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        result = super(Restore, self).save()
        file_path = self.txt_file.path
        call_command('loaddata', file_path)
        return result class FileDirectory(models.Model):
    path = models.CharField(max_length=512, default=default_filedir, blank=True)

    class Meta:
        verbose_name = '视频上传路径'
        verbose_name_plural = '视频上传路径管理'

    def __str__(self):
        return self.path

    def save(self, *args, **kwargs):
        if self.path is None or self.path == "":
            self.path = default_filedir()
        super(FileDirectory, self).save(*args, **kwargs) 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
import datetime
import threading
from pathlib import Path
from django.contrib import admin
from django.contrib.admin import SimpleListFilter
from django.core.management import call_command
from django.core import serializers as django_serializers
from django.http import HttpResponse
from django.contrib import messages
from uuslug import uuslug
from vodmanagement.forms import RestoreForm, CategoryAdminForm, VodForm, MultipleUploadForm
from vodmanagement.models import (
    Vod,
    VideoCategory,
    MultipleUpload,
    Restore,
    FileDirectory,
    VideoRegion
)
from vodmanagement.utils import *
    def copy_objects(self, request, queryset):
        for obj in queryset:
            for i in range(4):
                new_obj = obj
                new_obj.pk = None
                # new_obj.slug = create_slug(new_obj)
                new_obj.slug = uuslug(new_obj.title, instance=new_obj)
                new_obj.save()
        self.message_user(request, '%s item successfully copyed.' % queryset.count()
                          , messages.SUCCESS)

    def activate_vod(self, request, queryset):
        for item in queryset:
            item.active = 1
            item.save()
        self.message_user(request, '%s个节目成功激活.' % queryset.count()
                          , messages.SUCCESS)

    activate_vod.short_description = '激活节目列表'

    def deactivate_vod(self, request, queryset):
        for item in queryset:
            item.active = 0
            item.save()
        self.message_user(request, '%s个节目成功取消激活.' % queryset.count()
                          , messages.SUCCESS)

    deactivate_vod.short_description = '取消激活节目'

    def clear_view_count(self, request, queryset):
        queryset.update(view_count=0)
        self.message_user(request, '%s item successfully cleared view count.' % queryset.count()
                          , messages.SUCCESS)

    def backup(self, request, queryset):
        response = HttpResponse(content_type='text/plain')
        file_name = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S') + '-backup.json'
        response['Content-Disposition'] = 'attachment; filename=%s' % file_name
        directory = Path(settings.MEDIA_ROOT) / 'backup'
        full_file_name = directory / file_name
        directory.mkdir(parents=True, exist_ok=True)
        data = django_serializers.serialize('json', queryset)
        full_file_name.open('w').write(data)
        response.write(full_file_name.open('rb').read())
        return response

    backup.short_description = '备份选中节目'

    def backup_all(self, request, queryset):
        response = HttpResponse(content_type='text/plain')
        file_name = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S') + '-backup.json'
        response['Content-Disposition'] = 'attachment; filename=%s' % file_name
        directory = Path(settings.MEDIA_ROOT) / 'backup'
        full_file_name = directory / file_name
        directory.mkdir(parents=True, exist_ok=True)
        full_file_name.open('w').write('')
        call_command('dumpdata', 'vodmanagement', '-o', str(full_file_name))  # 使用Django提供的命令行工具备份数据
        response.write(full_file_name.open('rb').read())
        return response

    backup_all.short_description = '备份所有节目'

    def transcoding(self, request, queryset):
        def ff(obj):
            # TODO: 没有检测ffmpeg命令是否执行成功，如果失败会删除掉源文件
            video_path = Path(obj.video.path)
            ffmpeg_cmd = ''.join([
                'ffmpeg -y -i \"',
                str(video_path),
                '\" -vcodec copy -acodec copy \"',
                str(video_path.with_suffix('.mp4')),
                '\"'
            ])
            os.system(ffmpeg_cmd)
            os.remove(str(video_path))
            video_name_new = Path(obj.video.name).with_suffix('.mp4')
            obj.video.name = str(video_name_new)
            obj.save()

        for obj in queryset:
            if Path(obj.video.name).suffix != '.mp4':
                p = threading.Thread(target=ff, args=(obj,))
                p.start()
        self.message_user(request, '视频已提交后台转码'
                          , messages.SUCCESS)

    transcoding.short_description = '转为mp4'


@admin.register(VideoCategory)
class VideoCategoryModelAdmin(admin.ModelAdmin):
    list_display = ['category_description', 'colored_level', 'type', 'isSecret']
    list_editable = ['isSecret']
    search_fields = ['name']
    filter_horizontal = ['subset']
    ordering = ['level']
    form = CategoryAdminForm
    fieldsets = [
        ('描述', {'fields': ['name', 'level', 'subset']}),
        ('高级', {'fields': ['isSecret', 'type'], 'classes': ['collapse']})
    ]

    def category_description(self, obj):
        return str(obj)

    category_description.short_description = '分类名称'


class LinkModelAdmin(admin.ModelAdmin):
    list_display = ['name', 'category']
    list_editable = ['category']


@admin.register(MultipleUpload)
class MultipleUploadModelAdmin(admin.ModelAdmin):
    form = MultipleUploadForm
    change_form_template = 'vodmanagement/MultipleUpload/change_form.html'
    add_form_template = 'vodmanagement/MultipleUpload/change_form.html'



@admin.register(Restore)