Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
11 kB
4
Indexable
Never


def split_by_groups(df):
    index_list = list(df.index[df.isnull().all(1)])
    groups = []
    start_idx = 0
    for end_idx in index_list:
        group = df[start_idx:end_idx]
        groups.append(group)
        start_idx = end_idx + 1
    groups.append(df[start_idx:])

    return groups


def manage_group(group_frame):
    group_name = group_frame.iloc[0]["group"]
    client = group_frame.iloc[0]["client"]

    main_result_dir = "result"
    source_dir = f"result/{group_name}"
    result_dir_path = f"result/{group_name}_result"

    upload_client_path = dbx_upload_result_path + "/" + client

    folder_exists = False
    files_tree = dbx.files_list_folder(dbx_upload_result_path)

    for entry in files_tree.entries:
        if entry.name == client and isinstance(entry, dropbox.files.FolderMetadata):
            folder_exists = True
            break

    if not folder_exists:
        dbx.files_create_folder_v2(upload_client_path)

    if not os.path.exists(source_dir):
        os.makedirs(source_dir)

    if not os.path.exists(main_result_dir):
        os.makedirs(main_result_dir)

    if not os.path.exists(result_dir_path):
        os.makedirs(result_dir_path)

    mashups = []

    for index, row in group_frame.iterrows():
        local_path = f"{source_dir}/{index}.mp4"
        if row["video_source"] == "youtube":
           download_video_from_yt(row["youtube_link"], source_dir, f"{index}.mp4")
        elif row["video_source"] == "dropbox":
            download_video_from_db(row["video_name"], local_path)
        else:
            logging.critical("invalid source")
            return

        mp_clip = mpy.VideoFileClip(local_path)

        if not pd.isna(row['finish_result']):
            path = dbx_path + row['finish_result']
            try:
                # получаем список файлов и папок в указанной директории
                results = dbx.files_list_folder(path)
                for entry in results.entries:
                    if isinstance(entry, dropbox.files.FolderMetadata) and entry.path_display == path:
                        # папка уже существует, используем ее
                        print(f"Folder {path} already exists.")
                        break
                else:
                    # папки в списке нет, создаем новую
                    dbx.files_create_folder_v2(path)
                    print(f"Folder {path} has been created.")
            except dropbox.exceptions.ApiError as e:
                print(f"Error accessing folder {path}: {e}")
            upload_client_path = path

        #обрезать по длине
        if mp_clip.duration < 15:
            desired_duration = mp_clip.duration
        else:
            desired_duration = 15
        mp_clip = crop_clip_duration(desired_duration, row['timestamp_left'], row['timestamp_right'], mp_clip)


        #выровнять соотношение сторон
        aspect_ratio = mp_clip.w / mp_clip.h
        desired_ratio = 9 / 16
        mp_clip = crop_clip_size(desired_ratio, aspect_ratio, mp_clip)

        if row['invert_vertical']:
            print(row['invert_vertical'])
            mp_clip = mp_clip.fx(mpy.vfx.mirror_x)

        if not pd.isna(row['cut_orig_video']):
            mp_clip = crop_top_bottom_x(mp_clip, int(row['cut_orig_video']))

        if row["music_from_video"]:
            audio_clip = mp_clip.audio
        else:
            local_track_path = f"{source_dir}/track.mp3"
            track_path = row["track_name"]
            if not os.path.exists(local_track_path):
                with open(local_track_path, 'wb') as f:
                    metadata, res = dbx.files_download(dbx_path + track_path)
                    f.write(res.content)
            audio_clip = AudioFileClip(local_track_path)


        if row["origin"]:
            local_origin_path = f"{result_dir_path}/origin_{index}.mp4"
            if not os.path.exists(local_origin_path):
                mp_clip = mp_clip.set_audio(audio_clip)
                mp_clip.write_videofile(local_origin_path, **settings)
            upload_video_to_dbx(local_path=local_origin_path, dbx_upload_path=upload_client_path+f"/{group_name}_origin{index}.mp4")
        if row["subs"]:
            color = row["sub_color"] or "white"
            make_subs_clip(mp_clip, audio_clip, color, source_dir, result_dir_path, index, dbx_subs_path=row["sub_name"], upload_path=upload_client_path+f"/{group_name}_subs{index}.mp4")

        if row["mashup"]:
            mashups.append(mp_clip.subclip(0, 5).fx(mpy.vfx.fadein, 2).fx(mpy.vfx.fadeout, 2))

    if len(mashups) > 0:
        make_mashups(mashups, audio_clip, local_save_path=f"{result_dir_path}/mashup", upload_path=f"{upload_client_path}/{group_name}_mashup")



