diff --git a/backgrounds/nature.mp4 b/backgrounds/nature.mp4
new file mode 100644
index 0000000..e69de29
diff --git a/backgrounds/space.mp4 b/backgrounds/space.mp4
new file mode 100644
index 0000000..e69de29
diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc
index 2964e11..2d5aa34 100644
Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ
diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc
index 18a063c..f82619b 100644
Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ
diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc
index ebb8c6e..47fbe1e 100644
Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ
diff --git a/core/__pycache__/video_engine.cpython-311.pyc b/core/__pycache__/video_engine.cpython-311.pyc
new file mode 100644
index 0000000..6750035
Binary files /dev/null and b/core/__pycache__/video_engine.cpython-311.pyc differ
diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc
index 8d204fa..90224ea 100644
Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ
diff --git a/core/admin.py b/core/admin.py
index 8c38f3f..2a18c7e 100644
--- a/core/admin.py
+++ b/core/admin.py
@@ -1,3 +1,8 @@
from django.contrib import admin
+from .models import VideoTask
-# Register your models here.
+@admin.register(VideoTask)
+class VideoTaskAdmin(admin.ModelAdmin):
+ list_display = ('surah_name', 'verse_start', 'verse_end', 'reciter_name', 'status', 'created_at')
+ list_filter = ('status', 'created_at')
+ search_fields = ('surah_name', 'reciter_name')
\ No newline at end of file
diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py
new file mode 100644
index 0000000..7890823
--- /dev/null
+++ b/core/migrations/0001_initial.py
@@ -0,0 +1,33 @@
+# Generated by Django 5.2.7 on 2026-02-23 08:03
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='VideoTask',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('surah_number', models.IntegerField()),
+ ('surah_name', models.CharField(max_length=255)),
+ ('reciter_identifier', models.CharField(max_length=255)),
+ ('reciter_name', models.CharField(max_length=255)),
+ ('verse_start', models.IntegerField()),
+ ('verse_end', models.IntegerField()),
+ ('background_video', models.CharField(max_length=255)),
+ ('text_color', models.CharField(default='#FFFFFF', max_length=20)),
+ ('status', models.CharField(choices=[('pending', 'Pending'), ('processing', 'Processing'), ('completed', 'Completed'), ('failed', 'Failed')], default='pending', max_length=20)),
+ ('output_path', models.CharField(blank=True, max_length=500, null=True)),
+ ('error_message', models.TextField(blank=True, null=True)),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('updated_at', models.DateTimeField(auto_now=True)),
+ ],
+ ),
+ ]
diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc
new file mode 100644
index 0000000..97f3b3b
Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ
diff --git a/core/models.py b/core/models.py
index 71a8362..3d955e4 100644
--- a/core/models.py
+++ b/core/models.py
@@ -1,3 +1,26 @@
from django.db import models
-# Create your models here.
+class VideoTask(models.Model):
+ STATUS_CHOICES = [
+ ('pending', 'Pending'),
+ ('processing', 'Processing'),
+ ('completed', 'Completed'),
+ ('failed', 'Failed'),
+ ]
+
+ surah_number = models.IntegerField()
+ surah_name = models.CharField(max_length=255)
+ reciter_identifier = models.CharField(max_length=255)
+ reciter_name = models.CharField(max_length=255)
+ verse_start = models.IntegerField()
+ verse_end = models.IntegerField()
+ background_video = models.CharField(max_length=255)
+ text_color = models.CharField(max_length=20, default='#FFFFFF')
+ status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
+ output_path = models.CharField(max_length=500, blank=True, null=True)
+ error_message = models.TextField(blank=True, null=True)
+ created_at = models.DateTimeField(auto_now_add=True)
+ updated_at = models.DateTimeField(auto_now=True)
+
+ def __str__(self):
+ return f"{self.surah_name} ({self.verse_start}-{self.verse_end}) - {self.status}"
\ No newline at end of file
diff --git a/core/templates/core/index.html b/core/templates/core/index.html
index faec813..067d2a3 100644
--- a/core/templates/core/index.html
+++ b/core/templates/core/index.html
@@ -1,145 +1,214 @@
-{% extends "base.html" %}
+{% load static %}
+
+
+
+
+
+ {{ project_name }} - Quran Reels Generator
+
+
+
+
+
-{% block title %}{{ project_name }}{% endblock %}
-
-{% block head %}
-
-
-
-
-{% endblock %}
-
-{% block content %}
-
-
-
Analyzing your requirements and generating your app…
-
-
Loading…
+
-
-
-{% endblock %}
\ No newline at end of file
+
+
+
+
+
Create Beautiful Quran Reels
+
Select verses, pick a reciter, and generate professional videos in seconds.
+
+
+
+
+
+
+
+
+
diff --git a/core/urls.py b/core/urls.py
index 6299e3d..835cf8d 100644
--- a/core/urls.py
+++ b/core/urls.py
@@ -1,7 +1,8 @@
from django.urls import path
-
-from .views import home
+from .views import home, generate_video_view, get_surah_details
urlpatterns = [
path("", home, name="home"),
-]
+ path("generate/", generate_video_view, name="generate_video"),
+ path("surah-details/
/", get_surah_details, name="surah_details"),
+]
\ No newline at end of file
diff --git a/core/video_engine.py b/core/video_engine.py
new file mode 100644
index 0000000..edab27c
--- /dev/null
+++ b/core/video_engine.py
@@ -0,0 +1,92 @@
+import os
+import subprocess
+import requests
+import json
+from pathlib import Path
+
+WORKSPACE_ROOT = Path(__file__).resolve().parent.parent
+OUTPUTS_DIR = WORKSPACE_ROOT / "outputs"
+FINAL_VIDEO_DIR = OUTPUTS_DIR / "final_video"
+TEMP_AUDIO_DIR = OUTPUTS_DIR / "temp_audio"
+AUDIO_DIR = OUTPUTS_DIR / "audio"
+BACKGROUNDS_DIR = WORKSPACE_ROOT / "backgrounds"
+
+def generate_video(task_id):
+ from core.models import VideoTask
+ task = VideoTask.objects.get(id=task_id)
+ task.status = 'processing'
+ task.save()
+
+ try:
+ # 1. Fetch Verses Text and Audio
+ # For simplicity in this slice, we fetch from api.alquran.cloud
+ # We need both the text (for ImageMagick) and the audio (for FFmpeg)
+
+ verses_data = []
+ audio_files = []
+
+ # We'll use the 'ar.alafasy' or user-selected reciter
+ # Example: https://api.alquran.cloud/v1/surah/1/ar.alafasy
+ api_url = f"https://api.alquran.cloud/v1/surah/{task.surah_number}/{task.reciter_identifier}"
+ resp = requests.get(api_url)
+ resp.raise_for_status()
+ data = resp.json()['data']
+
+ all_ayahs = data['ayahs']
+ selected_ayahs = [a for a in all_ayahs if task.verse_start <= a['numberInSurah'] <= task.verse_end]
+
+ # Download audio files and prepare text
+ for i, ayah in enumerate(selected_ayahs):
+ audio_url = ayah['audio']
+ audio_path = TEMP_AUDIO_DIR / f"task_{task.id}_ayah_{i}.mp3"
+ with requests.get(audio_url, stream=True) as r:
+ r.raise_for_status()
+ with open(audio_path, 'wb') as f:
+ for chunk in r.iter_content(chunk_size=8192):
+ f.write(chunk)
+ audio_files.append(str(audio_path))
+ verses_data.append({
+ 'text': ayah['text'],
+ 'audio': str(audio_path)
+ })
+
+ # 2. Combine Audio
+ combined_audio = AUDIO_DIR / f"task_{task.id}_full.mp3"
+ # ffmpeg -i "concat:file1.mp3|file2.mp3" -acodec copy output.mp3
+ concat_str = "|".join(audio_files)
+ subprocess.run([
+ 'ffmpeg', '-y', '-i', f'concat:{concat_str}', '-acodec', 'libmp3lame', str(combined_audio)
+ ], check=True)
+
+ # 3. Generate Video with FFmpeg
+ # We use a background video and overlay the audio
+ bg_video = BACKGROUNDS_DIR / task.background_video
+ if not bg_video.exists():
+ # Fallback to a placeholder or first available background
+ available = list(BACKGROUNDS_DIR.glob("*.mp4"))
+ if available:
+ bg_video = available[0]
+ else:
+ raise Exception("No background video found in backgrounds/ folder")
+
+ output_video = FINAL_VIDEO_DIR / f"reels_{task.id}.mp4"
+
+ # Simple FFmpeg command: loop background, add audio, trim to audio length
+ # For text overlay, we'd ideally use drawtext or ImageMagick.
+ # Here we do a basic version:
+ subprocess.run([
+ 'ffmpeg', '-y', '-stream_loop', '-1', '-i', str(bg_video),
+ '-i', str(combined_audio), '-shortest', '-map', '0:v:0', '-map', '1:a:0',
+ '-pix_fmt', 'yuv420p', '-vf', f"drawtext=text='{task.surah_name}':fontcolor={task.text_color}:fontsize=48:x=(w-text_w)/2:y=(h-text_h)/2",
+ str(output_video)
+ ], check=True)
+
+ task.status = 'completed'
+ task.output_path = f"/outputs/final_video/{output_video.name}"
+ task.save()
+
+ except Exception as e:
+ task.status = 'failed'
+ task.error_message = str(e)
+ task.save()
+ raise e
diff --git a/core/views.py b/core/views.py
index c9aed12..ff007ee 100644
--- a/core/views.py
+++ b/core/views.py
@@ -1,25 +1,86 @@
import os
-import platform
-
-from django import get_version as django_version
-from django.shortcuts import render
-from django.utils import timezone
-
+import requests
+from django.shortcuts import render, redirect, get_object_or_404
+from django.http import JsonResponse
+from .models import VideoTask
+from .video_engine import generate_video
+import threading
def home(request):
- """Render the landing screen with loader and environment details."""
- host_name = request.get_host().lower()
- agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
- now = timezone.now()
+ # Fetch surahs and reciters for the form
+ surahs = []
+ reciters = []
+ try:
+ surah_resp = requests.get("https://api.alquran.cloud/v1/surah", timeout=5)
+ if surah_resp.status_code == 200:
+ surahs = surah_resp.json()['data']
+
+ reciter_resp = requests.get("https://api.alquran.cloud/v1/edition?format=audio&language=ar&type=versebyverse", timeout=5)
+ if reciter_resp.status_code == 200:
+ reciters = reciter_resp.json()['data']
+ except:
+ pass
+
+ backgrounds = []
+ if os.path.exists('backgrounds'):
+ backgrounds = [f for f in os.listdir('backgrounds') if f.endswith(('.mp4', '.mov'))]
+
+ if not backgrounds:
+ backgrounds = ["nature.mp4"]
+
+ tasks = VideoTask.objects.all().order_by('-created_at')[:10]
context = {
- "project_name": "New Style",
- "agent_brand": agent_brand,
- "django_version": django_version(),
- "python_version": platform.python_version(),
- "current_time": now,
- "host_name": host_name,
- "project_description": os.getenv("PROJECT_DESCRIPTION", ""),
- "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
+ "surahs": surahs,
+ "reciters": reciters,
+ "backgrounds": backgrounds,
+ "tasks": tasks,
+ "project_name": "Quran Reels Gen",
}
return render(request, "core/index.html", context)
+
+def generate_video_view(request):
+ if request.method == "POST":
+ surah_number = request.POST.get('surah')
+ reciter = request.POST.get('reciter')
+ verse_start = request.POST.get('verse_start')
+ verse_end = request.POST.get('verse_end')
+ background = request.POST.get('background')
+ text_color = request.POST.get('text_color', '#FFFFFF')
+
+ # Get surah name
+ surah_name = "Unknown"
+ try:
+ surah_resp = requests.get(f"https://api.alquran.cloud/v1/surah/{surah_number}", timeout=5)
+ if surah_resp.status_code == 200:
+ surah_name = surah_resp.json()['data']['englishName']
+ except:
+ pass
+
+ task = VideoTask.objects.create(
+ surah_number=surah_number,
+ surah_name=surah_name,
+ reciter_identifier=reciter,
+ reciter_name=reciter,
+ verse_start=verse_start,
+ verse_end=verse_end,
+ background_video=background,
+ text_color=text_color,
+ status='pending'
+ )
+
+ # Run generation in background thread
+ thread = threading.Thread(target=generate_video, args=(task.id,))
+ thread.start()
+
+ return redirect('home')
+ return redirect('home')
+
+def get_surah_details(request, surah_number):
+ try:
+ resp = requests.get(f"https://api.alquran.cloud/v1/surah/{surah_number}", timeout=5)
+ if resp.status_code == 200:
+ return JsonResponse(resp.json()['data'])
+ except:
+ pass
+ return JsonResponse({'error': 'Failed to fetch'}, status=400)
diff --git a/outputs/temp_audio/task_1_ayah_0.mp3 b/outputs/temp_audio/task_1_ayah_0.mp3
new file mode 100644
index 0000000..ef80dc5
Binary files /dev/null and b/outputs/temp_audio/task_1_ayah_0.mp3 differ
diff --git a/outputs/temp_audio/task_1_ayah_1.mp3 b/outputs/temp_audio/task_1_ayah_1.mp3
new file mode 100644
index 0000000..8e5b998
Binary files /dev/null and b/outputs/temp_audio/task_1_ayah_1.mp3 differ
diff --git a/outputs/temp_audio/task_1_ayah_2.mp3 b/outputs/temp_audio/task_1_ayah_2.mp3
new file mode 100644
index 0000000..473ad04
Binary files /dev/null and b/outputs/temp_audio/task_1_ayah_2.mp3 differ
diff --git a/outputs/temp_audio/task_1_ayah_3.mp3 b/outputs/temp_audio/task_1_ayah_3.mp3
new file mode 100644
index 0000000..601922e
Binary files /dev/null and b/outputs/temp_audio/task_1_ayah_3.mp3 differ
diff --git a/outputs/temp_audio/task_1_ayah_4.mp3 b/outputs/temp_audio/task_1_ayah_4.mp3
new file mode 100644
index 0000000..b36c662
Binary files /dev/null and b/outputs/temp_audio/task_1_ayah_4.mp3 differ
diff --git a/outputs/temp_audio/task_2_ayah_0.mp3 b/outputs/temp_audio/task_2_ayah_0.mp3
new file mode 100644
index 0000000..b43dfc9
Binary files /dev/null and b/outputs/temp_audio/task_2_ayah_0.mp3 differ