remove v2 ui and node (#1564)
This commit is contained in:
@@ -2,8 +2,6 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<SpaRoot>client-app\</SpaRoot>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
|
||||
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
|
||||
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
@@ -17,43 +15,6 @@
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
|
||||
<!-- Build Target: Run webpack dist build -->
|
||||
<Message Importance="high" Text="Running npm build..." />
|
||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
|
||||
|
||||
<!-- Include the newly-built files in the publish output -->
|
||||
<ItemGroup>
|
||||
<DistFiles Include="wwwroot\v2\**" />
|
||||
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
|
||||
<RelativePath>%(DistFiles.Identity)</RelativePath>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</ResolvedFileToPublish>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build">
|
||||
<!-- Build Target: Ensure Node.js is installed -->
|
||||
<Exec Command="node --version" ContinueOnError="true">
|
||||
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
|
||||
</Exec>
|
||||
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
|
||||
</Target>
|
||||
|
||||
<Target Name="DebugEnsureNpm" AfterTargets="DebugEnsureNodeEnv">
|
||||
<!-- Build Target: Ensure Node.js is installed -->
|
||||
<Exec Command="npm --version" ContinueOnError="true">
|
||||
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
|
||||
</Exec>
|
||||
</Target>
|
||||
|
||||
<Target Name="EnsureNodeModulesInstalled" BeforeTargets="Build" Inputs="package.json" Outputs="packages-lock.json">
|
||||
<!-- Build Target: Restore NPM packages using npm -->
|
||||
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
|
||||
|
||||
<Exec WorkingDirectory="$(SpaRoot)" Command="npm ci" />
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Blazored.FluentValidation" Version="2.1.0" />
|
||||
<PackageReference Include="Bugsnag.AspNet.Core" Version="3.1.0" />
|
||||
@@ -88,12 +49,6 @@
|
||||
<PackageReference Include="VueCliMiddleware" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="$(SpaRoot)**" />
|
||||
<None Remove="$(SpaRoot)**" />
|
||||
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ErsatzTV.Application\ErsatzTV.Application.csproj" />
|
||||
<ProjectReference Include="..\ErsatzTV.Core\ErsatzTV.Core.csproj" />
|
||||
|
||||
@@ -288,12 +288,6 @@ public class Startup
|
||||
services.AddFluentValidationAutoValidation();
|
||||
services.AddValidatorsFromAssemblyContaining<Startup>();
|
||||
|
||||
string v2 = Environment.GetEnvironmentVariable("ETV_UI_V2");
|
||||
if (!CurrentEnvironment.IsDevelopment() && !string.IsNullOrWhiteSpace(v2))
|
||||
{
|
||||
services.AddSpaStaticFiles(options => options.RootPath = "wwwroot/v2");
|
||||
}
|
||||
|
||||
services.AddMemoryCache();
|
||||
|
||||
services.AddRazorPages(
|
||||
@@ -535,51 +529,12 @@ public class Startup
|
||||
app.UseAuthorization();
|
||||
}
|
||||
|
||||
string v2 = Environment.GetEnvironmentVariable("ETV_UI_V2");
|
||||
if (!env.IsDevelopment() && !string.IsNullOrWhiteSpace(v2))
|
||||
{
|
||||
app.Map(
|
||||
"/v2",
|
||||
app2 =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(env.WebRootPath))
|
||||
{
|
||||
env.WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
|
||||
}
|
||||
|
||||
app2.UseRouting();
|
||||
|
||||
if (OidcHelper.IsEnabled)
|
||||
{
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
}
|
||||
|
||||
app2.UseEndpoints(e => e.MapFallbackToFile("index.html"));
|
||||
app2.UseFileServer(
|
||||
new FileServerOptions
|
||||
{
|
||||
FileProvider = new PhysicalFileProvider(Path.Combine(env.WebRootPath, "v2"))
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
app.UseEndpoints(
|
||||
endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
endpoints.MapBlazorHub();
|
||||
endpoints.MapFallbackToPage("/_Host");
|
||||
|
||||
// if (env.IsDevelopment())
|
||||
// {
|
||||
// endpoints.MapToVueCliProxy(
|
||||
// "/v2/{*path}",
|
||||
// new SpaOptions { SourcePath = "client-app" },
|
||||
// "serve",
|
||||
// regex: "Compiled successfully",
|
||||
// forceKill: true);
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
VUE_APP_I18N_LOCALE=en
|
||||
VUE_APP_I18N_FALLBACK_LOCALE=en
|
||||
@@ -1,28 +0,0 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# generated files
|
||||
src/assets/css/*.css
|
||||
src/models/*.js
|
||||
src/models/*.js.map
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none"
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
# ErsatzTV Vuetify UI - WIP
|
||||
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
To set a custom ErsatzTV api URL, use the following environment variable `VUE_APP_ETV_BASE_URL`.
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
presets: ['@vue/cli-plugin-babel/preset']
|
||||
};
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "esnext",
|
||||
"baseUrl": "./",
|
||||
"moduleResolution": "node",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
}
|
||||
}
|
||||
Generated
-22229
File diff suppressed because it is too large
Load Diff
@@ -1,80 +0,0 @@
|
||||
{
|
||||
"name": "client-app",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"i18n:report": "vue-cli-service i18n:report --src \"./src/**/*.?(js|vue)\" --locales \"./src/locales/**/*.json\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@mdi/font": "5.9.55",
|
||||
"@sweetalert2/theme-dark": "^5.0.11",
|
||||
"axios": "^0.26.1",
|
||||
"core-js": "^3.8.3",
|
||||
"pinia": "^2.0.11",
|
||||
"pinia-plugin-persistedstate": "^1.5.1",
|
||||
"roboto-fontface": "*",
|
||||
"sweetalert2": "^11.4.17",
|
||||
"vue": "^2.6.14",
|
||||
"vue-class-component": "^7.2.6",
|
||||
"vue-i18n": "^8.26.3",
|
||||
"vue-property-decorator": "^9.1.2",
|
||||
"vue-router": "^3.2.0",
|
||||
"vue-sweetalert2": "^5.0.5",
|
||||
"vuetify": "^2.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.16",
|
||||
"@babel/eslint-parser": "^7.12.16",
|
||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||
"@typescript-eslint/parser": "^5.4.0",
|
||||
"@vue/cli-plugin-babel": "~5.0.0",
|
||||
"@vue/cli-plugin-eslint": "~5.0.0",
|
||||
"@vue/cli-plugin-typescript": "~5.0.0",
|
||||
"@vue/cli-service": "~5.0.0",
|
||||
"@vue/composition-api": "^1.4.9",
|
||||
"@vue/eslint-config-typescript": "^9.1.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-vue": "^8.0.3",
|
||||
"sass": "~1.32.0",
|
||||
"sass-loader": "^10.0.0",
|
||||
"typescript": "~4.5.5",
|
||||
"vue-cli-plugin-i18n": "~2.3.1",
|
||||
"vue-cli-plugin-vuetify": "~2.4.7",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vuetify-loader": "^1.7.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/essential",
|
||||
"plugin:prettier/recommended",
|
||||
"eslint:recommended",
|
||||
"@vue/typescript"
|
||||
],
|
||||
"parserOptions": {
|
||||
"parser": "@typescript-eslint/parser"
|
||||
},
|
||||
"rules": {
|
||||
"prettier/prettier": [
|
||||
"error",
|
||||
{
|
||||
"endOfLine": "auto",
|
||||
"tabWidth": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead"
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,17 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,36 +0,0 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<Toolbar />
|
||||
<!-- Sizes your content based upon application components -->
|
||||
<v-main>
|
||||
<!-- Provides the application the proper gutter -->
|
||||
<v-container fluid>
|
||||
<!-- If using vue-router -->
|
||||
<router-view></router-view>
|
||||
</v-container>
|
||||
<SnackBar />
|
||||
</v-main>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
import Toolbar from '@/components/Navigation/ToolBar.vue';
|
||||
import SnackBar from '@/components/PopUps/SnackBar';
|
||||
export default Vue.extend({
|
||||
name: 'App',
|
||||
components: { Toolbar, SnackBar },
|
||||
data: () => ({})
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
main {
|
||||
background-attachment: fixed;
|
||||
background-repeat: no-repeat;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,12 +0,0 @@
|
||||
.swal2-container.swal2-center > .swal2-popup {
|
||||
background-color: #1E1E1E !important;
|
||||
border-color: green;
|
||||
border-width: thin;
|
||||
border-style: solid;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.swal2-html-container, .swal2-title {
|
||||
color: white !important;
|
||||
font-family:Cambria;
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="67.791206mm"
|
||||
height="36.611721mm"
|
||||
viewBox="0 0 67.791206 36.611721"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
|
||||
sodipodi:docname="ersatztv-logo.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.49497475"
|
||||
inkscape:cx="199.98633"
|
||||
inkscape:cy="92.251514"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="3408"
|
||||
inkscape:window-height="1364"
|
||||
inkscape:window-x="14"
|
||||
inkscape:window-y="36"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-66.205082,-134.16488)">
|
||||
<g
|
||||
aria-label="Etv"
|
||||
id="text78"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;letter-spacing:0px;word-spacing:0px;fill:#c0c000;fill-opacity:1;stroke:none;stroke-width:0.264583">
|
||||
<path
|
||||
d="m 66.205082,170.2805 v -36.11562 h 24.159765 v 6.02754 H 73.671293 v 8.60722 h 14.262695 v 5.8291 H 73.671293 v 9.64903 h 16.767968 v 6.00273 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;font-family:Roboto;-inkscape-font-specification:'Roboto, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#c0c000;fill-opacity:1;stroke-width:0.264583"
|
||||
id="path98" />
|
||||
<path
|
||||
d="m 107.75293,170.10687 q -2.00918,0.66973 -4.31601,0.66973 -3.522269,0 -5.605863,-1.83555 -2.083593,-1.83555 -2.083593,-6.10195 v -14.16348 h -3.943946 v -5.23379 h 3.943946 v -6.62285 h 7.168556 v 6.62285 h 4.56406 v 5.23379 h -4.56406 v 13.41934 q 0,1.68671 0.69453,2.23242 0.69453,0.5457 2.05879,0.5457 1.0914,0 2.08359,-0.19844 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;font-family:Roboto;-inkscape-font-specification:'Roboto, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#00c0c0;fill-opacity:1;stroke-width:0.264583"
|
||||
id="path100" />
|
||||
<path
|
||||
d="m 133.99629,143.44183 -9.05371,26.83867 h -6.82129 l -9.07852,-26.83867 h 7.51583 l 4.98574,18.03301 4.96093,-18.03301 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;font-family:Roboto;-inkscape-font-specification:'Roboto, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#00c000;fill-opacity:1;stroke-width:0.264583"
|
||||
id="path102" />
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
|
||||
x="58.779785"
|
||||
y="199.18695"
|
||||
id="text82"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan80"
|
||||
x="58.779785"
|
||||
y="199.18695"
|
||||
style="stroke-width:0.264583"></tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.3 KiB |
@@ -1,77 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="191.74141mm"
|
||||
height="34.2752mm"
|
||||
viewBox="0 0 191.74141 34.2752"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
|
||||
sodipodi:docname="ersatztv.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.35"
|
||||
inkscape:cx="368.16022"
|
||||
inkscape:cy="84.671368"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
inkscape:window-width="3436"
|
||||
inkscape:window-height="1389"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-8.4242743,-125.76403)">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:19.8158px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.495396"
|
||||
x="5.4054561"
|
||||
y="159.5748"
|
||||
id="text841"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan839"
|
||||
x="5.4054561"
|
||||
y="159.5748"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:47.558px;font-family:Roboto;-inkscape-font-specification:'Roboto, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.495396"><tspan
|
||||
style="fill:#c0c000;fill-opacity:1"
|
||||
id="tspan843">Ersatz</tspan><tspan
|
||||
style="fill:#00c0c0;fill-opacity:1"
|
||||
id="tspan845">T</tspan><tspan
|
||||
style="fill:#00c000;fill-opacity:1"
|
||||
id="tspan847">V</tspan></tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.7 KiB |
@@ -1,44 +0,0 @@
|
||||
<template>
|
||||
<v-select
|
||||
v-on:change="setUserLanguage($event)"
|
||||
:value="language"
|
||||
dense
|
||||
outlined
|
||||
:items="langs"
|
||||
:label="$t('sidebar.languages')"
|
||||
class="ma-2"
|
||||
></v-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'pinia';
|
||||
import { languageState } from '@/stores/languageState';
|
||||
|
||||
export default {
|
||||
name: 'language-changer',
|
||||
data() {
|
||||
return {
|
||||
langs: [
|
||||
{ text: this.$t('languages-code.en'), value: 'en' },
|
||||
{ text: this.$t('languages-code.pt-br'), value: 'pt-br' }
|
||||
]
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(languageState, ['language', 'setLanguage']),
|
||||
languageCode: {
|
||||
get() {
|
||||
return languageState.language;
|
||||
},
|
||||
set(value) {
|
||||
this.setLanguage(value);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setUserLanguage: ($event) => {
|
||||
languageState().setLanguage($event);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,27 +0,0 @@
|
||||
<template>
|
||||
<span>
|
||||
<v-img
|
||||
v-if="!isNavigationMini"
|
||||
src="@/assets/images/ersatztv.svg"
|
||||
class="ma-3"
|
||||
></v-img>
|
||||
<v-img
|
||||
v-if="isNavigationMini"
|
||||
src="@/assets/images/ersatztv-logo.svg"
|
||||
class="ma-1"
|
||||
></v-img>
|
||||
<v-divider inset></v-divider>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'pinia';
|
||||
import { applicationState } from '@/stores/applicationState';
|
||||
|
||||
export default {
|
||||
name: 'SideBarLogo',
|
||||
computed: {
|
||||
...mapState(applicationState, ['isNavigationMini'])
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,43 +0,0 @@
|
||||
<template>
|
||||
<v-list nav dense>
|
||||
<span v-for="(nav, i) in navigation" :key="i">
|
||||
<SideBarMenuItem
|
||||
v-if="(!nav.children || !nav.showchildren) && !nav.meta.hidden"
|
||||
:name="nav.name"
|
||||
:path="nav.path"
|
||||
:icon="nav.meta.icon"
|
||||
:disabled="nav.meta.disabled"
|
||||
/>
|
||||
<SideBarMenuItemExpandable
|
||||
v-else-if="nav.children"
|
||||
@click.native="disableMiniNavigation()"
|
||||
:name="nav.name"
|
||||
:icon="nav.meta.icon"
|
||||
:disabled="nav.meta.disabled"
|
||||
:children="nav.children"
|
||||
/>
|
||||
</span>
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SideBarMenuItem from './SideBarMenuItem';
|
||||
import SideBarMenuItemExpandable from './SideBarMenuItemExpandable';
|
||||
import { mapState } from 'pinia';
|
||||
import { applicationState } from '@/stores/applicationState';
|
||||
|
||||
export default {
|
||||
name: 'NavSidebar',
|
||||
components: { SideBarMenuItem, SideBarMenuItemExpandable },
|
||||
data: () => ({
|
||||
navigation: null
|
||||
}),
|
||||
computed: {
|
||||
...mapState(applicationState, ['disableMiniNavigation'])
|
||||
},
|
||||
beforeMount: function () {
|
||||
//Pull in navigation from routes and load into DOM
|
||||
this.navigation = this.$router.options.routes;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,37 +0,0 @@
|
||||
<template>
|
||||
<v-list-item-group color="primary">
|
||||
<v-list-item :to="path" :disabled="disabled">
|
||||
<v-list-item-icon>
|
||||
<v-icon v-text="icon" :disabled="disabled" />
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="$t(name)" />
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SideBarMenuItem',
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
path: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,73 +0,0 @@
|
||||
<template>
|
||||
<v-list-group
|
||||
color="primary"
|
||||
v-model="menuItemOpened"
|
||||
:disabled="disabled"
|
||||
:prepend-icon="icon"
|
||||
no-action
|
||||
>
|
||||
<template v-slot:activator>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="$t(name)"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</template>
|
||||
|
||||
<v-list-item
|
||||
v-for="child in children"
|
||||
:key="child.name"
|
||||
:to="child.path"
|
||||
:disabled="child.meta.disabled"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<v-icon
|
||||
v-text="child.meta.icon"
|
||||
:disabled="child.meta.disabled"
|
||||
/>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="$t(child.name)"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-group>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SideBarMenuItemExpandable',
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
children: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
nonmenuchildren: {
|
||||
type: Array,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
opened: false
|
||||
}),
|
||||
computed: {
|
||||
menuItemOpened: {
|
||||
get: function () {
|
||||
return this.opened;
|
||||
},
|
||||
set: function () {
|
||||
return !this.opened;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,28 +0,0 @@
|
||||
<template>
|
||||
<span v-if="!isNavigationMini" class="text-center">
|
||||
<v-divider inset></v-divider>
|
||||
<h4 class="pt-2">ErsatzTV {{ $t('sidebar.version') }}</h4>
|
||||
|
||||
<p>{{ currentServerVersion }}</p>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'pinia';
|
||||
import { applicationState } from '@/stores/applicationState';
|
||||
|
||||
export default {
|
||||
name: 'SideBarVersion',
|
||||
setup() {
|
||||
applicationState().getVersion();
|
||||
},
|
||||
computed: {
|
||||
...mapState(applicationState, [
|
||||
'currentServerVersion',
|
||||
'isNavigationMini'
|
||||
])
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,53 +0,0 @@
|
||||
<template>
|
||||
<nav>
|
||||
<v-app-bar flat app dense absolute>
|
||||
<v-app-bar-nav-icon @click.stop="toggleMiniNavigation()" />
|
||||
|
||||
<ToolBarSearch />
|
||||
<v-spacer />
|
||||
|
||||
<ToolBarLinks />
|
||||
</v-app-bar>
|
||||
<v-navigation-drawer app :mini-variant="isNavigationMini" permanent>
|
||||
<template v-slot:prepend>
|
||||
<SideBarLogo />
|
||||
</template>
|
||||
|
||||
<SideBarMenu />
|
||||
|
||||
<template v-slot:append>
|
||||
<SideBarLanguageSelect />
|
||||
<SideBarVersion />
|
||||
</template>
|
||||
</v-navigation-drawer>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SideBarLogo from './SideBarLogo.vue';
|
||||
import SideBarMenu from './SideBarMenu.vue';
|
||||
import SideBarVersion from './SideBarVersion';
|
||||
import ToolBarLinks from './ToolBarLinks';
|
||||
import ToolBarSearch from './ToolBarSearch';
|
||||
import { mapState } from 'pinia';
|
||||
import { applicationState } from '@/stores/applicationState';
|
||||
import SideBarLanguageSelect from './SideBarLanguageSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'NavToolbar',
|
||||
components: {
|
||||
SideBarMenu,
|
||||
SideBarLogo,
|
||||
SideBarVersion,
|
||||
ToolBarLinks,
|
||||
ToolBarSearch,
|
||||
SideBarLanguageSelect
|
||||
},
|
||||
computed: {
|
||||
...mapState(applicationState, [
|
||||
'isNavigationMini',
|
||||
'toggleMiniNavigation'
|
||||
])
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,96 +0,0 @@
|
||||
<template>
|
||||
<span>
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn
|
||||
class="ma-2"
|
||||
outlined
|
||||
color="primary"
|
||||
@click="copyTextToClipboard(navBarURLs.m3uURL)"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
small
|
||||
>
|
||||
<v-icon>mdi-playlist-play</v-icon> M3U
|
||||
</v-btn>
|
||||
</template>
|
||||
<span>{{ $t('tool-bar.click-to-copy') }}</span>
|
||||
</v-tooltip>
|
||||
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn
|
||||
class="ma-2"
|
||||
outlined
|
||||
color="primary"
|
||||
@click="copyTextToClipboard(navBarURLs.xmlURL)"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
small
|
||||
>
|
||||
<v-icon>mdi-xml</v-icon> XML
|
||||
</v-btn>
|
||||
</template>
|
||||
<span>{{ $t('tool-bar.click-to-copy') }}</span>
|
||||
</v-tooltip>
|
||||
|
||||
<v-btn
|
||||
icon
|
||||
color="secondary"
|
||||
:href="navBarURLs.documentationURL"
|
||||
target="_blank"
|
||||
>
|
||||
<v-icon>mdi-file-document</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<v-btn
|
||||
icon
|
||||
color="secondary"
|
||||
:href="navBarURLs.discordURL"
|
||||
target="_blank"
|
||||
>
|
||||
<v-icon>mdi-discord</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<v-btn
|
||||
icon
|
||||
color="secondary"
|
||||
:href="navBarURLs.githubURL"
|
||||
target="_blank"
|
||||
>
|
||||
<v-icon>mdi-github</v-icon>
|
||||
</v-btn>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'pinia';
|
||||
import { applicationState } from '@/stores/applicationState';
|
||||
import { snackbarState } from '@/stores/snackbarState';
|
||||
|
||||
export default {
|
||||
name: 'ToolBarLinks.vue',
|
||||
data: () => ({
|
||||
toast: false
|
||||
}),
|
||||
computed: {
|
||||
...mapState(applicationState, ['navBarURLs']),
|
||||
...mapState(snackbarState, ['showSnackbar'])
|
||||
},
|
||||
methods: {
|
||||
copyTextToClipboard(text) {
|
||||
try {
|
||||
navigator.clipboard.writeText(text);
|
||||
this.showSnackbar(this.$t('tool-bar.copy-success'));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.showSnackbar(
|
||||
this.$t('tool-bar.copy-failure', { message: error })
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,18 +0,0 @@
|
||||
<template>
|
||||
<v-text-field
|
||||
outlined
|
||||
class="ml-5"
|
||||
:label="$t('tool-bar.search')"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
hide-details
|
||||
dense
|
||||
></v-text-field>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ToolBarSearch'
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,35 +0,0 @@
|
||||
<template>
|
||||
<v-snackbar v-model="snackbar" :timeout="timeout">
|
||||
{{ currentMessage }}
|
||||
<v-btn text color="primary" @click.native="closeSnackbar()"
|
||||
>Close</v-btn
|
||||
>
|
||||
</v-snackbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'pinia';
|
||||
import { snackbarState } from '@/stores/snackbarState';
|
||||
|
||||
export default {
|
||||
data: () => ({
|
||||
timeout: 4000
|
||||
}),
|
||||
computed: {
|
||||
...mapState(snackbarState, [
|
||||
'currentMessage',
|
||||
'isVisible',
|
||||
'closeSnackbar',
|
||||
'openSnackbar'
|
||||
]),
|
||||
snackbar: {
|
||||
get() {
|
||||
return this.isVisible;
|
||||
},
|
||||
set() {
|
||||
this.closeSnackbar();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,206 +0,0 @@
|
||||
{
|
||||
"$vuetify": {
|
||||
"badge": "Badge",
|
||||
"close": "Close",
|
||||
"dataIterator": {
|
||||
"noResultsText": "No matching records found",
|
||||
"loadingText": "Loading items..."
|
||||
},
|
||||
"dataTable": {
|
||||
"itemsPerPageText": "Rows per page:",
|
||||
"ariaLabel": {
|
||||
"sortDescending": "Sorted descending.",
|
||||
"sortAscending": "Sorted ascending.",
|
||||
"sortNone": "Not sorted.",
|
||||
"activateNone": "Activate to remove sorting.",
|
||||
"activateDescending": "Activate to sort descending.",
|
||||
"activateAscending": "Activate to sort ascending."
|
||||
},
|
||||
"sortBy": "Sort by"
|
||||
},
|
||||
"dataFooter": {
|
||||
"itemsPerPageText": "Items per page:",
|
||||
"itemsPerPageAll": "All",
|
||||
"nextPage": "Next page",
|
||||
"prevPage": "Previous page",
|
||||
"firstPage": "First page",
|
||||
"lastPage": "Last page",
|
||||
"pageText": "{0}-{1} of {2}"
|
||||
},
|
||||
"datePicker": {
|
||||
"itemsSelected": "{0} selected",
|
||||
"nextMonthAriaLabel": "Next month",
|
||||
"nextYearAriaLabel": "Next year",
|
||||
"prevMonthAriaLabel": "Previous month",
|
||||
"prevYearAriaLabel": "Previous year"
|
||||
},
|
||||
"noDataText": "No data available",
|
||||
"carousel": {
|
||||
"prev": "Previous visual",
|
||||
"next": "Next visual",
|
||||
"ariaLabel": {
|
||||
"delimiter": "Carousel slide {0} of {1}"
|
||||
}
|
||||
},
|
||||
"calendar": {
|
||||
"moreEvents": "{0} more"
|
||||
},
|
||||
"fileInput": {
|
||||
"counter": "{0} files",
|
||||
"counterSize": "{0} files ({1} in total)"
|
||||
},
|
||||
"timePicker": {
|
||||
"am": "AM",
|
||||
"pm": "PM"
|
||||
},
|
||||
"pagination": {
|
||||
"ariaLabel": {
|
||||
"wrapper": "Pagination Navigation",
|
||||
"next": "Next page",
|
||||
"previous": "Previous page",
|
||||
"page": "Goto Page {0}",
|
||||
"currentPage": "Current Page, Page {0}"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"ariaLabel": {
|
||||
"icon": "Rating {0} of {1}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"languages-code": {
|
||||
"en": "English",
|
||||
"pt-br": "Portuguese (Brazil)"
|
||||
},
|
||||
"tool-bar": {
|
||||
"search": "Search...",
|
||||
"click-to-copy": "Click to copy to clipboard!",
|
||||
"copy-success": "Successfully copied text to clipboard!",
|
||||
"copy-failure": "Failed to copy text to clipboard! Error: {message}"
|
||||
},
|
||||
"sidebar": {
|
||||
"languages": "Languages",
|
||||
"version": "Version"
|
||||
},
|
||||
"home": {
|
||||
"title": "Home"
|
||||
},
|
||||
"ffmpeg-profiles": {
|
||||
"title": "FFmpeg Profiles",
|
||||
"add-profile": "Add FFmpeg Profile",
|
||||
"actions": "Actions",
|
||||
"delete-dialog-title": "Are you sure?",
|
||||
"delete-dialog-text": "Delete {profileName} FFmpeg Profile?",
|
||||
"no": "No",
|
||||
"yes": "Yes",
|
||||
"profile-deleted": "FFmpeg Profile deleted!",
|
||||
"table": {
|
||||
"name": "Name",
|
||||
"resolution": "Resolution",
|
||||
"video": "Video",
|
||||
"audio": "Audio"
|
||||
}
|
||||
},
|
||||
"edit-ffmpeg-profile": {
|
||||
"General": "General",
|
||||
"Video": "Video",
|
||||
"Audio": "Audio",
|
||||
"Name": "Name",
|
||||
"thread-count": "Thread Count",
|
||||
"preferred-resolution": "Preferred Resolution",
|
||||
"format": "Format",
|
||||
"bitrate": "Bitrate",
|
||||
"buffer-size": "Buffer Size",
|
||||
"hardware-acceleration": "Hardware Acceleration",
|
||||
"vaapi-driver": "VAAPI Driver",
|
||||
"vaapi-device": "VAAPI Device",
|
||||
"normalize-framerate": "Normalize Framerate",
|
||||
"auto-deinterlace-video": "Auto Deinterlace Video",
|
||||
"channels": "Channels",
|
||||
"sample-rate": "Sample Rate",
|
||||
"normalize-loudness": "Normalize Loudness",
|
||||
"save-profile": "Save Profile",
|
||||
"cancel": "Cancel",
|
||||
"help": "Help",
|
||||
"add-profile": "Add FFmpeg Profile",
|
||||
"edit-profile": "Edit FFmpeg Profile",
|
||||
"profile-saved": "FFmpeg Profile Saved!"
|
||||
},
|
||||
"watermarks": {
|
||||
"title": "Watermarks"
|
||||
},
|
||||
"media-sources": {
|
||||
"title": "Media Sources",
|
||||
"local": {
|
||||
"title": "Local"
|
||||
},
|
||||
"emby": {
|
||||
"title": "Emby"
|
||||
},
|
||||
"jellyfin": {
|
||||
"title": "Jellyfin"
|
||||
},
|
||||
"plex": {
|
||||
"title": "Plex"
|
||||
}
|
||||
},
|
||||
"lists": {
|
||||
"title": "Lists",
|
||||
"collections": {
|
||||
"title": "Collections"
|
||||
},
|
||||
"trakt-lists": {
|
||||
"title": "Trakt Lists"
|
||||
},
|
||||
"filler-presets": {
|
||||
"title": "Filler Presets"
|
||||
}
|
||||
},
|
||||
"schedules": {
|
||||
"title": "Schedules"
|
||||
},
|
||||
"playouts": {
|
||||
"title": "Playouts"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Settings"
|
||||
},
|
||||
"logs": {
|
||||
"title": "Logs"
|
||||
},
|
||||
"media": {
|
||||
"title": "Media",
|
||||
"libraries": {
|
||||
"title": "Libraries"
|
||||
},
|
||||
"trash": {
|
||||
"title": "Trash"
|
||||
},
|
||||
"tv-shows": {
|
||||
"title": "TV Shows"
|
||||
},
|
||||
"movies": {
|
||||
"title": "Movies"
|
||||
},
|
||||
"music-videos": {
|
||||
"title": "Music Videos"
|
||||
},
|
||||
"other-videos": {
|
||||
"title": "Other Videos"
|
||||
},
|
||||
"songs": {
|
||||
"title": "Songs"
|
||||
}
|
||||
},
|
||||
"channels": {
|
||||
"title": "Channels",
|
||||
"table": {
|
||||
"number": "Number",
|
||||
"logo": "Logo",
|
||||
"name": "Name",
|
||||
"language": "Language",
|
||||
"mode": "Mode",
|
||||
"ffmpeg-profile": "FFmpeg Profile"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
{
|
||||
"$vuetify": {
|
||||
"badge": "Distintivo",
|
||||
"close": "Fechar",
|
||||
"Actions": "Ações",
|
||||
"dataIterator": {
|
||||
"noResultsText": "Nenhum dado encontrado",
|
||||
"loadingText": "Carregando itens..."
|
||||
},
|
||||
"dataTable": {
|
||||
"itemsPerPageText": "Linhas por página:",
|
||||
"ariaLabel": {
|
||||
"sortDescending": "Ordenado decrescente.",
|
||||
"sortAscending": "Ordenado crescente.",
|
||||
"sortNone": "Não ordenado.",
|
||||
"activateNone": "Ative para remover a ordenação.",
|
||||
"activateDescending": "Ative para ordenar decrescente.",
|
||||
"activateAscending": "Ative para ordenar crescente."
|
||||
},
|
||||
"sortBy": "Ordenar por"
|
||||
},
|
||||
"dataFooter": {
|
||||
"itemsPerPageText": "Itens por página:",
|
||||
"itemsPerPageAll": "Todos",
|
||||
"nextPage": "Próxima página",
|
||||
"prevPage": "Página anterior",
|
||||
"firstPage": "Primeira página",
|
||||
"lastPage": "Última página",
|
||||
"pageText": "{0}-{1} de {2}"
|
||||
},
|
||||
"datePicker": {
|
||||
"itemsSelected": "{0} selecionado(s)",
|
||||
"nextMonthAriaLabel": "Próximo mês",
|
||||
"nextYearAriaLabel": "Próximo ano",
|
||||
"prevMonthAriaLabel": "Mês anterior",
|
||||
"prevYearAriaLabel": "Ano anterior"
|
||||
},
|
||||
"noDataText": "Não há dados disponíveis",
|
||||
"carousel": {
|
||||
"prev": "Visão anterior",
|
||||
"next": "Próxima visão",
|
||||
"ariaLabel": {
|
||||
"delimiter": "Slide {0} de {1} do carrossel"
|
||||
}
|
||||
},
|
||||
"calendar": {
|
||||
"moreEvents": "Mais {0}"
|
||||
},
|
||||
"fileInput": {
|
||||
"counter": "{0} arquivo(s)",
|
||||
"counterSize": "{0} arquivo(s) ({1} no total)"
|
||||
},
|
||||
"timePicker": {
|
||||
"am": "AM",
|
||||
"pm": "PM"
|
||||
},
|
||||
"pagination": {
|
||||
"ariaLabel": {
|
||||
"wrapper": "Navegação de paginação",
|
||||
"next": "Próxima página",
|
||||
"previous": "Página anterior",
|
||||
"page": "Ir à página {0}",
|
||||
"currentPage": "Página atual, página {0}"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"ariaLabel": {
|
||||
"icon": "Rating {0} de {1}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"languages-code": {
|
||||
"en": "Inglês",
|
||||
"pt-br": "Português (Brasil)"
|
||||
},
|
||||
"tool-bar": {
|
||||
"search": "Busca...",
|
||||
"click-to-copy": "Clique para copiar para a área de transferência!",
|
||||
"copy-success": "Texto copiado com sucesso para a área de transferência!",
|
||||
"copy-failure": "Falha ao copiar o texto para a área de transferência! Erro: {message}"
|
||||
},
|
||||
"sidebar": {
|
||||
"languages": "Línguas",
|
||||
"version": "Versão"
|
||||
},
|
||||
"home": {
|
||||
"title": "Início"
|
||||
},
|
||||
"ffmpeg-profiles": {
|
||||
"title": "Perfis FFmpeg",
|
||||
"add-profile": "Adicionar perfil FFmpeg",
|
||||
"actions": "Ações",
|
||||
"delete-dialog-title": "Tem certeza?",
|
||||
"delete-dialog-text": "Excluir perfil {profileName} do FFmpeg?",
|
||||
"no": "Não",
|
||||
"yes": "Sim",
|
||||
"profile-deleted": "Perfil do FFmpeg excluído!",
|
||||
"table": {
|
||||
"name": "Nome",
|
||||
"resolution": "Resolução",
|
||||
"video": "Vídeo",
|
||||
"audio": "Áudio"
|
||||
}
|
||||
},
|
||||
"edit-ffmpeg-profile": {
|
||||
"General": "Em geral",
|
||||
"Video": "Vídeo",
|
||||
"Audio": "Áudio",
|
||||
"Name": "Nome",
|
||||
"thread-count": "Contagem de fios",
|
||||
"preferred-resolution": "Resolução preferencial",
|
||||
"format": "Formato",
|
||||
"bitrate": "Taxa de bits",
|
||||
"buffer-size": "Tamanho do buffer",
|
||||
"hardware-acceleration": "Aceleraçao do hardware",
|
||||
"vaapi-driver": "Driver VAAPI",
|
||||
"vaapi-device": "Dispositivo VAAPI",
|
||||
"normalize-framerate": "Normalizar taxa de quadros",
|
||||
"auto-deinterlace-video": "Vídeo de desentrelaçamento automático",
|
||||
"channels": "Canais",
|
||||
"sample-rate": "Taxa de amostragem",
|
||||
"normalize-loudness": "Normalizar volume",
|
||||
"save-profile": "Salvar perfil",
|
||||
"cancel": "Cancelar",
|
||||
"help": "Ajuda",
|
||||
"add-profile": "Adicionar perfil FFmpeg",
|
||||
"edit-profile": "Editar perfil do FFmpeg",
|
||||
"profile-saved": "Perfil do FFmpeg salvo!"
|
||||
},
|
||||
"watermarks": {
|
||||
"title": "Marcas d'água"
|
||||
},
|
||||
"media-sources": {
|
||||
"title": "Fontes de mídia",
|
||||
"local": {
|
||||
"title": "Local"
|
||||
},
|
||||
"emby": {
|
||||
"title": "Emby"
|
||||
},
|
||||
"jellyfin": {
|
||||
"title": "Jellyfin"
|
||||
},
|
||||
"plex": {
|
||||
"title": "Plex"
|
||||
}
|
||||
},
|
||||
"lists": {
|
||||
"title": "Listas",
|
||||
"collections": {
|
||||
"title": "Coleções"
|
||||
},
|
||||
"trakt-lists": {
|
||||
"title": "Listas Trakt"
|
||||
},
|
||||
"filler-presets": {
|
||||
"title": "Predefinições de preenchimento"
|
||||
}
|
||||
},
|
||||
"schedules": {
|
||||
"title": "Horários"
|
||||
},
|
||||
"playouts": {
|
||||
"title": "Playouts"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Definições"
|
||||
},
|
||||
"logs": {
|
||||
"title": "Logs"
|
||||
},
|
||||
"media": {
|
||||
"title": "Mídias",
|
||||
"libraries": {
|
||||
"title": "Bibliotecas"
|
||||
},
|
||||
"trash": {
|
||||
"title": "Lixo"
|
||||
},
|
||||
"tv-shows": {
|
||||
"title": "Séries"
|
||||
},
|
||||
"movies": {
|
||||
"title": "Filmes"
|
||||
},
|
||||
"music-videos": {
|
||||
"title": "Vídeos de música"
|
||||
},
|
||||
"other-videos": {
|
||||
"title": "Other Videos"
|
||||
},
|
||||
"songs": {
|
||||
"title": "Songs"
|
||||
}
|
||||
},
|
||||
"channels": {
|
||||
"title": "Canais",
|
||||
"table": {
|
||||
"number": "Numero",
|
||||
"logo": "Logo",
|
||||
"name": "Nome",
|
||||
"language": "Idioma",
|
||||
"mode": "Modo",
|
||||
"ffmpeg-profile": "Perfil FFmpeg"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import App from './App.vue';
|
||||
import vuetify from './plugins/vuetify';
|
||||
import router from './router';
|
||||
import { createPinia, PiniaVuePlugin } from 'pinia';
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
|
||||
import autoPageTitleMixin from './mixins/autoPageTitle';
|
||||
import 'roboto-fontface/css/roboto/roboto-fontface.css';
|
||||
import '@mdi/font/css/materialdesignicons.css';
|
||||
import i18n from './plugins/i18n';
|
||||
import VueSweetalert2 from 'vue-sweetalert2';
|
||||
import 'sweetalert2/dist/sweetalert2.min.css';
|
||||
import './assets/css/global.scss';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
Vue.use(PiniaVuePlugin);
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate);
|
||||
// Mixin to automate the page title when navigating... Will default to "ErsatzTV if no title value exported from page.
|
||||
Vue.mixin(autoPageTitleMixin);
|
||||
|
||||
const options = {
|
||||
confirmButtonColor: '#1E1E1E',
|
||||
cancelButtonColor: '#1E1E1E',
|
||||
background: '#1E1E1E',
|
||||
iconColor: '#4CAF50'
|
||||
};
|
||||
Vue.use(VueSweetalert2, options);
|
||||
|
||||
new Vue({
|
||||
vuetify,
|
||||
router,
|
||||
pinia,
|
||||
i18n,
|
||||
render: (h) => h(App)
|
||||
}).$mount('#app');
|
||||
@@ -1,18 +0,0 @@
|
||||
function getTitle(vm) {
|
||||
const { title } = vm.$options;
|
||||
if (title) {
|
||||
return typeof title === 'function' ? title.call(vm) : title;
|
||||
}
|
||||
if (vm._data.title) {
|
||||
return vm._data.title;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
created() {
|
||||
const title = getTitle(this);
|
||||
if (title) {
|
||||
document.title = `ErsatzTV | ${title}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
export interface Channel {
|
||||
id: number;
|
||||
number: string;
|
||||
name: string;
|
||||
streamingMode: string;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
export interface FFmpegFullProfile {
|
||||
Id: number;
|
||||
name: string;
|
||||
threadCount: number;
|
||||
hardwareAcceleration: number;
|
||||
vaapiDriver: number;
|
||||
vaapiDevice: string;
|
||||
resolutionId: number;
|
||||
videoFormat: number;
|
||||
videoBitrate: number;
|
||||
videoBufferSize: number;
|
||||
audioFormat: number;
|
||||
audioBitrate: number;
|
||||
audioBufferSize: number;
|
||||
normalizeLoudness: boolean;
|
||||
audioChannels: number;
|
||||
audioSampleRate: number;
|
||||
normalizeFramerate: boolean;
|
||||
deinterlaceVideo: boolean;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
export interface FFmpegProfile {
|
||||
id: number;
|
||||
name: string;
|
||||
resolution: string;
|
||||
video: string;
|
||||
audio: string;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import VueI18n, { LocaleMessages } from 'vue-i18n';
|
||||
|
||||
Vue.use(VueI18n);
|
||||
|
||||
function loadLocaleMessages(): LocaleMessages {
|
||||
const locales = require.context(
|
||||
'../locales',
|
||||
true,
|
||||
/[A-Za-z0-9-_,\s]+\.json$/i
|
||||
);
|
||||
const messages: LocaleMessages = {};
|
||||
locales.keys().forEach((key) => {
|
||||
const matched = key.match(/([A-Za-z0-9-_]+)\./i);
|
||||
if (matched && matched.length > 1) {
|
||||
const locale = matched[1];
|
||||
messages[locale] = locales(key);
|
||||
}
|
||||
});
|
||||
return messages;
|
||||
}
|
||||
|
||||
export default new VueI18n({
|
||||
locale: process.env.VUE_APP_I18N_LOCALE || 'en',
|
||||
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en',
|
||||
messages: loadLocaleMessages()
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import Vuetify from 'vuetify';
|
||||
import colors from 'vuetify/lib/util/colors';
|
||||
import VueI18n from './i18n';
|
||||
|
||||
Vue.use(Vuetify);
|
||||
|
||||
export default new Vuetify({
|
||||
icons: {
|
||||
iconfont: 'mdi' // default - only for display purposes
|
||||
},
|
||||
theme: {
|
||||
themes: {
|
||||
dark: {
|
||||
primary: '#c0c000',
|
||||
secondary: '#00c0c0',
|
||||
accent: colors.yellow.accent2,
|
||||
error: colors.red,
|
||||
warning: colors.orange,
|
||||
info: colors.lightBlue,
|
||||
success: colors.green,
|
||||
background: '#121212'
|
||||
}
|
||||
},
|
||||
options: {
|
||||
customProperties: true
|
||||
},
|
||||
dark: true
|
||||
},
|
||||
lang: {
|
||||
t: (key, ...params) => VueI18n.t(key, params).toString()
|
||||
}
|
||||
});
|
||||
@@ -1,252 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import VueRouter from 'vue-router';
|
||||
import HomePage from '../views/HomePage.vue';
|
||||
import ChannelsPage from '../views/ChannelsPage.vue';
|
||||
import FFmpegProfilesPage from '../views/FFmpegProfilesPage.vue';
|
||||
import AddEditFFmpegProfilePage from '../views/AddEditFFmpegProfilePage.vue';
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home.title',
|
||||
component: HomePage,
|
||||
meta: {
|
||||
icon: 'mdi-home',
|
||||
disabled: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/channels',
|
||||
name: 'channels.title',
|
||||
component: ChannelsPage,
|
||||
meta: {
|
||||
icon: 'mdi-broadcast',
|
||||
disabled: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/ffmpeg-profiles',
|
||||
name: 'ffmpeg-profiles.title',
|
||||
component: FFmpegProfilesPage,
|
||||
meta: {
|
||||
icon: 'mdi-video-input-component',
|
||||
disabled: false
|
||||
},
|
||||
showchildren: false
|
||||
},
|
||||
{
|
||||
path: '/watermarks',
|
||||
name: 'watermarks.title',
|
||||
meta: {
|
||||
icon: 'mdi-watermark',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/sources',
|
||||
name: 'media-sources.title',
|
||||
meta: {
|
||||
icon: 'mdi-server-network',
|
||||
disabled: false
|
||||
},
|
||||
showchildren: true,
|
||||
children: [
|
||||
{
|
||||
path: '/sources/local',
|
||||
name: 'media-sources.local.title',
|
||||
meta: {
|
||||
icon: 'mdi-folder',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/sources/emby',
|
||||
name: 'media-sources.emby.title',
|
||||
meta: {
|
||||
icon: 'mdi-emby',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/sources/jellyfin',
|
||||
name: 'media-sources.jellyfin.title',
|
||||
meta: {
|
||||
icon: 'mdi-jellyfish',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/sources/plex',
|
||||
name: 'media-sources.plex.title',
|
||||
meta: {
|
||||
icon: 'mdi-plex',
|
||||
disabled: true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/media',
|
||||
name: 'media.title',
|
||||
meta: {
|
||||
icon: 'mdi-cog',
|
||||
disabled: false
|
||||
},
|
||||
showchildren: true,
|
||||
children: [
|
||||
{
|
||||
path: '/media/libraries',
|
||||
name: 'media.libraries.title',
|
||||
meta: {
|
||||
icon: 'mdi-library',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/media/trash',
|
||||
name: 'media.trash.title',
|
||||
meta: {
|
||||
icon: 'mdi-trash-can',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/media/tv-shows',
|
||||
name: 'media.tv-shows.title',
|
||||
meta: {
|
||||
icon: 'mdi-television-classic',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/media/movies',
|
||||
name: 'media.movies.title',
|
||||
meta: {
|
||||
icon: 'mdi-movie',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/media/music-videos',
|
||||
name: 'media.music-videos.title',
|
||||
meta: {
|
||||
icon: 'mdi-music-circle',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/media/other-videos',
|
||||
name: 'media.other-videos.title',
|
||||
meta: {
|
||||
icon: 'mdi-video',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/media/songs',
|
||||
name: 'media.songs.title',
|
||||
meta: {
|
||||
icon: 'mdi-album',
|
||||
disabled: true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/lists',
|
||||
name: 'lists.title',
|
||||
meta: {
|
||||
icon: 'mdi-format-list-bulleted',
|
||||
disabled: false
|
||||
},
|
||||
showchildren: true,
|
||||
children: [
|
||||
{
|
||||
path: '/lists/collections',
|
||||
name: 'lists.collections.title',
|
||||
meta: {
|
||||
icon: 'mdi-collage',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/lists/trakt-lists',
|
||||
name: 'lists.trakt-lists.title',
|
||||
meta: {
|
||||
icon: 'mdi-hammer',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/lists/filler-presets',
|
||||
name: 'lists.filler-presets.title',
|
||||
meta: {
|
||||
icon: 'mdi-tune-vertical',
|
||||
disabled: true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/schedules',
|
||||
name: 'schedules.title',
|
||||
meta: {
|
||||
icon: 'mdi-calendar',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/playouts',
|
||||
name: 'playouts.title',
|
||||
meta: {
|
||||
icon: 'mdi-clipboard-play-multiple',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/settings',
|
||||
name: 'settings.title',
|
||||
meta: {
|
||||
icon: 'mdi-cog',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/Logs',
|
||||
name: 'logs.title',
|
||||
meta: {
|
||||
icon: 'mdi-card-text',
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
//hidden routes - used for non-menu routes
|
||||
{
|
||||
path: '/add-ffmpeg-profile',
|
||||
name: 'add-ffmpeg-profile',
|
||||
component: AddEditFFmpegProfilePage,
|
||||
meta: {
|
||||
disabled: false,
|
||||
hidden: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/edit-ffmpeg-profile',
|
||||
name: 'edit-ffmpeg',
|
||||
component: AddEditFFmpegProfilePage,
|
||||
meta: {
|
||||
disabled: false,
|
||||
hidden: true
|
||||
},
|
||||
props: (route) => ({ query: route.query.id })
|
||||
}
|
||||
];
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: 'history',
|
||||
base: process.env.BASE_URL,
|
||||
routes
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -1,72 +0,0 @@
|
||||
import type { AxiosError, AxiosInstance, AxiosResponse } from 'axios';
|
||||
import axios from 'axios';
|
||||
|
||||
export function isAxiosError(value: any): value is AxiosError {
|
||||
return typeof value?.response === 'object';
|
||||
}
|
||||
|
||||
export abstract class AbstractApiService {
|
||||
protected readonly http: AxiosInstance;
|
||||
|
||||
protected constructor(
|
||||
protected readonly path?: string,
|
||||
protected readonly baseURL: string = process.env.VUE_APP_ETV_BASE_URL ??
|
||||
'/'
|
||||
) {
|
||||
if (path) {
|
||||
this.baseURL += path;
|
||||
}
|
||||
this.http = axios.create({
|
||||
baseURL
|
||||
// ... further stuff, e.g. `withCredentials: true`
|
||||
});
|
||||
this.http.defaults.headers.common['Accept'] =
|
||||
'application/json;charset=UTF-8';
|
||||
this.http.defaults.headers.common['Content-Type'] =
|
||||
'application/json;charset=UTF-8';
|
||||
}
|
||||
|
||||
protected createParams(record: Record<string, any>): URLSearchParams {
|
||||
const params: URLSearchParams = new URLSearchParams();
|
||||
for (const key in record) {
|
||||
if (Object.prototype.hasOwnProperty.call(record, key)) {
|
||||
const value: any = record[key];
|
||||
if (value !== null && value !== undefined) {
|
||||
params.append(key, value);
|
||||
} else {
|
||||
console.debug(
|
||||
`Param key '${key}' was null or undefined and will be ignored`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
protected handleResponse<T>(response: AxiosResponse<T>): T {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
protected handleError(error: unknown): never {
|
||||
if (error instanceof Error) {
|
||||
if (isAxiosError(error)) {
|
||||
if (error.response) {
|
||||
console.log(error.response.data);
|
||||
console.log(error.response.status);
|
||||
console.log(error.response.headers);
|
||||
throw error;
|
||||
} else if (error.request) {
|
||||
// The request was made but no response was received
|
||||
// `error.request` is an instance of XMLHttpRequest in the browser
|
||||
console.log(error.request);
|
||||
throw new Error(error as any);
|
||||
}
|
||||
} else {
|
||||
// Something happened in setting up the request that triggered an Error
|
||||
console.log('Error', error.message);
|
||||
throw new Error(error.message);
|
||||
}
|
||||
}
|
||||
throw new Error(error as any);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { AbstractApiService } from './AbstractApiService';
|
||||
import { Channel } from '@/models/Channel';
|
||||
|
||||
class ChannelApiService extends AbstractApiService {
|
||||
public constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public getAll(): Promise<Channel[]> {
|
||||
return this.http
|
||||
.get('/api/channels')
|
||||
.then(this.handleResponse.bind(this))
|
||||
.catch(this.handleError.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
export const channelApiService: ChannelApiService = new ChannelApiService();
|
||||
@@ -1,114 +0,0 @@
|
||||
import { AbstractApiService } from './AbstractApiService';
|
||||
import { FFmpegProfile } from '@/models/FFmpegProfile';
|
||||
import { FFmpegFullProfile } from '../models/FFmpegFullProfile';
|
||||
|
||||
class FFmpegProfileApiService extends AbstractApiService {
|
||||
public constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public getAll(): Promise<FFmpegProfile[]> {
|
||||
return this.http
|
||||
.get('/api/ffmpeg/profiles')
|
||||
.then(this.handleResponse.bind(this))
|
||||
.catch(this.handleError.bind(this));
|
||||
}
|
||||
|
||||
public getOne(id: string): Promise<FFmpegFullProfile[]> {
|
||||
return this.http
|
||||
.get('/api/ffmpeg/profiles/' + id)
|
||||
.then(this.handleResponse.bind(this))
|
||||
.catch(this.handleError.bind(this));
|
||||
}
|
||||
|
||||
public newFFmpegProfile(
|
||||
Name: string,
|
||||
ThreadCount: number,
|
||||
HardwareAcceleration: number,
|
||||
VaapiDriver: number,
|
||||
VaapiDevice: string,
|
||||
ResolutionId: number,
|
||||
VideoFormat: number,
|
||||
VideoBitrate: number,
|
||||
VideoBufferSize: number,
|
||||
AudioFormat: number,
|
||||
AudioBitrate: number,
|
||||
AudioBufferSize: number,
|
||||
NormalizeLoudness: boolean,
|
||||
AudioChannels: number,
|
||||
AudioSampleRate: number,
|
||||
NormalizeFramerate: boolean,
|
||||
DeinterlaceVideo: boolean
|
||||
) {
|
||||
const data = {
|
||||
Name: Name,
|
||||
ThreadCount: ThreadCount,
|
||||
HardwareAcceleration: HardwareAcceleration,
|
||||
VaapiDriver: VaapiDriver,
|
||||
VaapiDevice: VaapiDevice,
|
||||
ResolutionId: ResolutionId,
|
||||
VideoFormat: VideoFormat,
|
||||
VideoBitrate: VideoBitrate,
|
||||
VideoBufferSize: VideoBufferSize,
|
||||
AudioFormat: AudioFormat,
|
||||
AudioBitrate: AudioBitrate,
|
||||
AudioBufferSize: AudioBufferSize,
|
||||
NormalizeLoudness: NormalizeLoudness,
|
||||
AudioChannels: AudioChannels,
|
||||
AudioSampleRate: AudioSampleRate,
|
||||
NormalizeFramerate: NormalizeFramerate,
|
||||
DeinterlaceVideo: DeinterlaceVideo
|
||||
};
|
||||
this.http.post('/api/ffmpeg/profiles/new', data);
|
||||
}
|
||||
|
||||
public updateFFmpegProfile(
|
||||
Id: number,
|
||||
Name: string,
|
||||
ThreadCount: number,
|
||||
HardwareAcceleration: number,
|
||||
VaapiDriver: number,
|
||||
VaapiDevice: string,
|
||||
ResolutionId: number,
|
||||
VideoFormat: number,
|
||||
VideoBitrate: number,
|
||||
VideoBufferSize: number,
|
||||
AudioFormat: number,
|
||||
AudioBitrate: number,
|
||||
AudioBufferSize: number,
|
||||
NormalizeLoudness: boolean,
|
||||
AudioChannels: number,
|
||||
AudioSampleRate: number,
|
||||
NormalizeFramerate: boolean,
|
||||
DeinterlaceVideo: boolean
|
||||
) {
|
||||
const data = {
|
||||
Id: Id,
|
||||
Name: Name,
|
||||
ThreadCount: ThreadCount,
|
||||
HardwareAcceleration: HardwareAcceleration,
|
||||
VaapiDriver: VaapiDriver,
|
||||
VaapiDevice: VaapiDevice,
|
||||
ResolutionId: ResolutionId,
|
||||
VideoFormat: VideoFormat,
|
||||
VideoBitrate: VideoBitrate,
|
||||
VideoBufferSize: VideoBufferSize,
|
||||
AudioFormat: AudioFormat,
|
||||
AudioBitrate: AudioBitrate,
|
||||
AudioBufferSize: AudioBufferSize,
|
||||
NormalizeLoudness: NormalizeLoudness,
|
||||
AudioChannels: AudioChannels,
|
||||
AudioSampleRate: AudioSampleRate,
|
||||
NormalizeFramerate: NormalizeFramerate,
|
||||
DeinterlaceVideo: DeinterlaceVideo
|
||||
};
|
||||
this.http.put('/api/ffmpeg/profiles/update', data);
|
||||
}
|
||||
|
||||
public deleteRecord(id: string) {
|
||||
this.http.delete('/api/ffmpeg/delete/' + id);
|
||||
}
|
||||
}
|
||||
|
||||
export const ffmpegProfileApiService: FFmpegProfileApiService =
|
||||
new FFmpegProfileApiService();
|
||||
@@ -1,16 +0,0 @@
|
||||
import { AbstractApiService } from './AbstractApiService';
|
||||
|
||||
class VersionApiService extends AbstractApiService {
|
||||
public constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public version(): Promise<string> {
|
||||
return this.http
|
||||
.get('/api/version')
|
||||
.then(this.handleResponse.bind(this))
|
||||
.catch(this.handleError.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
export const versionApiService: VersionApiService = new VersionApiService();
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
import Vue, { VNode } from 'vue';
|
||||
|
||||
declare global {
|
||||
namespace JSX {
|
||||
interface Element extends VNode {}
|
||||
interface ElementClass extends Vue {}
|
||||
interface IntrinsicElements {
|
||||
[elem: string]: any;
|
||||
}
|
||||
}
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
declare module '*.vue' {
|
||||
import Vue from 'vue';
|
||||
export default Vue;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { versionApiService } from '@/services/VersionService';
|
||||
|
||||
const originURL = `${window.location.origin}`;
|
||||
|
||||
export const applicationState = defineStore('appState', {
|
||||
state: () => {
|
||||
return {
|
||||
miniMenu: false,
|
||||
currentVersion: 'unknown',
|
||||
m3uURL: originURL + '/iptv/channels.m3u', // this will need to be fixed for reverse proxies
|
||||
xmlURL: originURL + '/iptv/xmltv.xml', // this will need to be fixed for reverse proxies
|
||||
documentationURL: 'https://ersatztv.org/',
|
||||
githubURL: 'https://github.com/ErsatzTV/ErsatzTV',
|
||||
discordURL: 'https://discord.gg/hHaJm3yGy6'
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
isNavigationMini(state) {
|
||||
return state.miniMenu;
|
||||
},
|
||||
currentServerVersion(state) {
|
||||
return state.currentVersion;
|
||||
},
|
||||
navBarURLs(state) {
|
||||
return {
|
||||
m3uURL: state.m3uURL,
|
||||
xmlURL: state.xmlURL,
|
||||
documentationURL: state.documentationURL,
|
||||
githubURL: state.githubURL,
|
||||
discordURL: state.discordURL
|
||||
};
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
toggleMiniNavigation() {
|
||||
this.miniMenu = !this.miniMenu;
|
||||
},
|
||||
disableMiniNavigation() {
|
||||
this.miniMenu = false;
|
||||
},
|
||||
async getVersion() {
|
||||
this.currentVersion = await versionApiService.version();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,28 +0,0 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import VueI18n from '../plugins/i18n';
|
||||
|
||||
export const languageState = defineStore('languageState', {
|
||||
state: () => {
|
||||
return {
|
||||
language: 'en'
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
currentLanguageCode: (state) => {
|
||||
return state.language;
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setLanguage(languageCode) {
|
||||
this.language = languageCode;
|
||||
VueI18n.locale = languageCode;
|
||||
}
|
||||
},
|
||||
persist: {
|
||||
afterRestore: (context) => {
|
||||
if (context.store.language) {
|
||||
VueI18n.locale = context.store.language;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,27 +0,0 @@
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
export const snackbarState = defineStore('snackbarState', {
|
||||
state: () => {
|
||||
return {
|
||||
visible: false,
|
||||
message: ''
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
isVisible(state) {
|
||||
return state.visible;
|
||||
},
|
||||
currentMessage(state) {
|
||||
return state.message;
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
showSnackbar(message) {
|
||||
this.message = message;
|
||||
this.visible = true;
|
||||
},
|
||||
closeSnackbar() {
|
||||
this.visible = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,909 +0,0 @@
|
||||
<template>
|
||||
<div id="AddEditFFmpegProfile">
|
||||
<h1 id="title" class="mx-4" />
|
||||
<v-divider color="success" class="ma-2"></v-divider>
|
||||
<v-app>
|
||||
<v-form
|
||||
ref="form"
|
||||
v-model="isFormValid"
|
||||
id="ffmpegForm"
|
||||
lazy-validation
|
||||
>
|
||||
<v-container>
|
||||
<v-row justify="center">
|
||||
<v-flex shrink class="pb-10">
|
||||
<v-container style="max-height: 80px">
|
||||
<v-row justify="center">
|
||||
<h2 class="mx">
|
||||
{{ $t('edit-ffmpeg-profile.General') }}
|
||||
</h2>
|
||||
</v-row>
|
||||
</v-container>
|
||||
<v-container style="max-height: 80px">
|
||||
<v-text-field
|
||||
v-model="newProfile.name"
|
||||
:rules="textRules"
|
||||
:label="$t('edit-ffmpeg-profile.Name')"
|
||||
required
|
||||
></v-text-field>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 80px"
|
||||
>
|
||||
<v-text-field
|
||||
ref="myThreadCount"
|
||||
v-model="threadCount"
|
||||
:label="
|
||||
$t('edit-ffmpeg-profile.thread-count')
|
||||
"
|
||||
:rules="validInt"
|
||||
number
|
||||
required
|
||||
></v-text-field>
|
||||
<v-tooltip v-model="threadCountShow" top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-container style="max-height: 40px">
|
||||
<v-select
|
||||
v-model="selectedResolution"
|
||||
@change="preferredResolutionChange"
|
||||
:items="preferredResolutions"
|
||||
item-value="id"
|
||||
item-text="name"
|
||||
:label="
|
||||
$t(
|
||||
'edit-ffmpeg-profile.preferred-resolution'
|
||||
)
|
||||
"
|
||||
required
|
||||
></v-select>
|
||||
</v-container>
|
||||
</v-flex>
|
||||
<v-divider
|
||||
style="max-height: 500px"
|
||||
vertical
|
||||
color="grey"
|
||||
></v-divider>
|
||||
<v-flex shrink class="pb-10">
|
||||
<v-container style="max-height: 80px">
|
||||
<v-row justify="center">
|
||||
<h2 class="mx">
|
||||
{{ $t('edit-ffmpeg-profile.Video') }}
|
||||
</h2>
|
||||
</v-row>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 80px"
|
||||
>
|
||||
<v-select
|
||||
v-model="selectedVideoFormat"
|
||||
@change="videoFormatChanged"
|
||||
:items="videoFormats"
|
||||
item-value="id"
|
||||
item-text="name"
|
||||
id="videoFormatSelector"
|
||||
:label="$t('edit-ffmpeg-profile.format')"
|
||||
required
|
||||
></v-select>
|
||||
<v-tooltip v-model="videoFormatShow" top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 80px"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="newProfile.videoBitRate"
|
||||
:label="$t('edit-ffmpeg-profile.bitrate')"
|
||||
:rules="validIntNonZero"
|
||||
required
|
||||
></v-text-field>
|
||||
<v-tooltip v-model="videoBitRateShow" top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 80px"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="newProfile.videoBufferSize"
|
||||
:label="
|
||||
$t('edit-ffmpeg-profile.buffer-size')
|
||||
"
|
||||
:rules="validIntNonZero"
|
||||
required
|
||||
></v-text-field>
|
||||
<v-tooltip v-model="videoBufferSizeShow" top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 80px"
|
||||
>
|
||||
<v-select
|
||||
v-model="selectedHardwareAcceleration"
|
||||
@change="hardwareAccelerationChanged"
|
||||
:items="hardwareAccelerations"
|
||||
item-value="id"
|
||||
item-text="name"
|
||||
:label="
|
||||
$t(
|
||||
'edit-ffmpeg-profile.hardware-acceleration'
|
||||
)
|
||||
"
|
||||
required
|
||||
></v-select>
|
||||
<v-tooltip
|
||||
v-model="hardwareAccelerationShow"
|
||||
top
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 80px"
|
||||
>
|
||||
<v-select
|
||||
v-model="selectedVaapiDriver"
|
||||
@change="vaapiDriverChanged"
|
||||
:items="vaapiDrivers"
|
||||
:disabled="vaapiDriverDisabled"
|
||||
item-value="id"
|
||||
item-text="name"
|
||||
:label="
|
||||
$t('edit-ffmpeg-profile.vaapi-driver')
|
||||
"
|
||||
required
|
||||
></v-select>
|
||||
<v-tooltip v-model="vaapiDriverShow" top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 80px"
|
||||
>
|
||||
<v-select
|
||||
v-model="selectedVaapiDevice"
|
||||
@change="vaapiDeviceChanged"
|
||||
:items="vaapiDevices"
|
||||
:disabled="vaapiDriverDisabled"
|
||||
:label="
|
||||
$t('edit-ffmpeg-profile.vaapi-device')
|
||||
"
|
||||
required
|
||||
></v-select>
|
||||
<v-tooltip v-model="vaapiDeviceShow" top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 50px"
|
||||
>
|
||||
<v-checkbox
|
||||
class="mr-2"
|
||||
v-model="normalizeFrameRate"
|
||||
:label="
|
||||
$t(
|
||||
'edit-ffmpeg-profile.normalize-framerate'
|
||||
)
|
||||
"
|
||||
color="green lighten-1"
|
||||
required
|
||||
></v-checkbox>
|
||||
<v-tooltip v-model="normalizeFrameRateShow" top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pt-8"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 50px"
|
||||
>
|
||||
<v-checkbox
|
||||
class="mr-2"
|
||||
v-model="autoDeinterlaceVideo"
|
||||
:label="
|
||||
$t(
|
||||
'edit-ffmpeg-profile.auto-deinterlace-video'
|
||||
)
|
||||
"
|
||||
color="green lighten-1"
|
||||
required
|
||||
></v-checkbox>
|
||||
<v-tooltip
|
||||
v-model="autoDeinterlaceVideoShow"
|
||||
top
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pt-8"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
</v-flex>
|
||||
<v-divider
|
||||
style="max-height: 500px"
|
||||
vertical
|
||||
color="grey"
|
||||
></v-divider>
|
||||
<v-flex shrink class="pb-10">
|
||||
<v-container style="max-height: 80px">
|
||||
<v-row justify="center">
|
||||
<h2 class="mx">
|
||||
{{ $t('edit-ffmpeg-profile.Audio') }}
|
||||
</h2>
|
||||
</v-row>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 80px"
|
||||
>
|
||||
<v-select
|
||||
v-model="selectedAudioFormat"
|
||||
@change="audioFormatChanged"
|
||||
:items="audioFormats"
|
||||
item-value="id"
|
||||
item-text="name"
|
||||
:label="$t('edit-ffmpeg-profile.format')"
|
||||
ref="audioFormat"
|
||||
required
|
||||
></v-select>
|
||||
<v-tooltip v-model="audioFormatShow" top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 80px"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="newProfile.audioBitRate"
|
||||
:label="$t('edit-ffmpeg-profile.bitrate')"
|
||||
:rules="validIntNonZero"
|
||||
required
|
||||
></v-text-field>
|
||||
<v-tooltip v-model="audioBitRateShow" top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 80px"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="newProfile.audioBufferSize"
|
||||
:label="
|
||||
$t('edit-ffmpeg-profile.buffer-size')
|
||||
"
|
||||
:rules="validIntNonZero"
|
||||
required
|
||||
></v-text-field>
|
||||
<v-tooltip v-model="audioBufferSizeShow" top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 80px"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="newProfile.channels"
|
||||
:label="$t('edit-ffmpeg-profile.channels')"
|
||||
:rules="validIntNonZero"
|
||||
required
|
||||
></v-text-field>
|
||||
<v-tooltip v-model="audioChannelsShow" top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 80px"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="newProfile.audioSampleRate"
|
||||
:label="
|
||||
$t('edit-ffmpeg-profile.sample-rate')
|
||||
"
|
||||
:rules="validIntNonZero"
|
||||
required
|
||||
></v-text-field>
|
||||
<v-tooltip v-model="audioSampleRateShow" top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-container
|
||||
class="d-flex"
|
||||
style="max-height: 80px"
|
||||
>
|
||||
<v-checkbox
|
||||
v-model="normalizeLoudness"
|
||||
:label="
|
||||
$t(
|
||||
'edit-ffmpeg-profile.normalize-loudness'
|
||||
)
|
||||
"
|
||||
color="green lighten-1"
|
||||
required
|
||||
></v-checkbox>
|
||||
<v-tooltip v-model="normalizeLoudnessShow" top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-icon
|
||||
class="pl-2"
|
||||
color="grey"
|
||||
v-ripple="false"
|
||||
:retain-focus="false"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
mdi-help-circle-outline
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>Recommended Thread Count: 0</span>
|
||||
</v-tooltip>
|
||||
</v-container>
|
||||
<v-spacer style="height: 80px"></v-spacer>
|
||||
<v-container>
|
||||
<v-btn
|
||||
color="green lighten-1"
|
||||
class="ma-2"
|
||||
:disabled="!isFormValid"
|
||||
@click="saveFFmpegProfile()"
|
||||
>
|
||||
{{ $t('edit-ffmpeg-profile.save-profile') }}
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="cancel"
|
||||
class="ma-2"
|
||||
@click="cancelAdd()"
|
||||
>
|
||||
{{ $t('edit-ffmpeg-profile.cancel') }}
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="indigo accent-1"
|
||||
class="ma-2"
|
||||
@click="cancelAdd()"
|
||||
>
|
||||
{{ $t('edit-ffmpeg-profile.help') }}
|
||||
</v-btn>
|
||||
</v-container>
|
||||
</v-flex>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-form>
|
||||
</v-app>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component, Watch } from 'vue-property-decorator';
|
||||
import { ffmpegProfileApiService } from '@/services/FFmpegProfileService';
|
||||
|
||||
@Component
|
||||
export default class AddEditFFmpegProfile extends Vue {
|
||||
//@Name({ default: 'AddEditFFmpegProfile' }) AddEditFFmpegProfile!: string;
|
||||
//@Prop({ default: -1 }) private id!: number;
|
||||
public newProfile: any = {};
|
||||
private refForm: any = this.$refs.form;
|
||||
public isFormValid = false;
|
||||
public threadCountShow = false;
|
||||
public videoFormatShow = false;
|
||||
public videoBitRateShow = false;
|
||||
public videoBufferSizeShow = false;
|
||||
public hardwareAccelerationShow = false;
|
||||
public vaapiDriverShow = false;
|
||||
public vaapiDeviceShow = false;
|
||||
public normalizeFrameRateShow = false;
|
||||
public autoDeinterlaceVideoShow = false;
|
||||
public audioFormatShow = false;
|
||||
public audioBitRateShow = false;
|
||||
public audioBufferSizeShow = false;
|
||||
public audioChannelsShow = false;
|
||||
public audioSampleRateShow = false;
|
||||
public normalizeLoudnessShow = false;
|
||||
|
||||
public AddEditFFmpegProfile() {
|
||||
console.log('test');
|
||||
}
|
||||
|
||||
public audioFormats: [
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string }
|
||||
] = [
|
||||
{ id: 1, name: 'aac' },
|
||||
{ id: 2, name: 'ac3' }
|
||||
];
|
||||
|
||||
private _selectedAudioFormat: number = 2;
|
||||
public selectedAudioFormat: { id: number; name: string } = {
|
||||
id: 2,
|
||||
name: 'ac3'
|
||||
};
|
||||
|
||||
public preferredResolutions: [
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string }
|
||||
] = [
|
||||
{ id: 0, name: '720x480' },
|
||||
{ id: 1, name: '1280x720' },
|
||||
{ id: 2, name: '1920x1080' },
|
||||
{ id: 3, name: '3840x2160' }
|
||||
];
|
||||
|
||||
private _selectedResolution: number = 2;
|
||||
public selectedResolution: { id: number; name: string } = {
|
||||
id: 2,
|
||||
name: '1920x1080'
|
||||
};
|
||||
|
||||
public videoFormats: [
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string }
|
||||
] = [
|
||||
{ id: 1, name: 'h264' },
|
||||
{ id: 2, name: 'hevc' },
|
||||
{ id: 3, name: 'mpeg-2' }
|
||||
];
|
||||
|
||||
private _selectedVideoFormat: number = 1;
|
||||
public selectedVideoFormat: { id: number; name: string } = {
|
||||
id: 1,
|
||||
name: 'h264'
|
||||
};
|
||||
|
||||
public hardwareAccelerations: [
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string }
|
||||
] = [
|
||||
{ id: 0, name: 'None' },
|
||||
{ id: 1, name: 'Qsv' },
|
||||
{ id: 2, name: 'Nvenc' },
|
||||
{ id: 3, name: 'Vaapi' },
|
||||
{ id: 4, name: 'VideoToolbox' }
|
||||
];
|
||||
|
||||
private _selectedHardwareAcceleration: number = 0;
|
||||
public selectedHardwareAcceleration: { id: number; name: string } = {
|
||||
id: 0,
|
||||
name: 'None'
|
||||
};
|
||||
|
||||
public vaapiDrivers: [
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string },
|
||||
{ id: number; name: string }
|
||||
] = [
|
||||
{ id: 0, name: 'Default' },
|
||||
{ id: 1, name: 'iHD' },
|
||||
{ id: 2, name: 'i965' },
|
||||
{ id: 3, name: 'RadeonSI' },
|
||||
{ id: 4, name: 'Nouveau' }
|
||||
];
|
||||
|
||||
public vaapiDriverDisabled = true;
|
||||
private _selectedVaapiDriver: number = 0;
|
||||
public selectedVaapiDriver: { id: number; name: string } = {
|
||||
id: 0,
|
||||
name: 'Default'
|
||||
};
|
||||
|
||||
public selectedVaapiDevice: string = '';
|
||||
public vaapiDevices: [string, string] = ['', '/dev/dri/renderD128'];
|
||||
|
||||
public normalizeFrameRate: boolean = false;
|
||||
public autoDeinterlaceVideo: boolean = true;
|
||||
public normalizeLoudness: boolean = true;
|
||||
|
||||
saveFFmpegProfile() {
|
||||
//this means we're adding
|
||||
if (isNaN(this.id)) {
|
||||
ffmpegProfileApiService.newFFmpegProfile(
|
||||
this.newProfile.name,
|
||||
this.threadCount,
|
||||
this._selectedHardwareAcceleration,
|
||||
this._selectedVaapiDriver,
|
||||
this.selectedVaapiDevice,
|
||||
this._selectedResolution,
|
||||
this._selectedVideoFormat,
|
||||
this.newProfile.videoBitRate,
|
||||
this.newProfile.videoBufferSize,
|
||||
this._selectedAudioFormat,
|
||||
this.newProfile.audioBitRate,
|
||||
this.newProfile.audioBufferSize,
|
||||
this.normalizeLoudness,
|
||||
this.newProfile.channels,
|
||||
this.newProfile.audioSampleRate,
|
||||
this.normalizeFrameRate,
|
||||
this.autoDeinterlaceVideo
|
||||
);
|
||||
} else {
|
||||
//this means we're editing
|
||||
ffmpegProfileApiService.updateFFmpegProfile(
|
||||
this.id,
|
||||
this.newProfile.name,
|
||||
this.threadCount,
|
||||
this._selectedHardwareAcceleration,
|
||||
this._selectedVaapiDriver,
|
||||
this.selectedVaapiDevice,
|
||||
this._selectedResolution,
|
||||
this._selectedVideoFormat,
|
||||
this.newProfile.videoBitRate,
|
||||
this.newProfile.videoBufferSize,
|
||||
this._selectedAudioFormat,
|
||||
this.newProfile.audioBitRate,
|
||||
this.newProfile.audioBufferSize,
|
||||
this.normalizeLoudness,
|
||||
this.newProfile.channels,
|
||||
this.newProfile.audioSampleRate,
|
||||
this.normalizeFrameRate,
|
||||
this.autoDeinterlaceVideo
|
||||
);
|
||||
}
|
||||
const Toast = this.$swal.mixin({
|
||||
toast: true,
|
||||
position: 'top-end',
|
||||
showConfirmButton: false,
|
||||
timer: 3000,
|
||||
timerProgressBar: true,
|
||||
didOpen: (toast) => {
|
||||
toast.addEventListener('mouseenter', this.$swal.stopTimer);
|
||||
toast.addEventListener('mouseleave', this.$swal.resumeTimer);
|
||||
}
|
||||
});
|
||||
|
||||
Toast.fire({
|
||||
icon: 'success',
|
||||
title: this.$t('edit-ffmpeg-profile.profile-saved').toString()
|
||||
});
|
||||
this.$router.push({
|
||||
name: 'ffmpeg-profiles.title'
|
||||
});
|
||||
}
|
||||
|
||||
cancelAdd() {
|
||||
this.$router.push({
|
||||
name: 'ffmpeg-profiles.title'
|
||||
});
|
||||
}
|
||||
|
||||
//~change events~//
|
||||
public audioFormatChanged(selectObj: number) {
|
||||
this._selectedAudioFormat = selectObj;
|
||||
}
|
||||
|
||||
public preferredResolutionChange(selectObj: number) {
|
||||
this._selectedResolution = selectObj + 1;
|
||||
}
|
||||
|
||||
public videoFormatChanged(selectObj: number) {
|
||||
this._selectedVideoFormat = selectObj;
|
||||
}
|
||||
|
||||
public hardwareAccelerationChanged(selectObj: number) {
|
||||
this._selectedHardwareAcceleration = selectObj;
|
||||
this.applyVaapiValidation();
|
||||
}
|
||||
|
||||
public applyVaapiValidation() {
|
||||
//If they pick VAAPI as the hardware acceleration,
|
||||
//they can now choose a vaapi driver and device.
|
||||
//If not, they cannot change the default options.
|
||||
if (this._selectedHardwareAcceleration == 3) {
|
||||
this.vaapiDriverDisabled = false;
|
||||
} else {
|
||||
this.vaapiDriverDisabled = true;
|
||||
this._selectedVaapiDriver = 0;
|
||||
this.selectedVaapiDriver = { id: 0, name: 'Default' };
|
||||
this.selectedVaapiDevice = '';
|
||||
}
|
||||
}
|
||||
|
||||
public vaapiDriverChanged(selectObj: number) {
|
||||
this._selectedVaapiDriver = selectObj;
|
||||
}
|
||||
|
||||
public vaapiDeviceChanged(selectObj: string) {
|
||||
this.selectedVaapiDevice = selectObj;
|
||||
}
|
||||
|
||||
//~ end change events~//
|
||||
|
||||
public threadCount = 0;
|
||||
|
||||
get validIntNonZero() {
|
||||
return [
|
||||
(v: any) =>
|
||||
(v && /^[0-9]+$/.test(v)) || this.$t('Must be a valid number.'),
|
||||
(v: any) => (v && v > 0) || 'Must be greater than 0.'
|
||||
];
|
||||
}
|
||||
|
||||
get validInt() {
|
||||
return [
|
||||
(v: any) =>
|
||||
(v && /^[0-9]+$/.test(v)) || this.$t('Must be a valid number.')
|
||||
];
|
||||
}
|
||||
|
||||
get textRules() {
|
||||
return [(v: any) => (v && v.length > 0) || 'Value must not be empty.'];
|
||||
}
|
||||
|
||||
props!: { id: number };
|
||||
@Watch('id', { immediate: true }) async onItemChanged() {
|
||||
console.log('ID', this.id);
|
||||
this.id = Number(this.$route.query.id) ?? -1;
|
||||
await this.loadPage();
|
||||
}
|
||||
|
||||
private loaded = false;
|
||||
private id = -1;
|
||||
|
||||
title: string = 'Modify FFmpeg Profile';
|
||||
|
||||
async loadPage(): Promise<void> {
|
||||
if (this.loaded) {
|
||||
return;
|
||||
}
|
||||
var title = document.getElementById('title');
|
||||
if (title === null || title === undefined) {
|
||||
//sometimes the element isn't loaded yet, it'll come
|
||||
//back to this when it's good to go. So skip for now.
|
||||
return;
|
||||
}
|
||||
if (!isNaN(this.id)) {
|
||||
title.innerHTML = this.$t(
|
||||
'edit-ffmpeg-profile.edit-profile'
|
||||
).toString();
|
||||
var ffmpegFullProfile = await ffmpegProfileApiService.getOne(
|
||||
this.id.toString()
|
||||
);
|
||||
var result = ffmpegFullProfile[0];
|
||||
if (result !== undefined) {
|
||||
//We have a profile, let's load it.
|
||||
this.threadCount = result.threadCount;
|
||||
this.selectedVaapiDevice = result.vaapiDevice;
|
||||
this.autoDeinterlaceVideo = result.deinterlaceVideo;
|
||||
this.normalizeFrameRate = result.normalizeFramerate;
|
||||
this.normalizeLoudness = result.normalizeLoudness;
|
||||
this.newProfile = {
|
||||
name: result.name,
|
||||
videoBitRate: result.videoBitrate,
|
||||
videoBufferSize: result.videoBufferSize,
|
||||
audioBitRate: result.audioBitrate,
|
||||
audioBufferSize: result.audioBufferSize,
|
||||
channels: result.audioChannels,
|
||||
audioSampleRate: result.audioSampleRate
|
||||
};
|
||||
|
||||
this._selectedAudioFormat = result.audioFormat;
|
||||
this.selectedAudioFormat =
|
||||
this.audioFormats[result.audioFormat - 1];
|
||||
this._selectedVideoFormat = result.videoFormat;
|
||||
this.selectedVideoFormat =
|
||||
this.videoFormats[result.videoFormat - 1];
|
||||
this._selectedResolution = result.resolutionId;
|
||||
this.selectedResolution =
|
||||
this.preferredResolutions[result.resolutionId - 1];
|
||||
this._selectedHardwareAcceleration =
|
||||
result.hardwareAcceleration;
|
||||
this.selectedHardwareAcceleration =
|
||||
this.hardwareAccelerations[result.hardwareAcceleration];
|
||||
this._selectedVaapiDriver = result.vaapiDriver;
|
||||
this.selectedVaapiDriver =
|
||||
this.vaapiDrivers[result.vaapiDriver];
|
||||
this.applyVaapiValidation();
|
||||
this.loaded = true;
|
||||
} else {
|
||||
//an ID was entered (probably in the URL) that doesn't exist. Let's returnt to the profile list.
|
||||
console.log('No ffmpeg profile found for ID: ' + this.id);
|
||||
this.$router.push({
|
||||
name: 'ffmpeg-profiles.title'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
//new profile!
|
||||
title.innerHTML = this.$t(
|
||||
'edit-ffmpeg-profile.add-profile'
|
||||
).toString();
|
||||
this._selectedAudioFormat = 2;
|
||||
this._selectedResolution = 3;
|
||||
this._selectedVideoFormat = 1;
|
||||
this._selectedHardwareAcceleration = 0;
|
||||
this._selectedVaapiDriver = 0;
|
||||
this.selectedVaapiDevice = '';
|
||||
this.newProfile = {
|
||||
name: 'New Profile',
|
||||
videoBitRate: 2000,
|
||||
videoBufferSize: 4000,
|
||||
audioBitRate: 192,
|
||||
audioBufferSize: 384,
|
||||
channels: 2,
|
||||
audioSampleRate: 48
|
||||
};
|
||||
this.loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,62 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="channels"
|
||||
:sort-by="['number']"
|
||||
class="elevation-1"
|
||||
>
|
||||
<template v-slot:[`item.actions`]="{ item }">
|
||||
<v-btn icon class="mr-2" @click="editRow(item.id)">
|
||||
<v-icon>mdi-lead-pencil</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<v-btn icon @click.stop="deleteRow(item.id)">
|
||||
<v-icon>mdi-delete</v-icon></v-btn
|
||||
>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component } from 'vue-property-decorator';
|
||||
import { Channel } from '@/models/Channel';
|
||||
import { channelApiService } from '@/services/ChannelService';
|
||||
|
||||
@Component
|
||||
export default class Channels extends Vue {
|
||||
private channels: Channel[] = [];
|
||||
|
||||
get headers() {
|
||||
return [
|
||||
{ text: this.$t('channels.table.number'), value: 'number' },
|
||||
{ text: this.$t('channels.table.logo'), value: 'logo' },
|
||||
{ text: this.$t('channels.table.name'), value: 'name' },
|
||||
{ text: this.$t('channels.table.language'), value: 'language' },
|
||||
{ text: this.$t('channels.table.mode'), value: 'streamingMode' },
|
||||
{
|
||||
text: this.$t('channels.table.ffmpeg-profile'),
|
||||
value: 'ffmpegProfile'
|
||||
},
|
||||
{ text: 'Actions', value: 'actions', sortable: false }
|
||||
];
|
||||
}
|
||||
|
||||
deleteRow(item: any) {
|
||||
let index = this.channels.findIndex((it) => it.id === item.id);
|
||||
this.channels.splice(index, 1);
|
||||
}
|
||||
|
||||
editRow(item: any) {
|
||||
let index = this.channels.findIndex((it) => it.id === item.id);
|
||||
this.channels.splice(index, 1);
|
||||
}
|
||||
|
||||
title: string = 'Channels';
|
||||
|
||||
async mounted(): Promise<void> {
|
||||
this.channels = await channelApiService.getAll();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,123 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-btn color="success" class="ma-4" @click="addRecord()">{{
|
||||
$t('ffmpeg-profiles.add-profile')
|
||||
}}</v-btn>
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="ffmpegProfiles"
|
||||
:sort-by="['name']"
|
||||
class="elevation-1"
|
||||
>
|
||||
<template v-slot:[`item.actions`]="{ item }">
|
||||
<v-btn icon class="mr-2" @click="editRow(item.id)">
|
||||
<v-icon>mdi-lead-pencil</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<v-btn icon @click.stop="deleteRecord(item.id, item.name)">
|
||||
<v-icon>mdi-delete</v-icon></v-btn
|
||||
>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component } from 'vue-property-decorator';
|
||||
import { FFmpegProfile } from '@/models/FFmpegProfile';
|
||||
import { ffmpegProfileApiService } from '@/services/FFmpegProfileService';
|
||||
|
||||
@Component
|
||||
export default class FFmpegProfiles extends Vue {
|
||||
public ffmpegProfiles: FFmpegProfile[] = [];
|
||||
|
||||
get headers() {
|
||||
return [
|
||||
{ text: this.$t('ffmpeg-profiles.table.name'), value: 'name' },
|
||||
{
|
||||
text: this.$t('ffmpeg-profiles.table.resolution'),
|
||||
value: 'resolution'
|
||||
},
|
||||
{ text: this.$t('ffmpeg-profiles.table.video'), value: 'video' },
|
||||
{ text: this.$t('ffmpeg-profiles.table.audio'), value: 'audio' },
|
||||
{
|
||||
text: this.$t('ffmpeg-profiles.actions'),
|
||||
value: 'actions',
|
||||
sortable: false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
addRecord() {
|
||||
this.$router.push({
|
||||
name: 'add-ffmpeg-profile'
|
||||
});
|
||||
}
|
||||
|
||||
deleteRecord(record: any, recordName: any) {
|
||||
this.$swal
|
||||
.fire({
|
||||
title: this.$t(
|
||||
'ffmpeg-profiles.delete-dialog-title'
|
||||
).toString(),
|
||||
// text: this.$t(
|
||||
// 'Delete "' + recordName + '" FFmpeg Profile?'
|
||||
// ).toString(),
|
||||
text: this.$t('ffmpeg-profiles.delete-dialog-text', {
|
||||
profileName: '"' + recordName + '"'
|
||||
}).toString(),
|
||||
icon: 'warning',
|
||||
//iconColor: '#4CAF50',
|
||||
showCancelButton: true,
|
||||
cancelButtonText: this.$t('ffmpeg-profiles.no').toString(),
|
||||
confirmButtonText: this.$t('ffmpeg-profiles.yes').toString()
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
let index = this.ffmpegProfiles.findIndex(
|
||||
(it) => it.id === record
|
||||
);
|
||||
this.ffmpegProfiles.splice(index, 1);
|
||||
ffmpegProfileApiService.deleteRecord(String(record));
|
||||
const Toast = this.$swal.mixin({
|
||||
toast: true,
|
||||
position: 'top-end',
|
||||
showConfirmButton: false,
|
||||
timer: 3000,
|
||||
timerProgressBar: true,
|
||||
didOpen: (toast) => {
|
||||
toast.addEventListener(
|
||||
'mouseenter',
|
||||
this.$swal.stopTimer
|
||||
);
|
||||
toast.addEventListener(
|
||||
'mouseleave',
|
||||
this.$swal.resumeTimer
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Toast.fire({
|
||||
icon: 'success',
|
||||
title: this.$t(
|
||||
'ffmpeg-profiles.profile-deleted'
|
||||
).toString()
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
editRow(id: any) {
|
||||
this.$router.push({
|
||||
name: 'edit-ffmpeg',
|
||||
query: { id: id }
|
||||
});
|
||||
}
|
||||
|
||||
title: string = 'FFMpeg Profiles';
|
||||
|
||||
async mounted(): Promise<void> {
|
||||
this.ffmpegProfiles = await ffmpegProfileApiService.getAll();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,9 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>{{ $t(this.$route.name) }}</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {};
|
||||
</script>
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"strict": true,
|
||||
"allowJs": true,
|
||||
"experimentalDecorators": true,
|
||||
"jsx": "preserve",
|
||||
"moduleResolution": "node",
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"useDefineForClassFields": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"types": [
|
||||
"webpack-env",
|
||||
"vuetify",
|
||||
"vue-sweetalert2"
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
"tests/**/*.ts",
|
||||
"tests/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
const { defineConfig } = require('@vue/cli-service');
|
||||
|
||||
module.exports = defineConfig({
|
||||
transpileDependencies: ['vuetify'],
|
||||
runtimeCompiler: true,
|
||||
|
||||
pwa: {
|
||||
name: 'ErsatzTV'
|
||||
},
|
||||
publicPath: '/v2/',
|
||||
outputDir: '../wwwroot/v2',
|
||||
filenameHashing: false,
|
||||
pluginOptions: {
|
||||
i18n: {
|
||||
locale: 'en',
|
||||
fallbackLocale: 'en',
|
||||
localeDir: 'locales',
|
||||
enableInSFC: true
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user