Created
March 3, 2021 08:43
-
-
Save jmarsh24/e0cba0f3c25a57c5215dfcb83c8aa8b6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="loadMoreContainer"> | |
<div class="loadMoreResults"> | |
<%= "Displaying #{@page} / #{number_with_delimiter(@videos.size)} Results" %> | |
</div> | |
<% unless @next_page_items.empty? %> | |
<button class="load-more-link" data-action='click->loadmore#loadMore'> | |
Load More | |
</button> | |
<% end %> | |
</div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div id="header"> | |
<%= render 'shared/header' %> | |
</div> | |
<div id="filters"> | |
<%= render "videos/index/filters" %> | |
</div> | |
<div data-controller="loadmore" data-loadmore-nextpage-value="<%= @page + 1 %>"> | |
<div id="videos" class="video-section" data-loadmore-target="videos"> | |
<%= render "videos/index/videos" %> | |
</div> | |
<div id="load-more-container" data-loadmore-target="loadmore" > | |
<%= render "videos/index/load_more" %> | |
</div> | |
</div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Controller } from 'stimulus' | |
import Rails from '@rails/ujs' | |
export default class extends Controller { | |
static targets = ['videos', 'loadmore'] | |
static values = { nextpage: Number} | |
loadMore () { | |
const url = new URL(window.document.location) | |
if (url.searchParams == '') { | |
url.searchParams.append('page', this.nextpageValue) | |
} else { | |
url.searchParams.set('page', this.nextpageValue) | |
} | |
Rails.ajax({ | |
type: 'GET', | |
url: url, | |
dataType: 'json', | |
success: data => { | |
this.videosTarget.insertAdjacentHTML('beforeend', data.videos ) | |
this.loadmoreTarget.innerhtml = data.loadmore | |
} | |
}) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# == Schema Information | |
# | |
# Table name: videos | |
# | |
# id :bigint not null, primary key | |
# created_at :datetime not null | |
# updated_at :datetime not null | |
# title :text | |
# youtube_id :string | |
# leader_id :bigint | |
# follower_id :bigint | |
# description :string | |
# duration :integer | |
# upload_date :date | |
# view_count :integer | |
# tags :string | |
# song_id :bigint | |
# youtube_song :string | |
# youtube_artist :string | |
# acrid :string | |
# spotify_album_id :string | |
# spotify_album_name :string | |
# spotify_artist_id :string | |
# spotify_artist_id_2 :string | |
# spotify_artist_name :string | |
# spotify_artist_name_2 :string | |
# spotify_track_id :string | |
# spotify_track_name :string | |
# youtube_song_id :string | |
# isrc :string | |
# acr_response_code :integer | |
# channel_id :bigint | |
# scanned_song :boolean default(FALSE) | |
# hidden :boolean default(FALSE) | |
# hd :boolean default(FALSE) | |
# popularity :integer default(0) | |
# like_count :integer default(0) | |
# dislike_count :integer default(0) | |
# favorite_count :integer default(0) | |
# comment_count :integer default(0) | |
# event_id :bigint | |
# scanned_youtube_music :boolean default(FALSE) | |
# click_count :integer default(0) | |
# | |
class Video < ApplicationRecord | |
include Filterable | |
validates :youtube_id, presence: true, uniqueness: true | |
belongs_to :leader, optional: true | |
belongs_to :follower, optional: true | |
belongs_to :song, optional: true | |
belongs_to :channel, optional: false | |
belongs_to :event, optional: true | |
scope :filter_by_orchestra, ->(song_artist) { joins(:song).where("songs.artist ILIKE ?", song_artist) } | |
scope :filter_by_genre, ->(song_genre) { joins(:song).where("songs.genre ILIKE ?", song_genre) } | |
scope :filter_by_leader, ->(leader_name) { joins(:leader).where("leaders.name ILIKE ?", leader_name) } | |
scope :filter_by_follower, ->(follower_name) { joins(:follower).where("followers.name ILIKE ?", follower_name) } | |
scope :filter_by_channel, ->(channel_title) { joins(:channel).where("channels.title ILIKE ?", channel_title) } | |
scope :filter_by_event_id, ->(event_id) { where(event_id: event_id) } | |
scope :filter_by_song_id, ->(song_id) { where(song_id: song_id) } | |
scope :filter_by_hd, ->(boolean) { where(hd: boolean) } | |
scope :filter_by_hidden, -> { where(hidden: true) } | |
scope :filter_by_not_hidden, -> { where(hidden: false) } | |
scope :paginate, ->(page, per_page) { offset(per_page * (page - 1)).limit(per_page) } | |
# Active Admin scopes | |
scope :has_song, -> { where.not(song_id: nil) } | |
scope :has_leader, -> { where.not(leader_id: nil) } | |
scope :has_follower, -> { where.not(follower_id: nil) } | |
scope :has_youtube_match, -> { where.not(youtube_artist: nil) } | |
scope :missing_follower, -> { where(follower_id: nil) } | |
scope :missing_leader, -> { where(leader_id: nil) } | |
scope :missing_song, -> { where(song_id: nil) } | |
# Youtube Music Scopes | |
scope :scanned_youtube_music, -> { where(scanned_youtube_music: true) } | |
scope :unscanned_youtube_music, -> { where(scanned_youtube_music: false) } | |
# AcrCloud Response scopes | |
scope :successful_acrcloud, -> { where(acr_response_code: 0) } | |
scope :unsuccesful_acrcloud, -> { where.not(acr_response_code: [0, 1001]) } | |
scope :scanned_acrcloud, -> { where(acr_response_code: [0, 1001]) } | |
scope :unscanned_acrcloud, -> { where.not(acr_response_code: [0, 1001]) } | |
# Attribute Matching Scopes | |
scope :with_song_title, lambda { |song_title| | |
where("unaccent(spotify_track_name) ILIKE unaccent(:song_title) | |
OR unaccent(youtube_song) ILIKE unaccent(:song_title) | |
OR unaccent(title) ILIKE unaccent(:song_title) | |
OR unaccent(description) ILIKE unaccent(:song_title) | |
OR unaccent(tags) ILIKE unaccent(:song_title)", | |
song_title: "%#{song_title}%") | |
} | |
scope :with_song_artist_keyword, lambda { |song_artist_keyword| | |
where("spotify_artist_name ILIKE :song_artist_keyword | |
OR unaccent(spotify_artist_name_2) ILIKE unaccent(:song_artist_keyword) | |
OR unaccent(youtube_artist) ILIKE unaccent(:song_artist_keyword) | |
OR unaccent(description) ILIKE unaccent(:song_artist_keyword) | |
OR unaccent(title) ILIKE unaccent(:song_artist_keyword) | |
OR unaccent(tags) ILIKE unaccent(:song_artist_keyword) | |
OR unaccent(spotify_album_name) ILIKE unaccent(:song_artist_keyword)", | |
song_artist_keyword: "%#{song_artist_keyword}%") | |
} | |
scope :with_dancer_name_in_title, lambda { |dancer_name| | |
where("unaccent(title) ILIKE unaccent(:dancer_name)", dancer_name: "%#{dancer_name}%") | |
} | |
# Combined Scopes | |
scope :title_match_missing_leader, ->(leader_name) { missing_leader.with_dancer_name_in_title(leader_name) } | |
scope :title_match_missing_follower, ->(follower_name) { missing_follower.with_dancer_name_in_title(follower_name) } | |
class << self | |
# Filters videos by the results from the materialized | |
# full text search out of from VideosSearch | |
def filter_by_query(query) | |
where(id: VideosSearch.search(query).select(:video_id)) | |
end | |
# All videos where the response code is not successfully identified, | |
# send a request to acrcloud to search for a match | |
def fetch_all_acr_cloud_matches | |
where.unscanned_acrcloud.find_each do |video| | |
AcrMusicMatchWorker.perform_async(video.youtube_id) | |
end | |
end | |
# For every video where we haven't checked | |
# to see if youtube has a music match | |
# Create a import youtube worker which will | |
# check if youtube has identified the music contained in the video. | |
def fetch_all_youtube_matches | |
unscanned_youtube_music.find_each do |video| | |
YoutubeMusicMatchWorker.perform_async(video.youtube_id) | |
end | |
end | |
## Update all videos with leader name match in video title with leader relation. | |
def match_all_leaders | |
Leader.all.find_each do |leader| | |
videos = Video.title_match_missing_leader(leader.name) if leader.name.present? | |
videos = videos.or(Video.title_match_missing_leader(leader.abrev_name)) if leader.abrev_name.present? | |
videos = videos.or(Video.title_match_missing_leader(leader.abrev_name_nospace)) if leader.abrev_name_nospace.present? | |
videos = videos.or(Video.title_match_missing_leader(leader.nickname)) if leader.nickname.present? | |
next if videos.empty? | |
videos.update_all(leader_id: leader.id) | |
end | |
end | |
## Update all videos with follower name match in video title with follower relation. | |
def match_all_followers | |
Follower.all.find_each do |follower| | |
videos = Video.title_match_missing_follower(follower.name) if follower.name.present? | |
videos = videos.or(Video.title_match_missing_follower(follower.abrev_name)) if follower.abrev_name.present? | |
videos = videos.or(Video.title_match_missing_follower(follower.abrev_name_nospace)) if follower.abrev_name_nospace.present? | |
videos = videos.or(Video.title_match_missing_follower(follower.nickname)) if follower.nickname.present? | |
next if videos.empty? | |
videos.update_all(follower_id: follower.id) | |
end | |
end | |
# For every active song and in order of popularity search | |
# for videos that have both the song title and last name | |
# of the orchestra somewhere in the attributes | |
def match_all_songs | |
Song.filter_by_active.sort_by_popularity.find_each do |song| | |
videos = Video.missing_song | |
.with_song_title(song.title) | |
.with_song_artist_keyword(song.last_name_search) | |
next if videos.empty? | |
videos.update_all(song_id: song.id) | |
end | |
end | |
def import_all_playlists | |
Playlist.where(imported: false).find_each do |playlist| | |
Video.import_playlist(playlist.slug) | |
end | |
end | |
end | |
def clicked! | |
self.click_count += 1 | |
self.popularity += 1 | |
save! | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class VideosController < ApplicationController | |
before_action :authenticate_user!, only: %i[edit update] | |
before_action :set_video, only: %i[show edit] | |
NUMBER_OF_VIDEOS_PER_PAGE = 120 | |
helper_method :sort_column, :sort_direction | |
def index | |
@videos_total = Video.filter_by_not_hidden.size | |
@videos = Video.filter_by_not_hidden | |
.includes(:leader, :follower, :channel, :song, :event) | |
.order(sort_column + " " + sort_direction) | |
.filter_videos(filtering_params) | |
@videos_paginated = @videos.paginate(page, NUMBER_OF_VIDEOS_PER_PAGE) | |
@videos_paginated = @videos_paginated.shuffle if filtering_params.blank? | |
@next_page_items = @videos.paginate(page + 1, NUMBER_OF_VIDEOS_PER_PAGE) | |
@items_display_count = (@videos.size - (@videos.size - (page * NUMBER_OF_VIDEOS_PER_PAGE).clamp(0, @videos.size))) | |
@leaders = @videos.joins(:leader).pluck("leaders.name").uniq.sort.map(&:titleize) | |
@followers = @videos.joins(:follower).pluck("followers.name").uniq.sort.map(&:titleize) | |
@channels = @videos.joins(:channel).pluck("channels.title").uniq.compact.sort | |
@artists = @videos.joins(:song).pluck("songs.artist").uniq.compact.sort.map(&:titleize) | |
@genres = @videos.joins(:song).pluck("songs.genre").uniq.compact.sort.map(&:titleize).uniq | |
respond_to do |format| | |
format.html | |
format.json do | |
render json: { videos: render_to_string(partial: "videos/index/videos", formats: [:html]), | |
loadmore: render_to_string(partial: "videos/index/load_more", formats: [:html]) } | |
end | |
end | |
end | |
def show | |
@videos_total = Video.filter_by_not_hidden.size | |
videos = if Video.where(song_id: @video.song_id).size > 3 | |
Video.where(song_id: @video.song_id) | |
else | |
Video.where(channel_id: @video.channel_id) | |
end | |
@recommended_videos = videos.where(hidden: false) | |
.where.not(youtube_id: @video.youtube_id) | |
.order("popularity DESC") | |
.limit(3) | |
@video.clicked! | |
end | |
def edit | |
@video = Video.find_by(id: params[:id]) | |
end | |
def update | |
@video = Video.find_by(id: params[:id]) | |
@video.update(video_params) | |
redirect_to watch_path(v: @video.youtube_id) | |
end | |
private | |
def current_search | |
@current_search = params[:query] | |
end | |
def set_video | |
@video = Video.find_by(youtube_id: params[:v]) | |
end | |
def sort_column | |
acceptable_cols = ["songs.title", | |
"songs.artist", | |
"songs.genre", | |
"leaders.name", | |
"followers.name", | |
"channels.title", | |
"videos.upload_date", | |
"videos.view_count", | |
"songs.last_name_search", | |
"videos.popularity"] | |
acceptable_cols.include?(params[:sort]) ? params[:sort] : "videos.popularity" | |
end | |
def sort_direction | |
%w[asc desc].include?(params[:direction]) ? params[:direction] : "desc" | |
end | |
def page | |
@page ||= params.permit(:page).fetch(:page, 1).to_i | |
end | |
def video_params | |
params.require(:video).permit(:leader_id, :follower_id, :song_id, :event_id, :hidden) | |
end | |
def filtering_params | |
params.permit(:leader, :follower, :channel, :genre, :orchestra, :song_id, :query, :hd, :event_id) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment