Related
I am trying to display search result for Youtube videos while user are typing their search terms.
I am using Django, jquery and ajax.
Here are the important information from my different files (I am just showing the relevant info and cutting the other stuff) :
-> Urls.py file :
urlpatterns = [
path('video/search/', views.video_search, name="video_search"),]
-> add_video.html file :
<form method="post">
{% for field in search_form %}
<div class="form-group">
{{ field.errors }}
{{ field.label_tag }}
{% render_field field class="form-control" %}
</div>
{% endfor %}
</form>
<div id="search_result"></div>
-> forms.py file :
class SearchForm(forms.Form):
search_term = forms.CharField(max_length=255, label="Search for videos")
-> firstajax.js file :
$(function() {
var DelayTimer;
$('#id_search_term').keyup(function() {
clearTimeout(DelayTimer);
$('#search_result').text('Loading...');
DelayTimer = setTimeout(function() {
var text = $('#id_search_term').val();
$.ajax({
url: 'video/search/',
data: {
'search_term': text
},
dataType: 'json',
success: function(data) {
var results = '';
$('#search_result').text('');
data['items'].forEach(function(video){
results += video['snippet']['title']
});
$('#search_result').append(results);
}
});
}, 1000);
});
});
-> views.py file :
def video_search(request):
search_form = SearchForm(request.GET)
if search_form.is_valid():
encoded_search_term = parse.quote(search_form.cleaned_data["search_term"])
response = requests.get(f'https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=5&q={encoded_search_term}&key={YOUTUBE_API_KEY}')
return JsonResponse(response.json())
return JsonResponse({'error': 'Not able to validate form'})
Whenever I am typing in my search bar, I get just the "Loading" displaying in search_result div... And nothing else is happening. However, I get an HTTP 200 as response for my request and when I go and check the (local host)video/search/?search_term=mysearchterms, I can see the json I want like that :
{"kind": "youtube#searchListResponse", "etag": "B7bvQKmH1RYz_vKyhrqSeOp8_Y4", "nextPageToken": "CAYQAA", "regionCode": "FR", "pageInfo": {"totalResults": 1000000, "resultsPerPage": 6}, "items": [{"kind": "youtube#searchResult", "etag": "JbFNoD-7t_z8DeR3uysPXKr7RwE", "id": {"kind": "youtube#video", "videoId": "xPwa6NR37Ds"}, "snippet": {"publishedAt": "2020-05-11T21:01:17Z", "channelId": "UCiYcA0gJzg855iSKMrX3oHg", "title": "THE BEST SPOOKY SCARY SUNDAY SO FAR | Reacting To Scary Videos [SSS #023]", "description": "Can this REALLY be!? A #SpookyScarySunday with a perfect rating of 10/10? PLEASE check out more works from the ANIMATORS: Railroad (MeatCanyon): ...", "thumbnails": {"default": {"url": "https://i.ytimg.com/vi/xPwa6NR37Ds/default.jpg", "width": 120, "height": 90}, "medium": {"url": "https://i.ytimg.com/vi/xPwa6NR37Ds/mqdefault.jpg", "width": 320, "height": 180}, "high": {"url": "https://i.ytimg.com/vi/xPwa6NR37Ds/hqdefault.jpg", "width": 480, "height": 360}}, "channelTitle": "CoryxKenshin", "liveBroadcastContent": "none", "publishTime": "2020-05-11T21:01:17Z"}}, {"kind": "youtube#searchResult", "etag": "SVAGxv49Pbc2yFVKX0O7Hqp5tZQ", "id": {"kind": "youtube#video", "videoId": "JHeU7IclczY"}, "snippet": {"publishedAt": "2020-05-10T19:11:35Z", "channelId": "UCiYcA0gJzg855iSKMrX3oHg", "title": "DO NOT TAKE YOUR EYES OFF HIM | Reacting To Scary Videos [SSS #022]", "description": "For this #SpookyScarySunday episode, I compiled some old clips that have never 'officially' made it into an #SSS entry but as I am short on time HERE THEY ...", "thumbnails": {"default": {"url": "https://i.ytimg.com/vi/JHeU7IclczY/default.jpg", "width": 120, "height": 90}, "medium": {"url": "https://i.ytimg.com/vi/JHeU7IclczY/mqdefault.jpg", "width": 320, "height": 180}, "high": {"url": "https://i.ytimg.com/vi/JHeU7IclczY/hqdefault.jpg", "width": 480, "height": 360}}, "channelTitle": "CoryxKenshin", "liveBroadcastContent": "none", "publishTime": "2020-05-10T19:11:35Z"}}, {"kind": "youtube#searchResult", "etag": "Aw_CoF2Ep36gJuCBUFAT1huUqOE", "id": {"kind": "youtube#video", "videoId": "94zbEIlTHGI"}, "snippet": {"publishedAt": "2020-05-03T23:55:09Z", "channelId": "UCiYcA0gJzg855iSKMrX3oHg", "title": "THE ORIGIN OF SIREN HEAD | Reacting To Scary Videos [SSS #021]", "description": "Another week of #SpookyScarySunday with a HEAVY emphasis on the up and coming Creepypasta monster, SIREN HEAD. PLEASE check out more works ...", "thumbnails": {"default": {"url": "https://i.ytimg.com/vi/94zbEIlTHGI/default.jpg", "width": 120, "height": 90}, "medium": {"url": "https://i.ytimg.com/vi/94zbEIlTHGI/mqdefault.jpg", "width": 320, "height": 180}, "high": {"url": "https://i.ytimg.com/vi/94zbEIlTHGI/hqdefault.jpg", "width": 480, "height": 360}}, "channelTitle": "CoryxKenshin", "liveBroadcastContent": "none", "publishTime": "2020-05-03T23:55:09Z"}}, {"kind": "youtube#searchResult", "etag": "g1iEghTkqsu2DgxnposRwixYQNY", "id": {"kind": "youtube#video", "videoId": "ZQddjrlIjFo"}, "snippet": {"publishedAt": "2020-05-15T10:03:39Z", "channelId": "UCKzoPVx8qo1A2G_xpQpX2Yg", "title": "MGA KATANUNGAN TUNGKOL SA SSS SBWS PROGRAM | E-LEARNING | iSirMac", "description": "SSS Official Facebook Page: https://www.facebook.com/SSSPh/ PLS. SUBSCRIBE TO MY 2ND CHANNEL: ...", "thumbnails": {"default": {"url": "https://i.ytimg.com/vi/ZQddjrlIjFo/default.jpg", "width": 120, "height": 90}, "medium": {"url": "https://i.ytimg.com/vi/ZQddjrlIjFo/mqdefault.jpg", "width": 320, "height": 180}, "high": {"url": "https://i.ytimg.com/vi/ZQddjrlIjFo/hqdefault.jpg", "width": 480, "height": 360}}, "channelTitle": "iSirMac", "liveBroadcastContent": "none", "publishTime": "2020-05-15T10:03:39Z"}}, {"kind": "youtube#searchResult", "etag": "2XMimglxgRxl9cIgm6IzDAbjzzc", "id": {"kind": "youtube#video", "videoId": "dzrKV_ceVKs"}, "snippet": {"publishedAt": "2020-04-16T18:38:03Z", "channelId": "UCKHb_N_Zq0uv0_EYOiDhhgA", "title": "SSS 5K TO 8K NA AYUDA O TULONG PINANSIYAL SIMULA APRIL 16, 2020 | ALAMIN! | SOCIAL SECURITY SYSTEM", "description": "Unemployment Benefit kay SSS Pwedeng Makakuha ng Hanggang 20k Eto po Guideline kung Paano: https://www.youtube.com/watch?v=aztXcndZIMw Sa mga ...", "thumbnails": {"default": {"url": "https://i.ytimg.com/vi/dzrKV_ceVKs/default.jpg", "width": 120, "height": 90}, "medium": {"url": "https://i.ytimg.com/vi/dzrKV_ceVKs/mqdefault.jpg", "width": 320, "height": 180}, "high": {"url": "https://i.ytimg.com/vi/dzrKV_ceVKs/hqdefault.jpg", "width": 480, "height": 360}}, "channelTitle": "SuperMark TV", "liveBroadcastContent": "none", "publishTime": "2020-04-16T18:38:03Z"}}, {"kind": "youtube#searchResult", "etag": "4HzuPEryfra2aXgiWOZ00DoSdic", "id": {"kind": "youtube#video", "videoId": "edk2uac_x0Y"}, "snippet": {"publishedAt": "2020-04-19T18:21:52Z", "channelId": "UCiYcA0gJzg855iSKMrX3oHg", "title": "SPOOKY SCARY SUNDAY IS BACK | Reacting To Scary Stories [SSS #019]", "description": "The FIRST #SpookyScarySunday in a year and you guys BROUGHT THE HEAT!! PLEASE check out more works from the ANIMATORS: Golden Arches ...", "thumbnails": {"default": {"url": "https://i.ytimg.com/vi/edk2uac_x0Y/default.jpg", "width": 120, "height": 90}, "medium": {"url": "https://i.ytimg.com/vi/edk2uac_x0Y/mqdefault.jpg", "width": 320, "height": 180}, "high": {"url": "https://i.ytimg.com/vi/edk2uac_x0Y/hqdefault.jpg", "width": 480, "height": 360}}, "channelTitle": "CoryxKenshin", "liveBroadcastContent": "none", "publishTime": "2020-04-19T18:21:52Z"}}]}
It is weird because when I tried to check if the Ajax call was working it seems ok and also when I check with something easier like this :
-> views.py file:
def video_search(request):
search_form = SearchForm(request.GET)
if search_form.is_valid():
response = search_form.cleaned_data['search_term']
return JsonResponse({"Hello":response})
return JsonResponse({'error':'Not able to validate form'})
-> firstajax.js file:
$(function() {
var DelayTimer;
$('#id_search_term').keyup(function() {
clearTimeout(DelayTimer);
$('#search_result').text('Loading...');
DelayTimer = setTimeout(function() {
var text = $('#id_search_term').val();
$.ajax({
url: 'video/search/',
data: {
'search_term': text
},
dataType: 'json',
success: function(data) {
$('#search_result').text(data['Hello']);
}
});
}, 1000);
});
});
Then it works just fine and the "Loading..." text within my search_result div is replaced with the search term that I started typing as a user.
Any idea what is going wrong please ?
Thanks a lot for any help :)
T.
I've been trying to fetch videos from YouTube API, but it seems like whenever I try to fetch them, somehow the map function won't work. (TypeError: Cannot read property 'map' of undefined)
The code was successful in fetching array lists from here, but not from YouTube.
I suspect the problem occurred because the array that YouTube provided was inside an [items] object.
Here are my code:
PopularApp.js
import React, { Component, useState, useEffect } from 'react';
import PopularVid from "./components/PopularVid";
import axios from 'axios';
const PopularApp = () => {
const [video, setVideo] = useState([]);
const hotVids = video.items;
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [vidsPerPage, setVidsPerPage] = useState(10);
useEffect(() => { //whenever this function runs, it will run this/fetch data from API, neverending loop
const fetchPosts = async () => {
setLoading();
const res = await axios.get('https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails,statistics&chart=mostPopular&maxResults=12&key=myapikey');
setVideo(res.data);
setLoading(false);
}
fetchPosts();
}, []);
console.log(hotVids);
return(
<div>
<PopularVid videos={hotVids} loading={loading}/>
</div>
)
}
export default PopularApp;
PopularVid.js
import React from 'react';
const PopularVid = ({videos, loading}) => {
if(loading){
return <div>Loading...</div>
}
return <ul>
{videos.map(video=>(
<li key={video.id}>
{video.snippet.title}
</li>
))}
</ul>;
}
export default PopularVid;
And here is the sample of the YouTube json file that I am trying to parse:
{
"kind": "youtube#videoListResponse",
"etag": "_Y60U4EX77fYwquDNkByKBxEGC8",
"items": [
{
"kind": "youtube#video",
"etag": "V8SLDA5Sop7jpKOC9NnsckQoOwM",
"id": "lEIqjoO0-Bs",
"snippet": {
"publishedAt": "2020-04-29T19:06:00Z",
"channelId": "UCKrdjiuS66yXOdEZ_cOD_TA",
"title": "Video #1",
"description": "This is the description",
"thumbnails": {
"default": {
"url": "https://i.ytimg.com/vi/lEIqjoO0-Bs/default.jpg",
"width": 120,
"height": 90
},
"medium": {
"url": "https://i.ytimg.com/vi/lEIqjoO0-Bs/mqdefault.jpg",
"width": 320,
"height": 180
},
"high": {
"url": "https://i.ytimg.com/vi/lEIqjoO0-Bs/hqdefault.jpg",
"width": 480,
"height": 360
},
"standard": {
"url": "https://i.ytimg.com/vi/lEIqjoO0-Bs/sddefault.jpg",
"width": 640,
"height": 480
},
"maxres": {
"url": "https://i.ytimg.com/vi/lEIqjoO0-Bs/maxresdefault.jpg",
"width": 1280,
"height": 720
}
},
"channelTitle": "Channel",
"categoryId": "10",
"liveBroadcastContent": "none",
},
"statistics": {
"viewCount": "4633587",
"likeCount": "349875",
"dislikeCount": "6602",
"favoriteCount": "0",
"commentCount": "27237"
}
},
{
"kind": "youtube#video",
"etag": "2KGplnTU4KAR0gTjmL8nXnzlK34",
"id": "XRNjRcKZc1A",
"snippet": {
"publishedAt": "2020-04-29T16:00:30Z",
"channelId": "UC47kJWRBD-NREBvmBg5kWeA",
"title": "Video #2",
"description": "Description #2",
"thumbnails": {
"default": {
"url": "https://i.ytimg.com/vi/XRNjRcKZc1A/default.jpg",
"width": 120,
"height": 90
},
"medium": {
"url": "https://i.ytimg.com/vi/XRNjRcKZc1A/mqdefault.jpg",
"width": 320,
"height": 180
},
"high": {
"url": "https://i.ytimg.com/vi/XRNjRcKZc1A/hqdefault.jpg",
"width": 480,
"height": 360
},
"standard": {
"url": "https://i.ytimg.com/vi/XRNjRcKZc1A/sddefault.jpg",
"width": 640,
"height": 480
},
"maxres": {
"url": "https://i.ytimg.com/vi/XRNjRcKZc1A/maxresdefault.jpg",
"width": 1280,
"height": 720
}
},
"channelTitle": "King Von",
"categoryId": "10",
"liveBroadcastContent": "none",
"defaultAudioLanguage": "en"
},
"statistics": {
"viewCount": "901039",
"likeCount": "62449",
"dislikeCount": "1862",
"favoriteCount": "0",
"commentCount": "5184"
}
}
],
"nextPageToken": "CAIQAA",
"pageInfo": {
"totalResults": 200,
"resultsPerPage": 2
}
}
res.data is an object you can not use map for an object, you can use it for arrays. I believe what you need to map is res.data.items
Two things:
The initial value of hotVids is undefined. ([].items). After the data is fetched it should be OK.
loading is never true. Looks like you meant to set it to true inside useEffect. You also could have initialised it to true with useState.
To deal with data that isn’t loaded yet, you’d generally do one of two things: set a reasonable default (like your empty array), which can render successfully; or prevent rendering until loading is done (like your loading variable).
My media host is using JSONP to embed videos. I embed this script, along with a few others, in order to embed videos. My understanding is that it's using JSONP in order to overcome CORS issues.
What I do not understand is the last line of the script.
window['wistiajsonp-/embed/medias/8up1lc9606.jsonp'] = window['wistiajsonp-/embed/medias/8up1lc9606.jsonp'];
window['wistiajsonp-/embed/medias/8up1lc9606.jsonp'] = {
"media": {
"assets": [{
"type": "original",
"slug": "original",
"display_name": "Original file",
"width": 1920,
"height": 1080,
"ext": "mp4",
"size": 109515791,
"bitrate": 16127,
"public": true,
"status": 2,
"progress": 1.0,
"url": "https://embed-ssl.wistia.com/deliveries/9b53a11c8a871733aadd479d26a10d4555de2d66.bin",
"created_at": 1522785172
}, {
"type": "still_image",
"slug": "still_image_1920x1080",
"display_name": "Image",
"width": 1920,
"height": 1080,
"ext": "jpg",
"size": 216848,
"bitrate": 0,
"public": true,
"status": 2,
"progress": 1.0,
"url": "https://embed-ssl.wistia.com/deliveries/bf2cc0bf9de369545df9c9fa8be8371ab8b12f56.bin",
"created_at": 1522785744
}],
"options": {}
};
window['wistiajsonp-/embed/medias/8up1lc9606.jsonp'] = window['wistiajsonp-/embed/medias/8up1lc9606.jsonp'];
(Redacted for the sake of brevity)
Regarding the linked question: I am not talking about Swift; I am talking about JavaScript. Secondly, what I'm asking is directed at the purpose, not the implementation of such "self-assignment".
I am creating a file picker using the skydrive/onedrive api
I get a list of files using the url:
https://apis.live.net/v5.0/'+folder_path+'/files?access_token='+onedrive_access_token
But this doesn't return a thumbnail for the files (unlike other api's, googledrive for example).
I would like to get a thumbnail for each file, if it exists.
I cant find anywhere in the docs how to do this - is there a way I can?
After complete the call, you should get some result like this.
{
"data": [
{
"id": "[file id]",
"from": {
"name": "...",
"id": "..."
},
"name": "[file name]",
"description": "",
"parent_id": "[parent folder id]",
"size": 12345,
"comments_count": 0,
"comments_enabled": false,
"tags_count": 0,
"tags_enabled": true,
"is_embeddable": true,
"picture": "[thumbnail url] <<< this is what you want",
"source": "[public preview url]",
"upload_location": "...",
"link": "...",
"height": 270,
"width": 480,
"duration": 22443,
"bitrate": 802928,
"type": "video",
"shared_with": {
"access": "Just me"
},
"created_time": "2013-01-01T07:27:17+0000",
"updated_time": "2013-01-01T07:40:44+0000",
"client_updated_time": "2013-01-20T16:26:54+0000"
},
]
}
Which "picture" is the thumbnail url that you want.
I'm having trouble pulling in the content from my tumblr formatted as JSON. I registered an API key from tumblr, and have the right API link, but am missing something in the $.getJSON. Below I'll show what my JSON and my jQuery both look like.
Here's what my JSON looks like:
{
"meta": {
"status": 200,
"msg": "OK"
},
"response": {
"blog": {
"title": "BLOG TITLE",
"name": "BLOG NAME",
"posts": 96,
"url": "http://BLOGTITLE.tumblr.com/",
"updated": 1370605005,
"description": "BLOG DESCRIPTION",
"ask": false,
"ask_anon": false,
"is_nsfw": false,
"share_likes": true,
"likes": 0
},
"posts": [
{
"blog_name": "BLOG NAME",
"id": 52373434879,
"post_url": "POST URL",
"slug": "POST SLUG",
"type": "photo",
"date": "2013-03-07 11:36:44 GMT",
"timestamp": 1370605004,
"state": "published",
"format": "html",
"reblog_key": "T0m0e51u",
"tags": [],
"short_url": "SHORT URL",
"highlighted": [],
"note_count": 1,
"caption": "PHOTO CAPTION TEXT DESCRIPTION",
"image_permalink": "http://BLOGTITLE.tumblr.com/image/52373434879",
"photos": [
{
"caption": "",
"alt_sizes": [
{
"width": 640,
"height": 960,
"url": "http://31.media.tumblr.com/.../...jpg"
},
{
"width": 500,
"height": 750,
"url": "http://31.media.tumblr.com/.../..._500.jpg"
},
{
"width": 400,
"height": 600,
"url": "http://24.media.tumblr.com/.../..._400.jpg"
},
{
"width": 250,
"height": 375,
"url": "http://31.media.tumblr.com/.../..._250.jpg"
},
{
"width": 100,
"height": 150,
"url": "http://24.media.tumblr.com/.../..._100.jpg"
},
{
"width": 75,
"height": 75,
"url": "http://24.media.tumblr.com/.../..._75sq.jpg"
}
],
"original_size": {
"width": 640,
"height": 960,
"url": "http://31.media.tumblr.com/.../..._1280.jpg"
}
}
]
},
Here's what my jQuery looks like:
jQuery(document).ready(function(){
var url = "http://api.tumblr.com/v2/blog/BLOGNAME.tumblr.com/posts?api_key=APIKEY&limit=5";
var src;
var caption;
$.getJSON(url, function(results){
$.each(results.response, function(i,item){
src = "posts.photos.alt_sizes.url";
caption = posts.caption;
$("<img/>").attr("src", src).appendTo("#submissions").wrap('<div class="postImage"></div>').after('<span class="postCaption">' + caption + '</div>');
});
HTML:
<div id="submissions"></div>
I am pretty sure that the problem is in the $.getJSON or $.each, but I can't figure out exactly what. Any help?
Thanks.
You are probably getting an error because you are trying to access the variable post which is not defined. And you are iterating over results.response, but it looks like you want to iterate over results.response.posts, which is an array of blog posts.
Furthermore, each post seems to have an photos array from which you have to choose the element with photo size you want to have.
Example:
$.each(results.response.posts, function(i, item){
var src = item.photos[0].alt_sizes[0].url; // first picture, first size
var caption = item.caption;
$("<img/>").attr("src", src).appendTo("#submissions").wrap('<div class="postImage"></div>').after('<span class="postCaption">' + caption + '</div>');
});
Of course if a post doesn't have a photo and the array is empty, you will get a runtime error, but I assume you will account for these cases.
The other problem is that you cannot make an Ajax request to the tumblr API since it is an external domain. However, the tumblr API supports JSONP, so if you add &callback=? to the URL, you tell jQuery to use JSONP instead:
var url = "[...]/posts?api_key=APIKEY&limit=5&callback=?";
I recommend to read some basic JavaScript tutorials to learn how to work with arrays and objects:
Eloquent JavaScript - Data structures: Objects and Arrays
MDN - Working with objects
MDN - Predefined Core Objects: Array object