mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-06-03 13:44:33 -04:00
Merge pull request #3 from AnonymusRaccoon/dev
Adding transmuxing and method switching to the app.
This commit is contained in:
commit
7c04acfd5c
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,3 +1,12 @@
|
||||
## PROJECT CUSTOM IGNORES
|
||||
# Transcoder build (auto generated from Kyoo.Transcoder sub-project)
|
||||
Kyoo/Transcoder/Kyoo.Transcoder.dll
|
||||
Kyoo/Transcoder/Kyoo.Transcoder.ilk
|
||||
Kyoo/Transcoder/Kyoo.Transcoder.lib
|
||||
Kyoo/Transcoder/Kyoo.Transcoder.pdb
|
||||
Kyoo/Transcoder/Kyoo.Transcoder.exp
|
||||
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
|
@ -72,35 +72,35 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(ProjectDir)\ffmpeg\include;$(IncludePath)</IncludePath>
|
||||
<IncludePath>$(ProjectDir)\ffmpeg\include;./include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(ProjectDir)\ffmpeg\lib;$(LibraryPath)</LibraryPath>
|
||||
<OutDir>$(SolutionDir)Kyoo\Transcoder</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)Kyoo\Transcoder</OutDir>
|
||||
<IncludePath>$(ProjectDir)\ffmpeg\include;$(IncludePath)</IncludePath>
|
||||
<IncludePath>$(ProjectDir)\ffmpeg\include;./include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(ProjectDir)\ffmpeg\lib;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(ProjectDir)\ffmpeg\include;$(IncludePath)</IncludePath>
|
||||
<IncludePath>$(ProjectDir)\ffmpeg\include;./include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(ProjectDir)\ffmpeg\lib;$(LibraryPath)</LibraryPath>
|
||||
<OutDir>$(SolutionDir)Kyoo\Transcoder</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)Kyoo\Transcoder</OutDir>
|
||||
<IncludePath>$(ProjectDir)\ffmpeg\include;$(IncludePath)</IncludePath>
|
||||
<IncludePath>$(ProjectDir)\ffmpeg\include;./include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(ProjectDir)\ffmpeg\lib;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;KYOOTRANSCODER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);TRANSCODER_EXPORTS=1</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;KYOOTRANSCODER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);TRANSCODER_EXPORTS=1;_CRT_NONSTDC_NO_DEPRECATE</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
@ -115,11 +115,11 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;KYOOTRANSCODER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);TRANSCODER_EXPORTS=1</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_DEBUG;KYOOTRANSCODER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);TRANSCODER_EXPORTS=1;_CRT_NONSTDC_NO_DEPRECATE</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
@ -135,13 +135,13 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;KYOOTRANSCODER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);TRANSCODER_EXPORTS=1</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;KYOOTRANSCODER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);TRANSCODER_EXPORTS=1;_CRT_NONSTDC_NO_DEPRECATE</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
@ -158,13 +158,13 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;KYOOTRANSCODER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);TRANSCODER_EXPORTS=1</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>NDEBUG;KYOOTRANSCODER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);TRANSCODER_EXPORTS=1;_CRT_NONSTDC_NO_DEPRECATE</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
@ -181,19 +181,12 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src/framework.h" />
|
||||
<ClInclude Include="src/pch.h" />
|
||||
<ClInclude Include="src/Stream.h" />
|
||||
<ClInclude Include="src/Transcoder.h" />
|
||||
<ClInclude Include="include/helper.h" />
|
||||
<ClInclude Include="include/Stream.h" />
|
||||
<ClInclude Include="include/Transcoder.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src/dllmain.cpp" />
|
||||
<ClCompile Include="src/pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src/helper.cpp" />
|
||||
<ClCompile Include="src/Transcoder.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
@ -12,30 +12,27 @@
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Headers">
|
||||
<UniqueIdentifier>{851d2dff-3186-4d12-9f4a-4144143be6fb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src/Transcoder.h">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClInclude Include="include/helper.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src/pch.h">
|
||||
<Filter>Compiler Files</Filter>
|
||||
<ClInclude Include="include/Stream.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src/framework.h">
|
||||
<Filter>Compiler Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src/Stream.h">
|
||||
<Filter>Models</Filter>
|
||||
<ClInclude Include="include/Transcoder.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src/Transcoder.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src/pch.cpp">
|
||||
<Filter>Compiler Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src/dllmain.cpp">
|
||||
<Filter>Compiler Files</Filter>
|
||||
<ClCompile Include="src/helper.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
11
Kyoo.Transcoder/include/helper.h
Normal file
11
Kyoo.Transcoder/include/helper.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
extern "C"
|
||||
{
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/dict.h>
|
||||
#include <libavutil/timestamp.h>
|
||||
}
|
||||
int open_input_context(AVFormatContext** inputContext, const char* path);
|
||||
AVStream* copy_stream_to_output(AVFormatContext* out_ctx, AVStream* in_stream);
|
||||
int open_output_file_for_write(AVFormatContext* out_ctx, const char* out_path, AVDictionary **options);
|
||||
void process_packet(AVPacket& pkt, AVStream* in_stream, AVStream* out_stream);
|
49
Kyoo.Transcoder/include/stream.h
Normal file
49
Kyoo.Transcoder/include/stream.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
extern "C" struct Stream
|
||||
{
|
||||
char *title;
|
||||
char *language;
|
||||
char *codec;
|
||||
bool is_default;
|
||||
bool is_forced;
|
||||
char *path;
|
||||
|
||||
Stream()
|
||||
: title(nullptr), language(nullptr), codec(nullptr), is_default(nullptr), is_forced(nullptr), path(nullptr) {}
|
||||
|
||||
Stream(const char* title, const char* languageCode, const char* codec, bool isDefault, bool isForced)
|
||||
: title(nullptr), language(nullptr), codec(nullptr), is_default(isDefault), is_forced(isForced), path(nullptr)
|
||||
{
|
||||
if(title != nullptr)
|
||||
this->title= strdup(title);
|
||||
|
||||
if (languageCode != nullptr)
|
||||
language = strdup(languageCode);
|
||||
else
|
||||
language = strdup("und");
|
||||
|
||||
if (codec != nullptr)
|
||||
this->codec = strdup(codec);
|
||||
}
|
||||
|
||||
Stream(const char *title, const char *languageCode, const char *codec, bool isDefault, bool isForced, const char *path)
|
||||
: title(nullptr), language(nullptr), codec(nullptr), is_default(isDefault), is_forced(isForced), path(nullptr)
|
||||
{
|
||||
if (title != nullptr)
|
||||
this->title = strdup(title);
|
||||
|
||||
if (languageCode != nullptr)
|
||||
language = strdup(languageCode);
|
||||
else
|
||||
language = strdup("und");
|
||||
|
||||
if (codec != nullptr)
|
||||
this->codec = strdup(codec);
|
||||
|
||||
if (path != nullptr)
|
||||
this->path = strdup(path);
|
||||
}
|
||||
};
|
@ -11,11 +11,11 @@
|
||||
|
||||
extern "C" API int Init();
|
||||
|
||||
extern "C" API int Transmux(const char *path, const char *outPath);
|
||||
extern "C" API int transmux(const char *path, const char *out_path, float *playable_duration);
|
||||
|
||||
extern "C" API Stream *get_track_info(const char *path, int *stream_count, int *track_count);
|
||||
|
||||
//Take the path of the file and the path of the output directory. It will return the list of subtitle streams in the streams variable. The int returned is the number of subtitles extracted.
|
||||
extern "C" API Stream* ExtractSubtitles(const char *path, const char *outPath, int *streamCount, int *subtitleCount);
|
||||
extern "C" API Stream* extract_subtitles(const char *path, const char *outPath, int *streamCount, int *subtitleCount);
|
||||
|
||||
extern "C" API void FreeMemory(Stream *streamsPtr);
|
||||
|
||||
extern "C" API Stream* TestMemory(const char *path, const char *outPath, int *streamCount, int *subtitleCount);
|
||||
extern "C" API void free_memory(Stream *streamsPtr);
|
@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
#ifdef TRANSCODER_EXPORTS
|
||||
#define API __declspec(dllexport)
|
||||
#else
|
||||
#define API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
extern "C" struct Stream
|
||||
{
|
||||
char *title;
|
||||
char *language;
|
||||
char *codec;
|
||||
bool isDefault;
|
||||
bool isForced;
|
||||
char *path;
|
||||
|
||||
Stream()
|
||||
: title(NULL), language(NULL), codec(NULL), isDefault(NULL), isForced(NULL), path(NULL) {}
|
||||
|
||||
Stream(const char* title, const char* languageCode, const char* codec, bool isDefault, bool isForced)
|
||||
: title(NULL), language(NULL), codec(NULL), isDefault(isDefault), isForced(isForced), path(NULL)
|
||||
{
|
||||
if(title != NULL)
|
||||
this->title= _strdup(title);
|
||||
|
||||
if (languageCode != NULL)
|
||||
language = _strdup(languageCode);
|
||||
else
|
||||
language = _strdup("und");
|
||||
|
||||
if (codec != NULL)
|
||||
this->codec = _strdup(codec);
|
||||
}
|
||||
};
|
@ -1,197 +1,96 @@
|
||||
#include "pch.h"
|
||||
#include <filesystem>
|
||||
#include <sstream>
|
||||
#include "Transcoder.h"
|
||||
|
||||
//ffmpeg imports
|
||||
extern "C"
|
||||
{
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/dict.h>
|
||||
#include <libavutil/timestamp.h>
|
||||
}
|
||||
|
||||
constexpr enum AVRounding operator |(const enum AVRounding a, const enum AVRounding b)
|
||||
{
|
||||
return (enum AVRounding)(uint32_t(a) | uint32_t(b));
|
||||
}
|
||||
#include "transcoder.h"
|
||||
#include "helper.h"
|
||||
|
||||
int Init()
|
||||
{
|
||||
return sizeof(Stream);
|
||||
}
|
||||
|
||||
|
||||
#pragma region InternalProcess
|
||||
int open_input_context(AVFormatContext **inputContext, const char *path)
|
||||
int transmux(const char *path, const char *out_path, float *playable_duration)
|
||||
{
|
||||
if (avformat_open_input(inputContext, path, NULL, NULL))
|
||||
{
|
||||
std::cout << "Error: Can't open the file at " << path << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (avformat_find_stream_info(*inputContext, NULL) < 0)
|
||||
{
|
||||
std::cout << "Error: Could't find streams informations for the file at " << path << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
av_dump_format(*inputContext, 0, path, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVStream* copy_stream_to_output(AVFormatContext *outputContext, AVStream *inputStream)
|
||||
{
|
||||
AVStream *outputStream = avformat_new_stream(outputContext, NULL);
|
||||
if (outputStream == NULL)
|
||||
{
|
||||
std::cout << "Error: Couldn't create stream." << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (avcodec_parameters_copy(outputStream->codecpar, inputStream->codecpar) < 0)
|
||||
{
|
||||
std::cout << "Error: Couldn't copy parameters to the output file." << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
outputStream->codecpar->codec_tag = 0;
|
||||
|
||||
avformat_transfer_internal_stream_timing_info(outputContext->oformat, outputStream, inputStream, AVTimebaseSource::AVFMT_TBCF_AUTO);
|
||||
outputStream->time_base = av_add_q(av_stream_get_codec_timebase(outputStream), AVRational{ 0, 1 });
|
||||
outputStream->duration = av_rescale_q(inputStream->duration, inputStream->time_base, outputStream->time_base);
|
||||
outputStream->disposition = inputStream->disposition;
|
||||
outputStream->avg_frame_rate = inputStream->avg_frame_rate;
|
||||
outputStream->r_frame_rate = inputStream->r_frame_rate;
|
||||
|
||||
//av_dict_copy(&outputStream->metadata, inputStream->metadata, NULL);
|
||||
|
||||
//if (inputStream->nb_side_data)
|
||||
//{
|
||||
// for (int i = 0; i < inputStream->nb_side_data; i++)
|
||||
// {
|
||||
// std::cout << "Copying side packet #" << i << std::endl;
|
||||
|
||||
// AVPacketSideData *sidePkt = &inputStream->side_data[i];
|
||||
// uint8_t *newPkt = av_stream_new_side_data(outputStream, sidePkt->type, sidePkt->size);
|
||||
// if (newPkt == NULL)
|
||||
// {
|
||||
// std::cout << "Error copying side package." << std::endl;
|
||||
// //Should handle return here
|
||||
// return;
|
||||
// }
|
||||
// memcpy(newPkt, sidePkt->data, sidePkt->size);
|
||||
// }
|
||||
//}
|
||||
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
int open_output_file_for_write(AVFormatContext *outputContext, const char* outputPath)
|
||||
{
|
||||
if (!(outputContext->flags & AVFMT_NOFILE))
|
||||
{
|
||||
if (avio_open(&outputContext->pb, outputPath, AVIO_FLAG_WRITE) < 0)
|
||||
{
|
||||
std::cout << "Error: Couldn't open file at " << outputPath << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
std::cout << "Output flag set to AVFMT_NOFILE." << std::endl;
|
||||
|
||||
if (avformat_write_header(outputContext, NULL) < 0)
|
||||
{
|
||||
std::cout << "Error: Couldn't write headers to file at " << outputPath << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void process_packet(AVPacket &pkt, AVStream* inputStream, AVStream* outputStream)
|
||||
{
|
||||
pkt.pts = av_rescale_q_rnd(pkt.pts, inputStream->time_base, outputStream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
|
||||
pkt.dts = av_rescale_q_rnd(pkt.dts, inputStream->time_base, outputStream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
|
||||
pkt.duration = av_rescale_q(pkt.duration, inputStream->time_base, outputStream->time_base);
|
||||
pkt.pos = -1;
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
|
||||
|
||||
|
||||
int Transmux(const char *path, const char *outPath)
|
||||
{
|
||||
AVFormatContext *inputContext = NULL;
|
||||
AVFormatContext *in_ctx = NULL;
|
||||
AVFormatContext *out_ctx = NULL;
|
||||
AVStream *stream;
|
||||
AVPacket pkt;
|
||||
AVDictionary *options = NULL;
|
||||
int *stream_map;
|
||||
int stream_count;
|
||||
int ret = 0;
|
||||
|
||||
if (open_input_context(&inputContext, path) != 0)
|
||||
*playable_duration = 0;
|
||||
if (open_input_context(&in_ctx, path) != 0)
|
||||
return 1;
|
||||
|
||||
AVFormatContext *outputContext = NULL;
|
||||
if (avformat_alloc_output_context2(&outputContext, NULL, NULL, outPath) < 0)
|
||||
if (avformat_alloc_output_context2(&out_ctx, NULL, NULL, out_path) < 0)
|
||||
{
|
||||
std::cout << "Error: Couldn't create an output file." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int *streamsMap = new int[inputContext->nb_streams];
|
||||
int streamCount = 0;
|
||||
stream_map = new int[in_ctx->nb_streams];
|
||||
stream_count = 0;
|
||||
|
||||
for (unsigned int i = 0; i < inputContext->nb_streams; i++)
|
||||
for (unsigned int i = 0; i < in_ctx->nb_streams; i++)
|
||||
{
|
||||
AVStream *stream = inputContext->streams[i];
|
||||
stream = in_ctx->streams[i];
|
||||
if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
|
||||
{
|
||||
streamsMap[i] = streamCount;
|
||||
streamCount++;
|
||||
if (copy_stream_to_output(outputContext, stream) == NULL)
|
||||
stream_map[i] = stream_count;
|
||||
stream_count++;
|
||||
if (copy_stream_to_output(out_ctx, stream) == NULL)
|
||||
return 1;
|
||||
}
|
||||
else if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) //Should support multi-audio on a good format.
|
||||
{
|
||||
streamsMap[i] = streamCount;
|
||||
streamCount++;
|
||||
if (copy_stream_to_output(outputContext, stream) == NULL)
|
||||
stream_map[i] = stream_count;
|
||||
stream_count++;
|
||||
if (copy_stream_to_output(out_ctx, stream) == NULL)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
streamsMap[i] = -1;
|
||||
stream_map[i] = -1;
|
||||
}
|
||||
|
||||
av_dump_format(outputContext, 0, outPath, true);
|
||||
if (open_output_file_for_write(outputContext, outPath) != 0)
|
||||
av_dump_format(out_ctx, 0, out_path, true);
|
||||
|
||||
std::filesystem::create_directory(((std::string)out_path).substr(0, strrchr(out_path, '/') - out_path).append("/dash/"));
|
||||
av_dict_set(&options, "init_seg_name", "dash/init-stream$RepresentationID$.m4s", 0);
|
||||
av_dict_set(&options, "media_seg_name", "dash/chunk-stream$RepresentationID$-$Number%05d$.m4s", 0);
|
||||
av_dict_set(&options, "streaming", "1", 0);
|
||||
|
||||
if (open_output_file_for_write(out_ctx, out_path, &options) != 0)
|
||||
return 1;
|
||||
|
||||
AVPacket pkt;
|
||||
while (av_read_frame(inputContext, &pkt) == 0)
|
||||
while (av_read_frame(in_ctx, &pkt) == 0)
|
||||
{
|
||||
if (pkt.stream_index >= inputContext->nb_streams || streamsMap[pkt.stream_index] < 0)
|
||||
if ((unsigned int)pkt.stream_index >= in_ctx->nb_streams || stream_map[pkt.stream_index] < 0)
|
||||
{
|
||||
av_packet_unref(&pkt);
|
||||
continue;
|
||||
}
|
||||
|
||||
AVStream *inputStream = inputContext->streams[pkt.stream_index];
|
||||
pkt.stream_index = streamsMap[pkt.stream_index];
|
||||
AVStream *outputStream = outputContext->streams[pkt.stream_index];
|
||||
stream = in_ctx->streams[pkt.stream_index];
|
||||
pkt.stream_index = stream_map[pkt.stream_index];
|
||||
process_packet(pkt, stream, out_ctx->streams[pkt.stream_index]);
|
||||
if (pkt.stream_index == 0)
|
||||
*playable_duration += pkt.duration * (float)out_ctx->streams[pkt.stream_index]->time_base.num / out_ctx->streams[pkt.stream_index]->time_base.den;
|
||||
|
||||
process_packet(pkt, inputStream, outputStream);
|
||||
|
||||
if (av_interleaved_write_frame(outputContext, &pkt) < 0)
|
||||
if (av_interleaved_write_frame(out_ctx, &pkt) < 0)
|
||||
std::cout << "Error while writing a packet to the output file." << std::endl;
|
||||
|
||||
av_packet_unref(&pkt);
|
||||
}
|
||||
|
||||
av_write_trailer(outputContext);
|
||||
avformat_close_input(&inputContext);
|
||||
av_dict_free(&options);
|
||||
av_write_trailer(out_ctx);
|
||||
avformat_close_input(&in_ctx);
|
||||
|
||||
if (outputContext && !(outputContext->oformat->flags & AVFMT_NOFILE))
|
||||
avio_closep(&outputContext->pb);
|
||||
avformat_free_context(outputContext);
|
||||
delete[] streamsMap;
|
||||
if (out_ctx && !(out_ctx->oformat->flags & AVFMT_NOFILE))
|
||||
avio_close(out_ctx->pb);
|
||||
avformat_free_context(out_ctx);
|
||||
delete[] stream_map;
|
||||
|
||||
if (ret < 0 && ret != AVERROR_EOF)
|
||||
return 1;
|
||||
@ -199,154 +98,195 @@ int Transmux(const char *path, const char *outPath)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Stream *ExtractSubtitles(const char *path, const char *outPath, int *streamCount, int *subtitleCount)
|
||||
Stream *get_track_info(const char *path, int *stream_count, int *track_count)
|
||||
{
|
||||
AVFormatContext *inputContext = NULL;
|
||||
AVFormatContext *ctx = NULL;
|
||||
Stream *streams;
|
||||
|
||||
if (open_input_context(&inputContext, path) != 0)
|
||||
if (open_input_context(&ctx, path) != 0)
|
||||
return nullptr;
|
||||
|
||||
*streamCount = inputContext->nb_streams;
|
||||
*subtitleCount = 0;
|
||||
Stream *streams = new Stream[*streamCount];
|
||||
|
||||
const unsigned int outputCount = inputContext->nb_streams;
|
||||
AVFormatContext **outputList = new AVFormatContext*[outputCount];
|
||||
*stream_count = ctx->nb_streams;
|
||||
*track_count = 0;
|
||||
streams = new Stream[*stream_count];
|
||||
|
||||
//Initialize output and set headers.
|
||||
for (unsigned int i = 0; i < inputContext->nb_streams; i++)
|
||||
for (int i = 0; i < *stream_count; i++)
|
||||
{
|
||||
AVStream *inputStream = inputContext->streams[i];
|
||||
const AVCodecParameters *inputCodecpar = inputStream->codecpar;
|
||||
AVStream *stream = ctx->streams[i];
|
||||
const AVCodecParameters *codecpar = stream->codecpar;
|
||||
|
||||
if (inputCodecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)
|
||||
outputList[i] = NULL;
|
||||
if (codecpar->codec_type == AVMEDIA_TYPE_VIDEO || codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
{
|
||||
AVDictionaryEntry *languageptr = av_dict_get(stream->metadata, "language", NULL, 0);
|
||||
|
||||
*track_count += 1;
|
||||
|
||||
streams[i] = Stream(codecpar->codec_type == AVMEDIA_TYPE_VIDEO ? "VIDEO" : NULL, // title
|
||||
languageptr ? languageptr->value : NULL, // language
|
||||
avcodec_get_name(codecpar->codec_id), // format
|
||||
stream->disposition & AV_DISPOSITION_DEFAULT, // isDefault
|
||||
stream->disposition & AV_DISPOSITION_FORCED, // isForced
|
||||
path); // path
|
||||
}
|
||||
else
|
||||
streams[i] = Stream();
|
||||
}
|
||||
avformat_close_input(&ctx);
|
||||
return streams;
|
||||
}
|
||||
|
||||
Stream *extract_subtitles(const char *path, const char *out_path, int *stream_count, int *subtitle_count)
|
||||
{
|
||||
AVFormatContext *int_ctx = NULL;
|
||||
AVFormatContext **output_list;
|
||||
Stream *streams;
|
||||
AVPacket pkt;
|
||||
unsigned int out_count;
|
||||
|
||||
if (open_input_context(&int_ctx, path) != 0)
|
||||
return nullptr;
|
||||
|
||||
*stream_count = int_ctx->nb_streams;
|
||||
*subtitle_count = 0;
|
||||
streams = new Stream[*stream_count];
|
||||
|
||||
out_count = int_ctx->nb_streams;
|
||||
output_list = new AVFormatContext *[out_count];
|
||||
|
||||
//Initialize output and set headers.
|
||||
for (unsigned int i = 0; i < int_ctx->nb_streams; i++)
|
||||
{
|
||||
AVStream *in_stream = int_ctx->streams[i];
|
||||
const AVCodecParameters *in_codecpar = in_stream->codecpar;
|
||||
|
||||
if (in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)
|
||||
{
|
||||
output_list[i] = NULL;
|
||||
streams[i] = Stream();
|
||||
}
|
||||
else
|
||||
{
|
||||
*subtitleCount += 1;
|
||||
*subtitle_count += 1;
|
||||
|
||||
AVDictionaryEntry *languagePtr = av_dict_get(inputStream->metadata, "language", NULL, 0);
|
||||
AVDictionaryEntry *languageptr = av_dict_get(in_stream->metadata, "language", NULL, 0);
|
||||
|
||||
//Get metadata for file name
|
||||
streams[i] = Stream(NULL, //title
|
||||
languagePtr ? languagePtr->value : NULL, //language
|
||||
avcodec_get_name(inputCodecpar->codec_id), //format
|
||||
inputStream->disposition & AV_DISPOSITION_DEFAULT, //isDefault
|
||||
inputStream->disposition & AV_DISPOSITION_FORCED); //isForced
|
||||
languageptr ? languageptr->value : NULL, //language
|
||||
avcodec_get_name(in_codecpar->codec_id), //format
|
||||
in_stream->disposition & AV_DISPOSITION_DEFAULT, //isDefault
|
||||
in_stream->disposition & AV_DISPOSITION_FORCED); //isForced
|
||||
|
||||
//Create the language subfolder
|
||||
std::stringstream outStream;
|
||||
outStream << outPath << (char)std::filesystem::path::preferred_separator << streams[i].language;
|
||||
std::filesystem::create_directory(outStream.str());
|
||||
std::stringstream out_strstream;
|
||||
out_strstream << out_path << (char)std::filesystem::path::preferred_separator << streams[i].language;
|
||||
std::filesystem::create_directory(out_strstream.str());
|
||||
|
||||
//Get file name
|
||||
std::string fileName(path);
|
||||
size_t lastSeparator = fileName.find_last_of((char)std::filesystem::path::preferred_separator);
|
||||
fileName = fileName.substr(lastSeparator, fileName.find_last_of('.') - lastSeparator);
|
||||
std::string file_name(path);
|
||||
size_t last_separator = file_name.find_last_of((char)std::filesystem::path::preferred_separator);
|
||||
file_name = file_name.substr(last_separator, file_name.find_last_of('.') - last_separator);
|
||||
|
||||
//Construct output file name
|
||||
outStream << fileName << "." << streams[i].language;
|
||||
out_strstream << file_name << "." << streams[i].language;
|
||||
|
||||
if (streams[i].isDefault)
|
||||
outStream << ".default";
|
||||
if (streams[i].isForced)
|
||||
outStream << ".forced";
|
||||
if (streams[i].is_default)
|
||||
out_strstream << ".default";
|
||||
if (streams[i].is_forced)
|
||||
out_strstream << ".forced";
|
||||
|
||||
if (strcmp(streams[i].codec, "subrip") == 0)
|
||||
outStream << ".srt";
|
||||
out_strstream << ".srt";
|
||||
else if (strcmp(streams[i].codec, "ass") == 0)
|
||||
outStream << ".ass";
|
||||
out_strstream << ".ass";
|
||||
else
|
||||
{
|
||||
std::cout << "Unsupported subtitle codec: " << streams[i].codec << std::endl;
|
||||
outputList[i] = NULL;
|
||||
output_list[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
streams[i].path = _strdup(outStream.str().c_str());
|
||||
streams[i].path = strdup(out_strstream.str().c_str());
|
||||
|
||||
std::cout << "Stream #" << i << "(" << streams[i].language << "), stream type: " << inputCodecpar->codec_type << " codec: " << streams[i].codec << std::endl;
|
||||
std::cout << "Stream #" << i << "(" << streams[i].language << "), stream type: " << in_codecpar->codec_type << " codec: " << streams[i].codec << std::endl;
|
||||
|
||||
AVFormatContext *outputContext = NULL;
|
||||
if (avformat_alloc_output_context2(&outputContext, NULL, NULL, streams[i].path) < 0)
|
||||
AVFormatContext *out_ctx = NULL;
|
||||
if (avformat_alloc_output_context2(&out_ctx, NULL, NULL, streams[i].path) < 0)
|
||||
{
|
||||
std::cout << "Error: Couldn't create an output file." << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
av_dict_copy(&outputContext->metadata, inputContext->metadata, NULL);
|
||||
av_dict_copy(&out_ctx->metadata, int_ctx->metadata, NULL);
|
||||
|
||||
AVStream *outputStream = copy_stream_to_output(outputContext, inputStream);
|
||||
if (outputStream == NULL)
|
||||
AVStream *out_stream = copy_stream_to_output(out_ctx, in_stream);
|
||||
if (out_stream == NULL)
|
||||
goto end;
|
||||
|
||||
av_dump_format(outputContext, 0, streams[i].path, true);
|
||||
av_dump_format(out_ctx, 0, streams[i].path, true);
|
||||
|
||||
if (open_output_file_for_write(outputContext, streams[i].path) != 0)
|
||||
if (open_output_file_for_write(out_ctx, streams[i].path, NULL) != 0)
|
||||
goto end;
|
||||
|
||||
outputList[i] = outputContext;
|
||||
output_list[i] = out_ctx;
|
||||
|
||||
if (false)
|
||||
{
|
||||
end:
|
||||
if (outputContext && !(outputContext->flags & AVFMT_NOFILE))
|
||||
avio_closep(&outputContext->pb);
|
||||
avformat_free_context(outputContext);
|
||||
if (out_ctx && !(out_ctx->flags & AVFMT_NOFILE))
|
||||
avio_closep(&out_ctx->pb);
|
||||
avformat_free_context(out_ctx);
|
||||
|
||||
outputList[i] = nullptr;
|
||||
output_list[i] = nullptr;
|
||||
std::cout << "An error occured, cleaning up th output context for the stream #" << i << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Write subtitle data to files.
|
||||
AVPacket pkt;
|
||||
while (av_read_frame(inputContext, &pkt) == 0)
|
||||
while (av_read_frame(int_ctx, &pkt) == 0)
|
||||
{
|
||||
if (pkt.stream_index >= outputCount)
|
||||
if ((unsigned int)pkt.stream_index >= out_count)
|
||||
continue;
|
||||
|
||||
AVFormatContext *outputContext = outputList[pkt.stream_index];
|
||||
if (outputContext == nullptr)
|
||||
AVFormatContext *out_ctx = output_list[pkt.stream_index];
|
||||
if (out_ctx == nullptr)
|
||||
{
|
||||
av_packet_unref(&pkt);
|
||||
continue;
|
||||
}
|
||||
|
||||
AVStream *inputStream = inputContext->streams[pkt.stream_index];
|
||||
AVStream *outputStream = outputContext->streams[0];
|
||||
|
||||
process_packet(pkt, int_ctx->streams[pkt.stream_index], out_ctx->streams[0]);
|
||||
pkt.stream_index = 0;
|
||||
process_packet(pkt, inputStream, outputStream);
|
||||
|
||||
if (av_interleaved_write_frame(outputContext, &pkt) < 0)
|
||||
if (av_interleaved_write_frame(out_ctx, &pkt) < 0)
|
||||
std::cout << "Error while writing a packet to the output file." << std::endl;
|
||||
|
||||
av_packet_unref(&pkt);
|
||||
}
|
||||
|
||||
avformat_close_input(&inputContext);
|
||||
avformat_close_input(&int_ctx);
|
||||
|
||||
for (unsigned int i = 0; i < outputCount; i++)
|
||||
for (unsigned int i = 0; i < out_count; i++)
|
||||
{
|
||||
AVFormatContext *outputContext = outputList[i];
|
||||
AVFormatContext *out_ctx = output_list[i];
|
||||
|
||||
if (outputContext == NULL)
|
||||
if (out_ctx == NULL)
|
||||
continue;
|
||||
|
||||
av_write_trailer(outputContext);
|
||||
av_write_trailer(out_ctx);
|
||||
|
||||
if (outputContext && !(outputContext->flags & AVFMT_NOFILE))
|
||||
avio_closep(&outputContext->pb);
|
||||
avformat_free_context(outputContext);
|
||||
if (out_ctx && !(out_ctx->flags & AVFMT_NOFILE))
|
||||
avio_closep(&out_ctx->pb);
|
||||
avformat_free_context(out_ctx);
|
||||
}
|
||||
|
||||
delete[] outputList;
|
||||
delete[] output_list;
|
||||
return streams;
|
||||
}
|
||||
|
||||
void FreeMemory(Stream *streamsPtr)
|
||||
void free_memory(Stream *stream_ptr)
|
||||
{
|
||||
delete[] streamsPtr;
|
||||
delete[] stream_ptr;
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#include "pch.h"
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files
|
||||
#include <windows.h>
|
75
Kyoo.Transcoder/src/helper.cpp
Normal file
75
Kyoo.Transcoder/src/helper.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#include "helper.h"
|
||||
#include <iostream>
|
||||
|
||||
int open_input_context(AVFormatContext **in_ctx, const char *path)
|
||||
{
|
||||
if (avformat_open_input(in_ctx, path, NULL, NULL))
|
||||
{
|
||||
std::cout << "Error: Can't open the file at " << path << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (avformat_find_stream_info(*in_ctx, NULL) < 0)
|
||||
{
|
||||
std::cout << "Error: Could't find streams informations for the file at " << path << std::endl;
|
||||
return 1;
|
||||
}
|
||||
av_dump_format(*in_ctx, 0, path, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVStream *copy_stream_to_output(AVFormatContext *out_ctx, AVStream *in_stream)
|
||||
{
|
||||
AVStream *out_stream = avformat_new_stream(out_ctx, NULL);
|
||||
|
||||
if (out_stream == NULL)
|
||||
{
|
||||
std::cout << "Error: Couldn't create stream." << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
if (avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar) < 0)
|
||||
{
|
||||
std::cout << "Error: Couldn't copy parameters to the output file." << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
out_stream->codecpar->codec_tag = 0;
|
||||
avformat_transfer_internal_stream_timing_info(out_ctx->oformat, out_stream, in_stream, AVTimebaseSource::AVFMT_TBCF_AUTO);
|
||||
out_stream->time_base = av_add_q(av_stream_get_codec_timebase(out_stream), AVRational {0, 1});
|
||||
out_stream->duration = av_rescale_q(in_stream->duration, in_stream->time_base, out_stream->time_base);
|
||||
out_stream->disposition = in_stream->disposition;
|
||||
out_stream->avg_frame_rate = in_stream->avg_frame_rate;
|
||||
out_stream->r_frame_rate = in_stream->r_frame_rate;
|
||||
return out_stream;
|
||||
}
|
||||
|
||||
constexpr enum AVRounding operator |(const enum AVRounding a, const enum AVRounding b)
|
||||
{
|
||||
return (enum AVRounding)(uint32_t(a) | uint32_t(b));
|
||||
}
|
||||
|
||||
int open_output_file_for_write(AVFormatContext *out_ctx, const char *out_path, AVDictionary **options)
|
||||
{
|
||||
if (!(out_ctx->oformat->flags & AVFMT_NOFILE))
|
||||
{
|
||||
if (avio_open(&out_ctx->pb, out_path, AVIO_FLAG_WRITE) < 0)
|
||||
{
|
||||
std::cout << "Error: Couldn't open file at " << out_path << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
std::cout << "Output flag set to AVFMT_NOFILE." << std::endl;
|
||||
if (avformat_write_header(out_ctx, options) < 0)
|
||||
{
|
||||
std::cout << "Error: Couldn't write headers to file at " << out_path << std::endl;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void process_packet(AVPacket &pkt, AVStream *in_stream, AVStream *out_stream)
|
||||
{
|
||||
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
|
||||
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
|
||||
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
|
||||
pkt.pos = -1;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
|
@ -1,14 +0,0 @@
|
||||
// pch.h: This is a precompiled header file.
|
||||
// Files listed below are compiled only once, improving build performance for future builds.
|
||||
// This also affects IntelliSense performance, including code completion and many code browsing features.
|
||||
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
|
||||
// Do not add files here that you will be updating frequently as this negates the performance advantage.
|
||||
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
// add headers that you want to pre-compile here
|
||||
#include "framework.h"
|
||||
#include <iostream>
|
||||
|
||||
#endif //PCH_H
|
7
Kyoo/.editorconfig
Normal file
7
Kyoo/.editorconfig
Normal file
@ -0,0 +1,7 @@
|
||||
[*.cs]
|
||||
|
||||
# CS4014: Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
dotnet_diagnostic.CS4014.severity = silent
|
||||
|
||||
# IDE1006: Naming Styles
|
||||
dotnet_diagnostic.IDE1006.severity = none
|
8
Kyoo/.gitignore
vendored
8
Kyoo/.gitignore
vendored
@ -1,3 +1,11 @@
|
||||
## PROJECT CUSTOM IGNORES
|
||||
# Transcoder build (auto generated from Kyoo.Transcoder sub-project)
|
||||
Transcoder/Kyoo.Transcoder.dll
|
||||
Transcoder/Kyoo.Transcoder.ilk
|
||||
Transcoder/Kyoo.Transcoder.lib
|
||||
Transcoder/Kyoo.Transcoder.pdb
|
||||
|
||||
|
||||
/Properties/launchSettings.json
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
|
@ -32,8 +32,8 @@
|
||||
"scripts": [
|
||||
"./node_modules/jquery/dist/jquery.min.js",
|
||||
"./node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
|
||||
"./src/libraries/subtitles.js",
|
||||
"./node_modules/video.js/dist/video.min.js"
|
||||
"./node_modules/dashjs/dist/dash.all.min.js",
|
||||
"./src/libraries/subtitles.js"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
@ -56,7 +56,7 @@
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumWarning": "3mb",
|
||||
"maximumError": "5mb"
|
||||
},
|
||||
{
|
||||
|
302
Kyoo/ClientApp/package-lock.json
generated
302
Kyoo/ClientApp/package-lock.json
generated
@ -1134,21 +1134,6 @@
|
||||
"integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/runtime": {
|
||||
"version": "7.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.2.tgz",
|
||||
"integrity": "sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.3",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
|
||||
"integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/template": {
|
||||
"version": "7.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz",
|
||||
@ -1345,6 +1330,12 @@
|
||||
"integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/video.js": {
|
||||
"version": "7.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/video.js/-/video.js-7.3.2.tgz",
|
||||
"integrity": "sha512-r6oXapONKV4QRJ4K5/rOKlD9VdMQHY4JGVafJpf5ynDnJtV3PIxglS1i1VWNYQGZYGGL3aFDWedWNODLO4bxhw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/webpack-sources": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.5.tgz",
|
||||
@ -1364,20 +1355,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@videojs/http-streaming": {
|
||||
"version": "1.10.6",
|
||||
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-1.10.6.tgz",
|
||||
"integrity": "sha512-uPBuunHnxWeFRYxRX0j6h1IIWv3+QKvSkZGmW9TvqxWBqeNGSrQymR6tm1nVjQ2HhMVxVphQTUhUTTPDVWqmQg==",
|
||||
"requires": {
|
||||
"aes-decrypter": "3.0.0",
|
||||
"global": "^4.3.0",
|
||||
"m3u8-parser": "4.4.0",
|
||||
"mpd-parser": "0.8.1",
|
||||
"mux.js": "5.2.1",
|
||||
"url-toolkit": "^2.1.3",
|
||||
"video.js": "^6.8.0 || ^7.0.0"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz",
|
||||
@ -1604,16 +1581,6 @@
|
||||
"integrity": "sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==",
|
||||
"dev": true
|
||||
},
|
||||
"aes-decrypter": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.0.0.tgz",
|
||||
"integrity": "sha1-eEihwUW5/b9Xrj4rWxvHzwZEqPs=",
|
||||
"requires": {
|
||||
"commander": "^2.9.0",
|
||||
"global": "^4.3.2",
|
||||
"pkcs7": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"after": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
|
||||
@ -2787,6 +2754,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codem-isoboxer": {
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/codem-isoboxer/-/codem-isoboxer-0.3.6.tgz",
|
||||
"integrity": "sha512-LuO8/7LW6XuR5ERn1yavXAfodGRhuY2yP60JTZIw5yNYMCE5lUVbk3NFUCJxjnphQH+Xemp5hOGb1LgUXm00Xw=="
|
||||
},
|
||||
"collection-visit": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
|
||||
@ -2830,7 +2802,8 @@
|
||||
"commander": {
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
|
||||
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ=="
|
||||
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
|
||||
"dev": true
|
||||
},
|
||||
"commondir": {
|
||||
"version": "1.0.1",
|
||||
@ -3173,6 +3146,16 @@
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"dashjs": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dashjs/-/dashjs-3.0.0.tgz",
|
||||
"integrity": "sha512-XyVkjeHB4mqzf/Y7ARQ1IqbRBaee0osAulwCFV5ZNZ734wea8LbSC/23zKI32BulW7Kk6f7I6onW1WDMHRgz7Q==",
|
||||
"requires": {
|
||||
"codem-isoboxer": "0.3.6",
|
||||
"fast-deep-equal": "2.0.1",
|
||||
"imsc": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"date-format": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz",
|
||||
@ -3241,6 +3224,7 @@
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
|
||||
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"object-keys": "^1.0.12"
|
||||
}
|
||||
@ -3358,6 +3342,11 @@
|
||||
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
|
||||
"dev": true
|
||||
},
|
||||
"detect-browser": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-4.8.0.tgz",
|
||||
"integrity": "sha512-f4h2dFgzHUIpjpBLjhnDIteXv8VQiUm8XzAuzQtYUqECX/eKh67ykuiVoyb7Db7a0PUSmJa3OGXStG0CbQFUVw=="
|
||||
},
|
||||
"detect-indent": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
|
||||
@ -3452,11 +3441,6 @@
|
||||
"void-elements": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"dom-walk": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz",
|
||||
"integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg="
|
||||
},
|
||||
"domain-browser": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
|
||||
@ -3673,6 +3657,7 @@
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz",
|
||||
"integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es-to-primitive": "^1.2.0",
|
||||
"function-bind": "^1.1.1",
|
||||
@ -3686,6 +3671,7 @@
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
|
||||
"integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-callable": "^1.1.4",
|
||||
"is-date-object": "^1.0.1",
|
||||
@ -4013,8 +3999,7 @@
|
||||
"fast-deep-equal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
||||
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
|
||||
"dev": true
|
||||
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.0.0",
|
||||
@ -4170,14 +4155,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"for-each": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
|
||||
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
|
||||
"requires": {
|
||||
"is-callable": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"for-in": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
||||
@ -4289,16 +4266,17 @@
|
||||
"dev": true
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.7.tgz",
|
||||
"integrity": "sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==",
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz",
|
||||
"integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
},
|
||||
"genfun": {
|
||||
"version": "5.0.0",
|
||||
@ -4371,22 +4349,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"global": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz",
|
||||
"integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=",
|
||||
"requires": {
|
||||
"min-document": "^2.19.0",
|
||||
"process": "~0.5.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"process": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz",
|
||||
"integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8="
|
||||
}
|
||||
}
|
||||
},
|
||||
"globals": {
|
||||
"version": "9.18.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
|
||||
@ -4433,9 +4395,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
|
||||
"integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
|
||||
"version": "4.5.3",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
|
||||
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"neo-async": "^2.6.0",
|
||||
@ -4472,6 +4434,7 @@
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1"
|
||||
}
|
||||
@ -4517,7 +4480,8 @@
|
||||
"has-symbols": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
|
||||
"integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q="
|
||||
"integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
|
||||
"dev": true
|
||||
},
|
||||
"has-value": {
|
||||
"version": "1.0.0",
|
||||
@ -4730,9 +4694,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz",
|
||||
"integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==",
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
|
||||
"integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"agent-base": "^4.3.0",
|
||||
@ -4852,6 +4816,21 @@
|
||||
"resolve-cwd": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"imsc": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/imsc/-/imsc-1.1.0.tgz",
|
||||
"integrity": "sha512-z2aUE3X00O39fCgkLHEVbfKG/D9cBrmsbf4NjP7K1gQb06YBjgljq5nZD72HYMFG2lRJI7QY7v+JVxg6o6I/Jg==",
|
||||
"requires": {
|
||||
"sax": "1.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"sax": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
|
||||
"integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o="
|
||||
}
|
||||
}
|
||||
},
|
||||
"imurmurhash": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||
@ -4864,11 +4843,6 @@
|
||||
"integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
|
||||
"dev": true
|
||||
},
|
||||
"individual": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz",
|
||||
"integrity": "sha1-gzsJfa0jKU52EXqY+zjg2a1hu5c="
|
||||
},
|
||||
"infer-owner": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
|
||||
@ -5022,7 +4996,8 @@
|
||||
"is-callable": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
|
||||
"integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA=="
|
||||
"integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
|
||||
"dev": true
|
||||
},
|
||||
"is-data-descriptor": {
|
||||
"version": "0.1.4",
|
||||
@ -5047,7 +5022,8 @@
|
||||
"is-date-object": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
|
||||
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
|
||||
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
|
||||
"dev": true
|
||||
},
|
||||
"is-descriptor": {
|
||||
"version": "0.1.6",
|
||||
@ -5101,11 +5077,6 @@
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||
"dev": true
|
||||
},
|
||||
"is-function": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz",
|
||||
"integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU="
|
||||
},
|
||||
"is-glob": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
|
||||
@ -5170,6 +5141,7 @@
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
|
||||
"integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has": "^1.0.1"
|
||||
}
|
||||
@ -5184,6 +5156,7 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
|
||||
"integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-symbols": "^1.0.0"
|
||||
}
|
||||
@ -6379,11 +6352,6 @@
|
||||
"source-map-support": "^0.5.5"
|
||||
}
|
||||
},
|
||||
"keycode": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz",
|
||||
"integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ="
|
||||
},
|
||||
"killable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
|
||||
@ -6560,14 +6528,6 @@
|
||||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"m3u8-parser": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.4.0.tgz",
|
||||
"integrity": "sha512-iH2AygTFILtato+XAgnoPYzLHM4R3DjATj7Ozbk7EHdB2XoLF2oyOUguM7Kc4UVHbQHHL/QPaw98r7PbWzG0gg==",
|
||||
"requires": {
|
||||
"global": "^4.3.2"
|
||||
}
|
||||
},
|
||||
"magic-string": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz",
|
||||
@ -6867,14 +6827,6 @@
|
||||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
|
||||
"dev": true
|
||||
},
|
||||
"min-document": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
|
||||
"integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
|
||||
"requires": {
|
||||
"dom-walk": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"mini-css-extract-plugin": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz",
|
||||
@ -7021,15 +6973,6 @@
|
||||
"run-queue": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"mpd-parser": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.8.1.tgz",
|
||||
"integrity": "sha512-WBTJ1bKk8OLUIxBh6s1ju1e2yz/5CzhPbgi6P3F3kJHKhGy1Z+ElvEnuzEbtC/dnbRcJtMXazE3f93N5LLdp9Q==",
|
||||
"requires": {
|
||||
"global": "^4.3.2",
|
||||
"url-toolkit": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
@ -7058,11 +7001,6 @@
|
||||
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
|
||||
"dev": true
|
||||
},
|
||||
"mux.js": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.2.1.tgz",
|
||||
"integrity": "sha512-1t2payD3Y8izfZRq7tfUQlhL2fKzjeLr9v1/2qNCTkEQnd9Abtn1JgzsBgGZubEXh6lM5L8B0iLGoWQiukjtbQ=="
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
|
||||
@ -7372,7 +7310,8 @@
|
||||
"object-keys": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
|
||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||
"dev": true
|
||||
},
|
||||
"object-visit": {
|
||||
"version": "1.0.1",
|
||||
@ -7687,15 +7626,6 @@
|
||||
"safe-buffer": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"parse-headers": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.2.tgz",
|
||||
"integrity": "sha512-/LypJhzFmyBIDYP9aDVgeyEb5sQfbfY5mnDq4hVhlQ69js87wXfmEI5V3xI6vvXasqebp0oCytYFLxsBVfCzSg==",
|
||||
"requires": {
|
||||
"for-each": "^0.3.3",
|
||||
"string.prototype.trim": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
||||
@ -7853,11 +7783,6 @@
|
||||
"pinkie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"pkcs7": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pkcs7/-/pkcs7-1.0.2.tgz",
|
||||
"integrity": "sha1-ttulJ1KMKUK/wSLOLa/NteWQdOc="
|
||||
},
|
||||
"pkg-dir": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
|
||||
@ -8672,18 +8597,11 @@
|
||||
"aproba": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"rust-result": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/rust-result/-/rust-result-1.0.0.tgz",
|
||||
"integrity": "sha1-NMdbLm3Dn+WHXlveyFteD5FTb3I=",
|
||||
"requires": {
|
||||
"individual": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
|
||||
"integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
@ -8694,14 +8612,6 @@
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true
|
||||
},
|
||||
"safe-json-parse": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-4.0.0.tgz",
|
||||
"integrity": "sha1-fA9XjPzNEtM6ccDgVBPi7KFx6qw=",
|
||||
"requires": {
|
||||
"rust-result": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"safe-regex": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
|
||||
@ -9710,16 +9620,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"string.prototype.trim": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.0.tgz",
|
||||
"integrity": "sha512-9EIjYD/WdlvLpn987+ctkLf0FfvBefOCuiEr2henD8X+7jfwPnyvTdmW8OJhj5p+M0/96mBdynLWkxUr+rHlpg==",
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.13.0",
|
||||
"function-bind": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
@ -10129,16 +10029,23 @@
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz",
|
||||
"integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==",
|
||||
"version": "3.6.9",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.9.tgz",
|
||||
"integrity": "sha512-pcnnhaoG6RtrvHJ1dFncAe8Od6Nuy30oaJ82ts6//sGSXOP5UjBMEthiProjXmMNHOfd93sqlkztifFMcb+4yw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"commander": "~2.20.0",
|
||||
"commander": "~2.20.3",
|
||||
"source-map": "~0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
@ -10313,11 +10220,6 @@
|
||||
"requires-port": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"url-toolkit": {
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.1.6.tgz",
|
||||
"integrity": "sha512-UaZ2+50am4HwrV2crR/JAf63Q4VvPYphe63WGeoJxeu8gmOm0qxPt+KsukfakPNrX9aymGNEkkaoICwn+OuvBw=="
|
||||
},
|
||||
"use": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
|
||||
@ -10432,34 +10334,6 @@
|
||||
"extsprintf": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"video.js": {
|
||||
"version": "7.6.5",
|
||||
"resolved": "https://registry.npmjs.org/video.js/-/video.js-7.6.5.tgz",
|
||||
"integrity": "sha512-r0kC9SNJhXz9th/wwbRaLVOIZTvXkF+rhFq9/FWU+e+EJClwClRCgP8STGmfrPHDXrfWiJwH9YY21JZK61vGGQ==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.4.5",
|
||||
"@videojs/http-streaming": "1.10.6",
|
||||
"global": "4.3.2",
|
||||
"keycode": "^2.2.0",
|
||||
"safe-json-parse": "4.0.0",
|
||||
"videojs-font": "3.2.0",
|
||||
"videojs-vtt.js": "^0.14.1",
|
||||
"xhr": "2.4.0"
|
||||
}
|
||||
},
|
||||
"videojs-font": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-3.2.0.tgz",
|
||||
"integrity": "sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA=="
|
||||
},
|
||||
"videojs-vtt.js": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.14.1.tgz",
|
||||
"integrity": "sha512-YxOiywx6N9t3J5nqsE5WN2Sw4CSqVe3zV+AZm2T4syOc2buNJaD6ZoexSdeszx2sHLU/RRo2r4BJAXFDQ7Qo2Q==",
|
||||
"requires": {
|
||||
"global": "^4.3.1"
|
||||
}
|
||||
},
|
||||
"vm-browserify": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz",
|
||||
@ -12168,17 +12042,6 @@
|
||||
"ultron": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"xhr": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/xhr/-/xhr-2.4.0.tgz",
|
||||
"integrity": "sha1-4W5mpF+GmGHu76tBbV7/ci3ECZM=",
|
||||
"requires": {
|
||||
"global": "~4.3.0",
|
||||
"is-function": "^1.0.1",
|
||||
"parse-headers": "^2.0.0",
|
||||
"xtend": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"xml2js": {
|
||||
"version": "0.4.19",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
|
||||
@ -12212,7 +12075,8 @@
|
||||
"xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||
"dev": true
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.0",
|
||||
|
@ -22,12 +22,11 @@
|
||||
"@angular/platform-browser-dynamic": "~8.2.0",
|
||||
"@angular/router": "~8.2.0",
|
||||
"bootstrap": "^4.3.1",
|
||||
"dashjs": "^3.0.0",
|
||||
"detect-browser": "^4.8.0",
|
||||
"hammerjs": "^2.0.8",
|
||||
"jquery": "^3.4.1",
|
||||
"popper.js": "^1.15.0",
|
||||
"rxjs": "~6.4.0",
|
||||
"tslib": "^1.10.0",
|
||||
"video.js": "^7.6.5",
|
||||
"zone.js": "~0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -40,6 +39,7 @@
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/jquery": "^3.3.31",
|
||||
"@types/node": "~8.9.4",
|
||||
"@types/video.js": "^7.3.2",
|
||||
"codelyzer": "^5.0.0",
|
||||
"jasmine-core": "~3.4.0",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
|
@ -14,22 +14,22 @@ import { StreamResolverService } from "./services/stream-resolver.service";
|
||||
import { ShowDetailsComponent } from './show-details/show-details.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: "browse", component: BrowseComponent, pathMatch: "full", resolve: { shows: LibraryResolverService } },
|
||||
{ path: "browse/:library-slug", component: BrowseComponent, resolve: { shows: LibraryResolverService } },
|
||||
{ path: "show/:show-slug", component: ShowDetailsComponent, resolve: { show: ShowResolverService } },
|
||||
{ path: "browse", component: BrowseComponent, pathMatch: "full", resolve: { shows: LibraryResolverService } },
|
||||
{ path: "browse/:library-slug", component: BrowseComponent, resolve: { shows: LibraryResolverService } },
|
||||
{ path: "show/:show-slug", component: ShowDetailsComponent, resolve: { show: ShowResolverService } },
|
||||
{ path: "collection/:collection-slug", component: CollectionComponent, resolve: { collection: CollectionResolverService } },
|
||||
{ path: "people/:people-slug", component: CollectionComponent, resolve: { collection: PeopleResolverService } },
|
||||
{ path: "watch/:item", component: PlayerComponent, resolve: { item: StreamResolverService } },
|
||||
{ path: "search/:query", component: SearchComponent, resolve: { items: SearchResolverService } },
|
||||
{ path: "**", component: NotFoundComponent }
|
||||
{ path: "**", component: NotFoundComponent }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes,
|
||||
{
|
||||
scrollPositionRestoration: "enabled"
|
||||
})],
|
||||
exports: [RouterModule],
|
||||
imports: [RouterModule.forRoot(routes,
|
||||
{
|
||||
scrollPositionRestoration: "enabled"
|
||||
})],
|
||||
exports: [RouterModule],
|
||||
providers: [
|
||||
LibraryResolverService,
|
||||
ShowResolverService,
|
||||
|
@ -8,7 +8,7 @@ import { Show } from "../../models/show";
|
||||
templateUrl: './browse.component.html',
|
||||
styleUrls: ['./browse.component.scss']
|
||||
})
|
||||
export class BrowseComponent implements OnInit
|
||||
export class BrowseComponent
|
||||
{
|
||||
@Input() shows: Show[];
|
||||
sortType: string = "title";
|
||||
@ -16,13 +16,13 @@ export class BrowseComponent implements OnInit
|
||||
|
||||
sortTypes: string[] = ["title", "release date"];
|
||||
|
||||
constructor(private route: ActivatedRoute, private sanitizer: DomSanitizer) { }
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
if (this.shows == null)
|
||||
this.shows = this.route.snapshot.data.shows;
|
||||
}
|
||||
constructor(private route: ActivatedRoute, private sanitizer: DomSanitizer)
|
||||
{
|
||||
this.route.data.subscribe((data) =>
|
||||
{
|
||||
this.shows = data.shows;
|
||||
});
|
||||
}
|
||||
|
||||
getThumb(slug: string)
|
||||
{
|
||||
|
@ -8,16 +8,17 @@ import { DomSanitizer } from "@angular/platform-browser";
|
||||
templateUrl: './collection.component.html',
|
||||
styleUrls: ['./collection.component.scss']
|
||||
})
|
||||
export class CollectionComponent implements OnInit
|
||||
export class CollectionComponent
|
||||
{
|
||||
collection: Collection;
|
||||
|
||||
constructor(private route: ActivatedRoute, private sanitizer: DomSanitizer) { }
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
this.collection = this.route.snapshot.data.collection;
|
||||
}
|
||||
constructor(private route: ActivatedRoute, private sanitizer: DomSanitizer)
|
||||
{
|
||||
this.route.data.subscribe((data) =>
|
||||
{
|
||||
this.collection = data.collection;
|
||||
});
|
||||
}
|
||||
|
||||
getThumb()
|
||||
{
|
||||
|
@ -1,8 +1,6 @@
|
||||
<div id="root">
|
||||
<div class="player">
|
||||
<video id="player" poster="backdrop/{{this.item.showSlug}}" autoplay muted (click)="videoClicked()" class="video-js">
|
||||
<source src="/video/{{this.item.link}}" />
|
||||
<source src="/video/transmux/{{this.item.link}}" type="video/mp4" />
|
||||
<div class="player data-vjs-player">
|
||||
<video id="player" poster="backdrop/{{this.item.showSlug}}" autoplay muted (click)="videoClicked()">
|
||||
</video>
|
||||
</div>
|
||||
|
||||
@ -65,7 +63,7 @@
|
||||
<ng-template #elseBlock><p>{{this.minutes | number: '2.0-0'}}:{{this.seconds | number: '2.0-0'}} / {{this.maxMinutes | number: '2.0-0'}}:{{this.maxSeconds | number: '2.0-0'}}</p></ng-template>
|
||||
</div>
|
||||
<div class="right">
|
||||
<button id="volume" *ngIf="this.item.audios.length > 0" mat-icon-button matTooltipPosition="above" matTooltip="Select audio track">
|
||||
<button id="volume" *ngIf="this.item.audios.length > 1" mat-icon-button matTooltipPosition="above" matTooltip="Select audio track">
|
||||
<mat-icon>music_note</mat-icon>
|
||||
</button>
|
||||
<button *ngIf="this.item.subtitles.length > 0" mat-icon-button [matMenuTriggerFor]="subtitles" matTooltipPosition="above" matTooltip="Select subtitle track">
|
||||
|
@ -4,6 +4,8 @@ import { DomSanitizer, Title } from "@angular/platform-browser";
|
||||
import { ActivatedRoute, Event, NavigationCancel, NavigationEnd, NavigationStart, Router } from "@angular/router";
|
||||
import { Track, WatchItem } from "../../models/watch-item";
|
||||
import { Location } from "@angular/common";
|
||||
import { MediaPlayer } from "dashjs";
|
||||
import { getPlaybackMethod, method } from "../../videoSupport/playbackMethodDetector";
|
||||
|
||||
declare var SubtitleManager: any;
|
||||
|
||||
@ -38,7 +40,11 @@ export class PlayerComponent implements OnInit
|
||||
playTooltip: string = "Pause"; //Text used in the play tooltip
|
||||
fullscreenTooltip: string = "Fullscreen"; //Text used in the fullscreen tooltip
|
||||
|
||||
playMethod: method;
|
||||
|
||||
private player: HTMLVideoElement;
|
||||
private dashPlayer: dashjs.MediaPlayerClass = MediaPlayer().create();
|
||||
private dashPlayerInitialized: boolean = false;
|
||||
private thumb: HTMLElement;
|
||||
private progress: HTMLElement;
|
||||
private buffered: HTMLElement;
|
||||
@ -125,6 +131,19 @@ export class PlayerComponent implements OnInit
|
||||
this.next();
|
||||
}
|
||||
|
||||
this.player.onerror = () =>
|
||||
{
|
||||
if (this.playMethod == method.transcode)
|
||||
{
|
||||
this.snackBar.open("This episode can't be played.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 10000 });
|
||||
}
|
||||
else
|
||||
{
|
||||
this.playMethod += 1;
|
||||
this.selectPlayMethod();
|
||||
}
|
||||
}
|
||||
|
||||
let progressBar: HTMLElement = document.getElementById("progress-bar") as HTMLElement;
|
||||
$(progressBar).click((event) =>
|
||||
{
|
||||
@ -337,7 +356,14 @@ export class PlayerComponent implements OnInit
|
||||
|
||||
init()
|
||||
{
|
||||
//Load sub selected from the url.
|
||||
let queryMethod: string = this.route.snapshot.queryParams["method"];
|
||||
if (queryMethod)
|
||||
this.playMethod = method[queryMethod];
|
||||
else
|
||||
this.playMethod = getPlaybackMethod(this.player, this.item);
|
||||
|
||||
this.selectPlayMethod();
|
||||
|
||||
let sub: string = this.route.snapshot.queryParams["sub"];
|
||||
if (sub != null)
|
||||
{
|
||||
@ -353,6 +379,27 @@ export class PlayerComponent implements OnInit
|
||||
}, 750);
|
||||
}
|
||||
|
||||
selectPlayMethod()
|
||||
{
|
||||
if (this.dashPlayerInitialized)
|
||||
this.dashPlayer.reset();
|
||||
if (this.playMethod == method.direct)
|
||||
{
|
||||
this.player.src = "/video/" + this.item.link;
|
||||
this.dashPlayerInitialized = false;
|
||||
}
|
||||
else if (this.playMethod == method.transmux)
|
||||
{
|
||||
this.dashPlayer.initialize(this.player, "/video/transmux/" + this.item.link + "/", true);
|
||||
this.dashPlayerInitialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.dashPlayer.initialize(this.player, "/video/transcode/" + this.item.link + "/", true);
|
||||
this.dashPlayerInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
back()
|
||||
{
|
||||
this.location.back();
|
||||
|
@ -1,21 +1,21 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||
import { Observable, EMPTY } from 'rxjs';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
import { Show } from "../../models/show";
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
|
||||
import { EMPTY, Observable } from 'rxjs';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
import { WatchItem } from "../../models/watch-item";
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class StreamResolverService implements Resolve<Show>
|
||||
export class StreamResolverService implements Resolve<WatchItem>
|
||||
{
|
||||
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot): Show | Observable<Show> | Promise<Show>
|
||||
resolve(route: ActivatedRouteSnapshot): WatchItem | Observable<WatchItem> | Promise<WatchItem>
|
||||
{
|
||||
let item: string = route.paramMap.get("item");
|
||||
return this.http.get<Show>("api/watch/" + item).pipe(catchError((error: HttpErrorResponse) =>
|
||||
return this.http.get<WatchItem>("api/watch/" + item).pipe(catchError((error: HttpErrorResponse) =>
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
if (error.status == 404)
|
||||
|
@ -25,23 +25,26 @@ export class ShowDetailsComponent implements OnInit
|
||||
this.route.queryParams.subscribe(params =>
|
||||
{
|
||||
this.season = params["season"];
|
||||
});
|
||||
});
|
||||
|
||||
this.route.data.subscribe(data =>
|
||||
{
|
||||
this.show = data.show;
|
||||
this.title.setTitle(this.show.title + " - Kyoo");
|
||||
|
||||
if (this.season == null || this.show.seasons.find(x => x.seasonNumber == this.season) == null)
|
||||
this.season = 1;
|
||||
|
||||
this.getEpisodes();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
this.show = this.route.snapshot.data.show;
|
||||
this.title.setTitle(this.show.title + " - Kyoo");
|
||||
|
||||
if (this.season == null || this.show.seasons.find(x => x.seasonNumber == this.season) == null)
|
||||
this.season = 1;
|
||||
|
||||
this.toolbar = document.getElementById("toolbar");
|
||||
this.backdrop = document.getElementById("backdrop");
|
||||
window.addEventListener("scroll", this.scroll, true);
|
||||
this.toolbar.setAttribute("style", `background-color: rgba(0, 0, 0, 0) !important`);
|
||||
|
||||
this.getEpisodes();
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
|
@ -6,7 +6,6 @@ export interface WatchItem
|
||||
showSlug: string;
|
||||
seasonNumber: number;
|
||||
episodeNumber: number;
|
||||
video: string;
|
||||
title: string;
|
||||
link: string;
|
||||
duration: number;
|
||||
@ -15,6 +14,8 @@ export interface WatchItem
|
||||
previousEpisode: string;
|
||||
nextEpisode: Episode;
|
||||
|
||||
container: string;
|
||||
video: Track;
|
||||
audios: Track[];
|
||||
subtitles: Track[];
|
||||
}
|
||||
|
142
Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.js
Normal file
142
Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.js
Normal file
@ -0,0 +1,142 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var detect_browser_1 = require("detect-browser");
|
||||
var method;
|
||||
(function (method) {
|
||||
method[method["direct"] = 0] = "direct";
|
||||
method[method["transmux"] = 1] = "transmux";
|
||||
method[method["transcode"] = 2] = "transcode";
|
||||
})(method = exports.method || (exports.method = {}));
|
||||
;
|
||||
function getPlaybackMethod(player, item) {
|
||||
var browser = detect_browser_1.detect();
|
||||
// If we can't find the browser, transcode (It may or may not support containers/codecs)
|
||||
if (!browser)
|
||||
return method.transcode;
|
||||
if (containerIsSupported(player, item.container, browser.name) && item.audios.length <= 1) {
|
||||
if (videoCodecIsSupported(player, item.video.codec, browser.name) &&
|
||||
audioCodecIsSupported(player, item.audios.map(function (value) { return value.codec; }), browser.name))
|
||||
return method.direct;
|
||||
return method.transcode;
|
||||
}
|
||||
if (videoCodecIsSupported(player, item.video.codec, browser.name) &&
|
||||
audioCodecIsSupported(player, item.audios.map(function (value) { return value.codec; }), browser.name))
|
||||
return method.transmux;
|
||||
return method.transcode;
|
||||
}
|
||||
exports.getPlaybackMethod = getPlaybackMethod;
|
||||
function containerIsSupported(player, container, browser) {
|
||||
var supported = false;
|
||||
switch (container) {
|
||||
case "asf":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
//videoAudioCodecs = [];
|
||||
break;
|
||||
case "avi":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "mpg":
|
||||
case "mpeg":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "flv":
|
||||
supported = browser == "tizen" || browser == "orsay";
|
||||
break;
|
||||
case "3gp":
|
||||
case "mts":
|
||||
case "trp":
|
||||
case "vob":
|
||||
case "vro":
|
||||
supported = browser == "tizen" || browser == "orsay";
|
||||
break;
|
||||
case "mov":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge" || browser == "chrome";
|
||||
break;
|
||||
case "m2ts":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "wmv":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
//videoAudioCodecs = [];
|
||||
break;
|
||||
case "ts":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "mp4":
|
||||
case "m4v":
|
||||
supported = true;
|
||||
break;
|
||||
case "mkv":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "chrome" || browser == "edge";
|
||||
if (supported)
|
||||
break;
|
||||
if (player.canPlayType("video/x-matroska") || player.canPlayType("video/mkv"))
|
||||
supported = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
//SHOULD CHECK FOR DEPTH (8bits ok but 10bits unsuported for almost every browsers)
|
||||
function videoCodecIsSupported(player, codec, browser) {
|
||||
switch (codec) {
|
||||
case "h264":
|
||||
return !!player.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'); //The !! is used to parse the string as a bool
|
||||
case "h265":
|
||||
case "hevc":
|
||||
if (browser == "tizen" || browser == "orsay" || browser == "xboxOne" || browser == "ios")
|
||||
return true;
|
||||
//SHOULD SUPPORT CHROMECAST ULTRA
|
||||
// if (browser.chromecast)
|
||||
// {
|
||||
// var isChromecastUltra = userAgent.indexOf('aarch64') !== -1;
|
||||
// if (isChromecastUltra)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
return !!player.canPlayType('video/hevc; codecs="hevc, aac"');
|
||||
case "mpeg2video":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "vc1":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "msmpeg4v2":
|
||||
return browser == "orsay" || browser == "tizen";
|
||||
case "vp8":
|
||||
return !!player.canPlayType('video/webm; codecs="vp8');
|
||||
case "vp9":
|
||||
return !!player.canPlayType('video/webm; codecs="vp9"');
|
||||
case "vorbis":
|
||||
return browser == "orsay" || browser == "tizen" || !!player.canPlayType('video/webm; codecs="vp8');
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//SHOULD CHECK FOR NUMBER OF AUDIO CHANNEL (2 ok but 5 not in some browsers)
|
||||
function audioCodecIsSupported(player, codecs, browser) {
|
||||
for (var _i = 0, codecs_1 = codecs; _i < codecs_1.length; _i++) {
|
||||
var codec = codecs_1[_i];
|
||||
switch (codec) {
|
||||
case "mp3":
|
||||
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"') ||
|
||||
!!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"');
|
||||
case "aac":
|
||||
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"');
|
||||
case "mp2":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "pcm_s16le":
|
||||
case "pcm_s24le":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "aac_latm":
|
||||
return browser == "orsay" || browser == "tizen";
|
||||
case "opus":
|
||||
return !!player.canPlayType('audio/ogg; codecs="opus"');
|
||||
case "flac":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=playbackMethodDetector.js.map
|
@ -0,0 +1 @@
|
||||
{"version":3,"file":"playbackMethodDetector.js","sourceRoot":"","sources":["playbackMethodDetector.ts"],"names":[],"mappings":";;AACA,iDAAqD;AAErD,IAAY,MAKX;AALD,WAAY,MAAM;IAEjB,uCAAM,CAAA;IACN,2CAAQ,CAAA;IACR,6CAAS,CAAA;AACV,CAAC,EALW,MAAM,GAAN,cAAM,KAAN,cAAM,QAKjB;AAAA,CAAC;AAEF,SAAgB,iBAAiB,CAAC,MAAwB,EAAE,IAAe;IAE1E,IAAI,OAAO,GAAG,uBAAM,EAAE,CAAC;IAEvB,wFAAwF;IACxF,IAAI,CAAC,OAAO;QACX,OAAO,MAAM,CAAC,SAAS,CAAC;IAEzB,IAAI,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,EACzF;QACC,IAAI,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC;YAChE,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAC,KAAY,IAAK,OAAA,KAAK,CAAC,KAAK,EAAX,CAAW,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC;YAC3F,OAAO,MAAM,CAAC,MAAM,CAAC;QACtB,OAAO,MAAM,CAAC,SAAS,CAAC;KACxB;IAED,IAAI,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC;QAChE,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAC,KAAY,IAAK,OAAA,KAAK,CAAC,KAAK,EAAX,CAAW,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC;QAC3F,OAAO,MAAM,CAAC,QAAQ,CAAC;IACxB,OAAO,MAAM,CAAC,SAAS,CAAC;AACzB,CAAC;AApBD,8CAoBC;AAED,SAAS,oBAAoB,CAAC,MAAwB,EAAE,SAAiB,EAAE,OAAe;IAEzF,IAAI,SAAS,GAAY,KAAK,CAAC;IAE/B,QAAQ,SAAS,EACjB;QACC,KAAK,KAAK;YACT,SAAS,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM,CAAC;YAC1E,wBAAwB;YACxB,MAAM;QACP,KAAK,KAAK;YACT,SAAS,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM,CAAC;YAC1E,MAAM;QACP,KAAK,KAAK,CAAC;QACX,KAAK,MAAM;YACV,SAAS,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM,CAAC;YAC1E,MAAM;QACP,KAAK,KAAK;YACT,SAAS,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC;YACrD,MAAM;QACP,KAAK,KAAK,CAAC;QACX,KAAK,KAAK,CAAC;QACX,KAAK,KAAK,CAAC;QACX,KAAK,KAAK,CAAC;QACX,KAAK,KAAK;YACT,SAAS,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC;YACrD,MAAM;QACP,KAAK,KAAK;YACT,SAAS,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM,IAAI,OAAO,IAAI,QAAQ,CAAC;YACjG,MAAM;QACP,KAAK,MAAM;YACV,SAAS,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM,CAAC;YAC1E,MAAM;QACP,KAAK,KAAK;YACT,SAAS,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM,CAAC;YAC1E,wBAAwB;YACxB,MAAM;QACP,KAAK,IAAI;YACR,SAAS,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM,CAAC;YAC1E,MAAM;QACP,KAAK,KAAK,CAAC;QACX,KAAK,KAAK;YACT,SAAS,GAAG,IAAI,CAAC;YACjB,MAAM;QACP,KAAK,KAAK;YACT,SAAS,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,QAAQ,IAAI,OAAO,IAAI,MAAM,CAAC;YAEjG,IAAI,SAAS;gBACZ,MAAM;YAEP,IAAI,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC;gBAC5E,SAAS,GAAG,IAAI,CAAC;YAClB,MAAM;QACP;YACC,MAAM;KACP;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,mFAAmF;AACnF,SAAS,qBAAqB,CAAC,MAAwB,EAAE,KAAa,EAAE,OAAe;IAEtF,QAAQ,KAAK,EACb;QACC,KAAK,MAAM;YACV,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,4CAA4C,CAAC,CAAC,CAAC,8CAA8C;QAC1H,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM;YACV,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,SAAS,IAAI,OAAO,IAAI,KAAK;gBACvF,OAAO,IAAI,CAAC;YACV,iCAAiC;YACpC,2BAA2B;YACxB,IAAI;YAEJ,gEAAgE;YAChE,0BAA0B;YAC1B,KAAK;YACL,iBAAiB;YACjB,KAAK;YACL,IAAI;YACP,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,gCAAgC,CAAC,CAAC;QAC/D,KAAK,YAAY;YAChB,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM,CAAC;QACtE,KAAK,KAAK;YACT,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM,CAAC;QACtE,KAAK,WAAW;YACf,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC;QACjD,KAAK,KAAK;YACT,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC;QACxD,KAAK,KAAK;YACT,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC;QACzD,KAAK,QAAQ;YACZ,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC;QACpG;YACI,OAAO,KAAK,CAAC;KACjB;AACF,CAAC;AAED,4EAA4E;AAC5E,SAAS,qBAAqB,CAAC,MAAwB,EAAE,MAAgB,EAAE,OAAe;IAEzF,KAAkB,UAAM,EAAN,iBAAM,EAAN,oBAAM,EAAN,IAAM,EACxB;QADK,IAAI,KAAK,eAAA;QAEb,QAAQ,KAAK,EACb;YACC,KAAK,KAAK;gBACT,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,0CAA0C,CAAC;oBACtE,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,0CAA0C,CAAC,CAAC;YACnE,KAAK,KAAK;gBACT,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,4CAA4C,CAAC,CAAC;YAC3E,KAAK,KAAK;gBACT,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM,CAAC;YACtE,KAAK,WAAW,CAAC;YACjB,KAAK,WAAW;gBACf,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM,CAAC;YACtE,KAAK,UAAU;gBACd,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC;YACjD,KAAK,MAAM;gBACV,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC;YACzD,KAAK,MAAM;gBACV,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,MAAM,CAAC;YACtE;gBACC,OAAO,KAAK,CAAC;SACd;KACA;AACH,CAAC"}
|
158
Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.ts
Normal file
158
Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.ts
Normal file
@ -0,0 +1,158 @@
|
||||
import { WatchItem, Track } from "../models/watch-item";
|
||||
import { detect, BrowserInfo } from "detect-browser";
|
||||
|
||||
export enum method
|
||||
{
|
||||
direct,
|
||||
transmux,
|
||||
transcode
|
||||
};
|
||||
|
||||
export function getPlaybackMethod(player: HTMLVideoElement, item: WatchItem): method
|
||||
{
|
||||
let browser = detect();
|
||||
|
||||
// If we can't find the browser, transcode (It may or may not support containers/codecs)
|
||||
if (!browser)
|
||||
return method.transcode;
|
||||
|
||||
if (containerIsSupported(player, item.container, browser.name) && item.audios.length <= 1)
|
||||
{
|
||||
if (videoCodecIsSupported(player, item.video.codec, browser.name) &&
|
||||
audioCodecIsSupported(player, item.audios.map((value: Track) => value.codec), browser.name))
|
||||
return method.direct;
|
||||
return method.transcode;
|
||||
}
|
||||
|
||||
if (videoCodecIsSupported(player, item.video.codec, browser.name) &&
|
||||
audioCodecIsSupported(player, item.audios.map((value: Track) => value.codec), browser.name))
|
||||
return method.transmux;
|
||||
return method.transcode;
|
||||
}
|
||||
|
||||
function containerIsSupported(player: HTMLVideoElement, container: string, browser: string): boolean
|
||||
{
|
||||
let supported: boolean = false;
|
||||
|
||||
switch (container)
|
||||
{
|
||||
case "asf":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
//videoAudioCodecs = [];
|
||||
break;
|
||||
case "avi":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "mpg":
|
||||
case "mpeg":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "flv":
|
||||
supported = browser == "tizen" || browser == "orsay";
|
||||
break;
|
||||
case "3gp":
|
||||
case "mts":
|
||||
case "trp":
|
||||
case "vob":
|
||||
case "vro":
|
||||
supported = browser == "tizen" || browser == "orsay";
|
||||
break;
|
||||
case "mov":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge" || browser == "chrome";
|
||||
break;
|
||||
case "m2ts":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "wmv":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
//videoAudioCodecs = [];
|
||||
break;
|
||||
case "ts":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "mp4":
|
||||
case "m4v":
|
||||
supported = true;
|
||||
break;
|
||||
case "mkv":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "chrome" || browser == "edge";
|
||||
|
||||
if (supported)
|
||||
break;
|
||||
|
||||
if (player.canPlayType("video/x-matroska") || player.canPlayType("video/mkv"))
|
||||
supported = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
|
||||
//SHOULD CHECK FOR DEPTH (8bits ok but 10bits unsuported for almost every browsers)
|
||||
function videoCodecIsSupported(player: HTMLVideoElement, codec: string, browser: string): boolean
|
||||
{
|
||||
switch (codec)
|
||||
{
|
||||
case "h264":
|
||||
return !!player.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'); //The !! is used to parse the string as a bool
|
||||
case "h265":
|
||||
case "hevc":
|
||||
if (browser == "tizen" || browser == "orsay" || browser == "xboxOne" || browser == "ios")
|
||||
return true;
|
||||
//SHOULD SUPPORT CHROMECAST ULTRA
|
||||
// if (browser.chromecast)
|
||||
// {
|
||||
|
||||
// var isChromecastUltra = userAgent.indexOf('aarch64') !== -1;
|
||||
// if (isChromecastUltra)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
return !!player.canPlayType('video/hevc; codecs="hevc, aac"');
|
||||
case "mpeg2video":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "vc1":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "msmpeg4v2":
|
||||
return browser == "orsay" || browser == "tizen";
|
||||
case "vp8":
|
||||
return !!player.canPlayType('video/webm; codecs="vp8');
|
||||
case "vp9":
|
||||
return !!player.canPlayType('video/webm; codecs="vp9"');
|
||||
case "vorbis":
|
||||
return browser == "orsay" || browser == "tizen" || !!player.canPlayType('video/webm; codecs="vp8');
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//SHOULD CHECK FOR NUMBER OF AUDIO CHANNEL (2 ok but 5 not in some browsers)
|
||||
function audioCodecIsSupported(player: HTMLVideoElement, codecs: string[], browser: string): boolean
|
||||
{
|
||||
for (let codec of codecs)
|
||||
{
|
||||
switch (codec)
|
||||
{
|
||||
case "mp3":
|
||||
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"') ||
|
||||
!!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"');
|
||||
case "aac":
|
||||
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"');
|
||||
case "mp2":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "pcm_s16le":
|
||||
case "pcm_s24le":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "aac_latm":
|
||||
return browser == "orsay" || browser == "tizen";
|
||||
case "opus":
|
||||
return !!player.canPlayType('audio/ogg; codecs="opus"');
|
||||
case "flac":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
using Kyoo.InternalAPI;
|
||||
using Kyoo.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
@ -10,11 +13,13 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
private readonly ILibraryManager libraryManager;
|
||||
private readonly ITranscoder transcoder;
|
||||
private readonly string transmuxPath;
|
||||
|
||||
public VideoController(ILibraryManager libraryManager, ITranscoder transcoder)
|
||||
public VideoController(ILibraryManager libraryManager, ITranscoder transcoder, IConfiguration config)
|
||||
{
|
||||
this.libraryManager = libraryManager;
|
||||
this.transcoder = transcoder;
|
||||
transmuxPath = config.GetValue<string>("transmuxTempPath");
|
||||
}
|
||||
|
||||
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||
@ -28,16 +33,16 @@ namespace Kyoo.Controllers
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
[HttpGet("transmux/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||
public IActionResult Transmux(string showSlug, long seasonNumber, long episodeNumber)
|
||||
[HttpGet("transmux/{showSlug}-s{seasonNumber}e{episodeNumber}/")]
|
||||
public async Task<IActionResult> Transmux(string showSlug, long seasonNumber, long episodeNumber)
|
||||
{
|
||||
WatchItem episode = libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
|
||||
|
||||
if (episode != null && System.IO.File.Exists(episode.Path))
|
||||
{
|
||||
string path = transcoder.Transmux(episode);
|
||||
string path = await transcoder.Transmux(episode);
|
||||
if (path != null)
|
||||
return PhysicalFile(path, "video/mp4", true);
|
||||
return PhysicalFile(path, "application/dash+xml", true);
|
||||
else
|
||||
return StatusCode(500);
|
||||
}
|
||||
@ -45,18 +50,28 @@ namespace Kyoo.Controllers
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
[HttpGet("transmux/{episodeLink}/dash/{chunk}")]
|
||||
public IActionResult GetTransmuxedChunk(string episodeLink, string chunk)
|
||||
{
|
||||
string path = Path.Combine(transmuxPath, episodeLink);
|
||||
path = Path.Combine(path, "dash" + Path.DirectorySeparatorChar + chunk);
|
||||
|
||||
return PhysicalFile(path, "video/iso.segment");
|
||||
}
|
||||
|
||||
[HttpGet("transcode/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||
public IActionResult Transcode(string showSlug, long seasonNumber, long episodeNumber)
|
||||
{
|
||||
WatchItem episode = libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
|
||||
return null;
|
||||
//WatchItem episode = libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
|
||||
|
||||
if (episode != null && System.IO.File.Exists(episode.Path))
|
||||
{
|
||||
string path = transcoder.Transcode(episode.Path);
|
||||
return PhysicalFile(path, "video/mp4", true); //Should use mpeg dash
|
||||
}
|
||||
else
|
||||
return NotFound();
|
||||
//if (episode != null && System.IO.File.Exists(episode.Path))
|
||||
//{
|
||||
// string path = transcoder.Transcode(episode.Path);
|
||||
// return PhysicalFile(path, "video/mp4", true); //Should use mpeg dash
|
||||
//}
|
||||
//else
|
||||
// return NotFound();
|
||||
}
|
||||
}
|
||||
}
|
@ -252,14 +252,21 @@ namespace Kyoo.InternalAPI
|
||||
episode.SeasonID = seasonID;
|
||||
episode.id = libraryManager.RegisterEpisode(episode);
|
||||
|
||||
Track[] tracks = await transcoder.GetTrackInfo(episode.Path);
|
||||
foreach (Track track in tracks)
|
||||
{
|
||||
track.episodeID = episode.id;
|
||||
libraryManager.RegisterTrack(track);
|
||||
}
|
||||
|
||||
if (episode.Path.EndsWith(".mkv"))
|
||||
{
|
||||
if (!FindExtractedSubtitles(episode))
|
||||
{
|
||||
Track[] tracks = await transcoder.ExtractSubtitles(episode.Path);
|
||||
if (tracks != null)
|
||||
Track[] subtitles = await transcoder.ExtractSubtitles(episode.Path);
|
||||
if (subtitles != null)
|
||||
{
|
||||
foreach (Track track in tracks)
|
||||
foreach (Track track in subtitles)
|
||||
{
|
||||
track.episodeID = episode.id;
|
||||
libraryManager.RegisterTrack(track);
|
||||
@ -269,7 +276,6 @@ namespace Kyoo.InternalAPI
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private bool FindExtractedSubtitles(Episode episode)
|
||||
{
|
||||
string path = Path.Combine(Path.GetDirectoryName(episode.Path), "Subtitles");
|
||||
|
@ -19,8 +19,8 @@ namespace Kyoo.InternalAPI
|
||||
IEnumerable<Show> GetShowsByPeople(long peopleID);
|
||||
IEnumerable<string> GetLibrariesPath();
|
||||
|
||||
//Internal HTML read
|
||||
(List<Track> audios, List<Track> subtitles) GetStreams(long episodeID, string showSlug);
|
||||
//Internal read
|
||||
(Track video, List<Track> audios, List<Track> subtitles) GetStreams(long episodeID, string showSlug);
|
||||
Track GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag, bool forced);
|
||||
|
||||
//Public read
|
||||
|
@ -224,7 +224,7 @@ namespace Kyoo.InternalAPI
|
||||
}
|
||||
|
||||
|
||||
public (List<Track> audios, List<Track> subtitles) GetStreams(long episodeID, string episodeSlug)
|
||||
public (Track video, List<Track> audios, List<Track> subtitles) GetStreams(long episodeID, string episodeSlug)
|
||||
{
|
||||
string query = "SELECT * FROM tracks WHERE episodeID = $episodeID;";
|
||||
|
||||
@ -233,6 +233,7 @@ namespace Kyoo.InternalAPI
|
||||
cmd.Parameters.AddWithValue("$episodeID", episodeID);
|
||||
SQLiteDataReader reader = cmd.ExecuteReader();
|
||||
|
||||
Track video = null;
|
||||
List<Track> audios = new List<Track>();
|
||||
List<Track> subtitles = new List<Track>();
|
||||
|
||||
@ -240,13 +241,15 @@ namespace Kyoo.InternalAPI
|
||||
{
|
||||
Track track = Track.FromReader(reader).SetLink(episodeSlug);
|
||||
|
||||
if (track.type == StreamType.Audio)
|
||||
if (track.type == StreamType.Video)
|
||||
video = track;
|
||||
else if (track.type == StreamType.Audio)
|
||||
audios.Add(track);
|
||||
else if (track.type == StreamType.Subtitle)
|
||||
subtitles.Add(track);
|
||||
}
|
||||
|
||||
return (audios, subtitles);
|
||||
return (video, audios, subtitles);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,13 +6,16 @@ namespace Kyoo.InternalAPI
|
||||
{
|
||||
public interface ITranscoder
|
||||
{
|
||||
//Should transcode to a mp4 container (same video/audio format if possible, no subtitles).
|
||||
string Transmux(WatchItem episode);
|
||||
// Should transcode to a mp4 container (same video/audio format if possible, no subtitles).
|
||||
Task<string> Transmux(WatchItem episode);
|
||||
|
||||
//Should transcode to a mp4 container with a h264 video format and a AAC audio format, no subtitles.
|
||||
string Transcode(string path);
|
||||
// Should transcode to a mp4 container with a h264 video format and a AAC audio format, no subtitles.
|
||||
Task<string> Transcode(WatchItem episode);
|
||||
|
||||
//Extract all subtitles of a video and save them in the subtitles sub-folder.
|
||||
// Get video and audio tracks infos (codec, name, language...)
|
||||
Task<Track[]> GetTrackInfo(string path);
|
||||
|
||||
// Extract all subtitles of a video and save them in the subtitles sub-folder.
|
||||
Task<Track[]> ExtractSubtitles(string path);
|
||||
}
|
||||
}
|
||||
|
@ -11,15 +11,24 @@ namespace Kyoo.InternalAPI
|
||||
{
|
||||
public class Transcoder : ITranscoder
|
||||
{
|
||||
private readonly string tempPath;
|
||||
private readonly string transmuxPath;
|
||||
|
||||
public Transcoder(IConfiguration config)
|
||||
{
|
||||
tempPath = config.GetValue<string>("tempPath");
|
||||
transmuxPath = config.GetValue<string>("transmuxTempPath");
|
||||
|
||||
Debug.WriteLine("&Api INIT (unmanaged stream size): " + TranscoderAPI.Init() + ", Stream size: " + Marshal.SizeOf<Models.Watch.Stream>());
|
||||
}
|
||||
|
||||
public async Task<Track[]> GetTrackInfo(string path)
|
||||
{
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
TranscoderAPI.GetTrackInfo(path, out Track[] tracks);
|
||||
return tracks;
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<Track[]> ExtractSubtitles(string path)
|
||||
{
|
||||
string output = Path.Combine(Path.GetDirectoryName(path), "Subtitles");
|
||||
@ -31,24 +40,33 @@ namespace Kyoo.InternalAPI
|
||||
});
|
||||
}
|
||||
|
||||
public void GetVideo(string path)
|
||||
public async Task<string> Transmux(WatchItem episode)
|
||||
{
|
||||
Debug.WriteLine("&Getting video...");
|
||||
string folder = Path.Combine(transmuxPath, episode.Link);
|
||||
string manifest = Path.Combine(folder, episode.Link + ".mpd");
|
||||
float playableDuration = 0;
|
||||
bool transmuxFailed = false;
|
||||
|
||||
Directory.CreateDirectory(folder);
|
||||
Debug.WriteLine("&Transmuxing " + episode.Link + " at " + episode.Path + ", outputPath: " + folder);
|
||||
|
||||
if (File.Exists(manifest))
|
||||
return manifest;
|
||||
// Added an await and removed the while -> await because the dynamic dash file can't be played for now (maybe ffmpeg doesn't process in the playback order).
|
||||
/*await */Task.Run(() =>
|
||||
{
|
||||
transmuxFailed = TranscoderAPI.transmux(episode.Path, manifest.Replace('\\', '/'), out playableDuration) != 0;
|
||||
//playableDuration = float.MaxValue;
|
||||
});
|
||||
while (playableDuration < 20 || (!File.Exists(manifest) && !transmuxFailed))
|
||||
await Task.Delay(10);
|
||||
return transmuxFailed ? null : manifest;
|
||||
}
|
||||
|
||||
public string Transmux(WatchItem episode)
|
||||
public Task<string> Transcode(WatchItem episode)
|
||||
{
|
||||
string temp = Path.Combine(tempPath, episode.Link + ".mp4");
|
||||
Debug.WriteLine("&Transmuxing " + episode.Link + " at " + episode.Path + ", outputPath: " + temp);
|
||||
if (File.Exists(temp) || TranscoderAPI.Transmux(episode.Path, temp) == 0)
|
||||
return temp;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public string Transcode(string path)
|
||||
{
|
||||
return @"D:\Videos\Anohana\AnoHana S01E01.mp4";
|
||||
//NOT IMPLEMENTED YET
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Watch;
|
||||
|
||||
@ -14,20 +15,53 @@ namespace Kyoo.InternalAPI.TranscoderLink
|
||||
public extern static int Init();
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
public extern static int Transmux(string path, string outPath);
|
||||
public extern static int transmux(string path, string out_path, out float playableDuration);
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
private extern static IntPtr ExtractSubtitles(string path, string outPath, out int arrayLength, out int trackCount);
|
||||
private extern static IntPtr get_track_info(string path, out int array_length, out int track_count);
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
private extern static IntPtr extract_subtitles(string path, string out_path, out int array_length, out int track_count);
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
private extern static void FreeMemory(IntPtr streamsPtr);
|
||||
private extern static void free_memory(IntPtr stream_ptr);
|
||||
|
||||
|
||||
public static void GetTrackInfo(string path, out Track[] tracks)
|
||||
{
|
||||
int size = Marshal.SizeOf<Stream>();
|
||||
IntPtr ptr = get_track_info(path, out int arrayLength, out int trackCount);
|
||||
IntPtr streamsPtr = ptr;
|
||||
|
||||
if (trackCount > 0 && ptr != IntPtr.Zero)
|
||||
{
|
||||
tracks = new Track[trackCount];
|
||||
|
||||
int j = 0;
|
||||
for (int i = 0; i < arrayLength; i++)
|
||||
{
|
||||
Stream stream = Marshal.PtrToStructure<Stream>(streamsPtr);
|
||||
if (stream.Codec != null) //If the codec is null, the stream doesn't represent a usfull thing.
|
||||
{
|
||||
tracks[j] = Track.From(stream, stream.Title == "VIDEO" ? StreamType.Video : StreamType.Audio);
|
||||
j++;
|
||||
}
|
||||
streamsPtr += size;
|
||||
}
|
||||
}
|
||||
else
|
||||
tracks = null;
|
||||
|
||||
free_memory(ptr);
|
||||
Debug.WriteLine("&" + tracks?.Length + " tracks got at: " + path);
|
||||
}
|
||||
|
||||
public static void ExtractSubtitles(string path, string outPath, out Track[] tracks)
|
||||
{
|
||||
int size = Marshal.SizeOf<Stream>();
|
||||
|
||||
IntPtr ptr = ExtractSubtitles(path, outPath, out int arrayLength, out int trackCount);
|
||||
IntPtr ptr = extract_subtitles(path, outPath, out int arrayLength, out int trackCount);
|
||||
IntPtr streamsPtr = ptr;
|
||||
|
||||
if (trackCount > 0 && ptr != IntPtr.Zero)
|
||||
{
|
||||
tracks = new Track[trackCount];
|
||||
@ -47,12 +81,8 @@ namespace Kyoo.InternalAPI.TranscoderLink
|
||||
else
|
||||
tracks = null;
|
||||
|
||||
FreeMemory(ptr);
|
||||
free_memory(ptr);
|
||||
Debug.WriteLine("&" + tracks?.Length + " tracks got at: " + path);
|
||||
}
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
private extern static IntPtr TestMemory(string path, string outPath, out int arrayLength, out int trackCount);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,8 @@
|
||||
<None Remove="ClientApp\src\models\show.ts" />
|
||||
<None Remove="ClientApp\src\models\studio.ts" />
|
||||
<None Remove="ClientApp\src\models\watch-item.ts" />
|
||||
<None Remove="ClientApp\src\videoSupport\playbackMethodDetector.ts" />
|
||||
<None Remove="Transcoder\Kyoo.Transcoder.exp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -87,6 +89,7 @@
|
||||
<TypeScriptCompile Include="ClientApp\src\models\show.ts" />
|
||||
<TypeScriptCompile Include="ClientApp\src\models\studio.ts" />
|
||||
<TypeScriptCompile Include="ClientApp\src\models\watch-item.ts" />
|
||||
<TypeScriptCompile Include="ClientApp\src\videoSupport\playbackMethodDetector.ts" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -108,9 +111,6 @@
|
||||
<None Update="Transcoder\Kyoo.Transcoder.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Transcoder\Kyoo.Transcoder.exp">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Transcoder\Kyoo.Transcoder.ilk">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
@ -11,7 +11,7 @@ namespace Kyoo.Models
|
||||
{
|
||||
public enum StreamType
|
||||
{
|
||||
Audio, Subtitle, Unknow
|
||||
Video, Audio, Subtitle, Unknow
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
@ -78,28 +78,32 @@ namespace Kyoo.Models
|
||||
|
||||
public Track SetLink(string episodeSlug)
|
||||
{
|
||||
string language = Language;
|
||||
//Converting mkv track language to c# system language tag.
|
||||
if (language == "fre")
|
||||
language = "fra";
|
||||
|
||||
DisplayName = CultureInfo.GetCultures(CultureTypes.NeutralCultures).Where(x => x.ThreeLetterISOLanguageName == language).FirstOrDefault()?.DisplayName ?? language;
|
||||
Link = "/subtitle/" + episodeSlug + "." + Language;
|
||||
|
||||
if (IsForced)
|
||||
if (type == StreamType.Subtitle)
|
||||
{
|
||||
DisplayName += " Forced";
|
||||
Link += "-forced";
|
||||
string language = Language;
|
||||
//Converting mkv track language to c# system language tag.
|
||||
if (language == "fre")
|
||||
language = "fra";
|
||||
|
||||
DisplayName = CultureInfo.GetCultures(CultureTypes.NeutralCultures).Where(x => x.ThreeLetterISOLanguageName == language).FirstOrDefault()?.DisplayName ?? language;
|
||||
Link = "/subtitle/" + episodeSlug + "." + Language;
|
||||
|
||||
if (IsForced)
|
||||
{
|
||||
DisplayName += " Forced";
|
||||
Link += "-forced";
|
||||
}
|
||||
|
||||
if (Title != null && Title.Length > 1)
|
||||
DisplayName += " - " + Title;
|
||||
|
||||
if (Codec == "ass")
|
||||
Link += ".ass";
|
||||
else if (Codec == "subrip")
|
||||
Link += ".srt";
|
||||
}
|
||||
|
||||
if (Title != null && Title.Length > 1)
|
||||
DisplayName += " - " + Title;
|
||||
|
||||
if (Codec == "ass")
|
||||
Link += ".ass";
|
||||
else if (Codec == "subrip")
|
||||
Link += ".srt";
|
||||
|
||||
else
|
||||
Link = null;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Kyoo.InternalAPI;
|
||||
using Kyoo.Models.Watch;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -21,6 +20,8 @@ namespace Kyoo.Models
|
||||
public string previousEpisode;
|
||||
public Episode nextEpisode;
|
||||
|
||||
public string container;
|
||||
public Track video;
|
||||
public IEnumerable<Track> audios;
|
||||
public IEnumerable<Track> subtitles;
|
||||
|
||||
@ -60,7 +61,10 @@ namespace Kyoo.Models
|
||||
|
||||
public WatchItem SetStreams(ILibraryManager libraryManager)
|
||||
{
|
||||
(IEnumerable<Track> audios, IEnumerable<Track> subtitles) streams = libraryManager.GetStreams(episodeID, Link);
|
||||
(Track video, IEnumerable<Track> audios, IEnumerable<Track> subtitles) streams = libraryManager.GetStreams(episodeID, Link);
|
||||
|
||||
container = Path.Substring(Path.LastIndexOf('.') + 1);
|
||||
video = streams.video;
|
||||
audios = streams.audios;
|
||||
subtitles = streams.subtitles;
|
||||
return this;
|
||||
|
@ -13,7 +13,7 @@ namespace Kyoo
|
||||
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseKestrel()
|
||||
.UseKestrel((config) => { config.AddServerHeader = false; })
|
||||
.UseUrls("http://*:5000")
|
||||
.UseStartup<Startup>();
|
||||
}
|
||||
|
@ -53,6 +53,19 @@ namespace Kyoo
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.Use((ctx, next) =>
|
||||
{
|
||||
ctx.Response.Headers.Remove("X-Powered-By");
|
||||
ctx.Response.Headers.Remove("Server");
|
||||
ctx.Response.Headers.Add("Feature-Policy", "autoplay 'self'; fullscreen");
|
||||
ctx.Response.Headers.Add("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'");
|
||||
ctx.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
|
||||
ctx.Response.Headers.Add("Referrer-Policy", "no-referrer");
|
||||
ctx.Response.Headers.Add("Access-Control-Allow-Origin", "null");
|
||||
ctx.Response.Headers.Add("X-Content-Type-Options", "nosniff");
|
||||
return next();
|
||||
});
|
||||
|
||||
//app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
app.UseSpaStaticFiles();
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -9,7 +9,7 @@
|
||||
"AllowedHosts": "*",
|
||||
|
||||
"databasePath": "C://Projects/database.db",
|
||||
"tempPath": "C:\\\\Projects\\temp",
|
||||
"transmuxTempPath": "C:\\\\Projects\\temp\\transmux",
|
||||
"peoplePath": "D:\\\\Videos\\People",
|
||||
"plugins": "C:\\Projects\\Kyoo\\Debug",
|
||||
"providerPlugins": "C://Projects/Plugins/Providers",
|
||||
|
Loading…
x
Reference in New Issue
Block a user