PythonでMarkdownソフトを作る

# **🚀 Python + HTML で作る Markdown エディタ & サーバー（保存失敗のデバッグ対応）**

このコードは **Python + HTML** を使って **Markdown を編集・プレビューし、`.md` として保存できるエディタ** を実装するものです。

✅ **保存ボタンを押したらファイル名を入力し、`.md` として保存**  
✅ **Markdown をリアルタイムでプレビュー表示**  
✅ **Python サーバー経由で `.md` ファイルの保存・管理が可能**  
✅ **保存失敗時のエラーを詳細表示**  

---

## **📂 プロジェクト構成**
```plaintext
📁 プロジェクトフォルダ
 ├── markdown_server.py  # Python サーバー (Markdown ファイルの保存 & 読み込み)
 ├── markdown_editor.html  # HTML + JavaScript (Markdown エディタ & プレビュー)
 ├── saved_notes/  # `.md` ファイルの保存先
 └── saved_images/  # 画像ファイルの保存先
```

---

## **📝 `markdown_server.py`（Python サーバー）**
```python
import http.server
import socketserver
import json
import os

PORT = 8000
SAVE_DIR = "saved_notes"

# 保存フォルダを作成（なければ）
if not os.path.exists(SAVE_DIR):
    try:
        os.makedirs(SAVE_DIR)
        print(f"📁 フォルダ '{SAVE_DIR}' を作成しました。")
    except Exception as e:
        print(f"❌ フォルダ作成失敗: {e}")

class MarkdownServer(http.server.SimpleHTTPRequestHandler):
    def do_POST(self):
        if self.path == "/save":
            try:
                content_length = int(self.headers.get("Content-Length", 0))
                if content_length == 0:
                    raise ValueError("受信データが空です")

                post_data = self.rfile.read(content_length).decode("utf-8")
                print(f"📥 受信データの長さ: {content_length}")
                print(f"📥 受信データの中身: {post_data}")

                try:
                    data = json.loads(post_data)
                except json.JSONDecodeError as json_error:
                    print(f"❌ JSON パースエラー: {json_error}")
                    self.send_response(400)
                    self.end_headers()
                    self.wfile.write(f"❌ JSON パースエラー: {json_error}".encode("utf-8"))
                    return

                # ファイル名のバリデーション
                filename = data.get("filename", "").strip()
                content = data.get("content", "")

                if not filename:
                    raise ValueError("❌ ファイル名が空です")

                filename = os.path.basename(filename)  # ディレクトリ名を除外
                if not filename.endswith(".md"):
                    filename += ".md"

                filepath = os.path.join(SAVE_DIR, filename)
                print(f"📂 保存先: {filepath}")

                # 書き込み時のエラーハンドリング
                try:
                    with open(filepath, "w", encoding="utf-8") as f:
                        f.write(content)
                    self.send_response(200)
                    self.end_headers()
                    self.wfile.write(f"✅ {filename} に保存しました！".encode("utf-8"))
                    print(f"✅ {filename} に保存成功！")
                except OSError as write_error:
                    print(f"❌ 書き込みエラー: {write_error}")
                    self.send_response(500)
                    self.end_headers()
                    self.wfile.write(f"❌ 書き込みエラー: {write_error}".encode("utf-8"))

            except ValueError as value_error:
                print(f"❌ 値エラー: {value_error}")
                self.send_response(400)
                self.end_headers()
                self.wfile.write(f"❌ 値エラー: {value_error}".encode("utf-8"))
            except Exception as e:
                print(f"❌ その他のエラー: {e}")
                self.send_response(500)
                self.end_headers()
                self.wfile.write(f"❌ その他のエラー: {e}".encode("utf-8"))

# サーバー起動
try:
    with socketserver.TCPServer(("", PORT), MarkdownServer) as httpd:
        print(f"✅ サーバーが起動しました: http://localhost:{PORT}")
except Exception as e:
    print(f"❌ サーバー起動エラー: {e}")
    ---

## **📝 `markdown_editor.html`（Markdown エディタ）**
```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Markdown Editor</title>
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
    <style>
        body { font-family: Arial, sans-serif; display: flex; height: 100vh; margin: 0; }
        #editor-container, #preview-container {
            width: 50%;
            padding: 10px;
            overflow: auto;
            box-sizing: border-box;
        }
        #editor-container {
            border-right: 1px solid #ccc;
        }
        #editor {
            width: 100%;
            height: 90%;
            font-size: 16px;
            padding: 10px;
            box-sizing: border-box;
            resize: none;
        }
    </style>
    <script>
        function updatePreview() {
            let mdText = document.getElementById("editor").value;
            document.getElementById("preview").innerHTML = marked.parse(mdText);
        }

        function saveMarkdown() {
            let mdText = document.getElementById("editor").value;
            let filename = prompt("保存するファイル名を入力（.mdを省略可）", "markdown_note");

            if (!filename) {
                alert("ファイル名が入力されていません。");
                return;
            }
            if (!filename.endsWith(".md")) {
                filename += ".md";
            }

            fetch("http://localhost:8000/save", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ filename: filename, content: mdText })
            })
            .then(response => response.text())
            .then((message) => {
                if (message.includes("❌")) {
                    alert("保存に失敗しました: " + message);
                } else {
                    alert(`"${filename}" に保存しました！`);
                }
            })
            .catch(error => alert("保存に失敗しました！\nエラー詳細: " + error));
        }
    </script>
</head>
<body>
    <div id="editor-container">
        <button onclick="saveMarkdown()">📝 保存</button>
        <textarea id="editor" oninput="updatePreview()"># Markdown Editor

## ✅ チェックボックス
- [ ] 未完了のタスク
- [x] 完了したタスク

## 🔹 引用
> これは引用のサンプルです。

## 📌 コードブロック
\`\`\`python
print("Hello, Python!")
\`\`\`

        </textarea>
    </div>
    <div id="preview-container">
        <div id="preview"></div>
    </div>
</body>
</html>
```

---

## **📌 使い方**
1. **Pythonサーバーを起動**
   ```sh
   python markdown_server.py
   ```
   → `Serving at http://localhost:8000` と表示されたらOK！

2. **ブラウザで `markdown_editor.html` を開く**
   - **Markdown をエディタに入力**
   - **「📝 保存」ボタンを押し、ファイル名を入力**
   - **`saved_notes/` に `.md` が正しく保存されるか確認**
   - **エラーが出る場合はターミナルに詳細エラーが表示される**

---