Files
CapCutAPI/add_audio_track.py
2025-07-29 08:56:51 +08:00

163 lines
7.5 KiB
Python

# 导入必要的模块
import os
import pyJianYingDraft as draft
import time
from util import generate_draft_url, is_windows_path, url_to_hash
import re
from typing import Optional, Dict, Tuple, List
from pyJianYingDraft import exceptions, Audio_scene_effect_type, Tone_effect_type, Speech_to_song_type, CapCut_Voice_filters_effect_type,CapCut_Voice_characters_effect_type,CapCut_Speech_to_song_effect_type, trange
from create_draft import get_or_create_draft
from settings.local import IS_CAPCUT_ENV
def add_audio_track(
audio_url: str,
draft_folder: Optional[str] = None,
start: float = 0,
end: Optional[float] = None,
target_start: float = 0,
draft_id: Optional[str] = None,
volume: float = 1.0,
track_name: str = "audio_main",
speed: float = 1.0,
sound_effects: Optional[List[Tuple[str, Optional[List[Optional[float]]]]]]=None,
width: int = 1080,
height: int = 1920,
duration: Optional[float] = None # Added duration parameter
) -> Dict[str, str]:
"""
Add an audio track to the specified draft
:param draft_folder: Draft folder path, optional parameter
:param audio_url: Audio URL
:param start: Start time (seconds), default 0
:param end: End time (seconds), default None (use total audio duration)
:param target_start: Target track insertion position (seconds), default 0
:param draft_id: Draft ID, if None or corresponding zip file not found, a new draft will be created
:param volume: Volume level, range 0.0-1.0, default 1.0
:param track_name: Track name, default "audio_main"
:param speed: Playback speed, default 1.0
:param sound_effects: Scene sound effect list, each element is a tuple containing effect type name and parameter list, default None
:return: Updated draft information
"""
# Get or create draft
draft_id, script = get_or_create_draft(
draft_id=draft_id,
width=width,
height=height
)
# Add audio track (only when track doesn't exist)
if track_name is not None:
try:
imported_track = script.get_imported_track(draft.Track_type.audio, name=track_name)
# If no exception is thrown, the track already exists
except exceptions.TrackNotFound:
# Track doesn't exist, create a new track
script.add_track(draft.Track_type.audio, track_name=track_name)
else:
script.add_track(draft.Track_type.audio)
# If duration parameter is provided, prioritize it; otherwise use default audio duration of 0 seconds, real duration will be obtained during download
if duration is not None:
# Use the provided duration, skip duration retrieval and checking
audio_duration = duration
else:
# Use default audio duration of 0 seconds, real duration will be obtained when downloading the draft
audio_duration = 0.0 # Default audio duration is 0 seconds
# duration_result = get_video_duration(audio_url) # Reuse video duration retrieval function
# if not duration_result["success"]:
# print(f"Failed to get audio duration: {duration_result['error']}")
# # Check if audio duration exceeds 10 minutes
# if duration_result["output"] > 600: # 600 seconds = 10 minutes
# raise Exception(f"Audio duration exceeds 10-minute limit, current duration: {duration_result['output']} seconds")
# audio_duration = duration_result["output"]
# Download audio to local
# local_audio_path = download_audio(audio_url, draft_dir)
material_name = f"audio_{url_to_hash(audio_url)}.mp3" # Use original filename + timestamp + fixed mp3 extension
# Build draft_audio_path
draft_audio_path = None
if draft_folder:
if is_windows_path(draft_folder):
# Windows path processing
windows_drive, windows_path = re.match(r'([a-zA-Z]:)(.*)', draft_folder).groups()
parts = [p for p in windows_path.split('\\') if p]
draft_audio_path = os.path.join(windows_drive, *parts, draft_id, "assets", "audio", material_name)
# Normalize path (ensure consistent separators)
draft_audio_path = draft_audio_path.replace('/', '\\')
else:
# macOS/Linux path processing
draft_audio_path = os.path.join(draft_folder, draft_id, "assets", "audio", material_name)
# Set default value for audio end time
audio_end = end if end is not None else audio_duration
# Calculate audio duration
duration = audio_end - start
# Create audio segment
if draft_audio_path:
print('replace_path:', draft_audio_path)
audio_material = draft.Audio_material(replace_path=draft_audio_path, remote_url=audio_url, material_name=material_name, duration=audio_duration)
else:
audio_material = draft.Audio_material(remote_url=audio_url, material_name=material_name, duration=audio_duration)
audio_segment = draft.Audio_segment(
audio_material, # Pass material object
target_timerange=trange(f"{target_start}s", f"{duration}s"), # Use target_start and duration
source_timerange=trange(f"{start}s", f"{duration}s"),
speed=speed, # Set playback speed
volume=volume # Set volume
)
# Add scene sound effects
if sound_effects:
for effect_name, params in sound_effects:
# Choose different effect types based on IS_CAPCUT_ENV
effect_type = None
if IS_CAPCUT_ENV:
# In CapCut environment, look for effects in CapCut_Voice_filters_effect_type
try:
effect_type = getattr(CapCut_Voice_filters_effect_type, effect_name)
except AttributeError:
try:
# Look for effects in CapCut_Voice_characters_effect_type
effect_type = getattr(CapCut_Voice_characters_effect_type, effect_name)
except AttributeError:
# If still not found, look for effects in CapCut_Speech_to_song_effect_type
try:
effect_type = getattr(CapCut_Speech_to_song_effect_type, effect_name)
except AttributeError:
effect_type = None
else:
# In JianYing environment, look for effects in Audio_scene_effect_type
try:
effect_type = getattr(Audio_scene_effect_type, effect_name)
except AttributeError:
# If not found in Audio_scene_effect_type, continue searching in other effect types
try:
effect_type = getattr(Tone_effect_type, effect_name)
except AttributeError:
# If still not found, look for effects in Speech_to_song_type
try:
effect_type = getattr(Speech_to_song_type, effect_name)
except AttributeError:
effect_type = None
# If corresponding effect type is found, add it to the audio segment
if effect_type:
audio_segment.add_effect(effect_type, params)
else:
print(f"Warning: Audio effect named {effect_name} not found")
# Add audio segment to track
script.add_segment(audio_segment, track_name=track_name)
return {
"draft_id": draft_id,
"draft_url": generate_draft_url(draft_id)
}