# app.py import streamlit as st from pydub import AudioSegment from io import BytesIO import tempfile from datetime import timedelta # ✅ ffmpeg はサーバにインストール済みなので、明示的なパス指定は不要! # AudioSegment.converter や AudioSegment.ffprobe は書かなくてOK # アプリ設定 st.set_page_config(page_title="音声カッター", layout="centered") st.title("✂️ 音声ファイルカッター(シンプル&見やすい)") uploaded_file = st.file_uploader("音声ファイルを選んでください(mp3, wav, m4a)", type=["mp3", "wav", "m4a"]) def format_time(seconds: float) -> str: return str(timedelta(seconds=round(seconds))) if uploaded_file: st.audio(uploaded_file) try: # 一時ファイルに保存 with tempfile.NamedTemporaryFile(delete=False, suffix=".tmp") as tmp: tmp.write(uploaded_file.read()) audio = AudioSegment.from_file(tmp.name) duration_sec = len(audio) / 1000.0 if duration_sec < 0.01: st.warning("❗ 音声が短すぎて切り出せません。") st.stop() st.subheader("🎚️ 切り出したい範囲を選んでください") start_sec, end_sec = st.slider( f"範囲(全長 {format_time(duration_sec)})", min_value=0.0, max_value=duration_sec, value=(0.0, min(1.0, duration_sec)), step=0.01 ) col1, col2 = st.columns(2) col1.write(f"▶️ 開始時間: `{format_time(start_sec)}`") col2.write(f"⏹️ 終了時間: `{format_time(end_sec)}`") if st.button("🎬 切り出して保存"): if start_sec >= end_sec: st.warning("⚠️ 終了時間は開始時間より後にしてください。") else: start_ms = int(start_sec * 1000) end_ms = int(end_sec * 1000) cut_audio = audio[start_ms:end_ms] buf = BytesIO() cut_audio.export(buf, format="mp3") buf.seek(0) st.success("✅ 切り出し完了!") st.audio(buf, format="audio/mp3") st.download_button( label="💾 ダウンロード(MP3)", data=buf, file_name="cut_audio.mp3", mime="audio/mpeg" ) except Exception as e: st.error(f"❌ エラーが発生しました:\n\n{e}")