Much base work started
This commit is contained in:
100
app/models/work.rb
Normal file
100
app/models/work.rb
Normal file
@@ -0,0 +1,100 @@
|
||||
class Work < ApplicationRecord
|
||||
# 1. Includes/Concerns
|
||||
include Searchable
|
||||
|
||||
# 2. JSON Store for flexible metadata
|
||||
store :metadata, accessors: [:tmdb_data, :imdb_data, :custom_fields]
|
||||
store :tmdb_data, accessors: [:overview, :poster_path, :backdrop_path, :release_date, :genres]
|
||||
store :imdb_data, accessors: [:plot, :rating, :votes, :runtime, :director]
|
||||
store :custom_fields
|
||||
|
||||
# 3. Associations
|
||||
has_many :videos, dependent: :nullify
|
||||
has_many :external_ids, dependent: :destroy
|
||||
has_one :primary_video, -> { order("(video_metadata->>'height')::int DESC") }, class_name: "Video"
|
||||
|
||||
# 4. Validations
|
||||
validates :title, presence: true
|
||||
validates :year, numericality: { only_integer: true, greater_than: 1800 }, allow_nil: true
|
||||
validates :rating, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 10 }, allow_nil: true
|
||||
|
||||
# 5. Scopes
|
||||
scope :organized, -> { where(organized: true) }
|
||||
scope :unorganized, -> { where(organized: false) }
|
||||
scope :recent, -> { order(created_at: :desc) }
|
||||
scope :by_title, -> { order(:title) }
|
||||
scope :with_year, -> { where.not(year: nil) }
|
||||
|
||||
# 6. Delegations
|
||||
delegate :resolution_label, :duration, to: :primary_video, prefix: true, allow_nil: true
|
||||
|
||||
# 7. Class methods
|
||||
def self.search(query)
|
||||
where("title LIKE ? OR director LIKE ?", "%#{sanitize_sql_like(query)}%", "%#{sanitize_sql_like(query)}%")
|
||||
end
|
||||
|
||||
def self.find_by_external_id(source, value)
|
||||
joins(:external_ids).find_by(external_ids: { source: source, value: value })
|
||||
end
|
||||
|
||||
# 8. Instance methods
|
||||
def display_title
|
||||
year ? "#{title} (#{year})" : title
|
||||
end
|
||||
|
||||
def video_count
|
||||
videos.count
|
||||
end
|
||||
|
||||
def total_duration
|
||||
videos.sum("(video_metadata->>'duration')::float")
|
||||
end
|
||||
|
||||
def available_versions
|
||||
videos.group_by(&:resolution_label)
|
||||
end
|
||||
|
||||
def has_external_ids?
|
||||
external_ids.exists?
|
||||
end
|
||||
|
||||
def poster_url
|
||||
poster_path || tmdb_data['poster_path']
|
||||
end
|
||||
|
||||
def backdrop_url
|
||||
backdrop_path || tmdb_data['backdrop_path']
|
||||
end
|
||||
|
||||
def description
|
||||
return read_attribute(:description) if read_attribute(:description).present?
|
||||
tmdb_data['overview'] || imdb_data['plot']
|
||||
end
|
||||
|
||||
def effective_director
|
||||
return read_attribute(:director) if read_attribute(:director).present?
|
||||
imdb_data['director']
|
||||
end
|
||||
|
||||
def effective_rating
|
||||
return read_attribute(:rating) if read_attribute(:rating).present?
|
||||
imdb_data['rating']&.to_f
|
||||
end
|
||||
|
||||
# Convenience accessors for common external IDs
|
||||
# Auto-generated for all sources (will be implemented when we add ExternalId model logic)
|
||||
# ExternalId.sources.keys.each do |source_name|
|
||||
# define_method("#{source_name}_id") do
|
||||
# external_ids.find_by(source: source_name)&.value
|
||||
# end
|
||||
#
|
||||
# define_method("#{source_name}_id=") do |value|
|
||||
# return if value.blank?
|
||||
# external_ids.find_or_initialize_by(source: source_name).update!(value: value)
|
||||
# end
|
||||
#
|
||||
# define_method("#{source_name}_url") do
|
||||
# external_ids.find_by(source: source_name)&.url
|
||||
# end
|
||||
# end
|
||||
end
|
||||
Reference in New Issue
Block a user