Skip to content

Instantly share code, notes, and snippets.

@jmarsh24
Created March 3, 2021 08:43
Show Gist options
  • Save jmarsh24/e0cba0f3c25a57c5215dfcb83c8aa8b6 to your computer and use it in GitHub Desktop.
Save jmarsh24/e0cba0f3c25a57c5215dfcb83c8aa8b6 to your computer and use it in GitHub Desktop.
<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>
<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>
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
}
})
}
}
# == 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
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