Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
707 changes: 624 additions & 83 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

Binary file added public/images/001.avif
Binary file not shown.
Binary file added public/images/002.avif
Binary file not shown.
Binary file added public/images/003.avif
Binary file not shown.
Binary file added public/images/004.avif
Binary file not shown.
Binary file added public/images/005.avif
Binary file not shown.
Binary file added public/images/006.avif
Binary file not shown.
Binary file added public/images/007.avif
Binary file not shown.
Binary file added public/images/008.avif
Binary file not shown.
Binary file added public/images/009.avif
Binary file not shown.
Binary file added public/images/010.avif
Binary file not shown.
Binary file added public/images/011.avif
Binary file not shown.
Binary file added public/images/012.avif
Binary file not shown.
Binary file added public/images/013.avif
Binary file not shown.
Binary file added public/images/014.avif
Binary file not shown.
Binary file added public/images/015.avif
Binary file not shown.
Binary file added public/images/016.avif
Binary file not shown.
Binary file added public/images/017.avif
Binary file not shown.
Binary file added public/images/018.avif
Binary file not shown.
Binary file added public/images/019.avif
Binary file not shown.
Binary file added public/images/020.avif
Binary file not shown.
Binary file added public/images/021.avif
Binary file not shown.
Binary file added public/images/022.avif
Binary file not shown.
Binary file added public/images/023.avif
Binary file not shown.
Binary file added public/images/024.avif
Binary file not shown.
Binary file added public/images/025.avif
Binary file not shown.
Binary file added public/images/026.avif
Binary file not shown.
Binary file added public/images/027.avif
Binary file not shown.
Binary file added public/images/028.avif
Binary file not shown.
Binary file added public/images/029.avif
Binary file not shown.
Binary file added public/images/030.avif
Binary file not shown.
Binary file added public/images/031.avif
Binary file not shown.
Binary file added public/images/032.avif
Binary file not shown.
Binary file added public/images/033.avif
Binary file not shown.
Binary file added public/images/034.avif
Binary file not shown.
Binary file added public/images/035.avif
Binary file not shown.
Binary file added public/images/036.avif
Binary file not shown.
Binary file added public/images/037.avif
Binary file not shown.
2 changes: 1 addition & 1 deletion public/logos/anime.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/logos/documentary.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/logos/drama.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/logos/fightingsports.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/logos/mahjong.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/logos/music.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/logos/news.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/logos/reality.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/logos/shogi.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/logos/soccer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/logos/sumo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/logos/variety.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions workspaces/client/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,14 @@ export default [
{
ignores: ['dist/*', '.wireit/*'],
},
{
files: ['**/*.mjs'],
languageOptions: {
parser: 'espree',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
},
},
];
12 changes: 10 additions & 2 deletions workspaces/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
{
"name": "@wsh-2025/client",
"private": true,
"sideEffects": [
"*.css",
"./src/setups/*.ts",
"./src/main.tsx"
],
"scripts": {
"build": "wireit",
"format": "wireit",
Expand Down Expand Up @@ -28,7 +33,6 @@
"p-min-delay": "4.0.2",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-ellipsis-component": "1.1.11",
"react-final-form": "6.5.9",
"react-flip-toolkit": "7.2.4",
"react-router": "7.0.2",
Expand Down Expand Up @@ -63,14 +67,18 @@
"@unocss/preset-icons": "66.1.0-beta.5",
"@unocss/preset-wind3": "66.1.0-beta.5",
"@unocss/reset": "66.1.0-beta.5",
"@unocss/runtime": "66.1.0-beta.5",
"@unocss/webpack": "66.1.0-beta.6",
"@wsh-2025/configs": "workspace:*",
"arraybuffer-loader": "1.0.8",
"babel-loader": "9.2.1",
"core-js": "3.41.0",
"css-loader": "7.1.2",
"hls.js": "1.5.17",
"shaka-player": "4.12.5",
"style-loader": "4.0.0",
"terser-webpack-plugin": "5.3.14",
"typescript": "5.7.2",
"unocss": "66.1.0-beta.6",
"video.js": "8.21.0",
"webpack": "5.96.1",
"webpack-bundle-analyzer": "4.10.2",
Expand Down
2 changes: 2 additions & 0 deletions workspaces/client/src/app/Document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export const Document = () => {
<head>
<meta charSet="UTF-8" />
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
<script src="/public/runtime.js"></script>
<script src="/public/vendors.js"></script>
<script src="/public/main.js"></script>
</head>
<body className="size-full bg-[#000000] text-[#ffffff]">
Expand Down
31 changes: 6 additions & 25 deletions workspaces/client/src/app/createRoutes.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import lazy from 'p-min-delay';
import { RouteObject } from 'react-router';

import { Document, prefetch } from '@wsh-2025/client/src/app/Document';
Expand All @@ -11,10 +10,7 @@ export function createRoutes(store: ReturnType<typeof createStore>): RouteObject
{
index: true,
async lazy() {
const { HomePage, prefetch } = await lazy(
import('@wsh-2025/client/src/pages/home/components/HomePage'),
1000,
);
const { HomePage, prefetch } = await import('@wsh-2025/client/src/pages/home/components/HomePage');
return {
Component: HomePage,
async loader() {
Expand All @@ -25,10 +21,7 @@ export function createRoutes(store: ReturnType<typeof createStore>): RouteObject
},
{
async lazy() {
const { EpisodePage, prefetch } = await lazy(
import('@wsh-2025/client/src/pages/episode/components/EpisodePage'),
1000,
);
const { EpisodePage, prefetch } = await import('@wsh-2025/client/src/pages/episode/components/EpisodePage');
return {
Component: EpisodePage,
async loader({ params }) {
Expand All @@ -40,10 +33,7 @@ export function createRoutes(store: ReturnType<typeof createStore>): RouteObject
},
{
async lazy() {
const { prefetch, ProgramPage } = await lazy(
import('@wsh-2025/client/src/pages/program/components/ProgramPage'),
1000,
);
const { prefetch, ProgramPage } = await import('@wsh-2025/client/src/pages/program/components/ProgramPage');
return {
Component: ProgramPage,
async loader({ params }) {
Expand All @@ -55,10 +45,7 @@ export function createRoutes(store: ReturnType<typeof createStore>): RouteObject
},
{
async lazy() {
const { prefetch, SeriesPage } = await lazy(
import('@wsh-2025/client/src/pages/series/components/SeriesPage'),
1000,
);
const { prefetch, SeriesPage } = await import('@wsh-2025/client/src/pages/series/components/SeriesPage');
return {
Component: SeriesPage,
async loader({ params }) {
Expand All @@ -70,10 +57,7 @@ export function createRoutes(store: ReturnType<typeof createStore>): RouteObject
},
{
async lazy() {
const { prefetch, TimetablePage } = await lazy(
import('@wsh-2025/client/src/pages/timetable/components/TimetablePage'),
1000,
);
const { prefetch, TimetablePage } = await import('@wsh-2025/client/src/pages/timetable/components/TimetablePage');
return {
Component: TimetablePage,
async loader() {
Expand All @@ -85,10 +69,7 @@ export function createRoutes(store: ReturnType<typeof createStore>): RouteObject
},
{
async lazy() {
const { NotFoundPage, prefetch } = await lazy(
import('@wsh-2025/client/src/pages/not_found/components/NotFoundPage'),
1000,
);
const { NotFoundPage, prefetch } = await import('@wsh-2025/client/src/pages/not_found/components/NotFoundPage');
return {
Component: NotFoundPage,
async loader() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const AspectRatio = ({ children, ratioHeight, ratioWidth }: Props) => {
const height = (width * ratioHeight) / ratioWidth;

return (
<div ref={containerRef} className={`h-[${height}px] relative w-full`}>
<div ref={containerRef} className="relative w-full" style={{ height: `${height}px` }}>
{children}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const CarouselSection = ({ module }: Props) => {
data-scroll-restore={`carousel-${module.id}`}
>
{module.items.map((item) => (
<div key={item.id} className={`w-[${itemWidth}px] shrink-0 grow-0`}>
<div key={item.id} className="shrink-0 grow-0" style={{ width: `${itemWidth}px` }}>
{item.series != null ? <SeriesItem series={item.series} /> : null}
{item.episode != null ? <EpisodeItem episode={item.episode} /> : null}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Ellipsis from 'react-ellipsis-component';
import { Flipped } from 'react-flip-toolkit';
import { NavLink } from 'react-router';

Expand Down Expand Up @@ -35,11 +34,11 @@ export const EpisodeItem = ({ episode }: Props) => {
</div>
</Flipped>
<div className="p-[8px]">
<div className="mb-[4px] text-[14px] font-bold text-[#ffffff]">
<Ellipsis ellipsis reflowOnResize maxLine={2} text={episode.title} visibleLine={2} />
<div className="mb-[4px] text-[14px] font-bold text-[#ffffff] overflow-hidden" style={{ display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', textOverflow: 'ellipsis' }}>
{episode.title}
</div>
<div className="text-[12px] text-[#999999]">
<Ellipsis ellipsis reflowOnResize maxLine={2} text={episode.series.title} visibleLine={2} />
<div className="text-[12px] text-[#999999] overflow-hidden" style={{ display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', textOverflow: 'ellipsis' }}>
{episode.series.title}
</div>
</div>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { StandardSchemaV1 } from '@standard-schema/spec';
import * as schema from '@wsh-2025/schema/src/api/schema';
import { useRef } from 'react';
import Ellipsis from 'react-ellipsis-component';
import { Flipped } from 'react-flip-toolkit';
import { NavLink } from 'react-router';
import invariant from 'tiny-invariant';
Expand Down Expand Up @@ -34,11 +33,11 @@ export const JumbotronSection = ({ module }: Props) => {
return (
<>
<div className="grow-1 shrink-1 p-[24px]">
<div className="mb-[16px] w-full text-center text-[22px] font-bold text-[#ffffff]">
<Ellipsis ellipsis reflowOnResize maxLine={2} text={episode.title} visibleLine={2} />
<div className="mb-[16px] w-full text-center text-[22px] font-bold text-[#ffffff] overflow-hidden" style={{ display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', textOverflow: 'ellipsis' }}>
{episode.title}
</div>
<div className="w-full text-center text-[14px] font-bold text-[#ffffff]">
<Ellipsis ellipsis reflowOnResize maxLine={3} text={episode.description} visibleLine={3} />
<div className="w-full text-center text-[14px] font-bold text-[#ffffff] overflow-hidden" style={{ display: '-webkit-box', WebkitLineClamp: 3, WebkitBoxOrient: 'vertical', textOverflow: 'ellipsis' }}>
{episode.description}
</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Ellipsis from 'react-ellipsis-component';
import { Flipped } from 'react-flip-toolkit';
import { NavLink } from 'react-router';

Expand All @@ -25,8 +24,8 @@ export const SeriesItem = ({ series }: Props) => {
</Flipped>
</div>
<div className="p-[8px]">
<div className="text-[14px] font-bold text-[#ffffff]">
<Ellipsis ellipsis reflowOnResize maxLine={2} text={series.title} visibleLine={2} />
<div className="text-[14px] font-bold text-[#ffffff] overflow-hidden" style={{ display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', textOverflow: 'ellipsis' }}>
{series.title}
</div>
</div>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Ellipsis from 'react-ellipsis-component';
import { Flipped } from 'react-flip-toolkit';
import { NavLink } from 'react-router';

Expand Down Expand Up @@ -39,11 +38,11 @@ export const SeriesEpisodeItem = ({ episode, selected }: Props) => {
</Flipped>

<div className="grow-1 shrink-1">
<div className="mb-[8px] text-[18px] font-bold text-[#ffffff]">
<Ellipsis ellipsis reflowOnResize maxLine={2} text={episode.title} visibleLine={2} />
<div className="mb-[8px] text-[18px] font-bold text-[#ffffff] overflow-hidden" style={{ display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', textOverflow: 'ellipsis' }}>
{episode.title}
</div>
<div className="text-[12px] text-[#999999]">
<Ellipsis ellipsis reflowOnResize maxLine={2} text={episode.description} visibleLine={2} />
<div className="text-[12px] text-[#999999] overflow-hidden" style={{ display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', textOverflow: 'ellipsis' }}>
{episode.description}
</div>
</div>
</>
Expand Down
3 changes: 2 additions & 1 deletion workspaces/client/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import '@wsh-2025/client/src/setups/polyfills';
import '@wsh-2025/client/src/setups/luxon';
import '@wsh-2025/client/src/setups/unocss';
import '@unocss/reset/tailwind-compat.css';
import 'uno.css';

import { StrictMode } from 'react';
import { hydrateRoot } from 'react-dom/client';
Expand Down
13 changes: 6 additions & 7 deletions workspaces/client/src/pages/episode/components/EpisodePage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Suspense } from 'react';
import Ellipsis from 'react-ellipsis-component';
import { Flipped } from 'react-flip-toolkit';
import { Params, useParams } from 'react-router';
import invariant from 'tiny-invariant';
Expand Down Expand Up @@ -100,11 +99,11 @@ export const EpisodePage = () => {
</Flipped>

<div className="mb-[24px]">
<div className="text-[16px] text-[#ffffff]">
<Ellipsis ellipsis reflowOnResize maxLine={1} text={episode.series.title} visibleLine={1} />
<div className="text-[16px] text-[#ffffff] overflow-hidden text-ellipsis whitespace-nowrap">
{episode.series.title}
</div>
<h1 className="mt-[8px] text-[22px] font-bold text-[#ffffff]">
<Ellipsis ellipsis reflowOnResize maxLine={2} text={episode.title} visibleLine={2} />
<h1 className="mt-[8px] text-[22px] font-bold text-[#ffffff] overflow-hidden" style={{ display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', textOverflow: 'ellipsis' }}>
{episode.title}
</h1>
{episode.premium ? (
<div className="mt-[8px]">
Expand All @@ -113,8 +112,8 @@ export const EpisodePage = () => {
</span>
</div>
) : null}
<div className="mt-[16px] text-[16px] text-[#999999]">
<Ellipsis ellipsis reflowOnResize maxLine={3} text={episode.description} visibleLine={3} />
<div className="mt-[16px] text-[16px] text-[#999999] overflow-hidden" style={{ display: '-webkit-box', WebkitLineClamp: 3, WebkitBoxOrient: 'vertical', textOverflow: 'ellipsis' }}>
{episode.description}
</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ export const SeekThumbnail = ({ episode }: Props) => {
return (
<div
ref={ref}
className={`absolute h-[90px] w-[160px] bg-[size:auto_100%] bg-[url(${seekThumbnail})] bottom-0 translate-x-[-50%]`}
className="absolute h-[90px] w-[160px] bg-[size:auto_100%] bottom-0 translate-x-[-50%]"
style={{
backgroundImage: `url(${seekThumbnail})`,
backgroundSize: 'auto 100%',
backgroundPositionX: -1 * SEEK_THUMBNAIL_WIDTH * Math.floor(pointedTime),
left: Math.max(MIN_LEFT, Math.min(relativeX, MAX_LEFT)),
}}
Expand Down
13 changes: 11 additions & 2 deletions workspaces/client/src/pages/episode/hooks/useSeekThumbnail.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { FFmpeg } from '@ffmpeg/ffmpeg';
import { StandardSchemaV1 } from '@standard-schema/spec';
import * as schema from '@wsh-2025/schema/src/api/schema';
import { Parser } from 'm3u8-parser';
Expand All @@ -8,15 +7,25 @@ interface Params {
episode: StandardSchemaV1.InferOutput<typeof schema.getEpisodeByIdResponse>;
}

// FFmpegを動的にインポートする関数
async function loadFFmpeg() {
// 必要になった時点でモジュールをロード
const { FFmpeg } = await import('@ffmpeg/ffmpeg');
return FFmpeg;
}

async function getSeekThumbnail({ episode }: Params) {
// HLS のプレイリストを取得
const playlistUrl = `/streams/episode/${episode.id}/playlist.m3u8`;
const parser = new Parser();
parser.push(await fetch(playlistUrl).then((res) => res.text()));
parser.end();

// FFmpegモジュールを動的にロード
const FFmpegClass = await loadFFmpeg();

// FFmpeg の初期化
const ffmpeg = new FFmpeg();
const ffmpeg = new FFmpegClass();
await ffmpeg.load({
coreURL: await import('@ffmpeg/core?arraybuffer').then(({ default: b }) => {
return URL.createObjectURL(new Blob([b], { type: 'text/javascript' }));
Expand Down
13 changes: 6 additions & 7 deletions workspaces/client/src/pages/program/components/ProgramPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { DateTime } from 'luxon';
import { useEffect, useRef } from 'react';
import Ellipsis from 'react-ellipsis-component';
import { Flipped } from 'react-flip-toolkit';
import { Link, Params, useNavigate, useParams } from 'react-router';
import { useUpdate } from 'react-use';
Expand Down Expand Up @@ -140,19 +139,19 @@ export const ProgramPage = () => {
</Flipped>

<div className="mb-[24px]">
<div className="text-[16px] text-[#ffffff]">
<Ellipsis ellipsis reflowOnResize maxLine={1} text={program.episode.series.title} visibleLine={1} />
<div className="text-[16px] text-[#ffffff] overflow-hidden text-ellipsis whitespace-nowrap">
{program.episode.series.title}
</div>
<h1 className="mt-[8px] text-[22px] font-bold text-[#ffffff]">
<Ellipsis ellipsis reflowOnResize maxLine={2} text={program.title} visibleLine={2} />
<h1 className="mt-[8px] text-[22px] font-bold text-[#ffffff] overflow-hidden" style={{ display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', textOverflow: 'ellipsis' }}>
{program.title}
</h1>
<div className="mt-[8px] text-[16px] text-[#999999]">
{DateTime.fromISO(program.startAt).toFormat('L月d日 H:mm')}
{' 〜 '}
{DateTime.fromISO(program.endAt).toFormat('L月d日 H:mm')}
</div>
<div className="mt-[16px] text-[16px] text-[#999999]">
<Ellipsis ellipsis reflowOnResize maxLine={3} text={program.description} visibleLine={3} />
<div className="mt-[16px] text-[16px] text-[#999999] overflow-hidden" style={{ display: '-webkit-box', WebkitLineClamp: 3, WebkitBoxOrient: 'vertical', textOverflow: 'ellipsis' }}>
{program.description}
</div>
</div>

Expand Down
9 changes: 4 additions & 5 deletions workspaces/client/src/pages/series/components/SeriesPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Ellipsis from 'react-ellipsis-component';
import { Flipped } from 'react-flip-toolkit';
import { Params, useParams } from 'react-router';
import invariant from 'tiny-invariant';
Expand Down Expand Up @@ -41,11 +40,11 @@ export const SeriesPage = () => {
/>
</Flipped>
<div className="grow-1 shrink-1 overflow-hidden">
<h1 className="mb-[16px] text-[32px] font-bold text-[#ffffff]">
<Ellipsis ellipsis reflowOnResize maxLine={2} text={series.title} visibleLine={2} />
<h1 className="mb-[16px] text-[32px] font-bold text-[#ffffff] overflow-hidden" style={{ display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', textOverflow: 'ellipsis' }}>
{series.title}
</h1>
<div className="text-[14px] text-[#999999]">
<Ellipsis ellipsis reflowOnResize maxLine={3} text={series.description} visibleLine={3} />
<div className="text-[14px] text-[#999999] overflow-hidden" style={{ display: '-webkit-box', WebkitLineClamp: 3, WebkitBoxOrient: 'vertical', textOverflow: 'ellipsis' }}>
{series.description}
</div>
</div>
</header>
Expand Down
Loading