Skip to content

Commit

Permalink
❇️ Added Infinite Scroll and Video API (#197)
Browse files Browse the repository at this point in the history
* 💄 style improvements to upload page

* 👔 Updated top_videos logic and video api

* ❇️ Added infinite scroll

* ✅ Added tests
  • Loading branch information
prithvijitguha authored Feb 26, 2022
1 parent 105c2bc commit e1381a6
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 43 deletions.
3 changes: 2 additions & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ disable=raw-checker-failed,
suppressed-message,
useless-suppression,
deprecated-pragma,
use-symbolic-message-instead
use-symbolic-message-instead,
duplicate-code

# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
Expand Down
28 changes: 26 additions & 2 deletions crud/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,14 +436,20 @@ def get_video_link(db: Session, video_link: str):
return db.query(models.Video).filter(models.Video.video_link == video_link).first()


def get_top_videos(db: Session):
def get_top_videos(db: Session, skip: int = 0, limit: int = 100):
"""
Get top videos ordered by
views
Gets the top 10 videos
"""
return db.query(models.Video).order_by(models.Video.views.desc()).limit(10).all()
return (
db.query(models.Video)
.order_by(models.Video.views.desc())
.offset(skip)
.limit(limit)
.all()
)


# def delete video
Expand Down Expand Up @@ -562,3 +568,21 @@ def delete_comment(db: Session, comment_id: int):
except Exception as e:
print(f"Could not delete user={comment_id}: {e}")
return False


def get_profile_bool(db: Session, username: str):
"""Gets profile picture flag
Args:
db: Database
username: Username to check
Returns:
Bool value of User.profile_picture
"""
return (
db.query(models.User)
.filter(models.User.username == username)
.first()
.profile_picture
)
44 changes: 41 additions & 3 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import os

from html import escape
from typing import Optional
from typing import Optional, Union
from tempfile import NamedTemporaryFile

from fastapi import FastAPI, Request, Depends, Response, status
Expand All @@ -42,6 +42,9 @@
origins = [
"http://localhost",
"http://localhost:8080",
"http://localhost:8000",
"http://127.0.0.1:8000/",
"*",
]

# static files directory for javascript and css
Expand Down Expand Up @@ -110,6 +113,42 @@ def read_user(user_id: int, db: Session = Depends(get_db)):
return db_user


@app.get("/get_top_videos/{skip}/{limit}")
def get_videos(
skip: Union[int, str] = 0,
limit: Union[int, str] = 10,
db: Session = Depends(get_db),
):
"""Function to get top videos from database
Args:
db: Database
skip: video of videos to start
limit: video of videos to end
Returns:
Array of videos ordered by views
"""
return crud.get_top_videos(db, skip, limit)


@app.get("/get_profile_picture/{username}")
def get_profile_picture_bool(
username: str,
db: Session = Depends(get_db),
):
"""Gets the profile picture bool flag
Args:
username: Username to check
db: Database
Returns:
boolean value of Bool value of User.profile_picture
"""
return crud.get_profile_bool(db, username)


@app.get("/", response_class=HTMLResponse)
async def home(
request: Request,
Expand All @@ -131,8 +170,7 @@ async def home(
# sanitize active_user
if active_user:
active_user = utils.sanitize_active_user(active_user)

top_videos = crud.get_top_videos(db)
top_videos = get_videos(db=db)
thumbnail_drive = os.environ.get("thumbnail_drive")
cloud_url = os.environ.get("cloud_url")
thumbnail_url = f"{cloud_url}/{thumbnail_drive}"
Expand Down
4 changes: 3 additions & 1 deletion static/index.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
.profilePicture {
border-radius: 50%;
width: 40px;
height: 40px;
}

.videoThumbnail {
Expand All @@ -10,5 +12,5 @@

.videoThumbnail:hover {
transform: scale(1.5);
transition-delay:0.9s;
transition-delay:0.5s;
}
85 changes: 85 additions & 0 deletions static/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
var start = 11
var end = 20

function append_new_videos(data_array) {
//for each element create a video element
data_array.forEach(create_video_element)
}

function create_video_element(data) {
rows_html_collection = document.getElementsByClassName("row row-cols-5 mx-auto")
rows_array = Array.from(rows_html_collection)
//create class
main_div = document.createElement("div")
main_div.setAttribute("class", "mx-auto videoThumbnailContent");
//create a href element child
ahref = document.createElement("a");
ahref.href = `video/${data.video_link}`;

thumbnail = document.createElement("img")
thumbnail.setAttribute("class", "img-fluid videoThumbnail")
thumbnail.setAttribute("src", `https://d32dcw9m3mntm7.cloudfront.net/thumbnail/${data.video_link}`)
//create image profile pic as child element
profile_pic = document.createElement("img")
profile_pic.setAttribute("class", "profilePicture")
profile_pic_flag = get_profile_pic_bool(data.video_username)
if (profile_pic_flag == "true") {
profile_pic.src = `https://d32dcw9m3mntm7.cloudfront.net/profile_picture/${data.video_username}`
}
else {
profile_pic.src = "./static/assets/default_picture.jpg"
}
//create video name
videoName = document.createElement("h6")
videoName.setAttribute("class", "videoName w-100")
videoName.innerHTML = data.video_name
//create video username
videoUsername = document.createElement("p")
videoUsername.setAttribute("class", "videoUsername")
videoUsername.innerHTML = data.video_username
// create view count
view_count = document.createElement("strong")
view_count.setAttribute("class", "viewCount")
view_count.innerHTML = `${data.views} views`
// create timestamp
timestamp = document.createElement("h6")
timestamp.setAttribute("class", "timestamp timestampVideo")
timestamp.innerHTML = moment(data.ts_upload).fromNow();
ahref.appendChild(thumbnail)
main_div.appendChild(ahref)
main_div.appendChild(profile_pic)
main_div.appendChild(videoName)
main_div.appendChild(videoUsername)
main_div.appendChild(view_count)
main_div.appendChild(timestamp)



//append it to rows
rows_array.slice(-1).pop().appendChild(main_div)
}


async function get_profile_pic_bool(username) {
let response = await fetch(`/get_profile_picture/${username}`);
let data = await response.text();
return data;
}


function get_top_videos() {
fetch(`/get_top_videos/${start}/${end}`)
.then(response => response.json())
.then(data => append_new_videos(data));
start = start + end
end = end + end
}

// If scrolled to bottom, load the next 10 videos
window.onscroll = () => {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
get_top_videos()
}
};


20 changes: 20 additions & 0 deletions static/upload.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.uploadContents {
width: 85%;
text-align: center;
padding-left: 25%;
}

#demoVideo {
height: 45%;
width: 75%;
}

#thumbnailImage {
height: 45%;
width: 75%;
}

.formElements {
margin-top: 5%;
margin-bottom: 5%;
}
10 changes: 2 additions & 8 deletions static/upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ function checkVideo(){
//change the frame element source and title
$("#demoVideo").attr("src", URL.createObjectURL(video_file))
document.getElementById("demoVideo").play()

//enable the capture thumbnail button
document.getElementById("thumbnailCapturebtn").disabled = false;
//get video frame
video = document.getElementById("demoVideo");

Expand All @@ -70,7 +67,7 @@ function checkVideo(){

}
}

/*
function capture(){
//function to capture thumbnail
canvas = document.getElementById('thumbnailDisplay');
Expand All @@ -81,6 +78,7 @@ function checkVideo(){
//add video as source for display
document.getElementById("thumbnailImage").setAttribute("src", canvas_image)
}
*/

function checkImage(){
//get the element
Expand All @@ -107,11 +105,7 @@ function checkVideo(){
}




function get_metadata() {
//capture first image as thumbnail
capture()
//autofill video name
trimmed_name = video_file.name.split('.').slice(0, -1).join('.')
//durationdocument.getElementById("inputVideoName").value = video_file.name;
Expand Down
10 changes: 5 additions & 5 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,28 @@
{% block content %}
<!--css style sheet-->
<link rel="stylesheet" href="{{ url_for('static', path='/index.css') }}">
<script src="{{ url_for('static', path='/index.js') }}"></script>

<!--Add Thumbnails here-->
<!--mx auto sets margin auto-->
<div class="grid mx-auto">
<!--5 cols auto margin left and right-->
<div class="row row-cols-5 mx-auto">
{% for video in videos %}
<div class="mx-auto">
<div class="mx-auto videoThumbnailContent">
<a href="video/{{ video.video_link}}"><img class="img-fluid videoThumbnail" src="{{ thumbnail_url}}/{{ video.video_link }}" alt="thumbnail"></a>
<br><br>
<!--profilepicture flag present-->
{% if get_profile(video.video_username)%}
<img class="profilePicture" src="{{ profile_picture_url}}/{{ video.video_username }}"
width="30" height="30" alt="profile-picture" >
alt="profile-picture" >
{% else %}
<img class="profilePicture" src="{{ url_for('static', path='/assets/default_picture.jpg') }}"
width="30" height="30" alt="profile-picture" >
alt="profile-picture" >
{% endif %}
<h6 class="videoName w-100">{{ video.video_name }}</h6>
<p class="videoUsername">{{ video.video_username }}</p>
<strong class="viewCount">{{ video.views }} views</strong>
<h6 class="timestamp timestampVideo">Uploaded {{ video.ts_upload }}</h6>
<h6 class="timestamp timestampVideo">{{ video.ts_upload }}</h6>
</div>
{% endfor %}
</div>
Expand Down
Loading

0 comments on commit e1381a6

Please sign in to comment.