このコミットが含まれているのは:
@@ -6,15 +6,15 @@ class TheatreSkipEventsController < ApplicationController
|
|||||||
events =
|
events =
|
||||||
TheatreSkipEvent
|
TheatreSkipEvent
|
||||||
.where(theatre_id: params[:theatre_id])
|
.where(theatre_id: params[:theatre_id])
|
||||||
.includes(:tags, post: { tags: :tag_name })
|
.includes(:post, tags: :tag_name)
|
||||||
.order(created_at: :desc)
|
.order(created_at: :desc)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
|
|
||||||
render json: events.map { |event|
|
render json: events.map { |event|
|
||||||
{ id: event.id,
|
{ id: event.id,
|
||||||
theatre_id: event.theatre_id,
|
theatre_id: event.theatre_id,
|
||||||
post: PostRepr.base(event.post),
|
post: { id: event.post.id, title: event.post.title, url: event.post.url },
|
||||||
tags: event.tags.map { |tag| TagRepr.inline(tag) },
|
tags: event.tags.map { |tag| { id: tag.id, name: tag.name } },
|
||||||
programme_position: event.programme_position,
|
programme_position: event.programme_position,
|
||||||
created_at: event.created_at }
|
created_at: event.created_at }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,9 @@ class TheatrePostSelector
|
|||||||
candidates = weighted_candidates
|
candidates = weighted_candidates
|
||||||
sorted = candidates.sort_by { |candidate| [candidate.weight, candidate.post.id] }
|
sorted = candidates.sort_by { |candidate| [candidate.weight, candidate.post.id] }
|
||||||
|
|
||||||
{
|
{ tag_penalties: tag_penalty_json,
|
||||||
tag_penalties: tag_penalty_json,
|
|
||||||
lightest_posts: post_weight_json(sorted.first(limit)),
|
lightest_posts: post_weight_json(sorted.first(limit)),
|
||||||
heaviest_posts: post_weight_json(sorted.reverse.first(limit))
|
heaviest_posts: post_weight_json(sorted.reverse.first(limit)) }
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -48,8 +46,7 @@ class TheatrePostSelector
|
|||||||
post:,
|
post:,
|
||||||
penalty:,
|
penalty:,
|
||||||
tags: post_tags,
|
tags: post_tags,
|
||||||
weight: 1.0 / (1.0 + penalty)
|
weight: 1.0 / (1.0 + penalty))
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -87,10 +84,8 @@ class TheatrePostSelector
|
|||||||
tag = tags[tag_id]
|
tag = tags[tag_id]
|
||||||
next unless tag
|
next unless tag
|
||||||
|
|
||||||
{
|
{ tag: light_tag_json(tag),
|
||||||
tag: light_tag_json(tag),
|
penalty: }
|
||||||
penalty:
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.compact
|
.compact
|
||||||
.sort_by { |row| [-row[:penalty], row[:tag][:name].to_s] }
|
.sort_by { |row| [-row[:penalty], row[:tag][:name].to_s] }
|
||||||
@@ -98,27 +93,22 @@ class TheatrePostSelector
|
|||||||
|
|
||||||
def post_weight_json candidates
|
def post_weight_json candidates
|
||||||
candidates.map { |candidate|
|
candidates.map { |candidate|
|
||||||
{
|
{ post: light_post_json(candidate.post),
|
||||||
post: light_post_json(candidate.post),
|
|
||||||
weight: candidate.weight,
|
weight: candidate.weight,
|
||||||
penalty: candidate.penalty,
|
penalty: candidate.penalty,
|
||||||
tags: candidate.tags.map { |tag| light_tag_json(tag) }
|
tags: candidate.tags.map { |tag| light_tag_json(tag) } }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def light_post_json post
|
def light_post_json post
|
||||||
{
|
{ id: post.id,
|
||||||
id: post.id,
|
|
||||||
title: post.title,
|
title: post.title,
|
||||||
url: post.url
|
url: post.url }
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def light_tag_json tag
|
def light_tag_json tag
|
||||||
{
|
{ id: tag.id,
|
||||||
id: tag.id,
|
name: tag.name,
|
||||||
name: tag.name
|
category: tag.category }
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
生成ファイル
-1
@@ -339,7 +339,6 @@ ActiveRecord::Schema[8.0].define(version: 2026_06_06_000000) do
|
|||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.index ["expires_at"], name: "index_theatre_watching_users_on_expires_at"
|
t.index ["expires_at"], name: "index_theatre_watching_users_on_expires_at"
|
||||||
t.index ["theatre_id", "expires_at"], name: "idx_on_theatre_id_skip_expires_at_4c8de1dd42"
|
|
||||||
t.index ["theatre_id", "expires_at"], name: "index_theatre_watching_users_on_theatre_id_and_expires_at"
|
t.index ["theatre_id", "expires_at"], name: "index_theatre_watching_users_on_theatre_id_and_expires_at"
|
||||||
t.index ["theatre_id"], name: "index_theatre_watching_users_on_theatre_id"
|
t.index ["theatre_id"], name: "index_theatre_watching_users_on_theatre_id"
|
||||||
t.index ["user_id"], name: "index_theatre_watching_users_on_user_id"
|
t.index ["user_id"], name: "index_theatre_watching_users_on_user_id"
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { useValidationErrors } from '@/lib/useValidationErrors'
|
|||||||
import type { FC, FormEvent, ReactNode } from 'react'
|
import type { FC, FormEvent, ReactNode } from 'react'
|
||||||
|
|
||||||
import type { NiconicoMetadata,
|
import type { NiconicoMetadata,
|
||||||
|
NiconicoVideoInfo,
|
||||||
NiconicoViewerHandle,
|
NiconicoViewerHandle,
|
||||||
Post,
|
Post,
|
||||||
Category,
|
Category,
|
||||||
@@ -459,6 +460,19 @@ const TheatreDetailPage: FC<Props> = ({ user }: Props) => {
|
|||||||
await advancePost ()
|
await advancePost ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleNiconicoLoadComplete = (info: NiconicoVideoInfo) => {
|
||||||
|
const lengthMs = info.lengthInSeconds * 1_000
|
||||||
|
setVideoLength (lengthMs)
|
||||||
|
|
||||||
|
if (lengthMs <= 0)
|
||||||
|
{
|
||||||
|
void handlePlaybackError ()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
embedRef.current?.play ()
|
||||||
|
}
|
||||||
|
|
||||||
const handleSkipVote = async () => {
|
const handleSkipVote = async () => {
|
||||||
if (!(id) || !(post))
|
if (!(id) || !(post))
|
||||||
return
|
return
|
||||||
@@ -797,10 +811,7 @@ const TheatreDetailPage: FC<Props> = ({ user }: Props) => {
|
|||||||
key={post.id}
|
key={post.id}
|
||||||
ref={embedRef}
|
ref={embedRef}
|
||||||
post={post}
|
post={post}
|
||||||
onLoadComplete={info => {
|
onLoadComplete={handleNiconicoLoadComplete}
|
||||||
embedRef.current?.play ()
|
|
||||||
setVideoLength (info.lengthInSeconds * 1_000)
|
|
||||||
}}
|
|
||||||
onMetadataChange={syncPlayback}
|
onMetadataChange={syncPlayback}
|
||||||
onError={handlePlaybackError}/>) : (
|
onError={handlePlaybackError}/>) : (
|
||||||
<div className="grid min-h-72 place-items-center text-zinc-400">
|
<div className="grid min-h-72 place-items-center text-zinc-400">
|
||||||
|
|||||||
新しい課題から参照
ユーザをブロックする