def make_mashups(clips, audio, local_save_path, upload_path):
    # Находим наименьшую ширину и высоту среди всех клипов
    min_w = min([clip.size[0] for clip in clips])
    min_h = min([clip.size[1] for clip in clips])

    # Приводим все клипы к одному размеру
    resized_clips = []
    for clip in clips:
        if clip.size[0] != min_w or clip.size[1] != min_h:
            # Если размер клипа не совпадает с минимальным размером,
            # то обрезаем или изменяем масштаб
            if clip.size[0] > min_w:
                clip = clip.crop(x1=(clip.size[0]-min_w)/2, x2=min_w+(clip.size[0]-min_w)/2)
            elif clip.size[0] < min_w:
                clip = clip.resize(width=min_w)
            if clip.size[1] > min_h:
                clip = clip.crop(y1=(clip.size[1]-min_h)/2, y2=min_h+(clip.size[1]-min_h)/2)
            elif clip.size[1] < min_h:
                clip = clip.resize(height=min_h)
        resized_clips.append(clip)

    #массив всех комбинаций из клипов
    perms = permutations(resized_clips)
    count = 0
    for perm in perms:
        order = ''.join([str(resized_clips.index(clip) + 1) for clip in perm])
        final_clip = concatenate_videoclips(perm)
        final_clip = final_clip.set_audio(audio)
        if not os.path.exists(local_save_path):
            final_clip.write_videofile(local_save_path + f"_{order}.mp4", **settings)
        upload_video_to_dbx(local_path=local_save_path + f"_{order}.mp4", dbx_upload_path=upload_path + f"{order}.mp4")
        count = count + 1


def make_subs_clip(clip, audio_clip, color, source_dir, result_dir_path, index, dbx_subs_path, upload_path):
    local_sub_path = f"{source_dir}/subs.srt"
    local_subs_clip_path = f"{result_dir_path}/subs_{index}.mp4"
    if not os.path.exists(local_subs_clip_path):
        try:
            with open(local_sub_path, 'wb') as f:
                metadata, res = dbx.files_download(dbx_path + dbx_subs_path)
                f.write(res.content)
            sub_clip = make_subs(clip, local_sub_path, color)
            sub_clip = sub_clip.set_audio(audio_clip)

            sub_clip.write_videofile(local_subs_clip_path, **settings)
            upload_video_to_dbx(local_path=local_subs_clip_path, dbx_upload_path=upload_path)
        except Exception as e:
            logging.critical(f"something went wrong with subtitle file: {e}")


def make_subs(clip, sub_path, color):
    font_size = int(min(clip.size[0], clip.size[0]) * 0.05)
    generator = lambda txt: TextClip(txt, font='Arial', fontsize=font_size, color=color)
    subs = SubtitlesClip(sub_path, generator)
    subtitles = SubtitlesClip(subs, generator)
    result = CompositeVideoClip([clip, subtitles.set_pos(('center', 'center'))])
    return result


def download_video_from_db(path, local_path):
    print(path, local_path)
    if not os.path.exists(local_path):
        try:
            with open(local_path, 'wb') as f:
                metadata, res = dbx.files_download(dbx_path + path)
                f.write(res.content)
        except Exception as e:
            logging.critical(f"something went wrong: {e}")


def download_video_from_yt(link, group_name, file_name):
    yt = YouTube(link)
    print(link)
    yt.streams.filter(progressive=False, file_extension='webm').order_by('resolution')[-1].download(group_name, filename=file_name)


def upload_video_to_dbx(local_path, dbx_upload_path):
    try:
        with open(local_path, "rb") as f:
            dbx.files_upload(f.read(), dbx_upload_path)
    except Exception as e:
        logging.critical(f"something went wrong with upload file to dropbox: {e}")



def crop_clip_size(desired_ratio, aspect_ratio, clip):
    if aspect_ratio > desired_ratio:
        # вырезаем кусок по горизонтали
        width = int(clip.size[1] * desired_ratio)
        x_center = int((clip.size[0] - width) / 2)
        crop_area = (x_center, 0, x_center + width, clip.size[1])
    else:
        # вырезаем кусок по вертикали
        height = int(clip.size[0] / desired_ratio)
        y_center = int((clip.size[1] - height) / 2)
        crop_area = (0, y_center, clip.size[0], y_center + height)

    return clip.crop(*crop_area)


def crop_clip_duration(desired_duration, start, end, clip):
    if clip.duration > desired_duration:
        if pd.isna(end):
            minutes, seconds = start.split(':')
            start = int(minutes) * 60 + int(seconds)
            end = start + desired_duration
            clip = clip.subclip(start, end)
        else:
            clip = clip.subclip(start, end)
    return clip


def crop_top_bottom_x(clip, x):
    video_height = clip.size[1]
    crop_top = int(video_height * (x / 100))
    crop_bottom = int(video_height * (1 - x / 100))
    clip = clip.crop(y1=crop_top, y2=crop_bottom)
    return clip


def delete_folder(folder_path):
    print("deleting")
    for process in psutil.process_iter():
        try:
            for file in process.open_files():
                if file.path.startswith(folder_path):
                    process.kill()
                    break
        except Exception as e:
            pass
    shutil.rmtree(folder_path, ignore_errors=True)


def main():
    groups = split_by_groups(data_table)

    for group in groups:
        try:
            manage_group(group)
        except Exception as e:
            logging.critical(f"invalid group {group.iloc[0]['group']}: {e}")
    #remove_result()

main()


def remove_result():
    delete_folder("result")