レシピ追加機能の実装 YouTubeのサムネイル画像を取得、JavaScriptの記述【レシピ提案アプリ③】
こんにちは!前回に続いて、レシピ提案アプリの開発日記第3弾です🎉
今回は「レシピ追加機能」の実装について詳しく紹介します!
レシピ追加機能について
ユーザーがレシピを追加するために入力する情報は以下のとおりです。
-
YouTubeのURL
-
レシピ名
-
サムネイル画像(入力がなければ自動取得)
-
使用する食材
-
備考(特殊な調味料の説明など)
理想の機能
PyTubeを用いて、自動でタイトルや使用する食材等を抽出できればいいですが、
今回は簡単に実装していきたいので、後回しにしました。
| YouTubeから取得する情報 | アプリに反映するフィールド |
|---|---|
| タイトル | レシピ名 |
| 概要欄 | 使用する食材 |
| サムネイル画像 | サムネイル画像 |
さらに、食材リストは将来的に50種類以上になる予定なので、食材を検索・絞り込みできる機能も必要と考えました!
YouTubeのサムネイル画像を簡単に取得する方法
将来的にはPythonのpytubeライブラリで情報を自動取得したいですが、今回はもっとシンプルな方法を採用しました!
参考:YouTubeのサムネイルURLについて(外部サイト)
方法
YouTubeのURL例:
https://www.youtube.com/watch?v=UOzLY-2aJ30
この場合、?v=以降の**UOzLY-2aJ30** が Video ID です!
最高解像度のサムネイルURLはこのように作れます👇
https://img.youtube.com/vi/UOzLY-2aJ30/maxresdefault.jpg
他にも取得できるサイズ
-
sddefault.jpg -
hqdefault.jpg -
mqdefault.jpg -
default.jpg
必要に応じて使い分けが可能です👌
実際に作成したページ(add_recipe.html)
<!-- 一部抜粋 -->
<div class="container mt-5">
<h1 class="text-center">レシピ追加</h1>
<form id="add-recipe-form" class="mt-4">
<div class="mb-3">
<label for="youtube-url" class="form-label">YouTube URL</label>
<input type="url" class="form-control" id="youtube-url" name="youtube_url" required>
</div>
<div class="mb-3">
<label for="thumbnail" class="form-label">サムネイル画像</label>
<input type="text" class="form-control" id="thumbnail" name="thumbnail">
</div>
<div class="mb-3">
<label for="ingredients" class="form-label">使用する食材</label>
<select class="form-control" id="ingredients" name="ingredients" multiple>
<!-- サーバーから食材一覧を取得して表示 -->
</select>
</div>
<!-- 他にもカテゴリ選択や備考欄など -->
<button type="submit" class="btn btn-primary">追加</button>
</form>
</div>
JavaScriptの記述を振り返る
JavaScriptはまだ学習期間が浅く、初心者なので今回使ったコードの内容を
振り返りました。
1. CSRFトークンを取得する関数をJavaScriptで記述
DjangoのデフォルトのCSRF機能({% csrf_token %})を使わなかった理由は、
食材を入力する欄で、入力したワードを元に絞り込む機能をつくりたかったため(食材の数は50個くらいを想定しており探すのはめんどくさい)
このような非同期リクエストの機能を実装するにはDjangoのデフォルトのCSRF機能({% csrf_token %})では記述できないからです。
非同期リクエスト
ウェブページがサーバーと通信を行う際に、ページ全体を再読み込みすることなくデータの送受信を行う仕組みのこと
function getCSRFToken() {
const cookies = document.cookie.split(';');
for (let cookie of cookies) {
const [name, value] = cookie.trim().split('=');
if (name === 'csrftoken') {
return value;
}
}
return null;
}
2. レシピ追加フォームの非同期送信
フォーム送信時にページ全体をリロードせず、データだけ送信する仕組み
document.getElementById('add-recipe-form').addEventListener('submit', async function(event) {
event.preventDefault();
const formData = new FormData(event.target);
const data = {
name: formData.get('name'),
url: formData.get('youtube_url'),
thumbnail: formData.get('thumbnail'),
ingredients: formData.getAll('ingredients'),
categories: formData.getAll('categories'),
notes: formData.get('notes')
};
if (!data.name || !data.url || !data.ingredients.length || !data.categories.length) {
alert('必須フィールドをすべて入力してください。');
return;
}
try {
const response = await fetch('/recipes/add-recipe/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCSRFToken(),
},
body: JSON.stringify(data)
});
if (response.ok) {
alert('レシピが正常に追加されました!');
event.target.reset();
} else {
const errorData = await response.json();
alert(`エラーが発生しました: ${errorData.message || '不明なエラー'}`);
}
} catch (error) {
alert(`通信エラーが発生しました: ${error.message}`);
}
});
食材検索機能を追加
食材が50個以上あると選びにくくなるので、検索ボックスを追加しました!
次回の記事でこの部分は詳細を書いていく予定です。
document.addEventListener('DOMContentLoaded', function() {
const ingredientSelect = document.getElementById('ingredients');
const searchBox = document.createElement('input');
searchBox.type = 'text';
searchBox.placeholder = '食材を検索';
searchBox.classList.add('form-control', 'mb-3');
ingredientSelect.parentNode.insertBefore(searchBox, ingredientSelect);
searchBox.addEventListener('input', function() {
const filter = searchBox.value.toLowerCase();
const options = ingredientSelect.options;
for (let i = 0; i < options.length; i++) {
const option = options[i];
const text = option.textContent.toLowerCase();
const reading = option.getAttribute('data-reading')?.toLowerCase() || '';
option.style.display = text.includes(filter) || reading.includes(filter) ? '' : 'none';
}
});
});
これで、「とり」と入力すると「鶏むね肉」、「鶏もも肉」だけが表示されるようになります
レシピ提案アプリ開発記事一覧はこちらから ↓