sergio-fry/youtube-fetcher

View on GitHub
app/controllers/channels_controller.rb

Summary

Maintainability
A
35 mins
Test Coverage
A
94%
class ChannelsController < ApplicationController
  PODCAST_SOURCE_TYPE = nil.freeze
  PODCAST_YT_KLASS = Yt::Channel.freeze

  helper_method :new_videos

  class Channel < Podcast
    attr_accessor :url
  end

  def create
    if playlist_id.present?
      create_podcast playlist_id, 'playlist', Yt::Playlist.new(id: playlist_id).title
      redirect_to playlist_path(playlist_id)
    elsif channel_id.present?
      create_podcast channel_id, nil, Yt::Channel.new(id: channel_id).title
      redirect_to channel_path(channel_id)
    elsif channel_id_by_user_id.present?
      create_podcast channel_id_by_user_id, nil, Yt::Channel.new(id: channel_id_by_user_id).title
      redirect_to channel_path(channel_id_by_user_id)
    else
      redirect_to root_path
    end
  end

  class VideoEpisodeWrapper < ProxyObject
    def url
      Rails.application.routes.url_helpers.
        video_url(origin_id, format: :mp4, host: ENV.fetch('VIRTUAL_HOST', 'yt.mazavr.com'))
    end
  end

  def show
    @podcast = Podcast.find_by! origin_id: params[:id]

    @videos = if type == 'video' && Flipper.enabled?(:video)
                @podcast.video_episodes
              else
                @podcast.episodes
              end

    @videos = @videos.recent.limit(10)
    @videos = @videos.map { |v| VideoEpisodeWrapper.new v } if type == 'video'
    @videos = @videos.map { |v| Video.new v.origin_id, v }

    respond_to do |format|
      format.html
      format.atom do
        @podcast.update_attributes accessed_at: Time.now
        @podcast.update_attributes(video_requested_at: Time.now) if type == 'video'
        render content_type: :podcast
      end
    end
  end

  def new
    @channel = Channel.new
  end

  def index
    @channels = Podcast.page(params[:page]).per(10)
  end

  private

  def new_videos
    return [] if @podcast.created_at < 1.hour.ago
    attrs = Rails.cache.fetch "ChannelsController:#{@podcast.youtube_video_list.origin_id}:videos", expires_in: 15.minutes do
      @podcast.youtube_video_list.videos.map do |v|
        begin
        { origin_id: v.id, title: v.title, published_at: v.published_at }
        rescue
          nil
        end
      end.compact
    end

    attrs.map do |attr|
      Episode.new attr
    end.map { |v| Video.new v.origin_id, v }.reject do |e|
      Episode.exists?(origin_id: e.origin_id)
    end
  end

  def type
    params[:type] == 'video' ? 'video' : 'audio'
  end

  def create_podcast(origin_id, source_type, title)
    podcast = Podcast.find_or_initialize_by origin_id: origin_id
    podcast.update_attributes title: title, source_type: source_type, accessed_at: Time.now, video_requested_at: Time.now

    # TODO: limit episodes
    UpdatePodcastJob.set(queue: :high_priority).perform_later podcast

    podcast
  end

  def channel
    @channel ||= self::class::PODCAST_YT_KLASS.new id: params[:id]
  end

  def playlist_id
    m = channel_url.match(/youtube.com\/playlist\?list=(.+)/)

    return if m.blank?

    m[1]
  end

  def channel_id
    channel_url.split('/channel/')[1]
  end

  def user_id
    m = channel_url.match(/youtube.com\/user\/(.+)/)

    return if m.blank?

    m[1]
  end

  def channel_id_by_user_id
    @channel_id_by_user_id ||= begin
                                 url = "https://www.googleapis.com/youtube/v3/channels?key=#{ENV.fetch('YOUTUBE_API_KEY')}&forUsername=#{user_id}&part=id"
                                 data = JSON.parse open(url).read

                                 data['items'][0]['id']
                               end
  rescue
    nil
  end

  def channel_url
    params[:channels_controller_channel][:url]
  end
end