Spaces:
Paused
Paused
| import os | |
| import requests | |
| import time | |
| import math | |
| import re | |
| import shutil | |
| import json | |
| import subprocess | |
| import mimetypes | |
| from datetime import datetime, timedelta | |
| from moviepy import VideoFileClip | |
| import streamlit as st | |
| from streamlit_option_menu import option_menu | |
| from collections import defaultdict | |
| from tqdm import tqdm | |
| # from googletrans import Translator | |
| from bs4 import BeautifulSoup | |
| def format_number(number): | |
| if number < 1000: | |
| return str(number) | |
| elif number < 1000000: | |
| return f"{round(number / 1000)} ribu" | |
| elif number < 1000000000: | |
| return f"{round(number / 1000000)} juta" | |
| else: | |
| return f"{round(number / 1000000000)} miliar" | |
| def cut_video(filename, judul_video, start_time, end_time): | |
| start_time_parts = start_time.split(':') | |
| end_time_parts = end_time.split(':') | |
| start_time_seconds = int(start_time_parts[0]) * 3600 + int(start_time_parts[1]) * 60 + float(start_time_parts[2]) | |
| end_time_seconds = int(end_time_parts[0]) * 3600 + int(end_time_parts[1]) * 60 + float(end_time_parts[2]) | |
| potong = "/home/user/app/Hasil Potong" | |
| if not os.path.exists(potong): | |
| os.makedirs(potong) | |
| output_file_path = f'{potong}/{judul_video}.mp4' | |
| with VideoFileClip(filename) as video: | |
| subclip = video.subclip(start_time_seconds, end_time_seconds) | |
| subclip.write_videofile(output_file_path) | |
| return output_file_path | |
| def session(video_info, video_file, thumbnail_file, choice): | |
| st.session_state.video_info = video_info | |
| st.session_state.video_file = video_file | |
| st.session_state.thumbnail_file = thumbnail_file | |
| if choice: | |
| hasil = "Hasil Potongan" | |
| elif choice: | |
| hasil = "Hasil Compress" | |
| else: | |
| hasil = "" | |
| if 'video_info' in st.session_state: | |
| num_lines = st.session_state.video_info.count('\n') + 1 | |
| text_area_height = 25 * num_lines | |
| st.text_area("Informasi Video", st.session_state.video_info, height=text_area_height) | |
| if video_file != '': | |
| if thumbnail_file: | |
| st.image(st.session_state.thumbnail_file) | |
| st.video(st.session_state.video_file) | |
| with open(st.session_state.video_file, 'rb') as f: | |
| file_contents = f.read() | |
| st.download_button( | |
| label=f"Download {hasil} Video", | |
| data=file_contents, | |
| file_name=st.session_state.video_file.split("/")[-1].title().replace('Mp4', 'mp4'), | |
| mime='video/mp4' | |
| ) | |
| def cari_file (judul, directory): | |
| # Inisialisasi variabel untuk menyimpan thumbnail path | |
| file_path = "" | |
| # Iterasi melalui semua direktori dan sub-direktori di directory | |
| for root, dirs, files in os.walk(directory): | |
| for file in files: | |
| # Periksa apakah nama file sesuai dengan video_file dan berakhiran .jpg | |
| if judul in file: | |
| # Simpan thumbnail path | |
| file_path = os.path.join(root, file) | |
| # Hentikan pencarian setelah menemukan thumbnail | |
| break | |
| return file_path | |
| def convert_size(size_bytes): | |
| units = ["B", "KB", "MB", "GB", "TB"] | |
| index = 0 | |
| while size_bytes >= 1024 and index < len(units) - 1: | |
| size_bytes /= 1024 | |
| index += 1 | |
| return f"{size_bytes:.2f} {units[index]}" | |
| def add_space(name): | |
| new_name = '' | |
| for i in range(len(name)): | |
| if i > 0 and name[i].isupper() and name[i-1].islower(): | |
| new_name += ' ' | |
| new_name += name[i] | |
| return new_name | |
| def download_file(url, new_name, directory): | |
| headers = { | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3" | |
| } | |
| response = requests.get(url, stream=True, headers=headers) | |
| content_type = response.headers.get("Content-Type") | |
| extension = mimetypes.guess_extension(content_type) | |
| file_name = new_name + extension | |
| if not os.path.exists(directory): | |
| os.makedirs(directory) | |
| filename = f"{directory}/{file_name}" | |
| with open(filename, 'wb') as file: | |
| total_size = int(response.headers.get("Content-Length", 0)) | |
| progress_bar = tqdm(total=total_size, unit="B", unit_scale=True, ncols=80) | |
| for chunk in response.iter_content(chunk_size=1024): | |
| if chunk: | |
| file.write(chunk) | |
| progress_bar.update(len(chunk)) | |
| progress_bar.close() | |
| return filename | |
| # def convert_japanese_to_romaji(text): | |
| # translator = Translator(service_urls=['translate.google.com']) | |
| # translation = translator.translate(text, src='ja', dest='ja') | |
| # return translation.pronunciation | |
| # def translate_japanese_to_english(text): | |
| # translator = Translator(service_urls=['translate.google.com']) | |
| # translation = translator.translate(text, src='ja', dest='en') | |
| # return translation.text | |
| def get_video_resolution(input_file): | |
| command = ['ffprobe', '-v', 'error', '-select_streams', 'v:0', '-show_entries', 'stream=width,height', '-of', 'json', input_file] | |
| result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
| if result.returncode == 0: | |
| video_info = json.loads(result.stdout) | |
| width = video_info['streams'][0]['width'] | |
| height = video_info['streams'][0]['height'] | |
| return (width, height) | |
| else: | |
| print(f'Error getting video resolution: {result.stderr}') | |
| return None | |
| def get_video_info(url): | |
| response = requests.get(url) | |
| soup = BeautifulSoup(response.text, 'html.parser') | |
| # Mencari judul video di elemen meta dengan name="twitter:title" | |
| title = soup.find("meta", attrs={"name": "twitter:title"}) | |
| if title: | |
| video_title = title['content'] | |
| # Hapus semua karakter yang terdapat di dalam kurung siku (termasuk angka) | |
| video_title = re.sub(r'\[[^\]]*\]', '', video_title) | |
| # Hapus kata 'Cosplay ' | |
| video_title = video_title.replace('Cosplay ', '') | |
| # Tukar posisi kalimat yang dipisahkan oleh ' - ' | |
| if ' - ' in video_title: | |
| parts = video_title.split(' - ') | |
| video_title = f"{parts[1]} - {parts[0]}" | |
| actress = parts[0].lstrip() | |
| series = parts[1].lstrip() | |
| else: | |
| actress = '' | |
| series = '' | |
| # Ubah dua spasi menjadi satu spasi | |
| video_title = re.sub(r'\s{2,}', '', video_title) | |
| print(f"Artis: {actress} dan Series: {series}") | |
| # Mencari ThumbnailUrl di elemen meta dengan name="twitter:image" | |
| thumbnail = soup.find("meta", attrs={"name": "twitter:image"}) | |
| if thumbnail: | |
| thumbnail_url = thumbnail['content'] | |
| # Mencari VideoUrl | |
| script_tag = soup.find('script', type='application/ld+json') | |
| data = json.loads(script_tag.string) | |
| selected_video_url = None | |
| for item in data['@graph']: | |
| if item['@type'] == 'VideoObject': | |
| selected_video_url = item['contentURL'] | |
| # Mencari Digits | |
| if series == 'Cospuri': | |
| # Extract digits from thumbnail_url | |
| match = re.search(r'/0(\d{3})', thumbnail_url) | |
| if match: | |
| digits = match.group(1) | |
| elif series == 'Fellatio Japan': | |
| # Extract digits from thumbnail_url | |
| match = re.search(r'/(\d+)_', thumbnail_url) | |
| if match: | |
| digits = match.group(1) | |
| return actress, series, digits, selected_video_url, thumbnail_url | |
| def find_image_file(name, directory): | |
| for root, dirs, files in os.walk(directory): | |
| for file in files: | |
| if file == f'{name}.jpg': | |
| return os.path.join(root, file) | |
| return None | |
| def extract_number(video_file): | |
| # Use a regular expression to find the first group of digits in the video file name | |
| match = re.search(r'\d+', video_file) | |
| if match: | |
| # If a group of digits is found, return it as an integer | |
| return int(match.group()) | |
| else: | |
| # If no group of digits is found, return a large number to ensure that this video file is processed last | |
| return float('inf') | |
| def get_video_resolution(input_file): | |
| command = ['ffprobe', '-v', 'error', '-select_streams', 'v:0', '-show_entries', 'stream=width,height', '-of', 'json', input_file] | |
| result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
| if result.returncode == 0: | |
| video_info = json.loads(result.stdout) | |
| width = video_info['streams'][0]['width'] | |
| height = video_info['streams'][0]['height'] | |
| return (width, height) | |
| else: | |
| print(f'Error getting video resolution: {result.stderr}') | |
| return None | |
| def convert_videos(height, filename): | |
| download_folder = os.path.dirname(filename) | |
| konversi_folder = '/home/user/app/Hasil Konversi' | |
| if not os.path.exists(konversi_folder): | |
| os.makedirs(konversi_folder) | |
| video_extensions = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv', '.webm', '.mpeg', '.3gp', '.m4v', '.mpg', '.vob', '.ts', '.asf', '.rm', '.swf', '.ogv'] | |
| for file in os.listdir(download_folder): | |
| file_extension = os.path.splitext(file)[1].lower() | |
| if file_extension in video_extensions: | |
| input_file = os.path.join(download_folder, file) | |
| output_file = os.path.join(konversi_folder, file) | |
| # Get the original width and height of the video using ffprobe | |
| resolution = get_video_resolution(input_file) | |
| if resolution is not None: | |
| width_ori, height_ori = resolution | |
| # Calculate the width/height for conversion using the formula | |
| if (height_ori < width_ori): | |
| width = int((width_ori / height_ori) * height) | |
| if (width_ori / height_ori) * height % 1 != 0: | |
| width += 1 | |
| # Convert video using ffmpeg | |
| if height == 720: | |
| # command = f'ffmpeg -i "{input_file}" -s {width}x{height} -b:v 850k -bufsize 1000k -r 30 -b:a 160k -ar 44100 -ac 2 "{output_file}"' | |
| command = f'ffmpeg -i "{input_file}" -s {width}x{height} -b:v 1350k -bufsize 1500k -r 30 -b:a 160k -ar 48000 -ac 2 "{output_file}"' | |
| elif height == 480: | |
| command = f'ffmpeg -i "{input_file}" -s {width}x{height} -b:v 600k -bufsize 700k -r 24 -b:a 95k -ar 44100 -ac 2 "{output_file}"' | |
| elif height == 360: | |
| command = f'ffmpeg -i "{input_file}" -s {width}x{height} -b:v 250k -bufsize 300k -r 24 -b:a 50k -ar 44100 -ac 2 "{output_file}"' | |
| else: | |
| width = height | |
| height = int((height_ori / width_ori) * width) | |
| if (height_ori / width_ori) * width % 1 != 0: | |
| height += 1 | |
| # Convert video using ffmpeg | |
| if width == 720: | |
| # command = f'ffmpeg -i "{input_file}" -s {width}x{height} -b:v 850k -bufsize 1000k -r 30 -b:a 160k -ar 44100 -ac 2 "{output_file}"' | |
| command = f'ffmpeg -i "{input_file}" -s {width}x{height} -b:v 1350k -bufsize 1500k -r 30 -b:a 160k -ar 48000 -ac 2 "{output_file}"' | |
| elif width == 480: | |
| command = f'ffmpeg -i "{input_file}" -s {width}x{height} -b:v 600k -bufsize 700k -r 24 -b:a 95k -ar 44100 -ac 2 "{output_file}"' | |
| os.system(command) | |
| return output_file | |
| def join_video(name, thumbnail_file, video_file): | |
| output_dir = '/home/user/app/Hasil Join' | |
| if not os.path.exists(output_dir): | |
| os.makedirs(output_dir) | |
| # Tentukan jalur ke file audio yang akan digunakan untuk intro | |
| audio_file = 'sound.wav' | |
| # Tentukan jalur ke file output | |
| output_file = f'{output_dir}/{name}.mp4' | |
| # Gunakan ffmpeg untuk membuat video 1 detik dari file gambar dan audio | |
| subprocess.run(['ffmpeg', '-loop', '1', '-i', thumbnail_file, '-i', audio_file, '-c:v', 'libx264', '-b:v', '850k', '-bufsize', '1000k', '-r', '30', '-b:a', '160k', '-ar', '44100', '-ac', '2', '-t', '1', '-pix_fmt', 'yuv420p', '-vf', 'scale=1280:720','-shortest', f'{name}.mp4']) | |
| # Gunakan ffmpeg untuk menggabungkan intro dan video | |
| with open('input.txt', 'w') as f: | |
| f.write(f"file '{name}.mp4'\n") | |
| f.write(f"file '{video_file}'\n") | |
| subprocess.run(['ffmpeg','-f','concat','-safe','0','-i','input.txt','-c:v','libx264','-b:v','850k','-bufsize','1000k','-r','30','-b:a','160k','-ar','44100','-ac','2','-c:a','aac','-pix_fmt','yuv420p','-vf','scale=1280:720', output_file]) | |
| return output_file |