Skip to content

Commit b74c535

Browse files
committed
add contetn plan
1 parent 39ba4c4 commit b74c535

File tree

8 files changed

+8562
-1
lines changed

8 files changed

+8562
-1
lines changed

app/admin/content-plan/page.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Metadata } from "next";
2+
import Header from "../../../components/Header";
3+
import { ContentPlanList } from "../../../components/ContentPlanList";
4+
import contentPlanData from "../../../data/content-plan-cleaned.json";
5+
6+
export const metadata: Metadata = {
7+
title: "Content Plan | Admin",
8+
description: "Управление контент-планом для создания пресетов",
9+
};
10+
11+
export interface ContentPlanTrack {
12+
artist: string;
13+
song: string;
14+
instrument: string;
15+
part: string;
16+
songsterrUrl: string;
17+
trackIndex: number;
18+
}
19+
20+
export default function ContentPlanPage() {
21+
const tracks = contentPlanData.tracks as ContentPlanTrack[];
22+
23+
return (
24+
<div className="min-h-screen bg-gray-900 text-gray-100">
25+
<Header />
26+
27+
<div className="container mx-auto px-4 pb-8">
28+
<div className="flex justify-between items-center mb-6">
29+
<div>
30+
<h1 className="text-3xl font-bold text-white">Content Plan</h1>
31+
<p className="text-gray-400 mt-1">
32+
{tracks.length} треков в очереди на генерацию
33+
</p>
34+
</div>
35+
</div>
36+
37+
<ContentPlanList initialTracks={tracks} />
38+
</div>
39+
</div>
40+
);
41+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import { promises as fs } from "fs";
3+
import path from "path";
4+
5+
interface ContentPlanTrack {
6+
artist: string;
7+
song: string;
8+
instrument: string;
9+
part: string;
10+
songsterrUrl: string;
11+
trackIndex: number;
12+
}
13+
14+
interface ContentPlanData {
15+
tracks: ContentPlanTrack[];
16+
}
17+
18+
const CONTENT_PLAN_PATH = path.join(
19+
process.cwd(),
20+
"data",
21+
"content-plan-cleaned.json",
22+
);
23+
24+
export async function POST(request: NextRequest): Promise<NextResponse> {
25+
try {
26+
const body = (await request.json()) as { songsterrUrl: string };
27+
28+
if (!body.songsterrUrl) {
29+
return NextResponse.json(
30+
{ error: "songsterrUrl is required" },
31+
{ status: 400 },
32+
);
33+
}
34+
35+
// Read current data
36+
const fileContent = await fs.readFile(CONTENT_PLAN_PATH, "utf-8");
37+
const data: ContentPlanData = JSON.parse(fileContent);
38+
39+
// Find and remove the track
40+
const initialLength = data.tracks.length;
41+
data.tracks = data.tracks.filter(
42+
(track) => track.songsterrUrl !== body.songsterrUrl,
43+
);
44+
45+
if (data.tracks.length === initialLength) {
46+
return NextResponse.json({ error: "Track not found" }, { status: 404 });
47+
}
48+
49+
// Write back
50+
await fs.writeFile(
51+
CONTENT_PLAN_PATH,
52+
JSON.stringify(data, null, 2),
53+
"utf-8",
54+
);
55+
56+
return NextResponse.json({
57+
success: true,
58+
message: "Track deleted",
59+
remainingTracks: data.tracks.length,
60+
});
61+
} catch (error) {
62+
console.error("Error deleting track:", error);
63+
return NextResponse.json(
64+
{ error: "Failed to delete track" },
65+
{ status: 500 },
66+
);
67+
}
68+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import { promises as fs } from "fs";
3+
import path from "path";
4+
5+
interface ContentPlanTrack {
6+
artist: string;
7+
song: string;
8+
instrument: string;
9+
part: string;
10+
songsterrUrl: string;
11+
trackIndex: number;
12+
}
13+
14+
interface ContentPlanData {
15+
tracks: ContentPlanTrack[];
16+
}
17+
18+
const CONTENT_PLAN_PATH = path.join(
19+
process.cwd(),
20+
"data",
21+
"content-plan-cleaned.json",
22+
);
23+
24+
export async function POST(request: NextRequest): Promise<NextResponse> {
25+
try {
26+
const body = (await request.json()) as {
27+
songsterrUrl: string;
28+
positions?: number;
29+
};
30+
31+
if (!body.songsterrUrl) {
32+
return NextResponse.json(
33+
{ error: "songsterrUrl is required" },
34+
{ status: 400 },
35+
);
36+
}
37+
38+
const positions = body.positions ?? 10;
39+
40+
// Read current data
41+
const fileContent = await fs.readFile(CONTENT_PLAN_PATH, "utf-8");
42+
const data: ContentPlanData = JSON.parse(fileContent);
43+
44+
// Find the track index
45+
const currentIndex = data.tracks.findIndex(
46+
(track) => track.songsterrUrl === body.songsterrUrl,
47+
);
48+
49+
if (currentIndex === -1) {
50+
return NextResponse.json({ error: "Track not found" }, { status: 404 });
51+
}
52+
53+
// Calculate new position (don't exceed array bounds)
54+
const newIndex = Math.min(currentIndex + positions, data.tracks.length - 1);
55+
56+
// If already at end or would move beyond, just return success
57+
if (newIndex === currentIndex) {
58+
return NextResponse.json({
59+
success: true,
60+
message: "Track already at end of list",
61+
newPosition: currentIndex,
62+
});
63+
}
64+
65+
// Remove track from current position
66+
const removed = data.tracks.splice(currentIndex, 1);
67+
const track = removed[0];
68+
69+
// Insert at new position
70+
if (track) {
71+
data.tracks.splice(newIndex, 0, track);
72+
}
73+
74+
// Write back
75+
await fs.writeFile(
76+
CONTENT_PLAN_PATH,
77+
JSON.stringify(data, null, 2),
78+
"utf-8",
79+
);
80+
81+
return NextResponse.json({
82+
success: true,
83+
message: `Track postponed by ${String(newIndex - currentIndex)} positions`,
84+
oldPosition: currentIndex,
85+
newPosition: newIndex,
86+
});
87+
} catch (error) {
88+
console.error("Error postponing track:", error);
89+
return NextResponse.json(
90+
{ error: "Failed to postpone track" },
91+
{ status: 500 },
92+
);
93+
}
94+
}

0 commit comments

Comments
 (0)