mirror of
https://github.com/wgh136/nysoure.git
synced 2025-12-16 15:51:14 +00:00
typo
This commit is contained in:
@@ -5,9 +5,9 @@ import showToast from "./toast";
|
|||||||
import { useTranslation } from "../utils/i18n";
|
import { useTranslation } from "../utils/i18n";
|
||||||
import Button from "./button";
|
import Button from "./button";
|
||||||
|
|
||||||
export default function CharacterEditer({charactor, setCharactor, onDelete}: {
|
export default function CharacterEditer({character, setCharacter, onDelete}: {
|
||||||
charactor: CharacterParams;
|
character: CharacterParams;
|
||||||
setCharactor: (charactor: CharacterParams) => void;
|
setCharacter: (character: CharacterParams) => void;
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -26,8 +26,8 @@ export default function CharacterEditer({charactor, setCharactor, onDelete}: {
|
|||||||
const result = await network.uploadImage(file);
|
const result = await network.uploadImage(file);
|
||||||
setUploading(false);
|
setUploading(false);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
setCharactor({
|
setCharacter({
|
||||||
...charactor,
|
...character,
|
||||||
image: result.data!,
|
image: result.data!,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -51,7 +51,7 @@ export default function CharacterEditer({charactor, setCharactor, onDelete}: {
|
|||||||
}
|
}
|
||||||
<img
|
<img
|
||||||
className="w-full h-full object-cover bg-base-200/80 hover:bg-base-200 transition-colors"
|
className="w-full h-full object-cover bg-base-200/80 hover:bg-base-200 transition-colors"
|
||||||
src={charactor.image === 0 ? "/cp.webp" : network.getImageUrl(charactor.image)} alt={charactor.name}
|
src={character.image === 0 ? "/cp.webp" : network.getImageUrl(character.image)} alt={character.name}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -61,8 +61,8 @@ export default function CharacterEditer({charactor, setCharactor, onDelete}: {
|
|||||||
type="text"
|
type="text"
|
||||||
className="input input-sm input-bordered flex-1"
|
className="input input-sm input-bordered flex-1"
|
||||||
placeholder={t("Name")}
|
placeholder={t("Name")}
|
||||||
value={charactor.name}
|
value={character.name}
|
||||||
onChange={(e) => setCharactor({ ...charactor, name: e.target.value })}
|
onChange={(e) => setCharacter({ ...character, name: e.target.value })}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
className="btn btn-sm btn-error btn-square"
|
className="btn btn-sm btn-error btn-square"
|
||||||
@@ -78,14 +78,14 @@ export default function CharacterEditer({charactor, setCharactor, onDelete}: {
|
|||||||
type="text"
|
type="text"
|
||||||
className="input input-sm input-bordered"
|
className="input input-sm input-bordered"
|
||||||
placeholder="CV"
|
placeholder="CV"
|
||||||
value={charactor.cv}
|
value={character.cv}
|
||||||
onChange={(e) => setCharactor({ ...charactor, cv: e.target.value })}
|
onChange={(e) => setCharacter({ ...character, cv: e.target.value })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
className="select select-sm select-bordered"
|
className="select select-sm select-bordered"
|
||||||
value={charactor.role}
|
value={character.role}
|
||||||
onChange={(e) => setCharactor({ ...charactor, role: e.target.value as CharacterRole })}
|
onChange={(e) => setCharacter({ ...character, role: e.target.value as CharacterRole })}
|
||||||
>
|
>
|
||||||
<option value="primary">{t("Primary Role")}</option>
|
<option value="primary">{t("Primary Role")}</option>
|
||||||
<option value="side">{t("Side Role")}</option>
|
<option value="side">{t("Side Role")}</option>
|
||||||
@@ -95,9 +95,9 @@ export default function CharacterEditer({charactor, setCharactor, onDelete}: {
|
|||||||
<textarea
|
<textarea
|
||||||
className="textarea textarea-bordered w-full h-full resize-none text-xs"
|
className="textarea textarea-bordered w-full h-full resize-none text-xs"
|
||||||
placeholder={t("Aliases (one per line)")}
|
placeholder={t("Aliases (one per line)")}
|
||||||
value={charactor.alias.join('\n')}
|
value={character.alias.join('\n')}
|
||||||
onChange={(e) => setCharactor({
|
onChange={(e) => setCharacter({
|
||||||
...charactor,
|
...character,
|
||||||
alias: e.target.value.split('\n').filter(line => line.trim() !== '')
|
alias: e.target.value.split('\n').filter(line => line.trim() !== '')
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ export interface ResourceDetails {
|
|||||||
related: Resource[];
|
related: Resource[];
|
||||||
gallery: number[];
|
gallery: number[];
|
||||||
galleryNsfw: number[];
|
galleryNsfw: number[];
|
||||||
charactors: CharacterParams[];
|
characters: CharacterParams[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Storage {
|
export interface Storage {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export default function EditResourcePage() {
|
|||||||
const [links, setLinks] = useState<{ label: string; url: string }[]>([]);
|
const [links, setLinks] = useState<{ label: string; url: string }[]>([]);
|
||||||
const [galleryImages, setGalleryImages] = useState<number[]>([]);
|
const [galleryImages, setGalleryImages] = useState<number[]>([]);
|
||||||
const [galleryNsfw, setGalleryNsfw] = useState<number[]>([]);
|
const [galleryNsfw, setGalleryNsfw] = useState<number[]>([]);
|
||||||
const [charactors, setCharactors] = useState<CharacterParams[]>([]);
|
const [characters, setCharacters] = useState<CharacterParams[]>([]);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [isSubmitting, setSubmitting] = useState(false);
|
const [isSubmitting, setSubmitting] = useState(false);
|
||||||
const [isLoading, setLoading] = useState(true);
|
const [isLoading, setLoading] = useState(true);
|
||||||
@@ -61,7 +61,7 @@ export default function EditResourcePage() {
|
|||||||
setLinks(data.links ?? []);
|
setLinks(data.links ?? []);
|
||||||
setGalleryImages(data.gallery ?? []);
|
setGalleryImages(data.gallery ?? []);
|
||||||
setGalleryNsfw(data.galleryNsfw ?? []);
|
setGalleryNsfw(data.galleryNsfw ?? []);
|
||||||
setCharactors(data.charactors ?? []);
|
setCharacters(data.characters ?? []);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
} else {
|
} else {
|
||||||
showToast({ message: t("Failed to load resource"), type: "error" });
|
showToast({ message: t("Failed to load resource"), type: "error" });
|
||||||
@@ -107,7 +107,7 @@ export default function EditResourcePage() {
|
|||||||
links: links,
|
links: links,
|
||||||
gallery: galleryImages,
|
gallery: galleryImages,
|
||||||
gallery_nsfw: galleryNsfw,
|
gallery_nsfw: galleryNsfw,
|
||||||
characters: charactors,
|
characters: characters,
|
||||||
});
|
});
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
@@ -428,18 +428,18 @@ export default function EditResourcePage() {
|
|||||||
<p className={"my-1"}>{t("Characters")}</p>
|
<p className={"my-1"}>{t("Characters")}</p>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 my-2 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 my-2 gap-4">
|
||||||
{
|
{
|
||||||
charactors.map((charactor, index) => {
|
characters.map((character, index) => {
|
||||||
return <CharacterEditer
|
return <CharacterEditer
|
||||||
charactor={charactor}
|
character={character}
|
||||||
setCharactor={(newCharactor) => {
|
setCharacter={(newCharacter) => {
|
||||||
const newCharactors = [...charactors];
|
const newCharacters = [...characters];
|
||||||
newCharactors[index] = newCharactor;
|
newCharacters[index] = newCharacter;
|
||||||
setCharactors(newCharactors);
|
setCharacters(newCharacters);
|
||||||
}}
|
}}
|
||||||
onDelete={() => {
|
onDelete={() => {
|
||||||
const newCharactors = [...charactors];
|
const newCharacters = [...characters];
|
||||||
newCharactors.splice(index, 1);
|
newCharacters.splice(index, 1);
|
||||||
setCharactors(newCharactors);
|
setCharacters(newCharacters);
|
||||||
}} />;
|
}} />;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -449,7 +449,7 @@ export default function EditResourcePage() {
|
|||||||
className={"btn h-9"}
|
className={"btn h-9"}
|
||||||
type={"button"}
|
type={"button"}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCharactors([...charactors, { name: "", alias: [], cv: "", image: 0 }]);
|
setCharacters([...characters, { name: "", alias: [], cv: "", image: 0 }]);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MdAdd />
|
<MdAdd />
|
||||||
@@ -461,7 +461,7 @@ export default function EditResourcePage() {
|
|||||||
<FetchVndbCharactersButton
|
<FetchVndbCharactersButton
|
||||||
vnID={links.find(link => link.label.toLowerCase() === "vndb")?.url.split("/").pop() ?? ""}
|
vnID={links.find(link => link.label.toLowerCase() === "vndb")?.url.split("/").pop() ?? ""}
|
||||||
onFetch={(fetchedCharacters) => {
|
onFetch={(fetchedCharacters) => {
|
||||||
setCharactors(fetchedCharacters);
|
setCharacters(fetchedCharacters);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default function PublishPage() {
|
|||||||
const [galleryNsfw, setGalleryNsfw] = useState<number[]>([]);
|
const [galleryNsfw, setGalleryNsfw] = useState<number[]>([]);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [isSubmitting, setSubmitting] = useState(false);
|
const [isSubmitting, setSubmitting] = useState(false);
|
||||||
const [charactors, setCharactors] = useState<CharacterParams[]>([]);
|
const [characters, setCharacters] = useState<CharacterParams[]>([]);
|
||||||
const isFirstLoad = useRef(true);
|
const isFirstLoad = useRef(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -111,7 +111,7 @@ export default function PublishPage() {
|
|||||||
links: links,
|
links: links,
|
||||||
gallery: galleryImages,
|
gallery: galleryImages,
|
||||||
gallery_nsfw: galleryNsfw,
|
gallery_nsfw: galleryNsfw,
|
||||||
characters: charactors,
|
characters: characters,
|
||||||
});
|
});
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
localStorage.removeItem("publish_data");
|
localStorage.removeItem("publish_data");
|
||||||
@@ -435,18 +435,18 @@ export default function PublishPage() {
|
|||||||
<p className={"my-1"}>{t("Characters")}</p>
|
<p className={"my-1"}>{t("Characters")}</p>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 my-2 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 my-2 gap-4">
|
||||||
{
|
{
|
||||||
charactors.map((charactor, index) => {
|
characters.map((character, index) => {
|
||||||
return <CharacterEditer
|
return <CharacterEditer
|
||||||
charactor={charactor}
|
character={character}
|
||||||
setCharactor={(newCharactor) => {
|
setCharacter={(newCharacter) => {
|
||||||
const newCharactors = [...charactors];
|
const newCharacters = [...characters];
|
||||||
newCharactors[index] = newCharactor;
|
newCharacters[index] = newCharacter;
|
||||||
setCharactors(newCharactors);
|
setCharacters(newCharacters);
|
||||||
}}
|
}}
|
||||||
onDelete={() => {
|
onDelete={() => {
|
||||||
const newCharactors = [...charactors];
|
const newCharacters = [...characters];
|
||||||
newCharactors.splice(index, 1);
|
newCharacters.splice(index, 1);
|
||||||
setCharactors(newCharactors);
|
setCharacters(newCharacters);
|
||||||
}} />;
|
}} />;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -456,7 +456,7 @@ export default function PublishPage() {
|
|||||||
className={"btn my-2"}
|
className={"btn my-2"}
|
||||||
type={"button"}
|
type={"button"}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCharactors([...charactors, { name: "", alias: [], cv: "", image: 0 }]);
|
setCharacters([...characters, { name: "", alias: [], cv: "", image: 0 }]);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MdAdd />
|
<MdAdd />
|
||||||
|
|||||||
@@ -600,7 +600,7 @@ function Article({ resource }: { resource: ResourceDetails }) {
|
|||||||
</Markdown>
|
</Markdown>
|
||||||
</article>
|
</article>
|
||||||
<div className="border-b border-base-300 h-8"></div>
|
<div className="border-b border-base-300 h-8"></div>
|
||||||
<Characters charactors={resource.charactors} />
|
<Characters characters={resource.characters} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2078,10 +2078,10 @@ function GalleryImage({src, nfsw}: {src: string, nfsw: boolean}) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Characters({ charactors }: { charactors: CharacterParams[] }) {
|
function Characters({ characters }: { characters: CharacterParams[] }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (!charactors || charactors.length === 0) {
|
if (!characters || characters.length === 0) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2089,43 +2089,43 @@ function Characters({ charactors }: { charactors: CharacterParams[] }) {
|
|||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
<h3 className="text-xl font-bold mb-4">{t("Characters")}</h3>
|
<h3 className="text-xl font-bold mb-4">{t("Characters")}</h3>
|
||||||
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4">
|
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4">
|
||||||
{charactors.map((charactor, index) => (
|
{characters.map((character, index) => (
|
||||||
<CharacterCard key={index} charactor={charactor} />
|
<CharacterCard key={index} character={character} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CharacterCard({ charactor }: { charactor: CharacterParams }) {
|
function CharacterCard({ character }: { character: CharacterParams }) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const handleCVClick = (e: React.MouseEvent) => {
|
const handleCVClick = (e: React.MouseEvent) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (charactor.cv) {
|
if (character.cv) {
|
||||||
navigate(`/search?keyword=${encodeURIComponent(charactor.cv)}`);
|
navigate(`/search?keyword=${encodeURIComponent(character.cv)}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="group relative aspect-[3/4] overflow-hidden rounded-lg bg-base-200 shadow-sm">
|
<div className="group relative aspect-[3/4] overflow-hidden rounded-lg bg-base-200 shadow-sm">
|
||||||
<img
|
<img
|
||||||
src={network.getImageUrl(charactor.image)}
|
src={network.getImageUrl(character.image)}
|
||||||
alt={charactor.name}
|
alt={character.name}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="absolute bottom-1 left-1 right-1 px-2 py-2 border border-base-100/40 rounded-lg bg-base-100/60">
|
<div className="absolute bottom-1 left-1 right-1 px-2 py-2 border border-base-100/40 rounded-lg bg-base-100/60">
|
||||||
<h4 className="font-semibold text-sm leading-tight line-clamp border border-transparent px-1">
|
<h4 className="font-semibold text-sm leading-tight line-clamp border border-transparent px-1">
|
||||||
{charactor.name}
|
{character.name}
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
{charactor.cv && (
|
{character.cv && (
|
||||||
<button
|
<button
|
||||||
onClick={handleCVClick}
|
onClick={handleCVClick}
|
||||||
className="hover:bg-base-200/80 px-1 border border-transparent hover:border-base-300/50 rounded-sm text-xs transition-colors cursor-pointer"
|
className="hover:bg-base-200/80 px-1 border border-transparent hover:border-base-300/50 rounded-sm text-xs transition-colors cursor-pointer"
|
||||||
>
|
>
|
||||||
CV: {charactor.cv}
|
CV: {character.cv}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -282,16 +282,16 @@ func handleGetPinnedResources(c fiber.Ctx) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleGetCharactorsFromVndb(c fiber.Ctx) error {
|
func handleGetCharactersFromVndb(c fiber.Ctx) error {
|
||||||
vnID := c.Query("vnid")
|
vnID := c.Query("vnid")
|
||||||
if vnID == "" {
|
if vnID == "" {
|
||||||
return model.NewRequestError("VNDB ID is required")
|
return model.NewRequestError("VNDB ID is required")
|
||||||
}
|
}
|
||||||
characters, err := service.GetCharactorsFromVndb(vnID)
|
characters, err := service.GetCharactersFromVndb(vnID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return c.Status(fiber.StatusOK).JSON(model.Response[[]service.CharactorParams]{
|
return c.Status(fiber.StatusOK).JSON(model.Response[[]service.CharacterParams]{
|
||||||
Success: true,
|
Success: true,
|
||||||
Data: characters,
|
Data: characters,
|
||||||
Message: "Characters retrieved successfully",
|
Message: "Characters retrieved successfully",
|
||||||
@@ -306,7 +306,7 @@ func AddResourceRoutes(api fiber.Router) {
|
|||||||
resource.Get("/", handleListResources)
|
resource.Get("/", handleListResources)
|
||||||
resource.Get("/random", handleGetRandomResource)
|
resource.Get("/random", handleGetRandomResource)
|
||||||
resource.Get("/pinned", handleGetPinnedResources)
|
resource.Get("/pinned", handleGetPinnedResources)
|
||||||
resource.Get("/vndb/characters", handleGetCharactorsFromVndb)
|
resource.Get("/vndb/characters", handleGetCharactersFromVndb)
|
||||||
resource.Get("/:id", handleGetResource)
|
resource.Get("/:id", handleGetResource)
|
||||||
resource.Delete("/:id", handleDeleteResource)
|
resource.Delete("/:id", handleDeleteResource)
|
||||||
resource.Get("/tag/:tag", handleListResourcesWithTag)
|
resource.Get("/tag/:tag", handleListResourcesWithTag)
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func init() {
|
|||||||
&model.Activity{},
|
&model.Activity{},
|
||||||
&model.Collection{},
|
&model.Collection{},
|
||||||
&model.CollectionResource{},
|
&model.CollectionResource{},
|
||||||
&model.Charactor{},
|
&model.Character{},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ func GetUnusedImages() ([]model.Image, error) {
|
|||||||
Where("NOT EXISTS (SELECT 1 FROM resource_images WHERE image_id = images.id)").
|
Where("NOT EXISTS (SELECT 1 FROM resource_images WHERE image_id = images.id)").
|
||||||
Where("NOT EXISTS (SELECT 1 FROM comment_images WHERE image_id = images.id)").
|
Where("NOT EXISTS (SELECT 1 FROM comment_images WHERE image_id = images.id)").
|
||||||
Where("NOT EXISTS (SELECT 1 FROM collection_images WHERE image_id = images.id)").
|
Where("NOT EXISTS (SELECT 1 FROM collection_images WHERE image_id = images.id)").
|
||||||
Where("NOT EXISTS (SELECT 1 FROM charactors WHERE image_id = images.id)").
|
Where("NOT EXISTS (SELECT 1 FROM characters WHERE image_id = images.id)").
|
||||||
Where("created_at < ?", oneDayAgo).
|
Where("created_at < ?", oneDayAgo).
|
||||||
Find(&images).Error; err != nil {
|
Find(&images).Error; err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ import (
|
|||||||
func CreateResource(r model.Resource) (model.Resource, error) {
|
func CreateResource(r model.Resource) (model.Resource, error) {
|
||||||
err := db.Transaction(func(tx *gorm.DB) error {
|
err := db.Transaction(func(tx *gorm.DB) error {
|
||||||
r.ModifiedTime = time.Now()
|
r.ModifiedTime = time.Now()
|
||||||
charactors := r.Charactors
|
characters := r.Characters
|
||||||
r.Charactors = nil
|
r.Characters = nil
|
||||||
err := tx.Create(&r).Error
|
err := tx.Create(&r).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, c := range charactors {
|
for _, c := range characters {
|
||||||
c.ResourceID = r.ID
|
c.ResourceID = r.ID
|
||||||
if err := tx.Create(&c).Error; err != nil {
|
if err := tx.Create(&c).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -50,7 +50,7 @@ func GetResourceByID(id uint) (model.Resource, error) {
|
|||||||
Preload("Files").
|
Preload("Files").
|
||||||
Preload("Files.User").
|
Preload("Files.User").
|
||||||
Preload("Files.Storage").
|
Preload("Files.Storage").
|
||||||
Preload("Charactors").
|
Preload("Characters").
|
||||||
First(&r, id).Error; err != nil {
|
First(&r, id).Error; err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return model.Resource{}, model.NewNotFoundError("Resource not found")
|
return model.Resource{}, model.NewNotFoundError("Resource not found")
|
||||||
@@ -111,14 +111,14 @@ func UpdateResource(r model.Resource) error {
|
|||||||
return db.Transaction(func(tx *gorm.DB) error {
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
images := r.Images
|
images := r.Images
|
||||||
tags := r.Tags
|
tags := r.Tags
|
||||||
charactors := r.Charactors
|
characters := r.Characters
|
||||||
r.Charactors = nil
|
r.Characters = nil
|
||||||
r.Images = nil
|
r.Images = nil
|
||||||
r.Tags = nil
|
r.Tags = nil
|
||||||
r.Files = nil
|
r.Files = nil
|
||||||
r.ModifiedTime = time.Now()
|
r.ModifiedTime = time.Now()
|
||||||
oldCharactors := []model.Charactor{}
|
oldCharacters := []model.Character{}
|
||||||
if err := db.Model(&model.Charactor{}).Where("resource_id = ?", r.ID).Find(&oldCharactors).Error; err != nil {
|
if err := db.Model(&model.Character{}).Where("resource_id = ?", r.ID).Find(&oldCharacters).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := db.Save(&r).Error; err != nil {
|
if err := db.Save(&r).Error; err != nil {
|
||||||
@@ -130,9 +130,9 @@ func UpdateResource(r model.Resource) error {
|
|||||||
if err := db.Model(&r).Association("Tags").Replace(tags); err != nil {
|
if err := db.Model(&r).Association("Tags").Replace(tags); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, c := range oldCharactors {
|
for _, c := range oldCharacters {
|
||||||
shouldDelete := true
|
shouldDelete := true
|
||||||
for _, nc := range charactors {
|
for _, nc := range characters {
|
||||||
if c.ID == nc.ID {
|
if c.ID == nc.ID {
|
||||||
shouldDelete = false
|
shouldDelete = false
|
||||||
break
|
break
|
||||||
@@ -144,9 +144,9 @@ func UpdateResource(r model.Resource) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, c := range charactors {
|
for _, c := range characters {
|
||||||
shouldAdd := true
|
shouldAdd := true
|
||||||
for _, oc := range oldCharactors {
|
for _, oc := range oldCharacters {
|
||||||
if c.Equal(&oc) {
|
if c.Equal(&oc) {
|
||||||
shouldAdd = false
|
shouldAdd = false
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
type Charactor struct {
|
type Character struct {
|
||||||
ID uint `gorm:"primaryKey;autoIncrement"`
|
ID uint `gorm:"primaryKey;autoIncrement"`
|
||||||
Name string `gorm:"type:varchar(100);not null"`
|
Name string `gorm:"type:varchar(100);not null"`
|
||||||
Alias []string `gorm:"serializer:json"`
|
Alias []string `gorm:"serializer:json"`
|
||||||
@@ -11,7 +11,7 @@ type Charactor struct {
|
|||||||
Image *Image `gorm:"foreignKey:ImageID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
|
Image *Image `gorm:"foreignKey:ImageID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CharactorView struct {
|
type CharacterView struct {
|
||||||
Id uint `json:"id"`
|
Id uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Alias []string `json:"alias"`
|
Alias []string `json:"alias"`
|
||||||
@@ -20,8 +20,8 @@ type CharactorView struct {
|
|||||||
Image uint `json:"image"`
|
Image uint `json:"image"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Charactor) ToView() *CharactorView {
|
func (c *Character) ToView() *CharacterView {
|
||||||
return &CharactorView{
|
return &CharacterView{
|
||||||
Id: c.ID,
|
Id: c.ID,
|
||||||
Name: c.Name,
|
Name: c.Name,
|
||||||
Alias: c.Alias,
|
Alias: c.Alias,
|
||||||
@@ -31,7 +31,7 @@ func (c *Charactor) ToView() *CharactorView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Charactor) Equal(other *Charactor) bool {
|
func (c *Character) Equal(other *Character) bool {
|
||||||
if c.Name != other.Name || c.CV != other.CV || c.Role != other.Role || c.ImageID != other.ImageID {
|
if c.Name != other.Name || c.CV != other.CV || c.Role != other.Role || c.ImageID != other.ImageID {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ type Resource struct {
|
|||||||
ModifiedTime time.Time
|
ModifiedTime time.Time
|
||||||
Gallery []uint `gorm:"serializer:json"`
|
Gallery []uint `gorm:"serializer:json"`
|
||||||
GalleryNsfw []uint `gorm:"serializer:json"`
|
GalleryNsfw []uint `gorm:"serializer:json"`
|
||||||
Charactors []Charactor `gorm:"foreignKey:ResourceID"`
|
Characters []Character `gorm:"foreignKey:ResourceID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Link struct {
|
type Link struct {
|
||||||
@@ -57,7 +57,7 @@ type ResourceDetailView struct {
|
|||||||
Related []ResourceView `json:"related"`
|
Related []ResourceView `json:"related"`
|
||||||
Gallery []uint `json:"gallery"`
|
Gallery []uint `json:"gallery"`
|
||||||
GalleryNsfw []uint `json:"galleryNsfw"`
|
GalleryNsfw []uint `json:"galleryNsfw"`
|
||||||
Charactors []CharactorView `json:"charactors"`
|
Characters []CharacterView `json:"characters"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resource) ToView() ResourceView {
|
func (r *Resource) ToView() ResourceView {
|
||||||
@@ -96,9 +96,9 @@ func (r *Resource) ToDetailView() ResourceDetailView {
|
|||||||
for i, file := range r.Files {
|
for i, file := range r.Files {
|
||||||
files[i] = *file.ToView()
|
files[i] = *file.ToView()
|
||||||
}
|
}
|
||||||
charactors := make([]CharactorView, len(r.Charactors))
|
characters := make([]CharacterView, len(r.Characters))
|
||||||
for i, charactor := range r.Charactors {
|
for i, character := range r.Characters {
|
||||||
charactors[i] = *charactor.ToView()
|
characters[i] = *character.ToView()
|
||||||
}
|
}
|
||||||
return ResourceDetailView{
|
return ResourceDetailView{
|
||||||
ID: r.ID,
|
ID: r.ID,
|
||||||
@@ -116,6 +116,6 @@ func (r *Resource) ToDetailView() ResourceDetailView {
|
|||||||
Comments: r.Comments,
|
Comments: r.Comments,
|
||||||
Gallery: r.Gallery,
|
Gallery: r.Gallery,
|
||||||
GalleryNsfw: r.GalleryNsfw,
|
GalleryNsfw: r.GalleryNsfw,
|
||||||
Charactors: charactors,
|
Characters: characters,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ type ResourceParams struct {
|
|||||||
Images []uint `json:"images"`
|
Images []uint `json:"images"`
|
||||||
Gallery []uint `json:"gallery"`
|
Gallery []uint `json:"gallery"`
|
||||||
GalleryNsfw []uint `json:"gallery_nsfw"`
|
GalleryNsfw []uint `json:"gallery_nsfw"`
|
||||||
Charactors []CharactorParams `json:"characters"`
|
Characters []CharacterParams `json:"characters"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CharactorParams struct {
|
type CharacterParams struct {
|
||||||
Name string `json:"name" binding:"required"`
|
Name string `json:"name" binding:"required"`
|
||||||
Alias []string `json:"alias"`
|
Alias []string `json:"alias"`
|
||||||
CV string `json:"cv"`
|
CV string `json:"cv"`
|
||||||
@@ -83,13 +83,13 @@ func CreateResource(uid uint, params *ResourceParams) (uint, error) {
|
|||||||
nsfw = append(nsfw, id)
|
nsfw = append(nsfw, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
charactors := make([]model.Charactor, len(params.Charactors))
|
characters := make([]model.Character, len(params.Characters))
|
||||||
for i, c := range params.Charactors {
|
for i, c := range params.Characters {
|
||||||
role := c.Role
|
role := c.Role
|
||||||
if role == "" {
|
if role == "" {
|
||||||
role = "primary"
|
role = "primary"
|
||||||
}
|
}
|
||||||
charactors[i] = model.Charactor{
|
characters[i] = model.Character{
|
||||||
Name: c.Name,
|
Name: c.Name,
|
||||||
Alias: c.Alias,
|
Alias: c.Alias,
|
||||||
CV: c.CV,
|
CV: c.CV,
|
||||||
@@ -107,7 +107,7 @@ func CreateResource(uid uint, params *ResourceParams) (uint, error) {
|
|||||||
UserID: uid,
|
UserID: uid,
|
||||||
Gallery: gallery,
|
Gallery: gallery,
|
||||||
GalleryNsfw: nsfw,
|
GalleryNsfw: nsfw,
|
||||||
Charactors: charactors,
|
Characters: characters,
|
||||||
}
|
}
|
||||||
if r, err = dao.CreateResource(r); err != nil {
|
if r, err = dao.CreateResource(r); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
@@ -506,13 +506,13 @@ func UpdateResource(uid, rid uint, params *ResourceParams) error {
|
|||||||
nsfw = append(nsfw, id)
|
nsfw = append(nsfw, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
charactors := make([]model.Charactor, len(params.Charactors))
|
characters := make([]model.Character, len(params.Characters))
|
||||||
for i, c := range params.Charactors {
|
for i, c := range params.Characters {
|
||||||
role := c.Role
|
role := c.Role
|
||||||
if role == "" {
|
if role == "" {
|
||||||
role = "primary"
|
role = "primary"
|
||||||
}
|
}
|
||||||
charactors[i] = model.Charactor{
|
characters[i] = model.Character{
|
||||||
Name: c.Name,
|
Name: c.Name,
|
||||||
Alias: c.Alias,
|
Alias: c.Alias,
|
||||||
CV: c.CV,
|
CV: c.CV,
|
||||||
@@ -527,7 +527,7 @@ func UpdateResource(uid, rid uint, params *ResourceParams) error {
|
|||||||
r.Links = params.Links
|
r.Links = params.Links
|
||||||
r.Gallery = gallery
|
r.Gallery = gallery
|
||||||
r.GalleryNsfw = nsfw
|
r.GalleryNsfw = nsfw
|
||||||
r.Charactors = charactors
|
r.Characters = characters
|
||||||
|
|
||||||
images := make([]model.Image, len(params.Images))
|
images := make([]model.Image, len(params.Images))
|
||||||
for i, id := range params.Images {
|
for i, id := range params.Images {
|
||||||
@@ -607,7 +607,7 @@ func GetPinnedResources() ([]model.ResourceView, error) {
|
|||||||
return views, nil
|
return views, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCharactorsFromVndb(vnID string) ([]CharactorParams, error) {
|
func GetCharactersFromVndb(vnID string) ([]CharacterParams, error) {
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
jsonStr := fmt.Sprintf(`
|
jsonStr := fmt.Sprintf(`
|
||||||
{
|
{
|
||||||
@@ -658,11 +658,11 @@ func GetCharactorsFromVndb(vnID string) ([]CharactorParams, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(vndbResp.Results) == 0 {
|
if len(vndbResp.Results) == 0 {
|
||||||
return []CharactorParams{}, nil
|
return []CharacterParams{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
result := vndbResp.Results[0]
|
result := vndbResp.Results[0]
|
||||||
var charactors []CharactorParams
|
var characters []CharacterParams
|
||||||
processedCharacters := make(map[string]bool) // 避免重复角色
|
processedCharacters := make(map[string]bool) // 避免重复角色
|
||||||
|
|
||||||
// 遍历声优信息
|
// 遍历声优信息
|
||||||
@@ -700,7 +700,7 @@ func GetCharactorsFromVndb(vnID string) ([]CharactorParams, error) {
|
|||||||
cvName = va.Staff.Name
|
cvName = va.Staff.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
charactor := CharactorParams{
|
character := CharacterParams{
|
||||||
Name: characterName,
|
Name: characterName,
|
||||||
Alias: []string{},
|
Alias: []string{},
|
||||||
CV: cvName,
|
CV: cvName,
|
||||||
@@ -715,14 +715,14 @@ func GetCharactorsFromVndb(vnID string) ([]CharactorParams, error) {
|
|||||||
log.Error("Failed to download character image:", err)
|
log.Error("Failed to download character image:", err)
|
||||||
// 继续处理,即使图片下载失败
|
// 继续处理,即使图片下载失败
|
||||||
} else {
|
} else {
|
||||||
charactor.Image = imageID
|
character.Image = imageID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
charactors = append(charactors, charactor)
|
characters = append(characters, character)
|
||||||
}
|
}
|
||||||
|
|
||||||
return charactors, nil
|
return characters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// downloadAndCreateImage 下载图片并使用 CreateImage 保存
|
// downloadAndCreateImage 下载图片并使用 CreateImage 保存
|
||||||
|
|||||||
Reference in New Issue
Block a user