Hopefully fixed git issues...
This commit is contained in:
4
.env
4
.env
@@ -1,4 +0,0 @@
|
|||||||
DISCORD_CLIENT_ID=1440755333055250616
|
|
||||||
ANILIST_CLIENT_SECRET=fTql48IjI7ZAE2cbjFaMl2I5HhYHYr1kVDyDNpOk
|
|
||||||
ANILIST_CLIENT_ID=32898
|
|
||||||
JWT_SECRET=900c86474497ce3c329ba9949d834dbb1dd072163a5867957be929f3adc592d2d6352c03aecbfe065a8b9e9eff0e7fe7516a50dbf206d5e8c69bdcba22477cb6
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<EFBFBD><EFBFBD>
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
PlatformToolSet=v143:VCToolArchitecture=Native64Bit:VCToolsVersion=14.44.35207:TargetPlatformVersion=10.0.26100.0:
|
|
||||||
Release|x64|C:\Users\synta\Documents\WaifuBoard SRC Code (Multiple In Here)\Waifu Board (Server)\build\|
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
|
||||||
<ProjectConfiguration Include="Debug|x64">
|
|
||||||
<Configuration>Debug</Configuration>
|
|
||||||
<Platform>x64</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Release|x64">
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>x64</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
</ItemGroup>
|
|
||||||
<PropertyGroup Label="Globals">
|
|
||||||
<ProjectGuid>{E80660A8-73CA-0176-CBD2-DA941C5BB848}</ProjectGuid>
|
|
||||||
<Keyword>Win32Proj</Keyword>
|
|
||||||
<RootNamespace>anime_core</RootNamespace>
|
|
||||||
<IgnoreWarnCompileDuplicatedFilename>true</IgnoreWarnCompileDuplicatedFilename>
|
|
||||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
|
||||||
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props"/>
|
|
||||||
<PropertyGroup Label="Configuration">
|
|
||||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Label="Locals">
|
|
||||||
<PlatformToolset>v143</PlatformToolset>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/>
|
|
||||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props"/>
|
|
||||||
<ImportGroup Label="ExtensionSettings"/>
|
|
||||||
<ImportGroup Label="PropertySheets">
|
|
||||||
<Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/>
|
|
||||||
</ImportGroup>
|
|
||||||
<PropertyGroup Label="UserMacros"/>
|
|
||||||
<PropertyGroup>
|
|
||||||
<ExecutablePath>$(ExecutablePath);$(MSBuildProjectDirectory)\..\bin\;$(MSBuildProjectDirectory)\..\bin\</ExecutablePath>
|
|
||||||
<IgnoreImportLibrary>true</IgnoreImportLibrary>
|
|
||||||
<IntDir>$(Configuration)\obj\$(ProjectName)\</IntDir>
|
|
||||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
|
|
||||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
|
|
||||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
|
||||||
<TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.node</TargetExt>
|
|
||||||
<TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.node</TargetExt>
|
|
||||||
<TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.node</TargetExt>
|
|
||||||
<TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.node</TargetExt>
|
|
||||||
<TargetName>$(ProjectName)</TargetName>
|
|
||||||
<TargetPath>$(OutDir)\$(ProjectName).node</TargetPath>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<ClCompile>
|
|
||||||
<AdditionalIncludeDirectories>C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\include\node;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\src;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\openssl\config;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\openssl\openssl\include;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\uv\include;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\zlib;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\v8\include;C:\Users\synta\Documents\WaifuBoard SRC Code (Multiple In Here)\Waifu Board (Server)\node_modules\node-addon-api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
|
||||||
<AdditionalOptions>/Zc:__cplusplus -std:c++20 /Zm2000 %(AdditionalOptions)</AdditionalOptions>
|
|
||||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
|
||||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
|
||||||
<DebugInformationFormat>OldStyle</DebugInformationFormat>
|
|
||||||
<DisableSpecificWarnings>4351;4355;4800;4251;4275;4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
|
||||||
<ExceptionHandling>false</ExceptionHandling>
|
|
||||||
<MinimalRebuild>false</MinimalRebuild>
|
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
|
||||||
<OmitFramePointers>false</OmitFramePointers>
|
|
||||||
<Optimization>Disabled</Optimization>
|
|
||||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
|
||||||
<PreprocessorDefinitions>NODE_GYP_MODULE_NAME=anime_core;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;_FILE_OFFSET_BITS=64;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;NOMINMAX;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;NAPI_DISABLE_CPP_EXCEPTIONS;BUILDING_NODE_EXTENSION;HOST_BINARY="node.exe";DEBUG;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
|
||||||
<StringPooling>true</StringPooling>
|
|
||||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
|
||||||
<TreatWarningAsError>false</TreatWarningAsError>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
|
||||||
</ClCompile>
|
|
||||||
<Lib>
|
|
||||||
<AdditionalOptions>/LTCG:INCREMENTAL %(AdditionalOptions)</AdditionalOptions>
|
|
||||||
</Lib>
|
|
||||||
<Link>
|
|
||||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;delayimp.lib;"C:\\Users\\synta\\AppData\\Local\\node-gyp\\Cache\\25.2.1\\x64\\node.lib"</AdditionalDependencies>
|
|
||||||
<AdditionalOptions>/LTCG:INCREMENTAL /ignore:4199 %(AdditionalOptions)</AdditionalOptions>
|
|
||||||
<DelayLoadDLLs>node.exe;%(DelayLoadDLLs)</DelayLoadDLLs>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
<OutputFile>$(OutDir)$(ProjectName).node</OutputFile>
|
|
||||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
|
||||||
<TargetExt>.node</TargetExt>
|
|
||||||
<TargetMachine>MachineX64</TargetMachine>
|
|
||||||
</Link>
|
|
||||||
<ResourceCompile>
|
|
||||||
<AdditionalIncludeDirectories>C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\include\node;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\src;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\openssl\config;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\openssl\openssl\include;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\uv\include;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\zlib;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\v8\include;C:\Users\synta\Documents\WaifuBoard SRC Code (Multiple In Here)\Waifu Board (Server)\node_modules\node-addon-api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
|
||||||
<PreprocessorDefinitions>NODE_GYP_MODULE_NAME=anime_core;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;_FILE_OFFSET_BITS=64;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;NOMINMAX;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;NAPI_DISABLE_CPP_EXCEPTIONS;BUILDING_NODE_EXTENSION;HOST_BINARY="node.exe";DEBUG;_DEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
</ResourceCompile>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
|
||||||
<ClCompile>
|
|
||||||
<AdditionalIncludeDirectories>C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\include\node;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\src;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\openssl\config;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\openssl\openssl\include;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\uv\include;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\zlib;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\v8\include;C:\Users\synta\Documents\WaifuBoard SRC Code (Multiple In Here)\Waifu Board (Server)\node_modules\node-addon-api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
|
||||||
<AdditionalOptions>/Zc:__cplusplus -std:c++20 /Zm2000 %(AdditionalOptions)</AdditionalOptions>
|
|
||||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
|
||||||
<DebugInformationFormat>OldStyle</DebugInformationFormat>
|
|
||||||
<DisableSpecificWarnings>4351;4355;4800;4251;4275;4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
|
||||||
<ExceptionHandling>false</ExceptionHandling>
|
|
||||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
|
||||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
|
||||||
<OmitFramePointers>true</OmitFramePointers>
|
|
||||||
<Optimization>Full</Optimization>
|
|
||||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
|
||||||
<PreprocessorDefinitions>NODE_GYP_MODULE_NAME=anime_core;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;_FILE_OFFSET_BITS=64;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;NOMINMAX;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;NAPI_DISABLE_CPP_EXCEPTIONS;BUILDING_NODE_EXTENSION;HOST_BINARY="node.exe";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
|
||||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
|
||||||
<StringPooling>true</StringPooling>
|
|
||||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
|
||||||
<TreatWarningAsError>false</TreatWarningAsError>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
|
||||||
</ClCompile>
|
|
||||||
<Lib>
|
|
||||||
<AdditionalOptions>/LTCG:INCREMENTAL %(AdditionalOptions)</AdditionalOptions>
|
|
||||||
</Lib>
|
|
||||||
<Link>
|
|
||||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;delayimp.lib;"C:\\Users\\synta\\AppData\\Local\\node-gyp\\Cache\\25.2.1\\x64\\node.lib"</AdditionalDependencies>
|
|
||||||
<AdditionalOptions>/LTCG:INCREMENTAL /ignore:4199 %(AdditionalOptions)</AdditionalOptions>
|
|
||||||
<DelayLoadDLLs>node.exe;%(DelayLoadDLLs)</DelayLoadDLLs>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
<OutputFile>$(OutDir)$(ProjectName).node</OutputFile>
|
|
||||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
|
||||||
<TargetExt>.node</TargetExt>
|
|
||||||
<TargetMachine>MachineX64</TargetMachine>
|
|
||||||
</Link>
|
|
||||||
<ResourceCompile>
|
|
||||||
<AdditionalIncludeDirectories>C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\include\node;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\src;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\openssl\config;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\openssl\openssl\include;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\uv\include;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\zlib;C:\Users\synta\AppData\Local\node-gyp\Cache\25.2.1\deps\v8\include;C:\Users\synta\Documents\WaifuBoard SRC Code (Multiple In Here)\Waifu Board (Server)\node_modules\node-addon-api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
|
||||||
<PreprocessorDefinitions>NODE_GYP_MODULE_NAME=anime_core;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;_FILE_OFFSET_BITS=64;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;NOMINMAX;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;NAPI_DISABLE_CPP_EXCEPTIONS;BUILDING_NODE_EXTENSION;HOST_BINARY="node.exe";%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
</ResourceCompile>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="..\binding.gyp"/>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="..\src\main.cpp">
|
|
||||||
<ObjectFileName>$(IntDir)\src\main.obj</ObjectFileName>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="C:\Users\synta\Documents\WaifuBoard SRC Code (Multiple In Here)\Waifu Board (Server)\node_modules\node-gyp\src\win_delay_load_hook.cc"/>
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/>
|
|
||||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets"/>
|
|
||||||
<ImportGroup Label="ExtensionTargets"/>
|
|
||||||
</Project>
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup>
|
|
||||||
<Filter Include="..">
|
|
||||||
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="..\src">
|
|
||||||
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="C:">
|
|
||||||
<UniqueIdentifier>{7B735499-E5DD-1C2B-6C26-70023832A1CF}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="C:\Users">
|
|
||||||
<UniqueIdentifier>{E9F714C1-DA89-54E2-60CF-39FEB20BF756}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="C:\Users\synta">
|
|
||||||
<UniqueIdentifier>{D7D157CA-EDF9-12DF-226F-983123736FEF}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="C:\Users\synta\Documents">
|
|
||||||
<UniqueIdentifier>{87566BA0-CA33-1144-65F5-087C5F9D6C20}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="C:\Users\synta\Documents\WaifuBoard SRC Code (Multiple In Here)">
|
|
||||||
<UniqueIdentifier>{97B1B44F-2681-8BEF-5A42-2C7ED19BB9BD}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="C:\Users\synta\Documents\WaifuBoard SRC Code (Multiple In Here)\Waifu Board (Server)">
|
|
||||||
<UniqueIdentifier>{4A3EC618-7921-9CB6-9236-10DE349C556E}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="C:\Users\synta\Documents\WaifuBoard SRC Code (Multiple In Here)\Waifu Board (Server)\node_modules">
|
|
||||||
<UniqueIdentifier>{56DF7A98-063D-FB9D-485C-089023B4C16A}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="C:\Users\synta\Documents\WaifuBoard SRC Code (Multiple In Here)\Waifu Board (Server)\node_modules\node-gyp">
|
|
||||||
<UniqueIdentifier>{77348C0E-2034-7791-74D5-63C077DF5A3B}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="C:\Users\synta\Documents\WaifuBoard SRC Code (Multiple In Here)\Waifu Board (Server)\node_modules\node-gyp\src">
|
|
||||||
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="..">
|
|
||||||
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="..\src\main.cpp">
|
|
||||||
<Filter>..\src</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="C:\Users\synta\Documents\WaifuBoard SRC Code (Multiple In Here)\Waifu Board (Server)\node_modules\node-gyp\src\win_delay_load_hook.cc">
|
|
||||||
<Filter>C:\Users\synta\Documents\WaifuBoard SRC Code (Multiple In Here)\Waifu Board (Server)\node_modules\node-gyp\src</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<None Include="..\binding.gyp">
|
|
||||||
<Filter>..</Filter>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio 2015
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "anime_core", "anime_core.vcxproj", "{E80660A8-73CA-0176-CBD2-DA941C5BB848}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|x64 = Debug|x64
|
|
||||||
Release|x64 = Release|x64
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{E80660A8-73CA-0176-CBD2-DA941C5BB848}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{E80660A8-73CA-0176-CBD2-DA941C5BB848}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{E80660A8-73CA-0176-CBD2-DA941C5BB848}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{E80660A8-73CA-0176-CBD2-DA941C5BB848}.Release|x64.Build.0 = Release|x64
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
||||||
@@ -1,526 +0,0 @@
|
|||||||
# Do not edit. File was generated by node-gyp's "configure" step
|
|
||||||
{
|
|
||||||
"target_defaults": {
|
|
||||||
"cflags": [],
|
|
||||||
"configurations": {
|
|
||||||
"Debug": {
|
|
||||||
"v8_enable_v8_checks": 0,
|
|
||||||
"variables": {}
|
|
||||||
},
|
|
||||||
"Release": {
|
|
||||||
"v8_enable_v8_checks": 1,
|
|
||||||
"variables": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"default_configuration": "Release",
|
|
||||||
"defines": [],
|
|
||||||
"include_dirs": [],
|
|
||||||
"libraries": [],
|
|
||||||
"msbuild_toolset": "v143",
|
|
||||||
"msvs_windows_target_platform_version": "10.0.26100.0"
|
|
||||||
},
|
|
||||||
"variables": {
|
|
||||||
"asan": 0,
|
|
||||||
"clang": 0,
|
|
||||||
"control_flow_guard": "false",
|
|
||||||
"coverage": "false",
|
|
||||||
"dcheck_always_on": 0,
|
|
||||||
"debug_nghttp2": "false",
|
|
||||||
"debug_node": "false",
|
|
||||||
"enable_lto": "false",
|
|
||||||
"enable_pgo_generate": "false",
|
|
||||||
"enable_pgo_use": "false",
|
|
||||||
"error_on_warn": "false",
|
|
||||||
"force_dynamic_crt": 0,
|
|
||||||
"host_arch": "x64",
|
|
||||||
"icu_data_in": "..\\..\\deps\\icu-tmp\\icudt77l.dat",
|
|
||||||
"icu_endianness": "l",
|
|
||||||
"icu_gyp_path": "tools/icu/icu-generic.gyp",
|
|
||||||
"icu_path": "deps/icu-small",
|
|
||||||
"icu_small": "false",
|
|
||||||
"icu_ver_major": "77",
|
|
||||||
"libdir": "lib",
|
|
||||||
"llvm_version": "19.1.5",
|
|
||||||
"napi_build_version": "10",
|
|
||||||
"nasm_version": "3.01",
|
|
||||||
"node_builtin_shareable_builtins": [
|
|
||||||
"deps/cjs-module-lexer/lexer.js",
|
|
||||||
"deps/cjs-module-lexer/dist/lexer.js",
|
|
||||||
"deps/undici/undici.js",
|
|
||||||
"deps/amaro/dist/index.js"
|
|
||||||
],
|
|
||||||
"node_byteorder": "little",
|
|
||||||
"node_cctest_sources": [
|
|
||||||
"src/node_snapshot_stub.cc",
|
|
||||||
"test/cctest/inspector/test_network_requests_buffer.cc",
|
|
||||||
"test/cctest/inspector/test_node_protocol.cc",
|
|
||||||
"test/cctest/node_test_fixture.cc",
|
|
||||||
"test/cctest/test_aliased_buffer.cc",
|
|
||||||
"test/cctest/test_base64.cc",
|
|
||||||
"test/cctest/test_base_object_ptr.cc",
|
|
||||||
"test/cctest/test_cppgc.cc",
|
|
||||||
"test/cctest/test_crypto_clienthello.cc",
|
|
||||||
"test/cctest/test_dataqueue.cc",
|
|
||||||
"test/cctest/test_environment.cc",
|
|
||||||
"test/cctest/test_inspector_socket.cc",
|
|
||||||
"test/cctest/test_inspector_socket_server.cc",
|
|
||||||
"test/cctest/test_json_utils.cc",
|
|
||||||
"test/cctest/test_linked_binding.cc",
|
|
||||||
"test/cctest/test_lru_cache.cc",
|
|
||||||
"test/cctest/test_node_api.cc",
|
|
||||||
"test/cctest/test_node_crypto.cc",
|
|
||||||
"test/cctest/test_node_crypto_env.cc",
|
|
||||||
"test/cctest/test_node_postmortem_metadata.cc",
|
|
||||||
"test/cctest/test_node_task_runner.cc",
|
|
||||||
"test/cctest/test_path.cc",
|
|
||||||
"test/cctest/test_per_process.cc",
|
|
||||||
"test/cctest/test_platform.cc",
|
|
||||||
"test/cctest/test_quic_cid.cc",
|
|
||||||
"test/cctest/test_quic_error.cc",
|
|
||||||
"test/cctest/test_quic_preferredaddress.cc",
|
|
||||||
"test/cctest/test_quic_tokens.cc",
|
|
||||||
"test/cctest/test_report.cc",
|
|
||||||
"test/cctest/test_sockaddr.cc",
|
|
||||||
"test/cctest/test_string_bytes.cc",
|
|
||||||
"test/cctest/test_traced_value.cc",
|
|
||||||
"test/cctest/test_util.cc",
|
|
||||||
"test/cctest/node_test_fixture.h"
|
|
||||||
],
|
|
||||||
"node_debug_lib": "false",
|
|
||||||
"node_enable_d8": "false",
|
|
||||||
"node_enable_v8_vtunejit": "false",
|
|
||||||
"node_enable_v8windbg": "false",
|
|
||||||
"node_fipsinstall": "false",
|
|
||||||
"node_install_corepack": "false",
|
|
||||||
"node_install_npm": "true",
|
|
||||||
"node_library_files": [
|
|
||||||
"lib/_http_agent.js",
|
|
||||||
"lib/_http_client.js",
|
|
||||||
"lib/_http_common.js",
|
|
||||||
"lib/_http_incoming.js",
|
|
||||||
"lib/_http_outgoing.js",
|
|
||||||
"lib/_http_server.js",
|
|
||||||
"lib/_stream_duplex.js",
|
|
||||||
"lib/_stream_passthrough.js",
|
|
||||||
"lib/_stream_readable.js",
|
|
||||||
"lib/_stream_transform.js",
|
|
||||||
"lib/_stream_wrap.js",
|
|
||||||
"lib/_stream_writable.js",
|
|
||||||
"lib/_tls_common.js",
|
|
||||||
"lib/_tls_wrap.js",
|
|
||||||
"lib/assert.js",
|
|
||||||
"lib/assert/strict.js",
|
|
||||||
"lib/async_hooks.js",
|
|
||||||
"lib/buffer.js",
|
|
||||||
"lib/child_process.js",
|
|
||||||
"lib/cluster.js",
|
|
||||||
"lib/console.js",
|
|
||||||
"lib/constants.js",
|
|
||||||
"lib/crypto.js",
|
|
||||||
"lib/dgram.js",
|
|
||||||
"lib/diagnostics_channel.js",
|
|
||||||
"lib/dns.js",
|
|
||||||
"lib/dns/promises.js",
|
|
||||||
"lib/domain.js",
|
|
||||||
"lib/events.js",
|
|
||||||
"lib/fs.js",
|
|
||||||
"lib/fs/promises.js",
|
|
||||||
"lib/http.js",
|
|
||||||
"lib/http2.js",
|
|
||||||
"lib/https.js",
|
|
||||||
"lib/inspector.js",
|
|
||||||
"lib/inspector/promises.js",
|
|
||||||
"lib/internal/abort_controller.js",
|
|
||||||
"lib/internal/assert.js",
|
|
||||||
"lib/internal/assert/assertion_error.js",
|
|
||||||
"lib/internal/assert/myers_diff.js",
|
|
||||||
"lib/internal/assert/utils.js",
|
|
||||||
"lib/internal/async_context_frame.js",
|
|
||||||
"lib/internal/async_hooks.js",
|
|
||||||
"lib/internal/async_local_storage/async_context_frame.js",
|
|
||||||
"lib/internal/async_local_storage/async_hooks.js",
|
|
||||||
"lib/internal/blob.js",
|
|
||||||
"lib/internal/blocklist.js",
|
|
||||||
"lib/internal/bootstrap/node.js",
|
|
||||||
"lib/internal/bootstrap/realm.js",
|
|
||||||
"lib/internal/bootstrap/shadow_realm.js",
|
|
||||||
"lib/internal/bootstrap/switches/does_not_own_process_state.js",
|
|
||||||
"lib/internal/bootstrap/switches/does_own_process_state.js",
|
|
||||||
"lib/internal/bootstrap/switches/is_main_thread.js",
|
|
||||||
"lib/internal/bootstrap/switches/is_not_main_thread.js",
|
|
||||||
"lib/internal/bootstrap/web/exposed-wildcard.js",
|
|
||||||
"lib/internal/bootstrap/web/exposed-window-or-worker.js",
|
|
||||||
"lib/internal/buffer.js",
|
|
||||||
"lib/internal/child_process.js",
|
|
||||||
"lib/internal/child_process/serialization.js",
|
|
||||||
"lib/internal/cli_table.js",
|
|
||||||
"lib/internal/cluster/child.js",
|
|
||||||
"lib/internal/cluster/primary.js",
|
|
||||||
"lib/internal/cluster/round_robin_handle.js",
|
|
||||||
"lib/internal/cluster/shared_handle.js",
|
|
||||||
"lib/internal/cluster/utils.js",
|
|
||||||
"lib/internal/cluster/worker.js",
|
|
||||||
"lib/internal/console/constructor.js",
|
|
||||||
"lib/internal/console/global.js",
|
|
||||||
"lib/internal/constants.js",
|
|
||||||
"lib/internal/crypto/aes.js",
|
|
||||||
"lib/internal/crypto/argon2.js",
|
|
||||||
"lib/internal/crypto/certificate.js",
|
|
||||||
"lib/internal/crypto/cfrg.js",
|
|
||||||
"lib/internal/crypto/chacha20_poly1305.js",
|
|
||||||
"lib/internal/crypto/cipher.js",
|
|
||||||
"lib/internal/crypto/diffiehellman.js",
|
|
||||||
"lib/internal/crypto/ec.js",
|
|
||||||
"lib/internal/crypto/hash.js",
|
|
||||||
"lib/internal/crypto/hashnames.js",
|
|
||||||
"lib/internal/crypto/hkdf.js",
|
|
||||||
"lib/internal/crypto/kem.js",
|
|
||||||
"lib/internal/crypto/keygen.js",
|
|
||||||
"lib/internal/crypto/keys.js",
|
|
||||||
"lib/internal/crypto/mac.js",
|
|
||||||
"lib/internal/crypto/ml_dsa.js",
|
|
||||||
"lib/internal/crypto/ml_kem.js",
|
|
||||||
"lib/internal/crypto/pbkdf2.js",
|
|
||||||
"lib/internal/crypto/random.js",
|
|
||||||
"lib/internal/crypto/rsa.js",
|
|
||||||
"lib/internal/crypto/scrypt.js",
|
|
||||||
"lib/internal/crypto/sig.js",
|
|
||||||
"lib/internal/crypto/util.js",
|
|
||||||
"lib/internal/crypto/webcrypto.js",
|
|
||||||
"lib/internal/crypto/webidl.js",
|
|
||||||
"lib/internal/crypto/x509.js",
|
|
||||||
"lib/internal/data_url.js",
|
|
||||||
"lib/internal/debugger/inspect.js",
|
|
||||||
"lib/internal/debugger/inspect_client.js",
|
|
||||||
"lib/internal/debugger/inspect_repl.js",
|
|
||||||
"lib/internal/dgram.js",
|
|
||||||
"lib/internal/dns/callback_resolver.js",
|
|
||||||
"lib/internal/dns/promises.js",
|
|
||||||
"lib/internal/dns/utils.js",
|
|
||||||
"lib/internal/encoding.js",
|
|
||||||
"lib/internal/error_serdes.js",
|
|
||||||
"lib/internal/errors.js",
|
|
||||||
"lib/internal/errors/error_source.js",
|
|
||||||
"lib/internal/event_target.js",
|
|
||||||
"lib/internal/events/abort_listener.js",
|
|
||||||
"lib/internal/events/symbols.js",
|
|
||||||
"lib/internal/file.js",
|
|
||||||
"lib/internal/fixed_queue.js",
|
|
||||||
"lib/internal/freelist.js",
|
|
||||||
"lib/internal/freeze_intrinsics.js",
|
|
||||||
"lib/internal/fs/cp/cp-sync.js",
|
|
||||||
"lib/internal/fs/cp/cp.js",
|
|
||||||
"lib/internal/fs/dir.js",
|
|
||||||
"lib/internal/fs/glob.js",
|
|
||||||
"lib/internal/fs/promises.js",
|
|
||||||
"lib/internal/fs/read/context.js",
|
|
||||||
"lib/internal/fs/recursive_watch.js",
|
|
||||||
"lib/internal/fs/rimraf.js",
|
|
||||||
"lib/internal/fs/streams.js",
|
|
||||||
"lib/internal/fs/sync_write_stream.js",
|
|
||||||
"lib/internal/fs/utils.js",
|
|
||||||
"lib/internal/fs/watchers.js",
|
|
||||||
"lib/internal/heap_utils.js",
|
|
||||||
"lib/internal/histogram.js",
|
|
||||||
"lib/internal/http.js",
|
|
||||||
"lib/internal/http2/compat.js",
|
|
||||||
"lib/internal/http2/core.js",
|
|
||||||
"lib/internal/http2/util.js",
|
|
||||||
"lib/internal/inspector/network.js",
|
|
||||||
"lib/internal/inspector/network_http.js",
|
|
||||||
"lib/internal/inspector/network_http2.js",
|
|
||||||
"lib/internal/inspector/network_resources.js",
|
|
||||||
"lib/internal/inspector/network_undici.js",
|
|
||||||
"lib/internal/inspector_async_hook.js",
|
|
||||||
"lib/internal/inspector_network_tracking.js",
|
|
||||||
"lib/internal/js_stream_socket.js",
|
|
||||||
"lib/internal/legacy/processbinding.js",
|
|
||||||
"lib/internal/linkedlist.js",
|
|
||||||
"lib/internal/locks.js",
|
|
||||||
"lib/internal/main/check_syntax.js",
|
|
||||||
"lib/internal/main/embedding.js",
|
|
||||||
"lib/internal/main/eval_stdin.js",
|
|
||||||
"lib/internal/main/eval_string.js",
|
|
||||||
"lib/internal/main/inspect.js",
|
|
||||||
"lib/internal/main/mksnapshot.js",
|
|
||||||
"lib/internal/main/print_help.js",
|
|
||||||
"lib/internal/main/prof_process.js",
|
|
||||||
"lib/internal/main/repl.js",
|
|
||||||
"lib/internal/main/run_main_module.js",
|
|
||||||
"lib/internal/main/test_runner.js",
|
|
||||||
"lib/internal/main/watch_mode.js",
|
|
||||||
"lib/internal/main/worker_thread.js",
|
|
||||||
"lib/internal/mime.js",
|
|
||||||
"lib/internal/modules/cjs/loader.js",
|
|
||||||
"lib/internal/modules/customization_hooks.js",
|
|
||||||
"lib/internal/modules/esm/assert.js",
|
|
||||||
"lib/internal/modules/esm/create_dynamic_module.js",
|
|
||||||
"lib/internal/modules/esm/formats.js",
|
|
||||||
"lib/internal/modules/esm/get_format.js",
|
|
||||||
"lib/internal/modules/esm/hooks.js",
|
|
||||||
"lib/internal/modules/esm/load.js",
|
|
||||||
"lib/internal/modules/esm/loader.js",
|
|
||||||
"lib/internal/modules/esm/module_job.js",
|
|
||||||
"lib/internal/modules/esm/module_map.js",
|
|
||||||
"lib/internal/modules/esm/resolve.js",
|
|
||||||
"lib/internal/modules/esm/shared_constants.js",
|
|
||||||
"lib/internal/modules/esm/translators.js",
|
|
||||||
"lib/internal/modules/esm/utils.js",
|
|
||||||
"lib/internal/modules/esm/worker.js",
|
|
||||||
"lib/internal/modules/helpers.js",
|
|
||||||
"lib/internal/modules/package_json_reader.js",
|
|
||||||
"lib/internal/modules/run_main.js",
|
|
||||||
"lib/internal/modules/typescript.js",
|
|
||||||
"lib/internal/navigator.js",
|
|
||||||
"lib/internal/net.js",
|
|
||||||
"lib/internal/options.js",
|
|
||||||
"lib/internal/per_context/domexception.js",
|
|
||||||
"lib/internal/per_context/messageport.js",
|
|
||||||
"lib/internal/per_context/primordials.js",
|
|
||||||
"lib/internal/perf/event_loop_delay.js",
|
|
||||||
"lib/internal/perf/event_loop_utilization.js",
|
|
||||||
"lib/internal/perf/nodetiming.js",
|
|
||||||
"lib/internal/perf/observe.js",
|
|
||||||
"lib/internal/perf/performance.js",
|
|
||||||
"lib/internal/perf/performance_entry.js",
|
|
||||||
"lib/internal/perf/resource_timing.js",
|
|
||||||
"lib/internal/perf/timerify.js",
|
|
||||||
"lib/internal/perf/usertiming.js",
|
|
||||||
"lib/internal/perf/utils.js",
|
|
||||||
"lib/internal/priority_queue.js",
|
|
||||||
"lib/internal/process/execution.js",
|
|
||||||
"lib/internal/process/finalization.js",
|
|
||||||
"lib/internal/process/per_thread.js",
|
|
||||||
"lib/internal/process/permission.js",
|
|
||||||
"lib/internal/process/pre_execution.js",
|
|
||||||
"lib/internal/process/promises.js",
|
|
||||||
"lib/internal/process/report.js",
|
|
||||||
"lib/internal/process/signal.js",
|
|
||||||
"lib/internal/process/task_queues.js",
|
|
||||||
"lib/internal/process/warning.js",
|
|
||||||
"lib/internal/process/worker_thread_only.js",
|
|
||||||
"lib/internal/promise_hooks.js",
|
|
||||||
"lib/internal/querystring.js",
|
|
||||||
"lib/internal/quic/quic.js",
|
|
||||||
"lib/internal/quic/state.js",
|
|
||||||
"lib/internal/quic/stats.js",
|
|
||||||
"lib/internal/quic/symbols.js",
|
|
||||||
"lib/internal/readline/callbacks.js",
|
|
||||||
"lib/internal/readline/emitKeypressEvents.js",
|
|
||||||
"lib/internal/readline/interface.js",
|
|
||||||
"lib/internal/readline/promises.js",
|
|
||||||
"lib/internal/readline/utils.js",
|
|
||||||
"lib/internal/repl.js",
|
|
||||||
"lib/internal/repl/await.js",
|
|
||||||
"lib/internal/repl/completion.js",
|
|
||||||
"lib/internal/repl/history.js",
|
|
||||||
"lib/internal/repl/utils.js",
|
|
||||||
"lib/internal/socket_list.js",
|
|
||||||
"lib/internal/socketaddress.js",
|
|
||||||
"lib/internal/source_map/prepare_stack_trace.js",
|
|
||||||
"lib/internal/source_map/source_map.js",
|
|
||||||
"lib/internal/source_map/source_map_cache.js",
|
|
||||||
"lib/internal/source_map/source_map_cache_map.js",
|
|
||||||
"lib/internal/stream_base_commons.js",
|
|
||||||
"lib/internal/streams/add-abort-signal.js",
|
|
||||||
"lib/internal/streams/compose.js",
|
|
||||||
"lib/internal/streams/destroy.js",
|
|
||||||
"lib/internal/streams/duplex.js",
|
|
||||||
"lib/internal/streams/duplexify.js",
|
|
||||||
"lib/internal/streams/duplexpair.js",
|
|
||||||
"lib/internal/streams/end-of-stream.js",
|
|
||||||
"lib/internal/streams/fast-utf8-stream.js",
|
|
||||||
"lib/internal/streams/from.js",
|
|
||||||
"lib/internal/streams/lazy_transform.js",
|
|
||||||
"lib/internal/streams/legacy.js",
|
|
||||||
"lib/internal/streams/operators.js",
|
|
||||||
"lib/internal/streams/passthrough.js",
|
|
||||||
"lib/internal/streams/pipeline.js",
|
|
||||||
"lib/internal/streams/readable.js",
|
|
||||||
"lib/internal/streams/state.js",
|
|
||||||
"lib/internal/streams/transform.js",
|
|
||||||
"lib/internal/streams/utils.js",
|
|
||||||
"lib/internal/streams/writable.js",
|
|
||||||
"lib/internal/test/binding.js",
|
|
||||||
"lib/internal/test/transfer.js",
|
|
||||||
"lib/internal/test_runner/assert.js",
|
|
||||||
"lib/internal/test_runner/coverage.js",
|
|
||||||
"lib/internal/test_runner/harness.js",
|
|
||||||
"lib/internal/test_runner/mock/loader.js",
|
|
||||||
"lib/internal/test_runner/mock/mock.js",
|
|
||||||
"lib/internal/test_runner/mock/mock_timers.js",
|
|
||||||
"lib/internal/test_runner/reporter/dot.js",
|
|
||||||
"lib/internal/test_runner/reporter/junit.js",
|
|
||||||
"lib/internal/test_runner/reporter/lcov.js",
|
|
||||||
"lib/internal/test_runner/reporter/rerun.js",
|
|
||||||
"lib/internal/test_runner/reporter/spec.js",
|
|
||||||
"lib/internal/test_runner/reporter/tap.js",
|
|
||||||
"lib/internal/test_runner/reporter/utils.js",
|
|
||||||
"lib/internal/test_runner/reporter/v8-serializer.js",
|
|
||||||
"lib/internal/test_runner/runner.js",
|
|
||||||
"lib/internal/test_runner/snapshot.js",
|
|
||||||
"lib/internal/test_runner/test.js",
|
|
||||||
"lib/internal/test_runner/tests_stream.js",
|
|
||||||
"lib/internal/test_runner/utils.js",
|
|
||||||
"lib/internal/timers.js",
|
|
||||||
"lib/internal/tls/common.js",
|
|
||||||
"lib/internal/tls/secure-context.js",
|
|
||||||
"lib/internal/tls/wrap.js",
|
|
||||||
"lib/internal/trace_events_async_hooks.js",
|
|
||||||
"lib/internal/tty.js",
|
|
||||||
"lib/internal/url.js",
|
|
||||||
"lib/internal/util.js",
|
|
||||||
"lib/internal/util/colors.js",
|
|
||||||
"lib/internal/util/comparisons.js",
|
|
||||||
"lib/internal/util/debuglog.js",
|
|
||||||
"lib/internal/util/diff.js",
|
|
||||||
"lib/internal/util/inspect.js",
|
|
||||||
"lib/internal/util/inspector.js",
|
|
||||||
"lib/internal/util/parse_args/parse_args.js",
|
|
||||||
"lib/internal/util/parse_args/utils.js",
|
|
||||||
"lib/internal/util/trace_sigint.js",
|
|
||||||
"lib/internal/util/types.js",
|
|
||||||
"lib/internal/v8/startup_snapshot.js",
|
|
||||||
"lib/internal/v8_prof_polyfill.js",
|
|
||||||
"lib/internal/v8_prof_processor.js",
|
|
||||||
"lib/internal/validators.js",
|
|
||||||
"lib/internal/vm.js",
|
|
||||||
"lib/internal/vm/module.js",
|
|
||||||
"lib/internal/wasm_web_api.js",
|
|
||||||
"lib/internal/watch_mode/files_watcher.js",
|
|
||||||
"lib/internal/watchdog.js",
|
|
||||||
"lib/internal/webidl.js",
|
|
||||||
"lib/internal/webstorage.js",
|
|
||||||
"lib/internal/webstreams/adapters.js",
|
|
||||||
"lib/internal/webstreams/compression.js",
|
|
||||||
"lib/internal/webstreams/encoding.js",
|
|
||||||
"lib/internal/webstreams/queuingstrategies.js",
|
|
||||||
"lib/internal/webstreams/readablestream.js",
|
|
||||||
"lib/internal/webstreams/transfer.js",
|
|
||||||
"lib/internal/webstreams/transformstream.js",
|
|
||||||
"lib/internal/webstreams/util.js",
|
|
||||||
"lib/internal/webstreams/writablestream.js",
|
|
||||||
"lib/internal/worker.js",
|
|
||||||
"lib/internal/worker/clone_dom_exception.js",
|
|
||||||
"lib/internal/worker/io.js",
|
|
||||||
"lib/internal/worker/js_transferable.js",
|
|
||||||
"lib/internal/worker/messaging.js",
|
|
||||||
"lib/module.js",
|
|
||||||
"lib/net.js",
|
|
||||||
"lib/os.js",
|
|
||||||
"lib/path.js",
|
|
||||||
"lib/path/posix.js",
|
|
||||||
"lib/path/win32.js",
|
|
||||||
"lib/perf_hooks.js",
|
|
||||||
"lib/process.js",
|
|
||||||
"lib/punycode.js",
|
|
||||||
"lib/querystring.js",
|
|
||||||
"lib/quic.js",
|
|
||||||
"lib/readline.js",
|
|
||||||
"lib/readline/promises.js",
|
|
||||||
"lib/repl.js",
|
|
||||||
"lib/sea.js",
|
|
||||||
"lib/sqlite.js",
|
|
||||||
"lib/stream.js",
|
|
||||||
"lib/stream/consumers.js",
|
|
||||||
"lib/stream/promises.js",
|
|
||||||
"lib/stream/web.js",
|
|
||||||
"lib/string_decoder.js",
|
|
||||||
"lib/sys.js",
|
|
||||||
"lib/test.js",
|
|
||||||
"lib/test/reporters.js",
|
|
||||||
"lib/timers.js",
|
|
||||||
"lib/timers/promises.js",
|
|
||||||
"lib/tls.js",
|
|
||||||
"lib/trace_events.js",
|
|
||||||
"lib/tty.js",
|
|
||||||
"lib/url.js",
|
|
||||||
"lib/util.js",
|
|
||||||
"lib/util/types.js",
|
|
||||||
"lib/v8.js",
|
|
||||||
"lib/vm.js",
|
|
||||||
"lib/wasi.js",
|
|
||||||
"lib/worker_threads.js",
|
|
||||||
"lib/zlib.js"
|
|
||||||
],
|
|
||||||
"node_module_version": 141,
|
|
||||||
"node_no_browser_globals": "false",
|
|
||||||
"node_prefix": "\\usr\\local",
|
|
||||||
"node_release_urlbase": "https://nodejs.org/download/release/",
|
|
||||||
"node_shared": "false",
|
|
||||||
"node_shared_ada": "false",
|
|
||||||
"node_shared_brotli": "false",
|
|
||||||
"node_shared_cares": "false",
|
|
||||||
"node_shared_http_parser": "false",
|
|
||||||
"node_shared_libuv": "false",
|
|
||||||
"node_shared_nghttp2": "false",
|
|
||||||
"node_shared_nghttp3": "false",
|
|
||||||
"node_shared_ngtcp2": "false",
|
|
||||||
"node_shared_openssl": "false",
|
|
||||||
"node_shared_simdjson": "false",
|
|
||||||
"node_shared_simdutf": "false",
|
|
||||||
"node_shared_sqlite": "false",
|
|
||||||
"node_shared_uvwasi": "false",
|
|
||||||
"node_shared_zlib": "false",
|
|
||||||
"node_shared_zstd": "false",
|
|
||||||
"node_tag": "",
|
|
||||||
"node_target_type": "executable",
|
|
||||||
"node_use_amaro": "true",
|
|
||||||
"node_use_bundled_v8": "true",
|
|
||||||
"node_use_node_code_cache": "true",
|
|
||||||
"node_use_node_snapshot": "true",
|
|
||||||
"node_use_openssl": "true",
|
|
||||||
"node_use_sqlite": "true",
|
|
||||||
"node_use_v8_platform": "true",
|
|
||||||
"node_with_ltcg": "true",
|
|
||||||
"node_without_node_options": "false",
|
|
||||||
"node_write_snapshot_as_array_literals": "true",
|
|
||||||
"openssl_is_fips": "false",
|
|
||||||
"openssl_version": 810549327,
|
|
||||||
"ossfuzz": "false",
|
|
||||||
"shlib_suffix": "so.141",
|
|
||||||
"single_executable_application": "true",
|
|
||||||
"suppress_all_error_on_warn": "false",
|
|
||||||
"target_arch": "x64",
|
|
||||||
"ubsan": 0,
|
|
||||||
"use_ccache_win": 0,
|
|
||||||
"use_prefix_to_find_headers": "false",
|
|
||||||
"v8_enable_31bit_smis_on_64bit_arch": 0,
|
|
||||||
"v8_enable_extensible_ro_snapshot": 0,
|
|
||||||
"v8_enable_external_code_space": 0,
|
|
||||||
"v8_enable_gdbjit": 0,
|
|
||||||
"v8_enable_hugepage": 0,
|
|
||||||
"v8_enable_i18n_support": 1,
|
|
||||||
"v8_enable_inspector": 1,
|
|
||||||
"v8_enable_javascript_promise_hooks": 1,
|
|
||||||
"v8_enable_lite_mode": 0,
|
|
||||||
"v8_enable_maglev": 1,
|
|
||||||
"v8_enable_object_print": 1,
|
|
||||||
"v8_enable_pointer_compression": 0,
|
|
||||||
"v8_enable_pointer_compression_shared_cage": 0,
|
|
||||||
"v8_enable_sandbox": 0,
|
|
||||||
"v8_enable_short_builtin_calls": 1,
|
|
||||||
"v8_enable_wasm_simd256_revec": 1,
|
|
||||||
"v8_enable_webassembly": 1,
|
|
||||||
"v8_optimized_debug": 1,
|
|
||||||
"v8_promise_internal_field_count": 1,
|
|
||||||
"v8_random_seed": 0,
|
|
||||||
"v8_trace_maps": 0,
|
|
||||||
"v8_use_siphash": 1,
|
|
||||||
"want_separate_host_toolset": 0,
|
|
||||||
"nodedir": "C:\\Users\\synta\\AppData\\Local\\node-gyp\\Cache\\25.2.1",
|
|
||||||
"python": "C:\\Users\\synta\\AppData\\Local\\Python\\pythoncore-3.14-64\\python.exe",
|
|
||||||
"standalone_static_library": 1,
|
|
||||||
"msbuild_path": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe",
|
|
||||||
"user_agent": "npm/11.6.4 node/v25.2.1 win32 x64 workspaces/false",
|
|
||||||
"userconfig": "C:\\Users\\synta\\.npmrc",
|
|
||||||
"prefix": "C:\\Users\\synta\\AppData\\Roaming\\npm",
|
|
||||||
"npm_version": "11.6.4",
|
|
||||||
"node_gyp": "C:\\Users\\synta\\AppData\\Roaming\\npm\\node_modules\\npm\\node_modules\\node-gyp\\bin\\node-gyp.js",
|
|
||||||
"local_prefix": "C:\\Users\\synta\\Documents\\WaifuBoard SRC Code (Multiple In Here)\\Waifu Board (Server)",
|
|
||||||
"init_module": "C:\\Users\\synta\\.npm-init.js",
|
|
||||||
"global_prefix": "C:\\Users\\synta\\AppData\\Roaming\\npm",
|
|
||||||
"globalconfig": "C:\\Users\\synta\\AppData\\Roaming\\npm\\etc\\npmrc",
|
|
||||||
"cache": "C:\\Users\\synta\\AppData\\Local\\npm-cache"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BIN
dist/Waifu Board 2.0.0.exe
vendored
BIN
dist/Waifu Board 2.0.0.exe
vendored
Binary file not shown.
32
dist/builder-debug.yml
vendored
32
dist/builder-debug.yml
vendored
File diff suppressed because one or more lines are too long
22
dist/builder-effective-config.yaml
vendored
22
dist/builder-effective-config.yaml
vendored
@@ -1,22 +0,0 @@
|
|||||||
directories:
|
|
||||||
output: dist
|
|
||||||
buildResources: build
|
|
||||||
appId: app.waifuboard
|
|
||||||
productName: Waifu Board
|
|
||||||
files:
|
|
||||||
- filter:
|
|
||||||
- electron/**/*
|
|
||||||
- server.js
|
|
||||||
- main.js
|
|
||||||
- preload.js
|
|
||||||
- package.json
|
|
||||||
- views/**/*
|
|
||||||
- src/scripts/**/*
|
|
||||||
- public/assets/*
|
|
||||||
extraResources:
|
|
||||||
- filter:
|
|
||||||
- ./.env
|
|
||||||
win:
|
|
||||||
target: portable
|
|
||||||
icon: public/assets/waifuboards.ico
|
|
||||||
electronVersion: 39.2.5
|
|
||||||
21
dist/win-unpacked/LICENSE.electron.txt
vendored
21
dist/win-unpacked/LICENSE.electron.txt
vendored
@@ -1,21 +0,0 @@
|
|||||||
Copyright (c) Electron contributors
|
|
||||||
Copyright (c) 2013-2020 GitHub Inc.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
270541
dist/win-unpacked/LICENSES.chromium.html
vendored
270541
dist/win-unpacked/LICENSES.chromium.html
vendored
File diff suppressed because it is too large
Load Diff
BIN
dist/win-unpacked/Waifu Board.exe
vendored
BIN
dist/win-unpacked/Waifu Board.exe
vendored
Binary file not shown.
BIN
dist/win-unpacked/chrome_100_percent.pak
vendored
BIN
dist/win-unpacked/chrome_100_percent.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/chrome_200_percent.pak
vendored
BIN
dist/win-unpacked/chrome_200_percent.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/d3dcompiler_47.dll
vendored
BIN
dist/win-unpacked/d3dcompiler_47.dll
vendored
Binary file not shown.
BIN
dist/win-unpacked/dxcompiler.dll
vendored
BIN
dist/win-unpacked/dxcompiler.dll
vendored
Binary file not shown.
BIN
dist/win-unpacked/dxil.dll
vendored
BIN
dist/win-unpacked/dxil.dll
vendored
Binary file not shown.
BIN
dist/win-unpacked/ffmpeg.dll
vendored
BIN
dist/win-unpacked/ffmpeg.dll
vendored
Binary file not shown.
BIN
dist/win-unpacked/icudtl.dat
vendored
BIN
dist/win-unpacked/icudtl.dat
vendored
Binary file not shown.
BIN
dist/win-unpacked/libEGL.dll
vendored
BIN
dist/win-unpacked/libEGL.dll
vendored
Binary file not shown.
BIN
dist/win-unpacked/libGLESv2.dll
vendored
BIN
dist/win-unpacked/libGLESv2.dll
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/af.pak
vendored
BIN
dist/win-unpacked/locales/af.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/am.pak
vendored
BIN
dist/win-unpacked/locales/am.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/ar.pak
vendored
BIN
dist/win-unpacked/locales/ar.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/bg.pak
vendored
BIN
dist/win-unpacked/locales/bg.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/bn.pak
vendored
BIN
dist/win-unpacked/locales/bn.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/ca.pak
vendored
BIN
dist/win-unpacked/locales/ca.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/cs.pak
vendored
BIN
dist/win-unpacked/locales/cs.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/da.pak
vendored
BIN
dist/win-unpacked/locales/da.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/de.pak
vendored
BIN
dist/win-unpacked/locales/de.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/el.pak
vendored
BIN
dist/win-unpacked/locales/el.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/en-GB.pak
vendored
BIN
dist/win-unpacked/locales/en-GB.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/en-US.pak
vendored
BIN
dist/win-unpacked/locales/en-US.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/es-419.pak
vendored
BIN
dist/win-unpacked/locales/es-419.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/es.pak
vendored
BIN
dist/win-unpacked/locales/es.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/et.pak
vendored
BIN
dist/win-unpacked/locales/et.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/fa.pak
vendored
BIN
dist/win-unpacked/locales/fa.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/fi.pak
vendored
BIN
dist/win-unpacked/locales/fi.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/fil.pak
vendored
BIN
dist/win-unpacked/locales/fil.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/fr.pak
vendored
BIN
dist/win-unpacked/locales/fr.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/gu.pak
vendored
BIN
dist/win-unpacked/locales/gu.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/he.pak
vendored
BIN
dist/win-unpacked/locales/he.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/hi.pak
vendored
BIN
dist/win-unpacked/locales/hi.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/hr.pak
vendored
BIN
dist/win-unpacked/locales/hr.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/hu.pak
vendored
BIN
dist/win-unpacked/locales/hu.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/id.pak
vendored
BIN
dist/win-unpacked/locales/id.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/it.pak
vendored
BIN
dist/win-unpacked/locales/it.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/ja.pak
vendored
BIN
dist/win-unpacked/locales/ja.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/kn.pak
vendored
BIN
dist/win-unpacked/locales/kn.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/ko.pak
vendored
BIN
dist/win-unpacked/locales/ko.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/lt.pak
vendored
BIN
dist/win-unpacked/locales/lt.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/lv.pak
vendored
BIN
dist/win-unpacked/locales/lv.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/ml.pak
vendored
BIN
dist/win-unpacked/locales/ml.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/mr.pak
vendored
BIN
dist/win-unpacked/locales/mr.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/ms.pak
vendored
BIN
dist/win-unpacked/locales/ms.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/nb.pak
vendored
BIN
dist/win-unpacked/locales/nb.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/nl.pak
vendored
BIN
dist/win-unpacked/locales/nl.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/pl.pak
vendored
BIN
dist/win-unpacked/locales/pl.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/pt-BR.pak
vendored
BIN
dist/win-unpacked/locales/pt-BR.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/pt-PT.pak
vendored
BIN
dist/win-unpacked/locales/pt-PT.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/ro.pak
vendored
BIN
dist/win-unpacked/locales/ro.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/ru.pak
vendored
BIN
dist/win-unpacked/locales/ru.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/sk.pak
vendored
BIN
dist/win-unpacked/locales/sk.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/sl.pak
vendored
BIN
dist/win-unpacked/locales/sl.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/sr.pak
vendored
BIN
dist/win-unpacked/locales/sr.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/sv.pak
vendored
BIN
dist/win-unpacked/locales/sv.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/sw.pak
vendored
BIN
dist/win-unpacked/locales/sw.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/ta.pak
vendored
BIN
dist/win-unpacked/locales/ta.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/te.pak
vendored
BIN
dist/win-unpacked/locales/te.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/th.pak
vendored
BIN
dist/win-unpacked/locales/th.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/tr.pak
vendored
BIN
dist/win-unpacked/locales/tr.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/uk.pak
vendored
BIN
dist/win-unpacked/locales/uk.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/ur.pak
vendored
BIN
dist/win-unpacked/locales/ur.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/vi.pak
vendored
BIN
dist/win-unpacked/locales/vi.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/zh-CN.pak
vendored
BIN
dist/win-unpacked/locales/zh-CN.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/locales/zh-TW.pak
vendored
BIN
dist/win-unpacked/locales/zh-TW.pak
vendored
Binary file not shown.
BIN
dist/win-unpacked/resources.pak
vendored
BIN
dist/win-unpacked/resources.pak
vendored
Binary file not shown.
4
dist/win-unpacked/resources/.env
vendored
4
dist/win-unpacked/resources/.env
vendored
@@ -1,4 +0,0 @@
|
|||||||
DISCORD_CLIENT_ID=1440755333055250616
|
|
||||||
ANILIST_CLIENT_SECRET=fTql48IjI7ZAE2cbjFaMl2I5HhYHYr1kVDyDNpOk
|
|
||||||
ANILIST_CLIENT_ID=32898
|
|
||||||
JWT_SECRET=900c86474497ce3c329ba9949d834dbb1dd072163a5867957be929f3adc592d2d6352c03aecbfe065a8b9e9eff0e7fe7516a50dbf206d5e8c69bdcba22477cb6
|
|
||||||
BIN
dist/win-unpacked/resources/app.asar
vendored
BIN
dist/win-unpacked/resources/app.asar
vendored
Binary file not shown.
BIN
dist/win-unpacked/resources/elevate.exe
vendored
BIN
dist/win-unpacked/resources/elevate.exe
vendored
Binary file not shown.
BIN
dist/win-unpacked/snapshot_blob.bin
vendored
BIN
dist/win-unpacked/snapshot_blob.bin
vendored
Binary file not shown.
BIN
dist/win-unpacked/v8_context_snapshot.bin
vendored
BIN
dist/win-unpacked/v8_context_snapshot.bin
vendored
Binary file not shown.
BIN
dist/win-unpacked/vk_swiftshader.dll
vendored
BIN
dist/win-unpacked/vk_swiftshader.dll
vendored
Binary file not shown.
1
dist/win-unpacked/vk_swiftshader_icd.json
vendored
1
dist/win-unpacked/vk_swiftshader_icd.json
vendored
@@ -1 +0,0 @@
|
|||||||
{"file_format_version": "1.0.0", "ICD": {"library_path": ".\\vk_swiftshader.dll", "api_version": "1.0.5"}}
|
|
||||||
BIN
dist/win-unpacked/vulkan-1.dll
vendored
BIN
dist/win-unpacked/vulkan-1.dll
vendored
Binary file not shown.
@@ -1,76 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const database_1 = require("../shared/database");
|
|
||||||
async function anilist(fastify) {
|
|
||||||
fastify.get("/anilist", async (request, reply) => {
|
|
||||||
try {
|
|
||||||
const { code, state } = request.query;
|
|
||||||
if (!code)
|
|
||||||
return reply.status(400).send("No code");
|
|
||||||
if (!state)
|
|
||||||
return reply.status(400).send("No user state");
|
|
||||||
const userId = Number(state);
|
|
||||||
if (!userId || isNaN(userId)) {
|
|
||||||
return reply.status(400).send("Invalid user id");
|
|
||||||
}
|
|
||||||
const tokenRes = await fetch("https://anilist.co/api/v2/oauth/token", {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify({
|
|
||||||
grant_type: "authorization_code",
|
|
||||||
client_id: process.env.ANILIST_CLIENT_ID,
|
|
||||||
client_secret: process.env.ANILIST_CLIENT_SECRET,
|
|
||||||
redirect_uri: "http://localhost:54322/api/anilist",
|
|
||||||
code
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const tokenData = await tokenRes.json();
|
|
||||||
if (!tokenData.access_token) {
|
|
||||||
console.error("AniList token error:", tokenData);
|
|
||||||
return reply.status(500).send("Failed to get AniList token");
|
|
||||||
}
|
|
||||||
const userRes = await fetch("https://graphql.anilist.co", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: `${tokenData.token_type} ${tokenData.access_token}`
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
query: `query { Viewer { id } }`
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const userData = await userRes.json();
|
|
||||||
const anilistUserId = userData?.data?.Viewer?.id;
|
|
||||||
if (!anilistUserId) {
|
|
||||||
console.error("AniList Viewer error:", userData);
|
|
||||||
return reply.status(500).send("Failed to fetch AniList user");
|
|
||||||
}
|
|
||||||
const expiresAt = new Date(Date.now() + tokenData.expires_in * 1000).toISOString();
|
|
||||||
await (0, database_1.run)(`
|
|
||||||
INSERT INTO UserIntegration
|
|
||||||
(user_id, platform, access_token, refresh_token, token_type, anilist_user_id, expires_at)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
||||||
ON CONFLICT(user_id) DO UPDATE SET
|
|
||||||
access_token = excluded.access_token,
|
|
||||||
refresh_token = excluded.refresh_token,
|
|
||||||
token_type = excluded.token_type,
|
|
||||||
anilist_user_id = excluded.anilist_user_id,
|
|
||||||
expires_at = excluded.expires_at
|
|
||||||
`, [
|
|
||||||
userId,
|
|
||||||
"AniList",
|
|
||||||
tokenData.access_token,
|
|
||||||
tokenData.refresh_token,
|
|
||||||
tokenData.token_type,
|
|
||||||
anilistUserId,
|
|
||||||
expiresAt
|
|
||||||
], "userdata");
|
|
||||||
return reply.redirect("http://localhost:54322/?anilist=success");
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error("AniList error:", e);
|
|
||||||
return reply.redirect("http://localhost:54322/?anilist=error");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.default = anilist;
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const database_1 = require("../../shared/database");
|
|
||||||
async function anilist(fastify) {
|
|
||||||
fastify.get("/anilist", async (request, reply) => {
|
|
||||||
try {
|
|
||||||
const { code, state } = request.query;
|
|
||||||
if (!code)
|
|
||||||
return reply.status(400).send("No code");
|
|
||||||
if (!state)
|
|
||||||
return reply.status(400).send("No user state");
|
|
||||||
const userId = Number(state);
|
|
||||||
if (!userId || isNaN(userId)) {
|
|
||||||
return reply.status(400).send("Invalid user id");
|
|
||||||
}
|
|
||||||
const tokenRes = await fetch("https://anilist.co/api/v2/oauth/token", {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify({
|
|
||||||
grant_type: "authorization_code",
|
|
||||||
client_id: process.env.ANILIST_CLIENT_ID,
|
|
||||||
client_secret: process.env.ANILIST_CLIENT_SECRET,
|
|
||||||
redirect_uri: "http://localhost:54322/api/anilist",
|
|
||||||
code
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const tokenData = await tokenRes.json();
|
|
||||||
if (!tokenData.access_token) {
|
|
||||||
console.error("AniList token error:", tokenData);
|
|
||||||
return reply.status(500).send("Failed to get AniList token");
|
|
||||||
}
|
|
||||||
const userRes = await fetch("https://graphql.anilist.co", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: `${tokenData.token_type} ${tokenData.access_token}`
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
query: `query { Viewer { id } }`
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const userData = await userRes.json();
|
|
||||||
const anilistUserId = userData?.data?.Viewer?.id;
|
|
||||||
if (!anilistUserId) {
|
|
||||||
console.error("AniList Viewer error:", userData);
|
|
||||||
return reply.status(500).send("Failed to fetch AniList user");
|
|
||||||
}
|
|
||||||
const expiresAt = new Date(Date.now() + tokenData.expires_in * 1000).toISOString();
|
|
||||||
await (0, database_1.run)(`
|
|
||||||
INSERT INTO UserIntegration
|
|
||||||
(user_id, platform, access_token, refresh_token, token_type, anilist_user_id, expires_at)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
||||||
ON CONFLICT(user_id) DO UPDATE SET
|
|
||||||
access_token = excluded.access_token,
|
|
||||||
refresh_token = excluded.refresh_token,
|
|
||||||
token_type = excluded.token_type,
|
|
||||||
anilist_user_id = excluded.anilist_user_id,
|
|
||||||
expires_at = excluded.expires_at
|
|
||||||
`, [
|
|
||||||
userId,
|
|
||||||
"AniList",
|
|
||||||
tokenData.access_token,
|
|
||||||
tokenData.refresh_token,
|
|
||||||
tokenData.token_type,
|
|
||||||
anilistUserId,
|
|
||||||
expiresAt
|
|
||||||
], "userdata");
|
|
||||||
return reply.redirect("http://localhost:54322/?anilist=success");
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error("AniList error:", e);
|
|
||||||
return reply.redirect("http://localhost:54322/?anilist=error");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.default = anilist;
|
|
||||||
@@ -1,478 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.getUserAniList = getUserAniList;
|
|
||||||
exports.updateAniListEntry = updateAniListEntry;
|
|
||||||
exports.deleteAniListEntry = deleteAniListEntry;
|
|
||||||
exports.getSingleAniListEntry = getSingleAniListEntry;
|
|
||||||
const database_1 = require("../../shared/database");
|
|
||||||
const USER_DB = 'userdata';
|
|
||||||
// Configuración de reintentos
|
|
||||||
const RETRY_CONFIG = {
|
|
||||||
maxRetries: 3,
|
|
||||||
initialDelay: 1000,
|
|
||||||
maxDelay: 5000,
|
|
||||||
backoffMultiplier: 2
|
|
||||||
};
|
|
||||||
// Helper para hacer requests con reintentos y manejo de errores
|
|
||||||
async function fetchWithRetry(url, options, retries = RETRY_CONFIG.maxRetries) {
|
|
||||||
let lastError = null;
|
|
||||||
let delay = RETRY_CONFIG.initialDelay;
|
|
||||||
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
||||||
try {
|
|
||||||
const controller = new AbortController();
|
|
||||||
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10s timeout
|
|
||||||
const response = await fetch(url, {
|
|
||||||
...options,
|
|
||||||
signal: controller.signal
|
|
||||||
});
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
// Si es rate limit (429), esperamos más tiempo
|
|
||||||
if (response.status === 429) {
|
|
||||||
const retryAfter = response.headers.get('Retry-After');
|
|
||||||
const waitTime = retryAfter ? parseInt(retryAfter) * 1000 : delay;
|
|
||||||
if (attempt < retries) {
|
|
||||||
console.warn(`Rate limited. Esperando ${waitTime}ms antes de reintentar...`);
|
|
||||||
await new Promise(resolve => setTimeout(resolve, waitTime));
|
|
||||||
delay = Math.min(delay * RETRY_CONFIG.backoffMultiplier, RETRY_CONFIG.maxDelay);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Si es un error de servidor (5xx), reintentamos
|
|
||||||
if (response.status >= 500 && attempt < retries) {
|
|
||||||
console.warn(`Error del servidor (${response.status}). Reintentando en ${delay}ms...`);
|
|
||||||
await new Promise(resolve => setTimeout(resolve, delay));
|
|
||||||
delay = Math.min(delay * RETRY_CONFIG.backoffMultiplier, RETRY_CONFIG.maxDelay);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
lastError = error;
|
|
||||||
if (attempt < retries && (error instanceof Error && (error.name === 'AbortError' ||
|
|
||||||
error.message.includes('fetch') ||
|
|
||||||
error.message.includes('network')))) {
|
|
||||||
console.warn(`Error de conexión (intento ${attempt + 1}/${retries + 1}). Reintentando en ${delay}ms...`);
|
|
||||||
await new Promise(resolve => setTimeout(resolve, delay));
|
|
||||||
delay = Math.min(delay * RETRY_CONFIG.backoffMultiplier, RETRY_CONFIG.maxDelay);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw lastError || new Error('Request failed after all retries');
|
|
||||||
}
|
|
||||||
async function getUserAniList(appUserId) {
|
|
||||||
try {
|
|
||||||
const sql = `
|
|
||||||
SELECT access_token, anilist_user_id
|
|
||||||
FROM UserIntegration
|
|
||||||
WHERE user_id = ? AND platform = 'AniList';
|
|
||||||
`;
|
|
||||||
const integration = await (0, database_1.queryOne)(sql, [appUserId], USER_DB);
|
|
||||||
if (!integration)
|
|
||||||
return [];
|
|
||||||
const { access_token, anilist_user_id } = integration;
|
|
||||||
if (!access_token || !anilist_user_id)
|
|
||||||
return [];
|
|
||||||
const query = `
|
|
||||||
query ($userId: Int) {
|
|
||||||
anime: MediaListCollection(userId: $userId, type: ANIME) {
|
|
||||||
lists {
|
|
||||||
entries {
|
|
||||||
media {
|
|
||||||
id
|
|
||||||
title { romaji english userPreferred }
|
|
||||||
coverImage { extraLarge }
|
|
||||||
episodes
|
|
||||||
nextAiringEpisode { episode }
|
|
||||||
}
|
|
||||||
status
|
|
||||||
progress
|
|
||||||
score
|
|
||||||
repeat
|
|
||||||
notes
|
|
||||||
private
|
|
||||||
startedAt { year month day }
|
|
||||||
completedAt { year month day }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
manga: MediaListCollection(userId: $userId, type: MANGA) {
|
|
||||||
lists {
|
|
||||||
entries {
|
|
||||||
media {
|
|
||||||
id
|
|
||||||
type
|
|
||||||
format
|
|
||||||
title { romaji english userPreferred }
|
|
||||||
coverImage { extraLarge }
|
|
||||||
chapters
|
|
||||||
volumes
|
|
||||||
}
|
|
||||||
status
|
|
||||||
progress
|
|
||||||
score
|
|
||||||
repeat
|
|
||||||
notes
|
|
||||||
private
|
|
||||||
startedAt { year month day }
|
|
||||||
completedAt { year month day }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const res = await fetchWithRetry('https://graphql.anilist.co', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${access_token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
query,
|
|
||||||
variables: { userId: anilist_user_id }
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
if (!res.ok)
|
|
||||||
throw new Error(`AniList API error: ${res.status}`);
|
|
||||||
const json = await res.json();
|
|
||||||
if (json?.errors?.length)
|
|
||||||
throw new Error(json.errors[0].message);
|
|
||||||
const fromFuzzy = (d) => {
|
|
||||||
if (!d?.year)
|
|
||||||
return null;
|
|
||||||
const m = String(d.month || 1).padStart(2, '0');
|
|
||||||
const day = String(d.day || 1).padStart(2, '0');
|
|
||||||
return `${d.year}-${m}-${day}`;
|
|
||||||
};
|
|
||||||
const normalize = (lists, type) => {
|
|
||||||
const result = [];
|
|
||||||
for (const list of lists || []) {
|
|
||||||
for (const entry of list.entries || []) {
|
|
||||||
const media = entry.media;
|
|
||||||
const totalEpisodes = media?.episodes ||
|
|
||||||
(media?.nextAiringEpisode?.episode
|
|
||||||
? media.nextAiringEpisode.episode - 1
|
|
||||||
: 0);
|
|
||||||
const totalChapters = media?.chapters ||
|
|
||||||
(media?.volumes ? media.volumes * 10 : 0);
|
|
||||||
const resolvedType = type === 'MANGA' &&
|
|
||||||
(media?.format === 'LIGHT_NOVEL' || media?.format === 'NOVEL')
|
|
||||||
? 'NOVEL'
|
|
||||||
: type;
|
|
||||||
result.push({
|
|
||||||
user_id: appUserId,
|
|
||||||
entry_id: media.id,
|
|
||||||
source: 'anilist',
|
|
||||||
// ✅ AHORA TU FRONT RECIBE NOVEL
|
|
||||||
entry_type: resolvedType,
|
|
||||||
status: entry.status,
|
|
||||||
progress: entry.progress || 0,
|
|
||||||
score: entry.score || null,
|
|
||||||
start_date: fromFuzzy(entry.startedAt),
|
|
||||||
end_date: fromFuzzy(entry.completedAt),
|
|
||||||
repeat_count: entry.repeat || 0,
|
|
||||||
notes: entry.notes || null,
|
|
||||||
is_private: entry.private ? 1 : 0,
|
|
||||||
title: media?.title?.userPreferred
|
|
||||||
|| media?.title?.english
|
|
||||||
|| media?.title?.romaji
|
|
||||||
|| 'Unknown Title',
|
|
||||||
poster: media?.coverImage?.extraLarge
|
|
||||||
|| 'https://placehold.co/400x600?text=No+Cover',
|
|
||||||
total_episodes: resolvedType === 'ANIME' ? totalEpisodes : undefined,
|
|
||||||
total_chapters: resolvedType !== 'ANIME' ? totalChapters : undefined,
|
|
||||||
updated_at: new Date().toISOString()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
return [
|
|
||||||
...normalize(json?.data?.anime?.lists, 'ANIME'),
|
|
||||||
...normalize(json?.data?.manga?.lists, 'MANGA')
|
|
||||||
];
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error('Error fetching AniList data:', error);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function updateAniListEntry(token, params) {
|
|
||||||
try {
|
|
||||||
if (!token)
|
|
||||||
throw new Error('AniList token is required');
|
|
||||||
const mutation = `
|
|
||||||
mutation (
|
|
||||||
$mediaId: Int,
|
|
||||||
$status: MediaListStatus,
|
|
||||||
$progress: Int,
|
|
||||||
$score: Float,
|
|
||||||
$startedAt: FuzzyDateInput,
|
|
||||||
$completedAt: FuzzyDateInput,
|
|
||||||
$repeat: Int,
|
|
||||||
$notes: String,
|
|
||||||
$private: Boolean
|
|
||||||
) {
|
|
||||||
SaveMediaListEntry (
|
|
||||||
mediaId: $mediaId,
|
|
||||||
status: $status,
|
|
||||||
progress: $progress,
|
|
||||||
score: $score,
|
|
||||||
startedAt: $startedAt,
|
|
||||||
completedAt: $completedAt,
|
|
||||||
repeat: $repeat,
|
|
||||||
notes: $notes,
|
|
||||||
private: $private
|
|
||||||
) {
|
|
||||||
id
|
|
||||||
status
|
|
||||||
progress
|
|
||||||
score
|
|
||||||
startedAt { year month day }
|
|
||||||
completedAt { year month day }
|
|
||||||
repeat
|
|
||||||
notes
|
|
||||||
private
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const toFuzzyDate = (dateStr) => {
|
|
||||||
if (!dateStr)
|
|
||||||
return null;
|
|
||||||
const [year, month, day] = dateStr.split('-').map(Number);
|
|
||||||
return { year, month, day };
|
|
||||||
};
|
|
||||||
const variables = {
|
|
||||||
mediaId: Number(params.mediaId),
|
|
||||||
status: params.status ?? undefined,
|
|
||||||
progress: params.progress ?? undefined,
|
|
||||||
score: params.score ?? undefined,
|
|
||||||
startedAt: toFuzzyDate(params.start_date),
|
|
||||||
completedAt: toFuzzyDate(params.end_date),
|
|
||||||
repeat: params.repeat_count ?? undefined,
|
|
||||||
notes: params.notes ?? undefined,
|
|
||||||
private: typeof params.is_private === 'boolean'
|
|
||||||
? params.is_private
|
|
||||||
: params.is_private === 1
|
|
||||||
};
|
|
||||||
const res = await fetchWithRetry('https://graphql.anilist.co', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ query: mutation, variables }),
|
|
||||||
});
|
|
||||||
if (!res.ok) {
|
|
||||||
const errorText = await res.text();
|
|
||||||
throw new Error(`AniList update failed: ${res.status} - ${errorText}`);
|
|
||||||
}
|
|
||||||
const json = await res.json();
|
|
||||||
if (json?.errors?.length) {
|
|
||||||
throw new Error(`AniList GraphQL error: ${json.errors[0].message}`);
|
|
||||||
}
|
|
||||||
return json.data?.SaveMediaListEntry || null;
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error('Error updating AniList entry:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function deleteAniListEntry(token, mediaId) {
|
|
||||||
if (!token)
|
|
||||||
throw new Error("AniList token required");
|
|
||||||
try {
|
|
||||||
// 1️⃣ OBTENER VIEWER
|
|
||||||
const viewerQuery = `query { Viewer { id name } }`;
|
|
||||||
const vRes = await fetchWithRetry('https://graphql.anilist.co', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ query: viewerQuery }),
|
|
||||||
});
|
|
||||||
const vJson = await vRes.json();
|
|
||||||
const userId = vJson?.data?.Viewer?.id;
|
|
||||||
if (!userId)
|
|
||||||
throw new Error("Invalid AniList token");
|
|
||||||
// 2️⃣ DETECTAR TIPO REAL DEL MEDIA
|
|
||||||
const mediaQuery = `
|
|
||||||
query ($id: Int) {
|
|
||||||
Media(id: $id) {
|
|
||||||
id
|
|
||||||
type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const mTypeRes = await fetchWithRetry('https://graphql.anilist.co', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
query: mediaQuery,
|
|
||||||
variables: { id: mediaId }
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
const mTypeJson = await mTypeRes.json();
|
|
||||||
const mediaType = mTypeJson?.data?.Media?.type;
|
|
||||||
if (!mediaType) {
|
|
||||||
throw new Error("Media not found in AniList");
|
|
||||||
}
|
|
||||||
// 3️⃣ BUSCAR ENTRY CON TIPO REAL
|
|
||||||
const listQuery = `
|
|
||||||
query ($userId: Int, $mediaId: Int, $type: MediaType) {
|
|
||||||
MediaList(userId: $userId, mediaId: $mediaId, type: $type) {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const qRes = await fetchWithRetry('https://graphql.anilist.co', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
query: listQuery,
|
|
||||||
variables: {
|
|
||||||
userId,
|
|
||||||
mediaId,
|
|
||||||
type: mediaType
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
const qJson = await qRes.json();
|
|
||||||
const listEntryId = qJson?.data?.MediaList?.id;
|
|
||||||
if (!listEntryId) {
|
|
||||||
throw new Error("Entry not found in user's AniList");
|
|
||||||
}
|
|
||||||
// 4️⃣ BORRAR
|
|
||||||
const mutation = `
|
|
||||||
mutation ($id: Int) {
|
|
||||||
DeleteMediaListEntry(id: $id) {
|
|
||||||
deleted
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const delRes = await fetchWithRetry('https://graphql.anilist.co', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
query: mutation,
|
|
||||||
variables: { id: listEntryId }
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
const delJson = await delRes.json();
|
|
||||||
if (delJson?.errors?.length) {
|
|
||||||
throw new Error(delJson.errors[0].message);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.error("AniList DELETE failed:", err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getSingleAniListEntry(token, mediaId, type) {
|
|
||||||
try {
|
|
||||||
if (!token) {
|
|
||||||
throw new Error('AniList token is required');
|
|
||||||
}
|
|
||||||
// 1️⃣ Obtener userId desde el token
|
|
||||||
const viewerRes = await fetchWithRetry('https://graphql.anilist.co', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
query: `query { Viewer { id } }`
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const viewerJson = await viewerRes.json();
|
|
||||||
const userId = viewerJson?.data?.Viewer?.id;
|
|
||||||
if (!userId) {
|
|
||||||
throw new Error('Failed to get AniList userId');
|
|
||||||
}
|
|
||||||
// 2️⃣ Query correcta con userId
|
|
||||||
const query = `
|
|
||||||
query ($mediaId: Int, $type: MediaType, $userId: Int) {
|
|
||||||
MediaList(mediaId: $mediaId, type: $type, userId: $userId) {
|
|
||||||
id
|
|
||||||
status
|
|
||||||
progress
|
|
||||||
score
|
|
||||||
repeat
|
|
||||||
private
|
|
||||||
notes
|
|
||||||
startedAt { year month day }
|
|
||||||
completedAt { year month day }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const res = await fetchWithRetry('https://graphql.anilist.co', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
query,
|
|
||||||
variables: { mediaId, type, userId }
|
|
||||||
})
|
|
||||||
});
|
|
||||||
if (res.status === 404) {
|
|
||||||
return null; // ✅ No existe entry todavía → es totalmente válido
|
|
||||||
}
|
|
||||||
if (!res.ok) {
|
|
||||||
const errorText = await res.text();
|
|
||||||
throw new Error(`AniList fetch failed: ${res.status} - ${errorText}`);
|
|
||||||
}
|
|
||||||
const json = await res.json();
|
|
||||||
if (json?.errors?.length) {
|
|
||||||
if (json.errors[0].status === 404)
|
|
||||||
return null;
|
|
||||||
throw new Error(`GraphQL error: ${json.errors[0].message}`);
|
|
||||||
}
|
|
||||||
const entry = json?.data?.MediaList;
|
|
||||||
if (!entry)
|
|
||||||
return null;
|
|
||||||
return {
|
|
||||||
entry_id: mediaId,
|
|
||||||
source: 'anilist',
|
|
||||||
entry_type: type,
|
|
||||||
status: entry.status,
|
|
||||||
progress: entry.progress || 0,
|
|
||||||
score: entry.score ?? null,
|
|
||||||
start_date: entry.startedAt?.year
|
|
||||||
? `${entry.startedAt.year}-${String(entry.startedAt.month).padStart(2, '0')}-${String(entry.startedAt.day).padStart(2, '0')}`
|
|
||||||
: null,
|
|
||||||
end_date: entry.completedAt?.year
|
|
||||||
? `${entry.completedAt.year}-${String(entry.completedAt.month).padStart(2, '0')}-${String(entry.completedAt.day).padStart(2, '0')}`
|
|
||||||
: null,
|
|
||||||
repeat_count: entry.repeat || 0,
|
|
||||||
notes: entry.notes || null,
|
|
||||||
is_private: entry.private ? 1 : 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error('Error fetching single AniList entry:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || (function () {
|
|
||||||
var ownKeys = function(o) {
|
|
||||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
||||||
var ar = [];
|
|
||||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
||||||
return ar;
|
|
||||||
};
|
|
||||||
return ownKeys(o);
|
|
||||||
};
|
|
||||||
return function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.getAnime = getAnime;
|
|
||||||
exports.getAnimeEpisodes = getAnimeEpisodes;
|
|
||||||
exports.getTrending = getTrending;
|
|
||||||
exports.getTopAiring = getTopAiring;
|
|
||||||
exports.search = search;
|
|
||||||
exports.searchInExtension = searchInExtension;
|
|
||||||
exports.getWatchStream = getWatchStream;
|
|
||||||
const animeService = __importStar(require("./anime.service"));
|
|
||||||
const extensions_1 = require("../../shared/extensions");
|
|
||||||
async function getAnime(req, reply) {
|
|
||||||
try {
|
|
||||||
const { id } = req.params;
|
|
||||||
const source = req.query.source;
|
|
||||||
let anime;
|
|
||||||
if (source === 'anilist') {
|
|
||||||
anime = await animeService.getAnimeById(id);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const ext = (0, extensions_1.getExtension)(source);
|
|
||||||
anime = await animeService.getAnimeInfoExtension(ext, id);
|
|
||||||
}
|
|
||||||
return anime;
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
return { error: "Database error" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getAnimeEpisodes(req, reply) {
|
|
||||||
try {
|
|
||||||
const { id } = req.params;
|
|
||||||
const source = req.query.source || 'anilist';
|
|
||||||
const ext = (0, extensions_1.getExtension)(source);
|
|
||||||
return await animeService.searchEpisodesInExtension(ext, source, id);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
return { error: "Database error" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getTrending(req, reply) {
|
|
||||||
try {
|
|
||||||
const results = await animeService.getTrendingAnime();
|
|
||||||
return { results };
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
return { results: [] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getTopAiring(req, reply) {
|
|
||||||
try {
|
|
||||||
const results = await animeService.getTopAiringAnime();
|
|
||||||
return { results };
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
return { results: [] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function search(req, reply) {
|
|
||||||
try {
|
|
||||||
const query = req.query.q;
|
|
||||||
const results = await animeService.searchAnimeLocal(query);
|
|
||||||
if (results.length > 0) {
|
|
||||||
return { results: results };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
return { results: [] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function searchInExtension(req, reply) {
|
|
||||||
try {
|
|
||||||
const extensionName = req.params.extension;
|
|
||||||
const query = req.query.q;
|
|
||||||
const ext = (0, extensions_1.getExtension)(extensionName);
|
|
||||||
if (!ext)
|
|
||||||
return { results: [] };
|
|
||||||
const results = await animeService.searchAnimeInExtension(ext, extensionName, query);
|
|
||||||
return { results };
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return { results: [] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getWatchStream(req, reply) {
|
|
||||||
try {
|
|
||||||
const { animeId, episode, server, category, ext, source } = req.query;
|
|
||||||
const extension = (0, extensions_1.getExtension)(ext);
|
|
||||||
if (!extension)
|
|
||||||
return { error: "Extension not found" };
|
|
||||||
return await animeService.getStreamData(extension, episode, animeId, source, server, category);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
const error = err;
|
|
||||||
return { error: error.message };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || (function () {
|
|
||||||
var ownKeys = function(o) {
|
|
||||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
||||||
var ar = [];
|
|
||||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
||||||
return ar;
|
|
||||||
};
|
|
||||||
return ownKeys(o);
|
|
||||||
};
|
|
||||||
return function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const controller = __importStar(require("./anime.controller"));
|
|
||||||
async function animeRoutes(fastify) {
|
|
||||||
fastify.get('/anime/:id', controller.getAnime);
|
|
||||||
fastify.get('/anime/:id/:episodes', controller.getAnimeEpisodes);
|
|
||||||
fastify.get('/trending', controller.getTrending);
|
|
||||||
fastify.get('/top-airing', controller.getTopAiring);
|
|
||||||
fastify.get('/search', controller.search);
|
|
||||||
fastify.get('/search/:extension', controller.searchInExtension);
|
|
||||||
fastify.get('/watch/stream', controller.getWatchStream);
|
|
||||||
}
|
|
||||||
exports.default = animeRoutes;
|
|
||||||
@@ -1,388 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.getAnimeById = getAnimeById;
|
|
||||||
exports.getTrendingAnime = getTrendingAnime;
|
|
||||||
exports.getTopAiringAnime = getTopAiringAnime;
|
|
||||||
exports.searchAnimeLocal = searchAnimeLocal;
|
|
||||||
exports.getAnimeInfoExtension = getAnimeInfoExtension;
|
|
||||||
exports.searchAnimeInExtension = searchAnimeInExtension;
|
|
||||||
exports.searchEpisodesInExtension = searchEpisodesInExtension;
|
|
||||||
exports.getStreamData = getStreamData;
|
|
||||||
const queries_1 = require("../../shared/queries");
|
|
||||||
const database_1 = require("../../shared/database");
|
|
||||||
const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
||||||
const TTL = 60 * 60 * 6;
|
|
||||||
const ANILIST_URL = "https://graphql.anilist.co";
|
|
||||||
const MEDIA_FIELDS = `
|
|
||||||
id
|
|
||||||
idMal
|
|
||||||
title { romaji english native userPreferred }
|
|
||||||
type
|
|
||||||
format
|
|
||||||
status
|
|
||||||
description
|
|
||||||
startDate { year month day }
|
|
||||||
endDate { year month day }
|
|
||||||
season
|
|
||||||
seasonYear
|
|
||||||
episodes
|
|
||||||
duration
|
|
||||||
chapters
|
|
||||||
volumes
|
|
||||||
countryOfOrigin
|
|
||||||
isLicensed
|
|
||||||
source
|
|
||||||
hashtag
|
|
||||||
trailer { id site thumbnail }
|
|
||||||
updatedAt
|
|
||||||
coverImage { extraLarge large medium color }
|
|
||||||
bannerImage
|
|
||||||
genres
|
|
||||||
synonyms
|
|
||||||
averageScore
|
|
||||||
popularity
|
|
||||||
isLocked
|
|
||||||
trending
|
|
||||||
favourites
|
|
||||||
isAdult
|
|
||||||
siteUrl
|
|
||||||
tags { id name description category rank isGeneralSpoiler isMediaSpoiler isAdult }
|
|
||||||
relations {
|
|
||||||
edges {
|
|
||||||
relationType
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
title { romaji }
|
|
||||||
type
|
|
||||||
format
|
|
||||||
status
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
studios {
|
|
||||||
edges {
|
|
||||||
isMain
|
|
||||||
node { id name isAnimationStudio }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nextAiringEpisode { airingAt timeUntilAiring episode }
|
|
||||||
externalLinks { id url site type language color icon notes }
|
|
||||||
rankings { id rank type format year season allTime context }
|
|
||||||
stats {
|
|
||||||
scoreDistribution { score amount }
|
|
||||||
statusDistribution { status amount }
|
|
||||||
}
|
|
||||||
recommendations(perPage: 7, sort: RATING_DESC) {
|
|
||||||
nodes {
|
|
||||||
mediaRecommendation {
|
|
||||||
id
|
|
||||||
title { romaji }
|
|
||||||
coverImage { medium }
|
|
||||||
format
|
|
||||||
type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
async function fetchAniList(query, variables) {
|
|
||||||
const res = await fetch(ANILIST_URL, {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify({ query, variables })
|
|
||||||
});
|
|
||||||
const json = await res.json();
|
|
||||||
return json?.data;
|
|
||||||
}
|
|
||||||
async function getAnimeById(id) {
|
|
||||||
const row = await (0, database_1.queryOne)("SELECT full_data FROM anime WHERE id = ?", [id]);
|
|
||||||
if (row)
|
|
||||||
return JSON.parse(row.full_data);
|
|
||||||
const query = `
|
|
||||||
query ($id: Int) {
|
|
||||||
Media(id: $id, type: ANIME) { ${MEDIA_FIELDS} }
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const data = await fetchAniList(query, { id: Number(id) });
|
|
||||||
if (!data?.Media)
|
|
||||||
return { error: "Anime not found" };
|
|
||||||
await (0, database_1.queryOne)("INSERT INTO anime (id, title, updatedAt, full_data) VALUES (?, ?, ?, ?)", [
|
|
||||||
data.Media.id,
|
|
||||||
data.Media.title?.english || data.Media.title?.romaji,
|
|
||||||
data.Media.updatedAt || 0,
|
|
||||||
JSON.stringify(data.Media)
|
|
||||||
]);
|
|
||||||
return data.Media;
|
|
||||||
}
|
|
||||||
async function getTrendingAnime() {
|
|
||||||
const rows = await (0, database_1.queryAll)("SELECT full_data, updated_at FROM trending ORDER BY rank ASC LIMIT 10");
|
|
||||||
if (rows.length) {
|
|
||||||
const expired = (Date.now() / 1000 - rows[0].updated_at) > TTL;
|
|
||||||
if (!expired) {
|
|
||||||
return rows.map((r) => JSON.parse(r.full_data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const query = `
|
|
||||||
query {
|
|
||||||
Page(page: 1, perPage: 10) {
|
|
||||||
media(type: ANIME, sort: TRENDING_DESC) { ${MEDIA_FIELDS} }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const data = await fetchAniList(query, {});
|
|
||||||
const list = data?.Page?.media || [];
|
|
||||||
const now = Math.floor(Date.now() / 1000);
|
|
||||||
await (0, database_1.queryOne)("DELETE FROM trending");
|
|
||||||
let rank = 1;
|
|
||||||
for (const anime of list) {
|
|
||||||
await (0, database_1.queryOne)("INSERT INTO trending (rank, id, full_data, updated_at) VALUES (?, ?, ?, ?)", [rank++, anime.id, JSON.stringify(anime), now]);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
async function getTopAiringAnime() {
|
|
||||||
const rows = await (0, database_1.queryAll)("SELECT full_data, updated_at FROM top_airing ORDER BY rank ASC LIMIT 10");
|
|
||||||
if (rows.length) {
|
|
||||||
const expired = (Date.now() / 1000 - rows[0].updated_at) > TTL;
|
|
||||||
if (!expired) {
|
|
||||||
return rows.map((r) => JSON.parse(r.full_data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const query = `
|
|
||||||
query {
|
|
||||||
Page(page: 1, perPage: 10) {
|
|
||||||
media(type: ANIME, status: RELEASING, sort: SCORE_DESC) { ${MEDIA_FIELDS} }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const data = await fetchAniList(query, {});
|
|
||||||
const list = data?.Page?.media || [];
|
|
||||||
const now = Math.floor(Date.now() / 1000);
|
|
||||||
await (0, database_1.queryOne)("DELETE FROM top_airing");
|
|
||||||
let rank = 1;
|
|
||||||
for (const anime of list) {
|
|
||||||
await (0, database_1.queryOne)("INSERT INTO top_airing (rank, id, full_data, updated_at) VALUES (?, ?, ?, ?)", [rank++, anime.id, JSON.stringify(anime), now]);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
async function searchAnimeLocal(query) {
|
|
||||||
if (!query || query.length < 2)
|
|
||||||
return [];
|
|
||||||
const sql = `SELECT full_data FROM anime WHERE full_data LIKE ? LIMIT 50`;
|
|
||||||
const rows = await (0, database_1.queryAll)(sql, [`%${query}%`]);
|
|
||||||
const localResults = rows
|
|
||||||
.map((r) => JSON.parse(r.full_data))
|
|
||||||
.filter((anime) => {
|
|
||||||
const q = query.toLowerCase();
|
|
||||||
const titles = [
|
|
||||||
anime.title?.english,
|
|
||||||
anime.title?.romaji,
|
|
||||||
anime.title?.native,
|
|
||||||
...(anime.synonyms || [])
|
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.map(t => t.toLowerCase());
|
|
||||||
return titles.some(t => t.includes(q));
|
|
||||||
})
|
|
||||||
.slice(0, 10);
|
|
||||||
if (localResults.length >= 5) {
|
|
||||||
return localResults;
|
|
||||||
}
|
|
||||||
const gql = `
|
|
||||||
query ($search: String) {
|
|
||||||
Page(page: 1, perPage: 10) {
|
|
||||||
media(type: ANIME, search: $search) { ${MEDIA_FIELDS} }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const data = await fetchAniList(gql, { search: query });
|
|
||||||
const remoteResults = data?.Page?.media || [];
|
|
||||||
for (const anime of remoteResults) {
|
|
||||||
await (0, database_1.queryOne)("INSERT OR IGNORE INTO anime (id, title, updatedAt, full_data) VALUES (?, ?, ?, ?)", [
|
|
||||||
anime.id,
|
|
||||||
anime.title?.english || anime.title?.romaji,
|
|
||||||
anime.updatedAt || 0,
|
|
||||||
JSON.stringify(anime)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
const merged = [...localResults];
|
|
||||||
for (const anime of remoteResults) {
|
|
||||||
if (!merged.find(a => a.id === anime.id)) {
|
|
||||||
merged.push(anime);
|
|
||||||
}
|
|
||||||
if (merged.length >= 10)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return merged;
|
|
||||||
}
|
|
||||||
async function getAnimeInfoExtension(ext, id) {
|
|
||||||
if (!ext)
|
|
||||||
return { error: "not found" };
|
|
||||||
const extName = ext.constructor.name;
|
|
||||||
const cached = await (0, queries_1.getCachedExtension)(extName, id);
|
|
||||||
if (cached) {
|
|
||||||
try {
|
|
||||||
console.log(`[${extName}] Metadata cache hit for ID: ${id}`);
|
|
||||||
return JSON.parse(cached.metadata);
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((ext.type === 'anime-board') && ext.getMetadata) {
|
|
||||||
try {
|
|
||||||
const match = await ext.getMetadata(id);
|
|
||||||
if (match) {
|
|
||||||
const normalized = {
|
|
||||||
title: match.title ?? "Unknown",
|
|
||||||
summary: match.summary ?? "No summary available",
|
|
||||||
episodes: Number(match.episodes) || 0,
|
|
||||||
characters: Array.isArray(match.characters) ? match.characters : [],
|
|
||||||
season: match.season ?? null,
|
|
||||||
status: match.status ?? "Unknown",
|
|
||||||
studio: match.studio ?? "Unknown",
|
|
||||||
score: Number(match.score) || 0,
|
|
||||||
year: match.year ?? null,
|
|
||||||
genres: Array.isArray(match.genres) ? match.genres : [],
|
|
||||||
image: match.image ?? ""
|
|
||||||
};
|
|
||||||
await (0, queries_1.cacheExtension)(extName, id, normalized.title, normalized);
|
|
||||||
return normalized;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error(`Extension getMetadata failed:`, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { error: "not found" };
|
|
||||||
}
|
|
||||||
async function searchAnimeInExtension(ext, name, query) {
|
|
||||||
if (!ext)
|
|
||||||
return [];
|
|
||||||
if (ext.type === 'anime-board' && ext.search) {
|
|
||||||
try {
|
|
||||||
console.log(`[${name}] Searching for anime: ${query}`);
|
|
||||||
const matches = await ext.search({
|
|
||||||
query: query,
|
|
||||||
media: {
|
|
||||||
romajiTitle: query,
|
|
||||||
englishTitle: query,
|
|
||||||
startDate: { year: 0, month: 0, day: 0 }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (matches && matches.length > 0) {
|
|
||||||
return matches.map(m => ({
|
|
||||||
id: m.id,
|
|
||||||
extensionName: name,
|
|
||||||
title: { romaji: m.title, english: m.title, native: null },
|
|
||||||
coverImage: { large: m.image || '' },
|
|
||||||
averageScore: m.rating || m.score || null,
|
|
||||||
format: 'ANIME',
|
|
||||||
seasonYear: null,
|
|
||||||
isExtensionResult: true,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error(`Extension search failed for ${name}:`, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
async function searchEpisodesInExtension(ext, name, query) {
|
|
||||||
if (!ext)
|
|
||||||
return [];
|
|
||||||
const cacheKey = `anime:episodes:${name}:${query}`;
|
|
||||||
const cached = await (0, queries_1.getCache)(cacheKey);
|
|
||||||
if (cached) {
|
|
||||||
const isExpired = Date.now() - cached.created_at > CACHE_TTL_MS;
|
|
||||||
if (!isExpired) {
|
|
||||||
console.log(`[${name}] Episodes cache hit for: ${query}`);
|
|
||||||
try {
|
|
||||||
return JSON.parse(cached.result);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error(`[${name}] Error parsing cached episodes:`, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log(`[${name}] Episodes cache expired for: ${query}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ext.type === "anime-board" && ext.search && typeof ext.findEpisodes === "function") {
|
|
||||||
try {
|
|
||||||
const title = await (0, queries_1.getExtensionTitle)(name, query);
|
|
||||||
let mediaId;
|
|
||||||
if (!title) {
|
|
||||||
const matches = await ext.search({
|
|
||||||
query,
|
|
||||||
media: {
|
|
||||||
romajiTitle: query,
|
|
||||||
englishTitle: query,
|
|
||||||
startDate: { year: 0, month: 0, day: 0 }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!matches || matches.length === 0)
|
|
||||||
return [];
|
|
||||||
const res = matches[0];
|
|
||||||
if (!res?.id)
|
|
||||||
return [];
|
|
||||||
mediaId = res.id;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mediaId = query;
|
|
||||||
}
|
|
||||||
const chapterList = await ext.findEpisodes(mediaId);
|
|
||||||
if (!Array.isArray(chapterList))
|
|
||||||
return [];
|
|
||||||
const result = chapterList.map(ep => ({
|
|
||||||
id: ep.id,
|
|
||||||
number: ep.number,
|
|
||||||
url: ep.url,
|
|
||||||
title: ep.title
|
|
||||||
}));
|
|
||||||
await (0, queries_1.setCache)(cacheKey, result, CACHE_TTL_MS);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error(`Extension search failed for ${name}:`, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
async function getStreamData(extension, episode, id, source, server, category) {
|
|
||||||
const providerName = extension.constructor.name;
|
|
||||||
const cacheKey = `anime:stream:${providerName}:${id}:${episode}:${server || 'default'}:${category || 'sub'}`;
|
|
||||||
const cached = await (0, queries_1.getCache)(cacheKey);
|
|
||||||
if (cached) {
|
|
||||||
const isExpired = Date.now() - cached.created_at > CACHE_TTL_MS;
|
|
||||||
if (!isExpired) {
|
|
||||||
console.log(`[${providerName}] Stream data cache hit for episode ${episode}`);
|
|
||||||
try {
|
|
||||||
return JSON.parse(cached.result);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error(`[${providerName}] Error parsing cached stream data:`, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log(`[${providerName}] Stream data cache expired for episode ${episode}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!extension.findEpisodes || !extension.findEpisodeServer) {
|
|
||||||
throw new Error("Extension doesn't support required methods");
|
|
||||||
}
|
|
||||||
let episodes;
|
|
||||||
if (source === "anilist") {
|
|
||||||
const anime = await getAnimeById(id);
|
|
||||||
episodes = await searchEpisodesInExtension(extension, extension.constructor.name, anime.title.romaji);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
episodes = await extension.findEpisodes(id);
|
|
||||||
}
|
|
||||||
const targetEp = episodes.find(e => e.number === parseInt(episode));
|
|
||||||
if (!targetEp) {
|
|
||||||
throw new Error("Episode not found");
|
|
||||||
}
|
|
||||||
const serverName = server || "default";
|
|
||||||
const streamData = await extension.findEpisodeServer(targetEp, serverName);
|
|
||||||
await (0, queries_1.setCache)(cacheKey, streamData, CACHE_TTL_MS);
|
|
||||||
return streamData;
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || (function () {
|
|
||||||
var ownKeys = function(o) {
|
|
||||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
||||||
var ar = [];
|
|
||||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
||||||
return ar;
|
|
||||||
};
|
|
||||||
return ownKeys(o);
|
|
||||||
};
|
|
||||||
return function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.getBook = getBook;
|
|
||||||
exports.getTrending = getTrending;
|
|
||||||
exports.getPopular = getPopular;
|
|
||||||
exports.searchBooks = searchBooks;
|
|
||||||
exports.searchBooksInExtension = searchBooksInExtension;
|
|
||||||
exports.getChapters = getChapters;
|
|
||||||
exports.getChapterContent = getChapterContent;
|
|
||||||
const booksService = __importStar(require("./books.service"));
|
|
||||||
const extensions_1 = require("../../shared/extensions");
|
|
||||||
async function getBook(req, reply) {
|
|
||||||
try {
|
|
||||||
const { id } = req.params;
|
|
||||||
const source = req.query.source;
|
|
||||||
let book;
|
|
||||||
if (source === 'anilist') {
|
|
||||||
book = await booksService.getBookById(id);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const ext = (0, extensions_1.getExtension)(source);
|
|
||||||
const result = await booksService.getBookInfoExtension(ext, id);
|
|
||||||
book = result || null;
|
|
||||||
}
|
|
||||||
return book;
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
return { error: err.message };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getTrending(req, reply) {
|
|
||||||
try {
|
|
||||||
const results = await booksService.getTrendingBooks();
|
|
||||||
return { results };
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
return { results: [] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getPopular(req, reply) {
|
|
||||||
try {
|
|
||||||
const results = await booksService.getPopularBooks();
|
|
||||||
return { results };
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
return { results: [] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function searchBooks(req, reply) {
|
|
||||||
try {
|
|
||||||
const query = req.query.q;
|
|
||||||
const dbResults = await booksService.searchBooksLocal(query);
|
|
||||||
if (dbResults.length > 0) {
|
|
||||||
return { results: dbResults };
|
|
||||||
}
|
|
||||||
console.log(`[Books] Local DB miss for "${query}", fetching live...`);
|
|
||||||
const anilistResults = await booksService.searchBooksAniList(query);
|
|
||||||
if (anilistResults.length > 0) {
|
|
||||||
return { results: anilistResults };
|
|
||||||
}
|
|
||||||
return { results: [] };
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
const error = e;
|
|
||||||
console.error("Search Error:", error.message);
|
|
||||||
return { results: [] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function searchBooksInExtension(req, reply) {
|
|
||||||
try {
|
|
||||||
const extensionName = req.params.extension;
|
|
||||||
const query = req.query.q;
|
|
||||||
const ext = (0, extensions_1.getExtension)(extensionName);
|
|
||||||
if (!ext)
|
|
||||||
return { results: [] };
|
|
||||||
const results = await booksService.searchBooksInExtension(ext, extensionName, query);
|
|
||||||
return { results };
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
const error = e;
|
|
||||||
console.error("Search Error:", error.message);
|
|
||||||
return { results: [] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getChapters(req, reply) {
|
|
||||||
try {
|
|
||||||
const { id } = req.params;
|
|
||||||
const source = req.query.source || 'anilist';
|
|
||||||
const isExternal = source !== 'anilist';
|
|
||||||
return await booksService.getChaptersForBook(id, isExternal);
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return { chapters: [] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getChapterContent(req, reply) {
|
|
||||||
try {
|
|
||||||
const { bookId, chapter, provider } = req.params;
|
|
||||||
const source = req.query.source || 'anilist';
|
|
||||||
const content = await booksService.getChapterContent(bookId, chapter, provider, source);
|
|
||||||
return reply.send(content);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.error("getChapterContent error:", err.message);
|
|
||||||
return reply.code(500).send({ error: "Error loading chapter" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || (function () {
|
|
||||||
var ownKeys = function(o) {
|
|
||||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
||||||
var ar = [];
|
|
||||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
||||||
return ar;
|
|
||||||
};
|
|
||||||
return ownKeys(o);
|
|
||||||
};
|
|
||||||
return function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const controller = __importStar(require("./books.controller"));
|
|
||||||
async function booksRoutes(fastify) {
|
|
||||||
fastify.get('/book/:id', controller.getBook);
|
|
||||||
fastify.get('/books/trending', controller.getTrending);
|
|
||||||
fastify.get('/books/popular', controller.getPopular);
|
|
||||||
fastify.get('/search/books', controller.searchBooks);
|
|
||||||
fastify.get('/search/books/:extension', controller.searchBooksInExtension);
|
|
||||||
fastify.get('/book/:id/chapters', controller.getChapters);
|
|
||||||
fastify.get('/book/:bookId/:chapter/:provider', controller.getChapterContent);
|
|
||||||
}
|
|
||||||
exports.default = booksRoutes;
|
|
||||||
@@ -1,493 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.getBookById = getBookById;
|
|
||||||
exports.getTrendingBooks = getTrendingBooks;
|
|
||||||
exports.getPopularBooks = getPopularBooks;
|
|
||||||
exports.searchBooksLocal = searchBooksLocal;
|
|
||||||
exports.searchBooksAniList = searchBooksAniList;
|
|
||||||
exports.getBookInfoExtension = getBookInfoExtension;
|
|
||||||
exports.searchBooksInExtension = searchBooksInExtension;
|
|
||||||
exports.getChaptersForBook = getChaptersForBook;
|
|
||||||
exports.getChapterContent = getChapterContent;
|
|
||||||
const queries_1 = require("../../shared/queries");
|
|
||||||
const database_1 = require("../../shared/database");
|
|
||||||
const extensions_1 = require("../../shared/extensions");
|
|
||||||
const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
||||||
const TTL = 60 * 60 * 6;
|
|
||||||
const ANILIST_URL = "https://graphql.anilist.co";
|
|
||||||
async function fetchAniList(query, variables) {
|
|
||||||
const res = await fetch(ANILIST_URL, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"Accept": "application/json"
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ query, variables })
|
|
||||||
});
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(`AniList error ${res.status}`);
|
|
||||||
}
|
|
||||||
const json = await res.json();
|
|
||||||
return json?.data;
|
|
||||||
}
|
|
||||||
const MEDIA_FIELDS = `
|
|
||||||
id
|
|
||||||
title {
|
|
||||||
romaji
|
|
||||||
english
|
|
||||||
native
|
|
||||||
userPreferred
|
|
||||||
}
|
|
||||||
type
|
|
||||||
format
|
|
||||||
status
|
|
||||||
description
|
|
||||||
startDate { year month day }
|
|
||||||
endDate { year month day }
|
|
||||||
season
|
|
||||||
seasonYear
|
|
||||||
episodes
|
|
||||||
chapters
|
|
||||||
volumes
|
|
||||||
duration
|
|
||||||
genres
|
|
||||||
synonyms
|
|
||||||
averageScore
|
|
||||||
popularity
|
|
||||||
favourites
|
|
||||||
isAdult
|
|
||||||
siteUrl
|
|
||||||
coverImage {
|
|
||||||
extraLarge
|
|
||||||
large
|
|
||||||
medium
|
|
||||||
color
|
|
||||||
}
|
|
||||||
bannerImage
|
|
||||||
updatedAt
|
|
||||||
`;
|
|
||||||
async function getBookById(id) {
|
|
||||||
const row = await (0, database_1.queryOne)("SELECT full_data FROM books WHERE id = ?", [id]);
|
|
||||||
if (row) {
|
|
||||||
return JSON.parse(row.full_data);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
console.log(`[Book] Local miss for ID ${id}, fetching live...`);
|
|
||||||
const query = `
|
|
||||||
query ($id: Int) {
|
|
||||||
Media(id: $id, type: MANGA) {
|
|
||||||
id idMal title { romaji english native userPreferred } type format status description
|
|
||||||
startDate { year month day } endDate { year month day } season seasonYear seasonInt
|
|
||||||
episodes duration chapters volumes countryOfOrigin isLicensed source hashtag
|
|
||||||
trailer { id site thumbnail } updatedAt coverImage { extraLarge large medium color }
|
|
||||||
bannerImage genres synonyms averageScore meanScore popularity isLocked trending favourites
|
|
||||||
tags { id name description category rank isGeneralSpoiler isMediaSpoiler isAdult userId }
|
|
||||||
relations { edges { relationType node { id title { romaji } } } }
|
|
||||||
characters(page: 1, perPage: 10) { nodes { id name { full } } }
|
|
||||||
studios { nodes { id name isAnimationStudio } }
|
|
||||||
isAdult nextAiringEpisode { airingAt timeUntilAiring episode }
|
|
||||||
externalLinks { url site }
|
|
||||||
rankings { id rank type format year season allTime context }
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const response = await fetch('https://graphql.anilist.co', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
query,
|
|
||||||
variables: { id: parseInt(id.toString()) }
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const data = await response.json();
|
|
||||||
if (data?.data?.Media) {
|
|
||||||
const media = data.data.Media;
|
|
||||||
const insertSql = `
|
|
||||||
INSERT INTO books (id, title, updatedAt, full_data)
|
|
||||||
VALUES (?, ?, ?, ?)
|
|
||||||
ON CONFLICT(id) DO UPDATE SET
|
|
||||||
title = EXCLUDED.title,
|
|
||||||
updatedAt = EXCLUDED.updatedAt,
|
|
||||||
full_data = EXCLUDED.full_data;
|
|
||||||
`;
|
|
||||||
await (0, database_1.run)(insertSql, [
|
|
||||||
media.id,
|
|
||||||
media.title?.userPreferred || media.title?.romaji || media.title?.english || null,
|
|
||||||
media.updatedAt || Math.floor(Date.now() / 1000),
|
|
||||||
JSON.stringify(media)
|
|
||||||
]);
|
|
||||||
return media;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error("Fetch error:", e);
|
|
||||||
}
|
|
||||||
return { error: "Book not found" };
|
|
||||||
}
|
|
||||||
async function getTrendingBooks() {
|
|
||||||
const rows = await (0, database_1.queryAll)("SELECT full_data, updated_at FROM trending_books ORDER BY rank ASC LIMIT 10");
|
|
||||||
if (rows.length) {
|
|
||||||
const expired = (Date.now() / 1000 - rows[0].updated_at) > TTL;
|
|
||||||
if (!expired) {
|
|
||||||
return rows.map((r) => JSON.parse(r.full_data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const query = `
|
|
||||||
query {
|
|
||||||
Page(page: 1, perPage: 10) {
|
|
||||||
media(type: MANGA, sort: TRENDING_DESC) { ${MEDIA_FIELDS} }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const data = await fetchAniList(query, {});
|
|
||||||
const list = data?.Page?.media || [];
|
|
||||||
const now = Math.floor(Date.now() / 1000);
|
|
||||||
await (0, database_1.queryOne)("DELETE FROM trending_books");
|
|
||||||
let rank = 1;
|
|
||||||
for (const book of list) {
|
|
||||||
await (0, database_1.queryOne)("INSERT INTO trending_books (rank, id, full_data, updated_at) VALUES (?, ?, ?, ?)", [rank++, book.id, JSON.stringify(book), now]);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
async function getPopularBooks() {
|
|
||||||
const rows = await (0, database_1.queryAll)("SELECT full_data, updated_at FROM popular_books ORDER BY rank ASC LIMIT 10");
|
|
||||||
if (rows.length) {
|
|
||||||
const expired = (Date.now() / 1000 - rows[0].updated_at) > TTL;
|
|
||||||
if (!expired) {
|
|
||||||
return rows.map((r) => JSON.parse(r.full_data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const query = `
|
|
||||||
query {
|
|
||||||
Page(page: 1, perPage: 10) {
|
|
||||||
media(type: MANGA, sort: POPULARITY_DESC) { ${MEDIA_FIELDS} }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const data = await fetchAniList(query, {});
|
|
||||||
const list = data?.Page?.media || [];
|
|
||||||
const now = Math.floor(Date.now() / 1000);
|
|
||||||
await (0, database_1.queryOne)("DELETE FROM popular_books");
|
|
||||||
let rank = 1;
|
|
||||||
for (const book of list) {
|
|
||||||
await (0, database_1.queryOne)("INSERT INTO popular_books (rank, id, full_data, updated_at) VALUES (?, ?, ?, ?)", [rank++, book.id, JSON.stringify(book), now]);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
async function searchBooksLocal(query) {
|
|
||||||
if (!query || query.length < 2) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const sql = `SELECT full_data FROM books WHERE full_data LIKE ? LIMIT 50`;
|
|
||||||
const rows = await (0, database_1.queryAll)(sql, [`%${query}%`]);
|
|
||||||
const results = rows.map((row) => JSON.parse(row.full_data));
|
|
||||||
const clean = results.filter(book => {
|
|
||||||
const searchTerms = [
|
|
||||||
book.title.english,
|
|
||||||
book.title.romaji,
|
|
||||||
book.title.native,
|
|
||||||
...(book.synonyms || [])
|
|
||||||
].filter(Boolean).map(t => t.toLowerCase());
|
|
||||||
return searchTerms.some(term => term.includes(query.toLowerCase()));
|
|
||||||
});
|
|
||||||
return clean.slice(0, 10);
|
|
||||||
}
|
|
||||||
async function searchBooksAniList(query) {
|
|
||||||
const gql = `
|
|
||||||
query ($search: String) {
|
|
||||||
Page(page: 1, perPage: 5) {
|
|
||||||
media(search: $search, type: MANGA, isAdult: false) {
|
|
||||||
id title { romaji english native }
|
|
||||||
coverImage { extraLarge large }
|
|
||||||
bannerImage description averageScore format
|
|
||||||
seasonYear startDate { year }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const response = await fetch('https://graphql.anilist.co', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
|
|
||||||
body: JSON.stringify({ query: gql, variables: { search: query } })
|
|
||||||
});
|
|
||||||
const liveData = await response.json();
|
|
||||||
if (liveData.data && liveData.data.Page.media.length > 0) {
|
|
||||||
return liveData.data.Page.media;
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
async function getBookInfoExtension(ext, id) {
|
|
||||||
if (!ext)
|
|
||||||
return [];
|
|
||||||
const extName = ext.constructor.name;
|
|
||||||
const cached = await (0, queries_1.getCachedExtension)(extName, id);
|
|
||||||
if (cached) {
|
|
||||||
try {
|
|
||||||
return JSON.parse(cached.metadata);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
if (ext.type === 'book-board' && ext.getMetadata) {
|
|
||||||
try {
|
|
||||||
const info = await ext.getMetadata(id);
|
|
||||||
if (info) {
|
|
||||||
const normalized = {
|
|
||||||
id: info.id ?? id,
|
|
||||||
title: info.title ?? "",
|
|
||||||
format: info.format ?? "",
|
|
||||||
score: typeof info.score === "number" ? info.score : null,
|
|
||||||
genres: Array.isArray(info.genres) ? info.genres : [],
|
|
||||||
status: info.status ?? "",
|
|
||||||
published: info.published ?? "",
|
|
||||||
summary: info.summary ?? "",
|
|
||||||
chapters: Number.isFinite(info.chapters) ? info.chapters : 1,
|
|
||||||
image: typeof info.image === "string" ? info.image : ""
|
|
||||||
};
|
|
||||||
await (0, queries_1.cacheExtension)(extName, id, normalized.title, normalized);
|
|
||||||
return [normalized];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error(`Extension getInfo failed:`, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
async function searchBooksInExtension(ext, name, query) {
|
|
||||||
if (!ext)
|
|
||||||
return [];
|
|
||||||
if ((ext.type === 'book-board') && ext.search) {
|
|
||||||
try {
|
|
||||||
console.log(`[${name}] Searching for book: ${query}`);
|
|
||||||
const matches = await ext.search({
|
|
||||||
query: query,
|
|
||||||
media: {
|
|
||||||
romajiTitle: query,
|
|
||||||
englishTitle: query,
|
|
||||||
startDate: { year: 0, month: 0, day: 0 }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (matches?.length) {
|
|
||||||
return matches.map(m => ({
|
|
||||||
id: m.id,
|
|
||||||
extensionName: name,
|
|
||||||
title: { romaji: m.title, english: m.title, native: null },
|
|
||||||
coverImage: { large: m.image || '' },
|
|
||||||
averageScore: m.rating || m.score || null,
|
|
||||||
format: m.format,
|
|
||||||
seasonYear: null,
|
|
||||||
isExtensionResult: true
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error(`Extension search failed for ${name}:`, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
async function fetchBookMetadata(id) {
|
|
||||||
try {
|
|
||||||
const query = `query ($id: Int) {
|
|
||||||
Media(id: $id, type: MANGA) {
|
|
||||||
title { romaji english }
|
|
||||||
startDate { year month day }
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const res = await fetch('https://graphql.anilist.co', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ query, variables: { id: parseInt(id) } })
|
|
||||||
});
|
|
||||||
const d = await res.json();
|
|
||||||
return d.data?.Media || null;
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error("Failed to fetch book metadata:", e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function searchChaptersInExtension(ext, name, searchTitle, search, origin) {
|
|
||||||
const cacheKey = `chapters:${name}:${origin}:${search ? "search" : "id"}:${searchTitle}`;
|
|
||||||
const cached = await (0, queries_1.getCache)(cacheKey);
|
|
||||||
if (cached) {
|
|
||||||
const isExpired = Date.now() - cached.created_at > CACHE_TTL_MS;
|
|
||||||
if (!isExpired) {
|
|
||||||
console.log(`[${name}] Chapters cache hit for: ${searchTitle}`);
|
|
||||||
try {
|
|
||||||
return JSON.parse(cached.result);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error(`[${name}] Error parsing cached chapters:`, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log(`[${name}] Chapters cache expired for: ${searchTitle}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
console.log(`[${name}] Searching chapters for: ${searchTitle}`);
|
|
||||||
let mediaId;
|
|
||||||
if (search) {
|
|
||||||
const matches = await ext.search({
|
|
||||||
query: searchTitle,
|
|
||||||
media: {
|
|
||||||
romajiTitle: searchTitle,
|
|
||||||
englishTitle: searchTitle,
|
|
||||||
startDate: { year: 0, month: 0, day: 0 }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const best = matches?.[0];
|
|
||||||
if (!best) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
mediaId = best.id;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const match = await ext.getMetadata(searchTitle);
|
|
||||||
mediaId = match.id;
|
|
||||||
}
|
|
||||||
const chaps = await ext.findChapters(mediaId);
|
|
||||||
if (!chaps?.length) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
console.log(`[${name}] Found ${chaps.length} chapters.`);
|
|
||||||
const result = chaps.map((ch) => ({
|
|
||||||
id: ch.id,
|
|
||||||
number: parseFloat(ch.number.toString()),
|
|
||||||
title: ch.title,
|
|
||||||
date: ch.releaseDate,
|
|
||||||
provider: name,
|
|
||||||
index: ch.index
|
|
||||||
}));
|
|
||||||
await (0, queries_1.setCache)(cacheKey, result, CACHE_TTL_MS);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
const error = e;
|
|
||||||
console.error(`Failed to fetch chapters from ${name}:`, error.message);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getChaptersForBook(id, ext, onlyProvider) {
|
|
||||||
let bookData = null;
|
|
||||||
let searchTitle = "";
|
|
||||||
if (!ext) {
|
|
||||||
const result = await getBookById(id);
|
|
||||||
if (!result || "error" in result)
|
|
||||||
return { chapters: [] };
|
|
||||||
bookData = result;
|
|
||||||
const titles = [bookData.title.english, bookData.title.romaji].filter(Boolean);
|
|
||||||
searchTitle = titles[0];
|
|
||||||
}
|
|
||||||
const bookExtensions = (0, extensions_1.getBookExtensionsMap)();
|
|
||||||
let extension;
|
|
||||||
if (!searchTitle) {
|
|
||||||
for (const [name, ext] of bookExtensions) {
|
|
||||||
const title = await (0, queries_1.getExtensionTitle)(name, id);
|
|
||||||
if (title) {
|
|
||||||
searchTitle = title;
|
|
||||||
extension = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const allChapters = [];
|
|
||||||
let exts = "anilist";
|
|
||||||
if (ext)
|
|
||||||
exts = "ext";
|
|
||||||
for (const [name, ext] of bookExtensions) {
|
|
||||||
if (onlyProvider && name !== onlyProvider)
|
|
||||||
continue;
|
|
||||||
if (name == extension) {
|
|
||||||
const chapters = await searchChaptersInExtension(ext, name, id, false, exts);
|
|
||||||
allChapters.push(...chapters);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const chapters = await searchChaptersInExtension(ext, name, searchTitle, true, exts);
|
|
||||||
allChapters.push(...chapters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
chapters: allChapters.sort((a, b) => Number(a.number) - Number(b.number))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
async function getChapterContent(bookId, chapterIndex, providerName, source) {
|
|
||||||
const extensions = (0, extensions_1.getAllExtensions)();
|
|
||||||
const ext = extensions.get(providerName);
|
|
||||||
if (!ext) {
|
|
||||||
throw new Error("Provider not found");
|
|
||||||
}
|
|
||||||
const contentCacheKey = `content:${providerName}:${source}:${bookId}:${chapterIndex}`;
|
|
||||||
const cachedContent = await (0, queries_1.getCache)(contentCacheKey);
|
|
||||||
if (cachedContent) {
|
|
||||||
const isExpired = Date.now() - cachedContent.created_at > CACHE_TTL_MS;
|
|
||||||
if (!isExpired) {
|
|
||||||
console.log(`[${providerName}] Content cache hit for Book ID ${bookId}, Index ${chapterIndex}`);
|
|
||||||
try {
|
|
||||||
return JSON.parse(cachedContent.result);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error(`[${providerName}] Error parsing cached content:`, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log(`[${providerName}] Content cache expired for Book ID ${bookId}, Index ${chapterIndex}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const isExternal = source !== 'anilist';
|
|
||||||
const chapterList = await getChaptersForBook(bookId, isExternal, providerName);
|
|
||||||
if (!chapterList?.chapters || chapterList.chapters.length === 0) {
|
|
||||||
throw new Error("Chapters not found");
|
|
||||||
}
|
|
||||||
const providerChapters = chapterList.chapters.filter(c => c.provider === providerName);
|
|
||||||
const index = parseInt(chapterIndex, 10);
|
|
||||||
if (Number.isNaN(index)) {
|
|
||||||
throw new Error("Invalid chapter index");
|
|
||||||
}
|
|
||||||
if (!providerChapters[index]) {
|
|
||||||
throw new Error("Chapter index out of range");
|
|
||||||
}
|
|
||||||
const selectedChapter = providerChapters[index];
|
|
||||||
const chapterId = selectedChapter.id;
|
|
||||||
const chapterTitle = selectedChapter.title || null;
|
|
||||||
const chapterNumber = typeof selectedChapter.number === 'number' ? selectedChapter.number : index;
|
|
||||||
try {
|
|
||||||
if (!ext.findChapterPages) {
|
|
||||||
throw new Error("Extension doesn't support findChapterPages");
|
|
||||||
}
|
|
||||||
let contentResult;
|
|
||||||
if (ext.mediaType === "manga") {
|
|
||||||
const pages = await ext.findChapterPages(chapterId);
|
|
||||||
contentResult = {
|
|
||||||
type: "manga",
|
|
||||||
chapterId,
|
|
||||||
title: chapterTitle,
|
|
||||||
number: chapterNumber,
|
|
||||||
provider: providerName,
|
|
||||||
pages
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (ext.mediaType === "ln") {
|
|
||||||
const content = await ext.findChapterPages(chapterId);
|
|
||||||
contentResult = {
|
|
||||||
type: "ln",
|
|
||||||
chapterId,
|
|
||||||
title: chapterTitle,
|
|
||||||
number: chapterNumber,
|
|
||||||
provider: providerName,
|
|
||||||
content
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error("Unknown mediaType");
|
|
||||||
}
|
|
||||||
await (0, queries_1.setCache)(contentCacheKey, contentResult, CACHE_TTL_MS);
|
|
||||||
return contentResult;
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
const error = err;
|
|
||||||
console.error(`[Chapter] Error loading from ${providerName}:`, error.message);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.getExtensions = getExtensions;
|
|
||||||
exports.getAnimeExtensions = getAnimeExtensions;
|
|
||||||
exports.getBookExtensions = getBookExtensions;
|
|
||||||
exports.getGalleryExtensions = getGalleryExtensions;
|
|
||||||
exports.getExtensionSettings = getExtensionSettings;
|
|
||||||
exports.installExtension = installExtension;
|
|
||||||
exports.uninstallExtension = uninstallExtension;
|
|
||||||
const extensions_1 = require("../../shared/extensions");
|
|
||||||
async function getExtensions(req, reply) {
|
|
||||||
return { extensions: (0, extensions_1.getExtensionsList)() };
|
|
||||||
}
|
|
||||||
async function getAnimeExtensions(req, reply) {
|
|
||||||
const animeExtensions = (0, extensions_1.getAnimeExtensionsMap)();
|
|
||||||
return { extensions: Array.from(animeExtensions.keys()) };
|
|
||||||
}
|
|
||||||
async function getBookExtensions(req, reply) {
|
|
||||||
const bookExtensions = (0, extensions_1.getBookExtensionsMap)();
|
|
||||||
return { extensions: Array.from(bookExtensions.keys()) };
|
|
||||||
}
|
|
||||||
async function getGalleryExtensions(req, reply) {
|
|
||||||
const galleryExtensions = (0, extensions_1.getGalleryExtensionsMap)();
|
|
||||||
return { extensions: Array.from(galleryExtensions.keys()) };
|
|
||||||
}
|
|
||||||
async function getExtensionSettings(req, reply) {
|
|
||||||
const { name } = req.params;
|
|
||||||
const ext = (0, extensions_1.getExtension)(name);
|
|
||||||
if (!ext) {
|
|
||||||
return { error: "Extension not found" };
|
|
||||||
}
|
|
||||||
if (!ext.getSettings) {
|
|
||||||
return { episodeServers: ["default"], supportsDub: false };
|
|
||||||
}
|
|
||||||
return ext.getSettings();
|
|
||||||
}
|
|
||||||
async function installExtension(req, reply) {
|
|
||||||
const { fileName } = req.body;
|
|
||||||
if (!fileName || !fileName.endsWith('.js')) {
|
|
||||||
return reply.code(400).send({ error: "Invalid extension fileName provided" });
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const downloadUrl = `https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/${fileName}`;
|
|
||||||
await (0, extensions_1.saveExtensionFile)(fileName, downloadUrl);
|
|
||||||
req.server.log.info(`Extension installed: ${fileName}`);
|
|
||||||
return reply.code(200).send({ success: true, message: `Extension ${fileName} installed successfully.` });
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
req.server.log.error(`Failed to install extension ${fileName}:`, error);
|
|
||||||
return reply.code(500).send({ success: false, error: `Failed to install extension ${fileName}.` });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function uninstallExtension(req, reply) {
|
|
||||||
const { fileName } = req.body;
|
|
||||||
if (!fileName || !fileName.endsWith('.js')) {
|
|
||||||
return reply.code(400).send({ error: "Invalid extension fileName provided" });
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await (0, extensions_1.deleteExtensionFile)(fileName);
|
|
||||||
req.server.log.info(`Extension uninstalled: ${fileName}`);
|
|
||||||
return reply.code(200).send({ success: true, message: `Extension ${fileName} uninstalled successfully.` });
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
// @ts-ignore
|
|
||||||
if (error.code === 'ENOENT') {
|
|
||||||
return reply.code(200).send({ success: true, message: `Extension ${fileName} already uninstalled (file not found).` });
|
|
||||||
}
|
|
||||||
req.server.log.error(`Failed to uninstall extension ${fileName}:`, error);
|
|
||||||
return reply.code(500).send({ success: false, error: `Failed to uninstall extension ${fileName}.` });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || (function () {
|
|
||||||
var ownKeys = function(o) {
|
|
||||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
||||||
var ar = [];
|
|
||||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
||||||
return ar;
|
|
||||||
};
|
|
||||||
return ownKeys(o);
|
|
||||||
};
|
|
||||||
return function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const controller = __importStar(require("./extensions.controller"));
|
|
||||||
async function extensionsRoutes(fastify) {
|
|
||||||
fastify.get('/extensions', controller.getExtensions);
|
|
||||||
fastify.get('/extensions/anime', controller.getAnimeExtensions);
|
|
||||||
fastify.get('/extensions/book', controller.getBookExtensions);
|
|
||||||
fastify.get('/extensions/gallery', controller.getGalleryExtensions);
|
|
||||||
fastify.get('/extensions/:name/settings', controller.getExtensionSettings);
|
|
||||||
fastify.post('/extensions/install', controller.installExtension);
|
|
||||||
fastify.post('/extensions/uninstall', controller.uninstallExtension);
|
|
||||||
}
|
|
||||||
exports.default = extensionsRoutes;
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || (function () {
|
|
||||||
var ownKeys = function(o) {
|
|
||||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
||||||
var ar = [];
|
|
||||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
||||||
return ar;
|
|
||||||
};
|
|
||||||
return ownKeys(o);
|
|
||||||
};
|
|
||||||
return function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.searchInExtension = searchInExtension;
|
|
||||||
exports.getInfo = getInfo;
|
|
||||||
exports.getFavorites = getFavorites;
|
|
||||||
exports.getFavoriteById = getFavoriteById;
|
|
||||||
exports.addFavorite = addFavorite;
|
|
||||||
exports.removeFavorite = removeFavorite;
|
|
||||||
const galleryService = __importStar(require("./gallery.service"));
|
|
||||||
async function searchInExtension(req, reply) {
|
|
||||||
try {
|
|
||||||
const provider = req.query.provider;
|
|
||||||
const query = req.query.q || '';
|
|
||||||
const page = parseInt(req.query.page) || 1;
|
|
||||||
const perPage = parseInt(req.query.perPage) || 48;
|
|
||||||
if (!provider) {
|
|
||||||
return reply.code(400).send({ error: "Missing provider" });
|
|
||||||
}
|
|
||||||
return await galleryService.searchInExtension(provider, query, page, perPage);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.error("Gallery SearchInExtension Error:", err.message);
|
|
||||||
return {
|
|
||||||
results: [],
|
|
||||||
total: 0,
|
|
||||||
page: 1,
|
|
||||||
hasNextPage: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getInfo(req, reply) {
|
|
||||||
try {
|
|
||||||
const { id } = req.params;
|
|
||||||
const provider = req.query.provider;
|
|
||||||
return await galleryService.getGalleryInfo(id, provider);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
const error = err;
|
|
||||||
console.error("Gallery Info Error:", error.message);
|
|
||||||
return reply.code(404).send({ error: "Gallery item not found" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getFavorites(req, reply) {
|
|
||||||
try {
|
|
||||||
if (!req.user)
|
|
||||||
return reply.code(401).send({ error: "Unauthorized" });
|
|
||||||
const favorites = await galleryService.getFavorites(req.user.id);
|
|
||||||
return { favorites };
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.error("Get Favorites Error:", err.message);
|
|
||||||
return reply.code(500).send({ error: "Failed to retrieve favorites" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getFavoriteById(req, reply) {
|
|
||||||
try {
|
|
||||||
if (!req.user)
|
|
||||||
return reply.code(401).send({ error: "Unauthorized" });
|
|
||||||
const { id } = req.params;
|
|
||||||
const favorite = await galleryService.getFavoriteById(id, req.user.id);
|
|
||||||
if (!favorite) {
|
|
||||||
return reply.code(404).send({ error: "Favorite not found" });
|
|
||||||
}
|
|
||||||
return { favorite };
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.error("Get Favorite By ID Error:", err.message);
|
|
||||||
return reply.code(500).send({ error: "Failed to retrieve favorite" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function addFavorite(req, reply) {
|
|
||||||
try {
|
|
||||||
if (!req.user)
|
|
||||||
return reply.code(401).send({ error: "Unauthorized" });
|
|
||||||
const { id, title, image_url, thumbnail_url, tags, provider, headers } = req.body;
|
|
||||||
if (!id || !title || !image_url || !thumbnail_url) {
|
|
||||||
return reply.code(400).send({
|
|
||||||
error: "Missing required fields"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const result = await galleryService.addFavorite({
|
|
||||||
id,
|
|
||||||
user_id: req.user.id,
|
|
||||||
title,
|
|
||||||
image_url,
|
|
||||||
thumbnail_url,
|
|
||||||
tags: tags || '',
|
|
||||||
provider: provider || "",
|
|
||||||
headers: headers || ""
|
|
||||||
});
|
|
||||||
if (result.success) {
|
|
||||||
return reply.code(201).send(result);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return reply.code(409).send(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.error("Add Favorite Error:", err.message);
|
|
||||||
return reply.code(500).send({ error: "Failed to add favorite" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function removeFavorite(req, reply) {
|
|
||||||
try {
|
|
||||||
if (!req.user)
|
|
||||||
return reply.code(401).send({ error: "Unauthorized" });
|
|
||||||
const { id } = req.params;
|
|
||||||
const result = await galleryService.removeFavorite(id, req.user.id);
|
|
||||||
if (result.success) {
|
|
||||||
return { success: true, message: "Favorite removed successfully" };
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return reply.code(404).send({ error: "Favorite not found" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
console.error("Remove Favorite Error:", err.message);
|
|
||||||
return reply.code(500).send({ error: "Failed to remove favorite" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || (function () {
|
|
||||||
var ownKeys = function(o) {
|
|
||||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
||||||
var ar = [];
|
|
||||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
||||||
return ar;
|
|
||||||
};
|
|
||||||
return ownKeys(o);
|
|
||||||
};
|
|
||||||
return function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const controller = __importStar(require("./gallery.controller"));
|
|
||||||
async function galleryRoutes(fastify) {
|
|
||||||
fastify.get('/gallery/fetch/:id', controller.getInfo);
|
|
||||||
fastify.get('/gallery/search/provider', controller.searchInExtension);
|
|
||||||
fastify.get('/gallery/favorites', controller.getFavorites);
|
|
||||||
fastify.get('/gallery/favorites/:id', controller.getFavoriteById);
|
|
||||||
fastify.post('/gallery/favorites', controller.addFavorite);
|
|
||||||
fastify.delete('/gallery/favorites/:id', controller.removeFavorite);
|
|
||||||
}
|
|
||||||
exports.default = galleryRoutes;
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user