mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 04:20:12 +02:00
Compare commits
167 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dde48335cd | |||
| 8611f08f54 | |||
| cd18e683bf | |||
| 286441c1b1 | |||
| 5456c2c2b8 | |||
| 5cd4fc227e | |||
| 737d672918 | |||
| a6ac4c8f67 | |||
| c9217827ab | |||
| 0ff8fad071 | |||
| f3cb15eae2 | |||
| 5b34b287e2 | |||
| dc461a253f | |||
| 958416af4c | |||
| 1dd8eec4a5 | |||
| b263db5483 | |||
| 528f60c5f3 | |||
| 007b0166ab | |||
| d3fb2374ff | |||
| 676c091d28 | |||
| 58b7572a8b | |||
| fc77c32a0e | |||
| b5bdea1845 | |||
| 8eb591bd08 | |||
| 88be98f703 | |||
| df6b6d514d | |||
| b6d902e425 | |||
| d922d8b034 | |||
| f4db8fdb84 | |||
| 81ca6937bc | |||
| c382e01f64 | |||
| fb80b66310 | |||
| 63e3b97bca | |||
| fb584b35a9 | |||
| bdc372636b | |||
| 2c5671cf38 | |||
| bd12fbecac | |||
| c1d88ada91 | |||
| d6a3e1d90b | |||
| 789c7f3d81 | |||
| f3c785d0fa | |||
| 062c1c2b61 | |||
| eb078d62cd | |||
| c429ac9223 | |||
| bd26967ff2 | |||
| 620b810191 | |||
| 64866c59bd | |||
| 0afbe4c0a2 | |||
| 6782cd0dcc | |||
| 8f585a5be9 | |||
| ac0c396712 | |||
| b989a66991 | |||
| 2814b623e7 | |||
| 7d29a692ef | |||
| 3f9eb446f7 | |||
| d8f7b49ab6 | |||
| 35e70a3eff | |||
| ef9c16e940 | |||
| 0b39c35132 | |||
| 9f5b4e5410 | |||
| dbf840b185 | |||
| e0f0524eb9 | |||
| 8598313d12 | |||
| c84dd648ea | |||
| 01885c1a9b | |||
| 5121f57171 | |||
| 3d7ee10328 | |||
| 4db47b4d37 | |||
| 786a693526 | |||
| 1faef6a1a7 | |||
| 1598642389 | |||
| 8c4a7f4f91 | |||
| 5878f89339 | |||
| 4acbb1820d | |||
| 01f5745629 | |||
| 73dd781a88 | |||
| d777be6251 | |||
| 6689e84f67 | |||
| ad533a1d9c | |||
| b691891e62 | |||
| 53fa265af9 | |||
| 55f6a382d4 | |||
| 9c30acdd56 | |||
| b29d3e7f78 | |||
| c1330d92b2 | |||
| bea55d48a8 | |||
| ae41fe99bb | |||
| e3751229b6 | |||
| 87c9963354 | |||
| b7fb7c7f94 | |||
| b8ceb174b3 | |||
| 48f085b0ac | |||
| dfc0639f95 | |||
| 80ffd1a925 | |||
| c87bb65023 | |||
| 5ae21bd224 | |||
| 12d293a74c | |||
| 62f4bb0d7b | |||
| 9f11061433 | |||
| aba64b10d0 | |||
| c20e30e387 | |||
| c4b4300845 | |||
| f1e5ed41bc | |||
| 9b79502022 | |||
| 636c227a83 | |||
| e8a94a0b1c | |||
| fa93dfd771 | |||
| 8629994eb6 | |||
| c54423a667 | |||
| d28fc9f630 | |||
| bd2b39fdfb | |||
| 2912cd72ef | |||
| 9d31d952b7 | |||
| 8f692b6f4d | |||
| 7562c619d2 | |||
| 6b91ee4a25 | |||
| 9e689468f9 | |||
| 1cda4363ef | |||
| b6941df7a7 | |||
| 608b322f9e | |||
| daee582e92 | |||
| 6525a8a725 | |||
| ee1896c345 | |||
| ec625c2c65 | |||
| 52e4423cf1 | |||
| a9f7e808cb | |||
| 9c26187b45 | |||
| 90afa11f20 | |||
| 6463ea937b | |||
| ac682428e6 | |||
| 48917547b2 | |||
| 74554d9725 | |||
| 0d42a6ea49 | |||
| faadff0211 | |||
| 91715ebf7d | |||
| 1808f160b4 | |||
| e10a92a5c2 | |||
| 930165d006 | |||
| 249eaf89f8 | |||
| bf1cddae9d | |||
| 9db2e51d2d | |||
| 26c02e03c5 | |||
| 1cf587bc8f | |||
| 91ce2cd8a1 | |||
| 4f61e82068 | |||
| 1e6673fabd | |||
| 02951c92af | |||
| 05f8fb3114 | |||
| 169da10c1b | |||
| 5a79fee77e | |||
| 7ef80f14b0 | |||
| 36cc37e39f | |||
| d4e7c6bd18 | |||
| 90f79b4ae7 | |||
| cf74625bfc | |||
| f068d6e4b8 | |||
| e1aa8d74f3 | |||
| b0d86ee5c9 | |||
| 89e27ec6ff | |||
| 39c714a137 | |||
| a8fb7ff11e | |||
| 9b95f47a91 | |||
| 2267e9bc9d | |||
| 089311c673 | |||
| 773f349b66 | |||
| 3980c8ea97 | |||
| 257a5ceef0 |
+2
-5
@@ -1,12 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"global-require": "off",
|
||||
"import/no-dynamic-require": "off"
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/**
|
||||
* Base webpack config used across other specific configs
|
||||
*/
|
||||
|
||||
import webpack from 'webpack';
|
||||
import { dependencies as externals } from '../../release/app/package.json';
|
||||
import webpackPaths from './webpack.paths';
|
||||
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
||||
|
||||
const createStyledComponentsTransformer = require('typescript-plugin-styled-components').default;
|
||||
|
||||
const styledComponentsTransformer = createStyledComponentsTransformer();
|
||||
|
||||
const configuration: webpack.Configuration = {
|
||||
externals: [...Object.keys(externals || {})],
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
exclude: /node_modules/,
|
||||
test: /\.[jt]sx?$/,
|
||||
use: {
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
// Remove this line to enable type checking in webpack builds
|
||||
transpileOnly: true,
|
||||
getCustomTransformers: () => ({ before: [styledComponentsTransformer] }),
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
output: {
|
||||
// https://github.com/webpack/webpack/issues/1114
|
||||
library: {
|
||||
type: 'commonjs2',
|
||||
},
|
||||
|
||||
path: webpackPaths.srcPath,
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new webpack.EnvironmentPlugin({
|
||||
NODE_ENV: 'production',
|
||||
}),
|
||||
],
|
||||
|
||||
/**
|
||||
* Determine the array of extensions that should be used to resolve modules.
|
||||
*/
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
|
||||
fallback: {
|
||||
child_process: false,
|
||||
},
|
||||
plugins: [new TsconfigPathsPlugin({ baseUrl: webpackPaths.srcPath })],
|
||||
modules: [webpackPaths.srcPath, 'node_modules'],
|
||||
},
|
||||
|
||||
stats: 'errors-only',
|
||||
};
|
||||
|
||||
export default configuration;
|
||||
@@ -1,3 +0,0 @@
|
||||
/* eslint import/no-unresolved: off, import/no-self-import: off */
|
||||
|
||||
module.exports = require('./webpack.config.renderer.dev').default;
|
||||
@@ -1,84 +0,0 @@
|
||||
/**
|
||||
* Webpack config for production electron main process
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
|
||||
import TerserPlugin from 'terser-webpack-plugin';
|
||||
import webpack from 'webpack';
|
||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
||||
import { merge } from 'webpack-merge';
|
||||
|
||||
import checkNodeEnv from '../scripts/check-node-env';
|
||||
import deleteSourceMaps from '../scripts/delete-source-maps';
|
||||
import baseConfig from './webpack.config.base';
|
||||
import webpackPaths from './webpack.paths';
|
||||
|
||||
checkNodeEnv('production');
|
||||
deleteSourceMaps();
|
||||
|
||||
const devtoolsConfig =
|
||||
process.env.DEBUG_PROD === 'true'
|
||||
? {
|
||||
devtool: 'source-map',
|
||||
}
|
||||
: {};
|
||||
|
||||
const configuration: webpack.Configuration = {
|
||||
...devtoolsConfig,
|
||||
|
||||
mode: 'production',
|
||||
|
||||
target: 'electron-main',
|
||||
|
||||
entry: {
|
||||
main: path.join(webpackPaths.srcMainPath, 'main.ts'),
|
||||
preload: path.join(webpackPaths.srcMainPath, 'preload.ts'),
|
||||
},
|
||||
|
||||
output: {
|
||||
path: webpackPaths.distMainPath,
|
||||
filename: '[name].js',
|
||||
},
|
||||
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
parallel: true,
|
||||
}),
|
||||
],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new BundleAnalyzerPlugin({
|
||||
analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled',
|
||||
}),
|
||||
|
||||
/**
|
||||
* Create global constants which can be configured at compile time.
|
||||
*
|
||||
* Useful for allowing different behaviour between development builds and
|
||||
* release builds
|
||||
*
|
||||
* NODE_ENV should be production so that modules do not perform certain
|
||||
* development checks
|
||||
*/
|
||||
new webpack.EnvironmentPlugin({
|
||||
NODE_ENV: 'production',
|
||||
DEBUG_PROD: false,
|
||||
START_MINIMIZED: false,
|
||||
}),
|
||||
],
|
||||
|
||||
/**
|
||||
* Disables webpack processing of __dirname and __filename.
|
||||
* If you run the bundle in node.js it falls back to these values of node.js.
|
||||
* https://github.com/webpack/webpack/issues/2010
|
||||
*/
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: false,
|
||||
},
|
||||
};
|
||||
|
||||
export default merge(baseConfig, configuration);
|
||||
@@ -1,70 +0,0 @@
|
||||
import path from 'path';
|
||||
|
||||
import webpack from 'webpack';
|
||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
||||
import { merge } from 'webpack-merge';
|
||||
|
||||
import checkNodeEnv from '../scripts/check-node-env';
|
||||
import baseConfig from './webpack.config.base';
|
||||
import webpackPaths from './webpack.paths';
|
||||
|
||||
// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's
|
||||
// at the dev webpack config is not accidentally run in a production environment
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
checkNodeEnv('development');
|
||||
}
|
||||
|
||||
const configuration: webpack.Configuration = {
|
||||
devtool: 'inline-source-map',
|
||||
|
||||
mode: 'development',
|
||||
|
||||
target: 'electron-preload',
|
||||
|
||||
entry: path.join(webpackPaths.srcMainPath, 'preload.ts'),
|
||||
|
||||
output: {
|
||||
path: webpackPaths.dllPath,
|
||||
filename: 'preload.js',
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new BundleAnalyzerPlugin({
|
||||
analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled',
|
||||
}),
|
||||
|
||||
/**
|
||||
* Create global constants which can be configured at compile time.
|
||||
*
|
||||
* Useful for allowing different behaviour between development builds and
|
||||
* release builds
|
||||
*
|
||||
* NODE_ENV should be production so that modules do not perform certain
|
||||
* development checks
|
||||
*
|
||||
* By default, use 'development' as NODE_ENV. This can be overriden with
|
||||
* 'staging', for example, by changing the ENV variables in the npm scripts
|
||||
*/
|
||||
new webpack.EnvironmentPlugin({
|
||||
NODE_ENV: 'development',
|
||||
}),
|
||||
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
debug: true,
|
||||
}),
|
||||
],
|
||||
|
||||
/**
|
||||
* Disables webpack processing of __dirname and __filename.
|
||||
* If you run the bundle in node.js it falls back to these values of node.js.
|
||||
* https://github.com/webpack/webpack/issues/2010
|
||||
*/
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: false,
|
||||
},
|
||||
|
||||
watch: true,
|
||||
};
|
||||
|
||||
export default merge(baseConfig, configuration);
|
||||
@@ -1,127 +0,0 @@
|
||||
import 'webpack-dev-server';
|
||||
import path from 'path';
|
||||
|
||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import webpack from 'webpack';
|
||||
import { merge } from 'webpack-merge';
|
||||
|
||||
import checkNodeEnv from '../scripts/check-node-env';
|
||||
import baseConfig from './webpack.config.base';
|
||||
import webpackPaths from './webpack.paths';
|
||||
|
||||
const { version } = require('../../package.json');
|
||||
|
||||
// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's
|
||||
// at the dev webpack config is not accidentally run in a production environment
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
checkNodeEnv('development');
|
||||
}
|
||||
|
||||
const configuration: webpack.Configuration = {
|
||||
devtool: 'inline-source-map',
|
||||
|
||||
mode: 'development',
|
||||
|
||||
target: ['web'],
|
||||
|
||||
entry: {
|
||||
remote: path.join(webpackPaths.srcRemotePath, 'index.tsx'),
|
||||
worker: path.join(webpackPaths.srcRemotePath, 'service-worker.ts'),
|
||||
},
|
||||
|
||||
output: {
|
||||
path: webpackPaths.dllPath,
|
||||
publicPath: '/',
|
||||
filename: '[name].js',
|
||||
library: {
|
||||
type: 'umd',
|
||||
},
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.s?css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
modules: true,
|
||||
sourceMap: true,
|
||||
importLoaders: 1,
|
||||
},
|
||||
},
|
||||
'sass-loader',
|
||||
],
|
||||
include: /\.module\.s?(c|a)ss$/,
|
||||
},
|
||||
{
|
||||
test: /\.s?css$/,
|
||||
use: ['style-loader', 'css-loader', 'sass-loader'],
|
||||
exclude: /\.module\.s?(c|a)ss$/,
|
||||
},
|
||||
// Fonts
|
||||
{
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
// Images
|
||||
{
|
||||
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
|
||||
/**
|
||||
* Create global constants which can be configured at compile time.
|
||||
*
|
||||
* Useful for allowing different behaviour between development builds and
|
||||
* release builds
|
||||
*
|
||||
* NODE_ENV should be production so that modules do not perform certain
|
||||
* development checks
|
||||
*
|
||||
* By default, use 'development' as NODE_ENV. This can be overriden with
|
||||
* 'staging', for example, by changing the ENV variables in the npm scripts
|
||||
*/
|
||||
new webpack.EnvironmentPlugin({
|
||||
NODE_ENV: 'development',
|
||||
}),
|
||||
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
debug: true,
|
||||
}),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
filename: path.join('index.html'),
|
||||
template: path.join(webpackPaths.srcRemotePath, 'index.ejs'),
|
||||
favicon: path.join(webpackPaths.assetsPath, 'icons', 'favicon.ico'),
|
||||
minify: {
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeComments: true,
|
||||
},
|
||||
isBrowser: true,
|
||||
env: process.env.NODE_ENV,
|
||||
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||
nodeModules: webpackPaths.appNodeModulesPath,
|
||||
templateParameters: {
|
||||
version,
|
||||
prod: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: false,
|
||||
},
|
||||
|
||||
watch: true,
|
||||
};
|
||||
|
||||
export default merge(baseConfig, configuration);
|
||||
@@ -1,142 +0,0 @@
|
||||
/**
|
||||
* Build config for electron renderer process
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
|
||||
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
|
||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||
import TerserPlugin from 'terser-webpack-plugin';
|
||||
import webpack from 'webpack';
|
||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
||||
import { merge } from 'webpack-merge';
|
||||
|
||||
import checkNodeEnv from '../scripts/check-node-env';
|
||||
import deleteSourceMaps from '../scripts/delete-source-maps';
|
||||
import baseConfig from './webpack.config.base';
|
||||
import webpackPaths from './webpack.paths';
|
||||
|
||||
const { version } = require('../../package.json');
|
||||
|
||||
checkNodeEnv('production');
|
||||
deleteSourceMaps();
|
||||
|
||||
const devtoolsConfig =
|
||||
process.env.DEBUG_PROD === 'true'
|
||||
? {
|
||||
devtool: 'source-map',
|
||||
}
|
||||
: {};
|
||||
|
||||
const configuration: webpack.Configuration = {
|
||||
...devtoolsConfig,
|
||||
|
||||
mode: 'production',
|
||||
|
||||
target: ['web'],
|
||||
|
||||
entry: {
|
||||
remote: path.join(webpackPaths.srcRemotePath, 'index.tsx'),
|
||||
worker: path.join(webpackPaths.srcRemotePath, 'service-worker.ts'),
|
||||
},
|
||||
|
||||
output: {
|
||||
path: webpackPaths.distRemotePath,
|
||||
publicPath: './',
|
||||
filename: '[name].js',
|
||||
library: {
|
||||
type: 'umd',
|
||||
},
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.s?(a|c)ss$/,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
modules: true,
|
||||
sourceMap: true,
|
||||
importLoaders: 1,
|
||||
},
|
||||
},
|
||||
'sass-loader',
|
||||
],
|
||||
include: /\.module\.s?(c|a)ss$/,
|
||||
},
|
||||
{
|
||||
test: /\.s?(a|c)ss$/,
|
||||
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
|
||||
exclude: /\.module\.s?(c|a)ss$/,
|
||||
},
|
||||
// Fonts
|
||||
{
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
// Images
|
||||
{
|
||||
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
parallel: true,
|
||||
}),
|
||||
new CssMinimizerPlugin(),
|
||||
],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
/**
|
||||
* Create global constants which can be configured at compile time.
|
||||
*
|
||||
* Useful for allowing different behaviour between development builds and
|
||||
* release builds
|
||||
*
|
||||
* NODE_ENV should be production so that modules do not perform certain
|
||||
* development checks
|
||||
*/
|
||||
new webpack.EnvironmentPlugin({
|
||||
NODE_ENV: 'production',
|
||||
DEBUG_PROD: false,
|
||||
}),
|
||||
|
||||
new MiniCssExtractPlugin({
|
||||
filename: 'remote.css',
|
||||
}),
|
||||
|
||||
new BundleAnalyzerPlugin({
|
||||
analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled',
|
||||
}),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: path.join(webpackPaths.srcRemotePath, 'index.ejs'),
|
||||
favicon: path.join(webpackPaths.assetsPath, 'icons', 'favicon.ico'),
|
||||
minify: {
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeComments: true,
|
||||
},
|
||||
isBrowser: true,
|
||||
env: process.env.NODE_ENV,
|
||||
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||
templateParameters: {
|
||||
version,
|
||||
prod: true,
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
export default merge(baseConfig, configuration);
|
||||
@@ -1,79 +0,0 @@
|
||||
/**
|
||||
* Builds the DLL for development electron renderer process
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
|
||||
import webpack from 'webpack';
|
||||
import { merge } from 'webpack-merge';
|
||||
|
||||
import { dependencies } from '../../package.json';
|
||||
import checkNodeEnv from '../scripts/check-node-env';
|
||||
import baseConfig from './webpack.config.base';
|
||||
import webpackPaths from './webpack.paths';
|
||||
|
||||
checkNodeEnv('development');
|
||||
|
||||
const dist = webpackPaths.dllPath;
|
||||
|
||||
const configuration: webpack.Configuration = {
|
||||
context: webpackPaths.rootPath,
|
||||
|
||||
devtool: 'eval',
|
||||
|
||||
mode: 'development',
|
||||
|
||||
target: 'electron-renderer',
|
||||
|
||||
externals: ['fsevents', 'crypto-browserify'],
|
||||
|
||||
/**
|
||||
* Use `module` from `webpack.config.renderer.dev.js`
|
||||
*/
|
||||
module: require('./webpack.config.renderer.dev').default.module,
|
||||
|
||||
entry: {
|
||||
renderer: Object.keys(dependencies || {}),
|
||||
},
|
||||
|
||||
output: {
|
||||
path: dist,
|
||||
filename: '[name].dev.dll.js',
|
||||
library: {
|
||||
name: 'renderer',
|
||||
type: 'var',
|
||||
},
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new webpack.DllPlugin({
|
||||
path: path.join(dist, '[name].json'),
|
||||
name: '[name]',
|
||||
}),
|
||||
|
||||
/**
|
||||
* Create global constants which can be configured at compile time.
|
||||
*
|
||||
* Useful for allowing different behaviour between development builds and
|
||||
* release builds
|
||||
*
|
||||
* NODE_ENV should be production so that modules do not perform certain
|
||||
* development checks
|
||||
*/
|
||||
new webpack.EnvironmentPlugin({
|
||||
NODE_ENV: 'development',
|
||||
}),
|
||||
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
debug: true,
|
||||
options: {
|
||||
context: webpackPaths.srcPath,
|
||||
output: {
|
||||
path: webpackPaths.dllPath,
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
export default merge(baseConfig, configuration);
|
||||
@@ -1,201 +0,0 @@
|
||||
import 'webpack-dev-server';
|
||||
import { execSync, spawn } from 'child_process';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
|
||||
import chalk from 'chalk';
|
||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import webpack from 'webpack';
|
||||
import { merge } from 'webpack-merge';
|
||||
|
||||
import checkNodeEnv from '../scripts/check-node-env';
|
||||
import baseConfig from './webpack.config.base';
|
||||
import webpackPaths from './webpack.paths';
|
||||
|
||||
// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's
|
||||
// at the dev webpack config is not accidentally run in a production environment
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
checkNodeEnv('development');
|
||||
}
|
||||
|
||||
const port = process.env.PORT || 4343;
|
||||
const manifest = path.resolve(webpackPaths.dllPath, 'renderer.json');
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const requiredByDLLConfig = module.parent!.filename.includes('webpack.config.renderer.dev.dll');
|
||||
|
||||
/**
|
||||
* Warn if the DLL is not built
|
||||
*/
|
||||
if (!requiredByDLLConfig && !(fs.existsSync(webpackPaths.dllPath) && fs.existsSync(manifest))) {
|
||||
console.log(
|
||||
chalk.black.bgYellow.bold(
|
||||
'The DLL files are missing. Sit back while we build them for you with "npm run build-dll"',
|
||||
),
|
||||
);
|
||||
execSync('npm run postinstall');
|
||||
}
|
||||
|
||||
const configuration: webpack.Configuration = {
|
||||
devtool: 'inline-source-map',
|
||||
|
||||
mode: 'development',
|
||||
|
||||
target: ['web', 'electron-renderer'],
|
||||
|
||||
entry: [
|
||||
`webpack-dev-server/client?http://localhost:${port}/dist`,
|
||||
'webpack/hot/only-dev-server',
|
||||
path.join(webpackPaths.srcRendererPath, 'index.tsx'),
|
||||
],
|
||||
|
||||
output: {
|
||||
path: webpackPaths.distRendererPath,
|
||||
publicPath: '/',
|
||||
filename: 'renderer.dev.js',
|
||||
library: {
|
||||
type: 'umd',
|
||||
},
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.s?css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
modules: {
|
||||
localIdentName: '[name]__[local]--[hash:base64:5]',
|
||||
exportLocalsConvention: 'camelCaseOnly',
|
||||
},
|
||||
sourceMap: true,
|
||||
importLoaders: 1,
|
||||
},
|
||||
},
|
||||
'sass-loader',
|
||||
],
|
||||
include: /\.module\.s?(c|a)ss$/,
|
||||
},
|
||||
{
|
||||
test: /\.s?css$/,
|
||||
use: ['style-loader', 'css-loader', 'sass-loader'],
|
||||
exclude: /\.module\.s?(c|a)ss$/,
|
||||
},
|
||||
// Fonts
|
||||
{
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
// Images
|
||||
{
|
||||
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
...(requiredByDLLConfig
|
||||
? []
|
||||
: [
|
||||
new webpack.DllReferencePlugin({
|
||||
context: webpackPaths.dllPath,
|
||||
manifest: require(manifest),
|
||||
sourceType: 'var',
|
||||
}),
|
||||
]),
|
||||
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
|
||||
/**
|
||||
* Create global constants which can be configured at compile time.
|
||||
*
|
||||
* Useful for allowing different behaviour between development builds and
|
||||
* release builds
|
||||
*
|
||||
* NODE_ENV should be production so that modules do not perform certain
|
||||
* development checks
|
||||
*
|
||||
* By default, use 'development' as NODE_ENV. This can be overriden with
|
||||
* 'staging', for example, by changing the ENV variables in the npm scripts
|
||||
*/
|
||||
new webpack.EnvironmentPlugin({
|
||||
NODE_ENV: 'development',
|
||||
}),
|
||||
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
debug: true,
|
||||
}),
|
||||
|
||||
new ReactRefreshWebpackPlugin(),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
filename: path.join('index.html'),
|
||||
template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
|
||||
minify: {
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeComments: true,
|
||||
},
|
||||
isBrowser: false,
|
||||
env: process.env.NODE_ENV,
|
||||
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||
nodeModules: webpackPaths.appNodeModulesPath,
|
||||
templateParameters: {
|
||||
web: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: false,
|
||||
},
|
||||
|
||||
devServer: {
|
||||
port,
|
||||
compress: true,
|
||||
hot: true,
|
||||
headers: { 'Access-Control-Allow-Origin': '*' },
|
||||
static: {
|
||||
publicPath: '/',
|
||||
},
|
||||
historyApiFallback: {
|
||||
verbose: true,
|
||||
},
|
||||
setupMiddlewares(middlewares) {
|
||||
console.log('Starting preload.js builder...');
|
||||
const preloadProcess = spawn('npm', ['run', 'start:preload'], {
|
||||
shell: true,
|
||||
stdio: 'inherit',
|
||||
})
|
||||
.on('close', (code: number) => process.exit(code!))
|
||||
.on('error', (spawnError) => console.error(spawnError));
|
||||
|
||||
console.log('Starting remote.js builder...');
|
||||
const remoteProcess = spawn('npm', ['run', 'start:remote'], {
|
||||
shell: true,
|
||||
stdio: 'inherit',
|
||||
})
|
||||
.on('close', (code: number) => process.exit(code!))
|
||||
.on('error', (spawnError) => console.error(spawnError));
|
||||
|
||||
console.log('Starting Main Process...');
|
||||
spawn('npm', ['run', 'start:main'], {
|
||||
shell: true,
|
||||
stdio: 'inherit',
|
||||
})
|
||||
.on('close', (code: number) => {
|
||||
preloadProcess.kill();
|
||||
remoteProcess.kill();
|
||||
process.exit(code!);
|
||||
})
|
||||
.on('error', (spawnError) => console.error(spawnError));
|
||||
return middlewares;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default merge(baseConfig, configuration);
|
||||
@@ -1,137 +0,0 @@
|
||||
/**
|
||||
* Build config for electron renderer process
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
|
||||
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
|
||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||
import TerserPlugin from 'terser-webpack-plugin';
|
||||
import webpack from 'webpack';
|
||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
||||
import { merge } from 'webpack-merge';
|
||||
|
||||
import checkNodeEnv from '../scripts/check-node-env';
|
||||
import deleteSourceMaps from '../scripts/delete-source-maps';
|
||||
import baseConfig from './webpack.config.base';
|
||||
import webpackPaths from './webpack.paths';
|
||||
|
||||
checkNodeEnv('production');
|
||||
deleteSourceMaps();
|
||||
|
||||
const devtoolsConfig =
|
||||
process.env.DEBUG_PROD === 'true'
|
||||
? {
|
||||
devtool: 'source-map',
|
||||
}
|
||||
: {};
|
||||
|
||||
const configuration: webpack.Configuration = {
|
||||
...devtoolsConfig,
|
||||
|
||||
mode: 'production',
|
||||
|
||||
target: ['web', 'electron-renderer'],
|
||||
|
||||
entry: [path.join(webpackPaths.srcRendererPath, 'index.tsx')],
|
||||
|
||||
output: {
|
||||
path: webpackPaths.distRendererPath,
|
||||
publicPath: './',
|
||||
filename: 'renderer.js',
|
||||
library: {
|
||||
type: 'umd',
|
||||
},
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.s?(a|c)ss$/,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
modules: {
|
||||
localIdentName: '[name]__[local]--[hash:base64:5]',
|
||||
exportLocalsConvention: 'camelCaseOnly',
|
||||
},
|
||||
sourceMap: true,
|
||||
importLoaders: 1,
|
||||
},
|
||||
},
|
||||
'sass-loader',
|
||||
],
|
||||
include: /\.module\.s?(c|a)ss$/,
|
||||
},
|
||||
{
|
||||
test: /\.s?(a|c)ss$/,
|
||||
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
|
||||
exclude: /\.module\.s?(c|a)ss$/,
|
||||
},
|
||||
// Fonts
|
||||
{
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
// Images
|
||||
{
|
||||
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
parallel: true,
|
||||
}),
|
||||
new CssMinimizerPlugin(),
|
||||
],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
/**
|
||||
* Create global constants which can be configured at compile time.
|
||||
*
|
||||
* Useful for allowing different behaviour between development builds and
|
||||
* release builds
|
||||
*
|
||||
* NODE_ENV should be production so that modules do not perform certain
|
||||
* development checks
|
||||
*/
|
||||
new webpack.EnvironmentPlugin({
|
||||
NODE_ENV: 'production',
|
||||
DEBUG_PROD: false,
|
||||
}),
|
||||
|
||||
new MiniCssExtractPlugin({
|
||||
filename: 'style.css',
|
||||
}),
|
||||
|
||||
new BundleAnalyzerPlugin({
|
||||
analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled',
|
||||
}),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
|
||||
minify: {
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeComments: true,
|
||||
},
|
||||
isBrowser: false,
|
||||
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||
templateParameters: {
|
||||
web: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
export default merge(baseConfig, configuration);
|
||||
@@ -1,147 +0,0 @@
|
||||
import 'webpack-dev-server';
|
||||
import path from 'path';
|
||||
|
||||
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
|
||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import webpack from 'webpack';
|
||||
import { merge } from 'webpack-merge';
|
||||
|
||||
import checkNodeEnv from '../scripts/check-node-env';
|
||||
import baseConfig from './webpack.config.base';
|
||||
import webpackPaths from './webpack.paths';
|
||||
|
||||
// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's
|
||||
// at the dev webpack config is not accidentally run in a production environment
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
checkNodeEnv('development');
|
||||
}
|
||||
|
||||
const port = process.env.PORT || 4343;
|
||||
|
||||
const configuration: webpack.Configuration = {
|
||||
devtool: 'inline-source-map',
|
||||
|
||||
mode: 'development',
|
||||
|
||||
target: ['web', 'electron-renderer'],
|
||||
|
||||
entry: [
|
||||
`webpack-dev-server/client?http://localhost:${port}/dist`,
|
||||
'webpack/hot/only-dev-server',
|
||||
path.join(webpackPaths.srcRendererPath, 'index.tsx'),
|
||||
],
|
||||
|
||||
output: {
|
||||
path: webpackPaths.distRendererPath,
|
||||
publicPath: '/',
|
||||
filename: 'renderer.dev.js',
|
||||
library: {
|
||||
type: 'umd',
|
||||
},
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.s?css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
modules: {
|
||||
localIdentName: '[name]__[local]--[hash:base64:5]',
|
||||
exportLocalsConvention: 'camelCaseOnly',
|
||||
},
|
||||
sourceMap: true,
|
||||
importLoaders: 1,
|
||||
},
|
||||
},
|
||||
'sass-loader',
|
||||
],
|
||||
include: /\.module\.s?(c|a)ss$/,
|
||||
},
|
||||
{
|
||||
test: /\.s?css$/,
|
||||
use: ['style-loader', 'css-loader', 'sass-loader'],
|
||||
exclude: /\.module\.s?(c|a)ss$/,
|
||||
},
|
||||
// Fonts
|
||||
{
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
// Images
|
||||
{
|
||||
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
|
||||
/**
|
||||
* Create global constants which can be configured at compile time.
|
||||
*
|
||||
* Useful for allowing different behaviour between development builds and
|
||||
* release builds
|
||||
*
|
||||
* NODE_ENV should be production so that modules do not perform certain
|
||||
* development checks
|
||||
*
|
||||
* By default, use 'development' as NODE_ENV. This can be overriden with
|
||||
* 'staging', for example, by changing the ENV variables in the npm scripts
|
||||
*/
|
||||
new webpack.EnvironmentPlugin({
|
||||
NODE_ENV: 'development',
|
||||
}),
|
||||
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
debug: true,
|
||||
}),
|
||||
|
||||
new ReactRefreshWebpackPlugin(),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
filename: path.join('index.html'),
|
||||
template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
|
||||
favicon: path.join(webpackPaths.assetsPath, 'icons', 'favicon.ico'),
|
||||
minify: {
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeComments: true,
|
||||
},
|
||||
isBrowser: false,
|
||||
env: process.env.NODE_ENV,
|
||||
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||
nodeModules: webpackPaths.appNodeModulesPath,
|
||||
templateParameters: {
|
||||
web: false, // with hot reload, we don't have NGINX injecting variables
|
||||
},
|
||||
}),
|
||||
],
|
||||
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: false,
|
||||
},
|
||||
|
||||
devServer: {
|
||||
port,
|
||||
compress: true,
|
||||
hot: true,
|
||||
headers: { 'Access-Control-Allow-Origin': '*' },
|
||||
static: {
|
||||
publicPath: '/',
|
||||
},
|
||||
historyApiFallback: {
|
||||
verbose: true,
|
||||
},
|
||||
setupMiddlewares(middlewares) {
|
||||
return middlewares;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default merge(baseConfig, configuration);
|
||||
@@ -1,138 +0,0 @@
|
||||
/**
|
||||
* Build config for electron renderer process
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
|
||||
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
|
||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||
import TerserPlugin from 'terser-webpack-plugin';
|
||||
import webpack from 'webpack';
|
||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
||||
import { merge } from 'webpack-merge';
|
||||
|
||||
import checkNodeEnv from '../scripts/check-node-env';
|
||||
import deleteSourceMaps from '../scripts/delete-source-maps';
|
||||
import baseConfig from './webpack.config.base';
|
||||
import webpackPaths from './webpack.paths';
|
||||
|
||||
checkNodeEnv('production');
|
||||
deleteSourceMaps();
|
||||
|
||||
const devtoolsConfig =
|
||||
process.env.DEBUG_PROD === 'true'
|
||||
? {
|
||||
devtool: 'source-map',
|
||||
}
|
||||
: {};
|
||||
|
||||
const configuration: webpack.Configuration = {
|
||||
...devtoolsConfig,
|
||||
|
||||
mode: 'production',
|
||||
|
||||
target: ['web'],
|
||||
|
||||
entry: [path.join(webpackPaths.srcRendererPath, 'index.tsx')],
|
||||
|
||||
output: {
|
||||
path: webpackPaths.distWebPath,
|
||||
publicPath: 'auto',
|
||||
filename: 'renderer.js',
|
||||
library: {
|
||||
type: 'umd',
|
||||
},
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.s?(a|c)ss$/,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
modules: {
|
||||
localIdentName: '[name]__[local]--[hash:base64:5]',
|
||||
exportLocalsConvention: 'camelCaseOnly',
|
||||
},
|
||||
sourceMap: true,
|
||||
importLoaders: 1,
|
||||
},
|
||||
},
|
||||
'sass-loader',
|
||||
],
|
||||
include: /\.module\.s?(c|a)ss$/,
|
||||
},
|
||||
{
|
||||
test: /\.s?(a|c)ss$/,
|
||||
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
|
||||
exclude: /\.module\.s?(c|a)ss$/,
|
||||
},
|
||||
// Fonts
|
||||
{
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
// Images
|
||||
{
|
||||
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
parallel: true,
|
||||
}),
|
||||
new CssMinimizerPlugin(),
|
||||
],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
/**
|
||||
* Create global constants which can be configured at compile time.
|
||||
*
|
||||
* Useful for allowing different behaviour between development builds and
|
||||
* release builds
|
||||
*
|
||||
* NODE_ENV should be production so that modules do not perform certain
|
||||
* development checks
|
||||
*/
|
||||
new webpack.EnvironmentPlugin({
|
||||
NODE_ENV: 'production',
|
||||
DEBUG_PROD: false,
|
||||
}),
|
||||
|
||||
new MiniCssExtractPlugin({
|
||||
filename: 'style.css',
|
||||
}),
|
||||
|
||||
new BundleAnalyzerPlugin({
|
||||
analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled',
|
||||
}),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
|
||||
favicon: path.join(webpackPaths.assetsPath, 'icons', 'favicon.ico'),
|
||||
minify: {
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeComments: true,
|
||||
},
|
||||
isBrowser: false,
|
||||
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||
templateParameters: {
|
||||
web: true,
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
export default merge(baseConfig, configuration);
|
||||
@@ -1,46 +0,0 @@
|
||||
const path = require('path');
|
||||
|
||||
const rootPath = path.join(__dirname, '../..');
|
||||
|
||||
const dllPath = path.join(__dirname, '../dll');
|
||||
|
||||
const srcPath = path.join(rootPath, 'src');
|
||||
const assetsPath = path.join(rootPath, 'assets');
|
||||
const srcMainPath = path.join(srcPath, 'main');
|
||||
const srcRemotePath = path.join(srcPath, 'remote');
|
||||
const srcRendererPath = path.join(srcPath, 'renderer');
|
||||
|
||||
const releasePath = path.join(rootPath, 'release');
|
||||
const appPath = path.join(releasePath, 'app');
|
||||
const appPackagePath = path.join(appPath, 'package.json');
|
||||
const appNodeModulesPath = path.join(appPath, 'node_modules');
|
||||
const srcNodeModulesPath = path.join(srcPath, 'node_modules');
|
||||
|
||||
const distPath = path.join(appPath, 'dist');
|
||||
const distMainPath = path.join(distPath, 'main');
|
||||
const distRemotePath = path.join(distPath, 'remote');
|
||||
const distRendererPath = path.join(distPath, 'renderer');
|
||||
const distWebPath = path.join(distPath, 'web');
|
||||
|
||||
const buildPath = path.join(releasePath, 'build');
|
||||
|
||||
export default {
|
||||
assetsPath,
|
||||
rootPath,
|
||||
dllPath,
|
||||
srcPath,
|
||||
srcMainPath,
|
||||
srcRemotePath,
|
||||
srcRendererPath,
|
||||
releasePath,
|
||||
appPath,
|
||||
appPackagePath,
|
||||
appNodeModulesPath,
|
||||
srcNodeModulesPath,
|
||||
distPath,
|
||||
distMainPath,
|
||||
distRemotePath,
|
||||
distRendererPath,
|
||||
distWebPath,
|
||||
buildPath,
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export default 'test-file-stub';
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"global-require": "off",
|
||||
"import/no-dynamic-require": "off",
|
||||
"import/no-extraneous-dependencies": "off"
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// Check if the renderer and main bundles are built
|
||||
import path from 'path';
|
||||
import chalk from 'chalk';
|
||||
import fs from 'fs';
|
||||
import webpackPaths from '../configs/webpack.paths';
|
||||
|
||||
const mainPath = path.join(webpackPaths.distMainPath, 'main.js');
|
||||
const remotePath = path.join(webpackPaths.distMainPath, 'remote.js');
|
||||
const rendererPath = path.join(webpackPaths.distRendererPath, 'renderer.js');
|
||||
|
||||
if (!fs.existsSync(mainPath)) {
|
||||
throw new Error(
|
||||
chalk.whiteBright.bgRed.bold(
|
||||
'The main process is not built yet. Build it by running "npm run build:main"',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (!fs.existsSync(remotePath)) {
|
||||
throw new Error(
|
||||
chalk.whiteBright.bgRed.bold(
|
||||
'The remote process is not built yet. Build it by running "npm run build:remote"',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (!fs.existsSync(rendererPath)) {
|
||||
throw new Error(
|
||||
chalk.whiteBright.bgRed.bold(
|
||||
'The renderer process is not built yet. Build it by running "npm run build:renderer"',
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import chalk from 'chalk';
|
||||
import { execSync } from 'child_process';
|
||||
import { dependencies } from '../../package.json';
|
||||
|
||||
if (dependencies) {
|
||||
const dependenciesKeys = Object.keys(dependencies);
|
||||
const nativeDeps = fs
|
||||
.readdirSync('node_modules')
|
||||
.filter((folder) => fs.existsSync(`node_modules/${folder}/binding.gyp`));
|
||||
if (nativeDeps.length === 0) {
|
||||
process.exit(0);
|
||||
}
|
||||
try {
|
||||
// Find the reason for why the dependency is installed. If it is installed
|
||||
// because of a devDependency then that is okay. Warn when it is installed
|
||||
// because of a dependency
|
||||
const { dependencies: dependenciesObject } = JSON.parse(
|
||||
execSync(`npm ls ${nativeDeps.join(' ')} --json`).toString()
|
||||
);
|
||||
const rootDependencies = Object.keys(dependenciesObject);
|
||||
const filteredRootDependencies = rootDependencies.filter((rootDependency) =>
|
||||
dependenciesKeys.includes(rootDependency)
|
||||
);
|
||||
if (filteredRootDependencies.length > 0) {
|
||||
const plural = filteredRootDependencies.length > 1;
|
||||
console.log(`
|
||||
${chalk.whiteBright.bgYellow.bold(
|
||||
'Webpack does not work with native dependencies.'
|
||||
)}
|
||||
${chalk.bold(filteredRootDependencies.join(', '))} ${
|
||||
plural ? 'are native dependencies' : 'is a native dependency'
|
||||
} and should be installed inside of the "./release/app" folder.
|
||||
First, uninstall the packages from "./package.json":
|
||||
${chalk.whiteBright.bgGreen.bold('npm uninstall your-package')}
|
||||
${chalk.bold(
|
||||
'Then, instead of installing the package to the root "./package.json":'
|
||||
)}
|
||||
${chalk.whiteBright.bgRed.bold('npm install your-package')}
|
||||
${chalk.bold('Install the package to "./release/app/package.json"')}
|
||||
${chalk.whiteBright.bgGreen.bold(
|
||||
'cd ./release/app && npm install your-package'
|
||||
)}
|
||||
Read more about native dependencies at:
|
||||
${chalk.bold(
|
||||
'https://electron-react-boilerplate.js.org/docs/adding-dependencies/#module-structure'
|
||||
)}
|
||||
`);
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Native dependencies could not be checked');
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import chalk from 'chalk';
|
||||
|
||||
export default function checkNodeEnv(expectedEnv) {
|
||||
if (!expectedEnv) {
|
||||
throw new Error('"expectedEnv" not set');
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV !== expectedEnv) {
|
||||
console.log(
|
||||
chalk.whiteBright.bgRed.bold(
|
||||
`"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config`
|
||||
)
|
||||
);
|
||||
process.exit(2);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import chalk from 'chalk';
|
||||
import detectPort from 'detect-port';
|
||||
|
||||
const port = process.env.PORT || '4343';
|
||||
|
||||
detectPort(port, (err, availablePort) => {
|
||||
if (port !== String(availablePort)) {
|
||||
throw new Error(
|
||||
chalk.whiteBright.bgRed.bold(
|
||||
`Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 npm start`
|
||||
)
|
||||
);
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
import rimraf from 'rimraf';
|
||||
import process from 'process';
|
||||
import webpackPaths from '../configs/webpack.paths';
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const commandMap = {
|
||||
dist: webpackPaths.distPath,
|
||||
release: webpackPaths.releasePath,
|
||||
dll: webpackPaths.dllPath,
|
||||
};
|
||||
|
||||
args.forEach((x) => {
|
||||
const pathToRemove = commandMap[x];
|
||||
if (pathToRemove !== undefined) {
|
||||
rimraf.sync(pathToRemove);
|
||||
}
|
||||
});
|
||||
@@ -1,9 +0,0 @@
|
||||
import path from 'path';
|
||||
import rimraf from 'rimraf';
|
||||
import webpackPaths from '../configs/webpack.paths';
|
||||
|
||||
export default function deleteSourceMaps() {
|
||||
rimraf.sync(path.join(webpackPaths.distMainPath, '*.js.map'));
|
||||
rimraf.sync(path.join(webpackPaths.distRemotePath, '*.js.map'));
|
||||
rimraf.sync(path.join(webpackPaths.distRendererPath, '*.js.map'));
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { execSync } from 'child_process';
|
||||
import fs from 'fs';
|
||||
import { dependencies } from '../../release/app/package.json';
|
||||
import webpackPaths from '../configs/webpack.paths';
|
||||
|
||||
if (
|
||||
Object.keys(dependencies || {}).length > 0 &&
|
||||
fs.existsSync(webpackPaths.appNodeModulesPath)
|
||||
) {
|
||||
const electronRebuildCmd =
|
||||
'../../node_modules/.bin/electron-rebuild --force --types prod,dev,optional --module-dir .';
|
||||
const cmd =
|
||||
process.platform === 'win32'
|
||||
? electronRebuildCmd.replace(/\//g, '\\')
|
||||
: electronRebuildCmd;
|
||||
execSync(cmd, {
|
||||
cwd: webpackPaths.appPath,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import webpackPaths from '../configs/webpack.paths';
|
||||
|
||||
const { srcNodeModulesPath } = webpackPaths;
|
||||
const { appNodeModulesPath } = webpackPaths;
|
||||
|
||||
if (!fs.existsSync(srcNodeModulesPath) && fs.existsSync(appNodeModulesPath)) {
|
||||
fs.symlinkSync(appNodeModulesPath, srcNodeModulesPath, 'junction');
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
const { notarize } = require('electron-notarize');
|
||||
const { build } = require('../../package.json');
|
||||
|
||||
exports.default = async function notarizeMacos(context) {
|
||||
const { electronPlatformName, appOutDir } = context;
|
||||
if (electronPlatformName !== 'darwin') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (process.env.CI !== 'true') {
|
||||
console.warn('Skipping notarizing step. Packaging is not running in CI');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!('APPLE_ID' in process.env && 'APPLE_ID_PASS' in process.env)) {
|
||||
console.warn(
|
||||
'Skipping notarizing step. APPLE_ID and APPLE_ID_PASS env variables must be set'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const appName = context.packager.appInfo.productFilename;
|
||||
|
||||
await notarize({
|
||||
appBundleId: build.appId,
|
||||
appPath: `${appOutDir}/${appName}.app`,
|
||||
appleId: process.env.APPLE_ID,
|
||||
appleIdPassword: process.env.APPLE_ID_PASS,
|
||||
});
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
.eslintcache
|
||||
|
||||
# Dependency directory
|
||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||
node_modules
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
src/i18n
|
||||
release/app/dist
|
||||
release/build
|
||||
.erb/dll
|
||||
|
||||
.idea
|
||||
npm-debug.log.*
|
||||
*.css.d.ts
|
||||
*.sass.d.ts
|
||||
*.scss.d.ts
|
||||
|
||||
# eslint ignores hidden directories by default:
|
||||
# https://github.com/eslint/eslint/issues/8429
|
||||
!.erb
|
||||
@@ -1,97 +0,0 @@
|
||||
module.exports = {
|
||||
extends: ['erb', 'plugin:typescript-sort-keys/recommended'],
|
||||
ignorePatterns: ['.erb/*', 'server'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
createDefaultProgram: true,
|
||||
ecmaVersion: 12,
|
||||
parser: '@typescript-eslint/parser',
|
||||
project: './tsconfig.json',
|
||||
sourceType: 'module',
|
||||
tsconfigRootDir: './',
|
||||
},
|
||||
plugins: ['@typescript-eslint', 'import', 'sort-keys-fix'],
|
||||
rules: {
|
||||
'@typescript-eslint/naming-convention': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-shadow': ['off'],
|
||||
'@typescript-eslint/no-unused-vars': ['error'],
|
||||
'@typescript-eslint/no-use-before-define': ['error'],
|
||||
'default-case': 'off',
|
||||
'import/extensions': 'off',
|
||||
'import/no-absolute-path': 'off',
|
||||
// A temporary hack related to IDE not resolving correct package.json
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
'import/no-unresolved': 'error',
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
alphabetize: {
|
||||
caseInsensitive: true,
|
||||
order: 'asc',
|
||||
},
|
||||
groups: ['builtin', 'external', 'internal', ['parent', 'sibling']],
|
||||
'newlines-between': 'never',
|
||||
pathGroups: [
|
||||
{
|
||||
group: 'external',
|
||||
pattern: 'react',
|
||||
position: 'before',
|
||||
},
|
||||
],
|
||||
pathGroupsExcludedImportTypes: ['react'],
|
||||
},
|
||||
],
|
||||
'import/prefer-default-export': 'off',
|
||||
'jsx-a11y/click-events-have-key-events': 'off',
|
||||
'jsx-a11y/interactive-supports-focus': 'off',
|
||||
'jsx-a11y/media-has-caption': 'off',
|
||||
'no-await-in-loop': 'off',
|
||||
'no-console': 'off',
|
||||
'no-nested-ternary': 'off',
|
||||
'no-restricted-syntax': 'off',
|
||||
'no-shadow': 'off',
|
||||
'no-underscore-dangle': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'no-use-before-define': 'off',
|
||||
'prefer-destructuring': 'off',
|
||||
'react/function-component-definition': 'off',
|
||||
'react/jsx-filename-extension': [2, { extensions: ['.js', '.jsx', '.ts', '.tsx'] }],
|
||||
'react/jsx-no-useless-fragment': 'off',
|
||||
'react/jsx-props-no-spreading': 'off',
|
||||
'react/jsx-sort-props': [
|
||||
'error',
|
||||
{
|
||||
callbacksLast: true,
|
||||
ignoreCase: false,
|
||||
noSortAlphabetically: false,
|
||||
reservedFirst: true,
|
||||
shorthandFirst: true,
|
||||
shorthandLast: false,
|
||||
},
|
||||
],
|
||||
'react/no-array-index-key': 'off',
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
'react/require-default-props': 'off',
|
||||
'sort-keys-fix/sort-keys-fix': 'warn',
|
||||
},
|
||||
settings: {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||
},
|
||||
'import/resolver': {
|
||||
// See https://github.com/benmosher/eslint-plugin-import/issues/1396#issuecomment-575727774 for line below
|
||||
node: {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
},
|
||||
typescript: {
|
||||
alwaysTryTypes: true,
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
webpack: {
|
||||
config: require.resolve('./.erb/configs/webpack.config.eslint.ts'),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
name: Feature request
|
||||
description: Request a feature to be added to Feishin
|
||||
title: '[Feature]: '
|
||||
labels: ['enhancement']
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: check-duplicate
|
||||
attributes:
|
||||
label: I have already checked through the existing feature requests and found no duplicates
|
||||
options:
|
||||
- label: 'Yes'
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: server-specific
|
||||
attributes:
|
||||
label: Is this a server-specific feature?
|
||||
options:
|
||||
- Not server-specific
|
||||
- OpenSubsonic
|
||||
- Jellyfin
|
||||
- Navidrome
|
||||
default: 0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: What do you want to be added?
|
||||
placeholder: I would like to see [...]
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,74 @@
|
||||
name: Bug report
|
||||
description: You're having technical issues.
|
||||
title: '[Bug]: '
|
||||
labels: ['bug']
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: check-duplicate
|
||||
attributes:
|
||||
label: I have already checked through the existing bug reports and found no duplicates
|
||||
options:
|
||||
- label: 'Yes'
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: App Version
|
||||
description: What version of the app are you running?
|
||||
placeholder: ex. 1.0.0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: server-version
|
||||
attributes:
|
||||
label: Music Server and Version
|
||||
description: What music server are you using?
|
||||
placeholder: ex. Navidrome v0.55.0, LMS v3.67.0, Jellyfin v10.10.7, etc.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: environments
|
||||
attributes:
|
||||
label: What local environments are you seeing the problem on?
|
||||
multiple: true
|
||||
options:
|
||||
- Desktop Windows
|
||||
- Desktop macOS
|
||||
- Desktop Linux
|
||||
- Web Firefox
|
||||
- Web Chrome
|
||||
- Web Safari
|
||||
- Web Microsoft Edge
|
||||
- Other (please specify in the next field)
|
||||
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Include screenshots and error logs if possible. The browser devtools can be opened using CTRL + SHIFT + I (Windows/Linux) or CMD + SHIFT + I (macOS).
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: How can we reproduce this issue? Are there any specific settings that are enabled that could be the cause?
|
||||
placeholder: |
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code.
|
||||
render: shell
|
||||
@@ -1,63 +0,0 @@
|
||||
name: Bug report
|
||||
description: You're having technical issues. 🐞
|
||||
labels: ['bug']
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: What should have happened?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Current Behavior
|
||||
description: What went wrong? Add screenshots to help explain your problem. (Open the browser dev tools in the menu or using CTRL + SHIFT + I)
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
placeholder: |
|
||||
<!-- Add relevant code and/or a live example -->
|
||||
<!-- Add stack traces -->
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Possible Solution
|
||||
description: Suggest a reason for the bug or how to fix it.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Context
|
||||
description: How has this issue affected you? What are you trying to accomplish?
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
attributes:
|
||||
label: Application version
|
||||
placeholder: (e.g. v0.1.0)
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Operating System and version
|
||||
placeholder: (e.g. Windows 11 desktop, Webapp in Firefox)
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Server and Version
|
||||
placeholder: (e.g. Navidrome v0.48.0)
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Node Version (if developing locally)
|
||||
validations:
|
||||
required: false
|
||||
@@ -1,5 +1,11 @@
|
||||
blank_issues_enabled: true
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Question
|
||||
- name: Questions or help
|
||||
url: https://github.com/jeffvli/feishin/discussions
|
||||
about: Please ask and answer questions here.
|
||||
about: Ask questions or get help in the discussions section
|
||||
- name: Discord Community
|
||||
url: https://discord.gg/FVKpcMDy5f
|
||||
about: The discord/matrix servers are bridged so you can join whichever you prefer
|
||||
- name: Matrix Community
|
||||
url: https://matrix.to/#/#sonixd:matrix.org
|
||||
about: The discord/matrix servers are bridged so you can join whichever you prefer
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
name: Feature request - NOT ACCEPTING NEW FEATURE REQUESTS
|
||||
description: Feature requests are currently closed. The application is actively being rewritten https://github.com/audioling/audioling.
|
||||
labels: ['enhancement']
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: What do you want to be added?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is this a server-specific feature? (e.g. Jellyfin only)
|
||||
options:
|
||||
- label: 'Yes'
|
||||
required: false
|
||||
@@ -3,6 +3,7 @@ name: Publish Docker to GHCR
|
||||
permissions: write-all
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
@@ -49,6 +50,6 @@ jobs:
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm/v7
|
||||
linux/arm64/v8
|
||||
linux/amd64
|
||||
linux/arm/v7
|
||||
linux/arm64/v8
|
||||
|
||||
@@ -24,11 +24,9 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Setup Docker buildx
|
||||
@@ -41,6 +39,6 @@ jobs:
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm/v7
|
||||
linux/arm64/v8
|
||||
linux/amd64
|
||||
linux/arm/v7
|
||||
linux/arm64/v8
|
||||
|
||||
@@ -14,17 +14,15 @@ jobs:
|
||||
- name: Checkout git repo
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Node and NPM
|
||||
uses: actions/setup-node@v1
|
||||
- name: Install Node and PNPM
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
node-version: 18
|
||||
cache: npm
|
||||
version: 9
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm install --legacy-peer-deps
|
||||
run: pnpm install
|
||||
|
||||
- name: Publish releases
|
||||
- name: Build and Publish releases
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: nick-invision/retry@v2.8.2
|
||||
@@ -33,12 +31,11 @@ jobs:
|
||||
max_attempts: 3
|
||||
retry_on: error
|
||||
command: |
|
||||
npm run postinstall
|
||||
npm run build
|
||||
npm exec electron-builder -- --publish always --linux
|
||||
on_retry_command: npm cache clean --force
|
||||
pnpm run package:linux
|
||||
pnpm run publish:linux
|
||||
on_retry_command: pnpm cache delete
|
||||
|
||||
- name: Publish releases (arm64)
|
||||
- name: Build and Publish releases (arm64)
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: nick-invision/retry@v2.8.2
|
||||
@@ -47,7 +44,6 @@ jobs:
|
||||
max_attempts: 3
|
||||
retry_on: error
|
||||
command: |
|
||||
npm run postinstall
|
||||
npm run build
|
||||
npm exec electron-builder -- --publish always --arm64
|
||||
on_retry_command: npm cache clean --force
|
||||
pnpm run package:linux-arm64
|
||||
pnpm run publish:linux-arm64
|
||||
on_retry_command: pnpm cache delete
|
||||
|
||||
@@ -14,17 +14,15 @@ jobs:
|
||||
- name: Checkout git repo
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Node and NPM
|
||||
uses: actions/setup-node@v1
|
||||
- name: Install Node and PNPM
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
node-version: 18
|
||||
cache: npm
|
||||
version: 9
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm install --legacy-peer-deps
|
||||
run: pnpm install
|
||||
|
||||
- name: Publish releases
|
||||
- name: Build and Publish releases
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: nick-invision/retry@v2.8.2
|
||||
@@ -33,7 +31,6 @@ jobs:
|
||||
max_attempts: 3
|
||||
retry_on: error
|
||||
command: |
|
||||
npm run postinstall
|
||||
npm run build
|
||||
npm exec electron-builder -- --publish always --mac
|
||||
on_retry_command: npm cache clean --force
|
||||
pnpm run package:mac
|
||||
pnpm run publish:mac
|
||||
on_retry_command: pnpm cache delete
|
||||
|
||||
@@ -17,15 +17,13 @@ jobs:
|
||||
- name: Checkout git repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Node and NPM
|
||||
uses: actions/setup-node@v3
|
||||
- name: Install Node and PNPM
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
node-version: 18
|
||||
cache: npm
|
||||
version: 9
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm install --legacy-peer-deps
|
||||
run: pnpm install
|
||||
|
||||
- name: Build for Windows
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
@@ -35,7 +33,7 @@ jobs:
|
||||
max_attempts: 3
|
||||
retry_on: error
|
||||
command: |
|
||||
npm run package:pr:windows
|
||||
pnpm run package:win:pr
|
||||
|
||||
- name: Build for Linux
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
@@ -45,7 +43,7 @@ jobs:
|
||||
max_attempts: 3
|
||||
retry_on: error
|
||||
command: |
|
||||
npm run package:pr:linux
|
||||
pnpm run package:linux:pr
|
||||
|
||||
- name: Build for MacOS
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
@@ -55,41 +53,41 @@ jobs:
|
||||
max_attempts: 3
|
||||
retry_on: error
|
||||
command: |
|
||||
npm run package:pr:macos
|
||||
pnpm run package:mac:pr
|
||||
|
||||
- name: Zip Windows Binaries
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
Compress-Archive -Path "release/build/*.exe" -DestinationPath "release/build/windows-binaries.zip" -Force
|
||||
Compress-Archive -Path "dist/*.exe" -DestinationPath "dist/windows-binaries.zip" -Force
|
||||
|
||||
- name: Zip Linux Binaries
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
zip -r release/build/linux-binaries.zip release/build/*.{AppImage,deb,rpm}
|
||||
zip -r dist/linux-binaries.zip dist/*.{AppImage,deb,rpm}
|
||||
|
||||
- name: Zip MacOS Binaries
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
run: |
|
||||
zip -r release/build/macos-binaries.zip release/build/*.dmg
|
||||
zip -r dist/macos-binaries.zip dist/*.dmg
|
||||
|
||||
- name: Upload Windows Binaries
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-binaries
|
||||
path: release/build/windows-binaries.zip
|
||||
path: dist/windows-binaries.zip
|
||||
|
||||
- name: Upload Linux Binaries
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-binaries
|
||||
path: release/build/linux-binaries.zip
|
||||
path: dist/linux-binaries.zip
|
||||
|
||||
- name: Upload MacOS Binaries
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: macos-binaries
|
||||
path: release/build/macos-binaries.zip
|
||||
path: dist/macos-binaries.zip
|
||||
|
||||
@@ -14,17 +14,15 @@ jobs:
|
||||
- name: Checkout git repo
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Node and NPM
|
||||
uses: actions/setup-node@v1
|
||||
- name: Install Node and PNPM
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
node-version: 18
|
||||
cache: npm
|
||||
version: 9
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm install --legacy-peer-deps
|
||||
run: pnpm install
|
||||
|
||||
- name: Publish releases
|
||||
- name: Build and Publish releases
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: nick-invision/retry@v2.8.2
|
||||
@@ -33,7 +31,6 @@ jobs:
|
||||
max_attempts: 3
|
||||
retry_on: error
|
||||
command: |
|
||||
npm run postinstall
|
||||
npm run build
|
||||
npm exec electron-builder -- --publish always --win
|
||||
on_retry_command: npm cache clean --force
|
||||
pnpm run package:win
|
||||
pnpm run publish:win
|
||||
on_retry_command: pnpm cache delete
|
||||
|
||||
@@ -14,21 +14,13 @@ jobs:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Node.js and NPM
|
||||
uses: actions/setup-node@v2
|
||||
- name: Install Node.js and PNPM
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
node-version: 16
|
||||
cache: npm
|
||||
version: 9
|
||||
|
||||
- name: npm install
|
||||
run: |
|
||||
npm install --legacy-peer-deps
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: npm test
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
npm run lint
|
||||
npm run package
|
||||
npm exec tsc
|
||||
npm test
|
||||
- name: Lint Files
|
||||
run: pnpm run lint
|
||||
|
||||
+5
-29
@@ -1,31 +1,7 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
.eslintcache
|
||||
|
||||
# Dependency directory
|
||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||
node_modules
|
||||
|
||||
# OSX
|
||||
dist
|
||||
out
|
||||
.DS_Store
|
||||
|
||||
release/app/dist
|
||||
release/build
|
||||
.erb/dll
|
||||
|
||||
.idea
|
||||
npm-debug.log.*
|
||||
*.css.d.ts
|
||||
*.sass.d.ts
|
||||
*.scss.d.ts
|
||||
|
||||
.env*
|
||||
.eslintcache
|
||||
*.log*
|
||||
release
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged
|
||||
@@ -0,0 +1,6 @@
|
||||
out
|
||||
dist
|
||||
pnpm-lock.yaml
|
||||
LICENSE.md
|
||||
tsconfig.json
|
||||
tsconfig.*.json
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 4,
|
||||
"useTabs": false,
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.css", "**/*.scss", "**/*.html"],
|
||||
"options": {
|
||||
"singleQuote": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"proseWrap": "never",
|
||||
"htmlWhitespaceSensitivity": "strict",
|
||||
"endOfLine": "lf",
|
||||
"singleAttributePerLine": true
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
singleQuote: true
|
||||
semi: true
|
||||
printWidth: 100
|
||||
tabWidth: 4
|
||||
trailingComma: all
|
||||
useTabs: false
|
||||
arrowParens: always
|
||||
proseWrap: never
|
||||
htmlWhitespaceSensitivity: strict
|
||||
endOfLine: lf
|
||||
singleAttributePerLine: true
|
||||
bracketSpacing: true
|
||||
plugins:
|
||||
- prettier-plugin-packagejson
|
||||
+9
-7
@@ -1,17 +1,19 @@
|
||||
{
|
||||
"customSyntax": "postcss-styled-syntax",
|
||||
"extends": [
|
||||
"stylelint-config-standard",
|
||||
"stylelint-config-styled-components",
|
||||
"stylelint-config-css-modules",
|
||||
"stylelint-config-recess-order"
|
||||
],
|
||||
"rules": {
|
||||
"declaration-empty-line-before": null,
|
||||
"declaration-block-no-redundant-longhand-properties": null,
|
||||
"selector-class-pattern": null,
|
||||
"block-no-empty": null,
|
||||
"selector-type-case": ["lower", { "ignoreTypes": ["/^\\$\\w+/"] }],
|
||||
"selector-type-no-unknown": [true, { "ignoreTypes": ["/-styled-mixin/", "/^\\$\\w+/"] }],
|
||||
"declaration-colon-newline-after": null,
|
||||
"property-no-vendor-prefix": null
|
||||
"declaration-block-no-shorthand-property-overrides": null,
|
||||
"declaration-block-no-redundant-longhand-properties": null,
|
||||
"at-rule-no-unknown": [true, { "ignoreAtRules": ["mixin", "value"] }],
|
||||
"function-no-unknown": [true, { "ignoreFunctions": ["darken", "alpha", "lighten"] }],
|
||||
"declaration-property-value-no-unknown": null,
|
||||
"no-descending-specificity": null,
|
||||
"no-empty-source": null
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-8
@@ -1,10 +1,3 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"EditorConfig.EditorConfig",
|
||||
"stylelint.vscode-stylelint",
|
||||
"esbenp.prettier-vscode",
|
||||
"clinyong.vscode-css-modules",
|
||||
"Huuums.vscode-fast-folder-structure"
|
||||
]
|
||||
"recommendations": ["dbaeumer.vscode-eslint"]
|
||||
}
|
||||
|
||||
Vendored
+37
-26
@@ -1,28 +1,39 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Electron: Main",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"protocol": "inspector",
|
||||
"runtimeExecutable": "npm",
|
||||
"runtimeArgs": ["run start:main --inspect=5858 --remote-debugging-port=9223"],
|
||||
"preLaunchTask": "Start Webpack Dev"
|
||||
},
|
||||
{
|
||||
"name": "Electron: Renderer",
|
||||
"type": "chrome",
|
||||
"request": "attach",
|
||||
"port": 9223,
|
||||
"webRoot": "${workspaceFolder}",
|
||||
"timeout": 15000
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
"name": "Electron: All",
|
||||
"configurations": ["Electron: Main", "Electron: Renderer"]
|
||||
}
|
||||
]
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug Main Process",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite",
|
||||
"windows": {
|
||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd"
|
||||
},
|
||||
"runtimeArgs": ["--sourcemap"],
|
||||
"env": {
|
||||
"REMOTE_DEBUGGING_PORT": "9222"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Debug Renderer Process",
|
||||
"port": 9222,
|
||||
"request": "attach",
|
||||
"type": "chrome",
|
||||
"webRoot": "${workspaceFolder}/src/renderer",
|
||||
"timeout": 60000,
|
||||
"presentation": {
|
||||
"hidden": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
"name": "Debug All",
|
||||
"configurations": ["Debug Main Process", "Debug Renderer Process"],
|
||||
"presentation": {
|
||||
"order": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+22
-10
@@ -1,4 +1,13 @@
|
||||
{
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"files.associations": {
|
||||
".eslintrc": "jsonc",
|
||||
".prettierrc": "jsonc",
|
||||
@@ -9,7 +18,7 @@
|
||||
{ "directory": "./", "changeProcessCWD": true },
|
||||
{ "directory": "./server", "changeProcessCWD": true }
|
||||
],
|
||||
"typescript.tsserver.experimental.enableProjectDiagnostics": true,
|
||||
"typescript.tsserver.experimental.enableProjectDiagnostics": false,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.fixAll.stylelint": "explicit",
|
||||
@@ -17,10 +26,6 @@
|
||||
"source.formatDocument": "explicit"
|
||||
},
|
||||
"css.validate": true,
|
||||
"less.validate": false,
|
||||
"scss.validate": true,
|
||||
"scss.lint.unknownAtRules": "warning",
|
||||
"scss.lint.unknownProperties": "warning",
|
||||
"javascript.validate.enable": false,
|
||||
"javascript.format.enable": false,
|
||||
"typescript.format.enable": false,
|
||||
@@ -33,14 +38,21 @@
|
||||
"npm-debug.log.*": true,
|
||||
"test/**/__snapshots__": true,
|
||||
"package-lock.json": true,
|
||||
"*.{css,sass,scss}.d.ts": true
|
||||
"*.{css,sass,scss}.d.ts": true,
|
||||
"out/**/*": true,
|
||||
"dist/**/*": true
|
||||
},
|
||||
"i18n-ally.localesPaths": ["src/i18n", "src/i18n/locales"],
|
||||
"typescript.tsdk": "node_modules\\typescript\\lib",
|
||||
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||
"stylelint.validate": ["css", "scss", "typescript", "typescriptreact"],
|
||||
"stylelint.config": null,
|
||||
"stylelint.validate": ["css", "postcss"],
|
||||
"typescript.updateImportsOnFileMove.enabled": "always",
|
||||
"[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
|
||||
"typescript.preferences.autoImportFileExcludePatterns": [
|
||||
"@mantine/core",
|
||||
"@mantine/modals",
|
||||
"@mantine/dates"
|
||||
],
|
||||
"[typescriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
|
||||
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": true,
|
||||
"folderTemplates.structures": [
|
||||
@@ -53,14 +65,14 @@
|
||||
"template": "Functional Component with CSS Modules"
|
||||
},
|
||||
{
|
||||
"fileName": "<FTName | kebabcase>.module.scss"
|
||||
"fileName": "<FTName | kebabcase>.module.css"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"folderTemplates.fileTemplates": {
|
||||
"Functional Component with CSS Modules": [
|
||||
"import styles from './<FTName | kebabcase>.module.scss';",
|
||||
"import styles from './<FTName | kebabcase>.module.css';",
|
||||
"",
|
||||
"interface <FTName | pascalcase>Props {}",
|
||||
"",
|
||||
|
||||
Vendored
-25
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"label": "Start Webpack Dev",
|
||||
"script": "start:renderer",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "custom",
|
||||
"pattern": {
|
||||
"regexp": "____________"
|
||||
},
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": "Compiling\\.\\.\\.$",
|
||||
"endsPattern": "(Compiled successfully|Failed to compile)\\.$"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+11
-8
@@ -1,19 +1,22 @@
|
||||
# --- Builder stage
|
||||
FROM node:18-alpine as builder
|
||||
FROM node:23-alpine as builder
|
||||
WORKDIR /app
|
||||
|
||||
#Copy package.json first to cache node_modules
|
||||
COPY package.json package-lock.json .
|
||||
# Scripts include electron-specific dependencies, which we don't need
|
||||
RUN npm install --legacy-peer-deps --ignore-scripts
|
||||
#Copy code and build with cached modules
|
||||
# Copy package.json first to cache node_modules
|
||||
COPY package.json pnpm-lock.yaml .
|
||||
|
||||
RUN npm install -g pnpm
|
||||
|
||||
RUN pnpm install
|
||||
|
||||
# Copy code and build with cached modules
|
||||
COPY . .
|
||||
RUN npm run build:web
|
||||
RUN pnpm run build:web
|
||||
|
||||
# --- Production stage
|
||||
FROM nginx:alpine-slim
|
||||
|
||||
COPY --chown=nginx:nginx --from=builder /app/release/app/dist/web /usr/share/nginx/html
|
||||
COPY --chown=nginx:nginx --from=builder /app/out/web /usr/share/nginx/html
|
||||
COPY ./settings.js.template /etc/nginx/templates/settings.js.template
|
||||
COPY ng.conf.template /etc/nginx/templates/default.conf.template
|
||||
|
||||
|
||||
@@ -29,25 +29,17 @@
|
||||
|
||||
---
|
||||
|
||||
## MAINTENANCE NOTICE
|
||||
|
||||
Feishin is currently undergoing a major rewrite. New feature requests will not be accepted. The rewrite is being actively developed at the [audioling](https://github.com/audioling/audioling) repository.
|
||||
|
||||
Follow the repository or join the discord/matrix server for updates.
|
||||
|
||||
---
|
||||
|
||||
Rewrite of [Sonixd](https://github.com/jeffvli/sonixd).
|
||||
|
||||
## Features
|
||||
|
||||
- [x] MPV player backend
|
||||
- [x] Web player backend
|
||||
- [x] Modern UI
|
||||
- [x] Scrobble playback to your server
|
||||
- [x] Smart playlist editor (Navidrome)
|
||||
- [x] Synchronized and unsynchronized lyrics support
|
||||
- [ ] [Request a feature](https://github.com/jeffvli/feishin/issues) or [view taskboard](https://github.com/users/jeffvli/projects/5/views/1)
|
||||
- [x] MPV player backend
|
||||
- [x] Web player backend
|
||||
- [x] Modern UI
|
||||
- [x] Scrobble playback to your server
|
||||
- [x] Smart playlist editor (Navidrome)
|
||||
- [x] Synchronized and unsynchronized lyrics support
|
||||
- [ ] [Request a feature](https://github.com/jeffvli/feishin/issues) or [view taskboard](https://github.com/users/jeffvli/projects/5/views/1)
|
||||
|
||||
## Screenshots
|
||||
|
||||
@@ -109,8 +101,8 @@ services:
|
||||
|
||||
2. After restarting the app, you will be prompted to select a server. Click the `Open menu` button and select `Manage servers`. Click the `Add server` button in the popup and fill out all applicable details. You will need to enter the full URL to your server, including the protocol and port if applicable (e.g. `https://navidrome.my-server.com` or `http://192.168.0.1:4533`).
|
||||
|
||||
- **Navidrome** - For the best experience, select "Save password" when creating the server and configure the `SessionTimeout` setting in your Navidrome config to a larger value (e.g. 72h).
|
||||
- **Linux users** - The default password store uses `libsecret`. `kwallet4/5/6` are also supported, but must be explicitly set in Settings > Window > Passwords/secret score.
|
||||
- **Navidrome** - For the best experience, select "Save password" when creating the server and configure the `SessionTimeout` setting in your Navidrome config to a larger value (e.g. 72h).
|
||||
- **Linux users** - The default password store uses `libsecret`. `kwallet4/5/6` are also supported, but must be explicitly set in Settings > Window > Passwords/secret score.
|
||||
|
||||
3. _Optional_ - If you want to host Feishin on a subpath (not `/`), then pass in the following environment variable: `PUBLIC_PATH=PATH`. For example, to host on `/feishin`, pass in `PUBLIC_PATH=/feishin`.
|
||||
|
||||
@@ -124,20 +116,20 @@ First thing to do is check that your MPV binary path is correct. Navigate to the
|
||||
|
||||
### What music servers does Feishin support?
|
||||
|
||||
Feishin supports any music server that implements a [Navidrome](https://www.navidrome.org/) or [Jellyfin](https://jellyfin.org/) API. **Subsonic API is not currently supported**. This will likely be added in [later when the new Subsonic API is decided on](https://support.symfonium.app/t/subsonic-servers-participation/1233).
|
||||
Feishin supports any music server that implements a [Navidrome](https://www.navidrome.org/), [Jellyfin](https://jellyfin.org/), or [OpenSubsonic compatible](https://opensubsonic.netlify.app/) API.
|
||||
|
||||
- [Navidrome](https://github.com/navidrome/navidrome)
|
||||
- [Jellyfin](https://github.com/jellyfin/jellyfin)
|
||||
- Subsonic-compatible servers
|
||||
- [Airsonic-Advanced](https://github.com/airsonic-advanced/airsonic-advanced)
|
||||
- [Ampache](https://ampache.org)
|
||||
- [Astiga](https://asti.ga/)
|
||||
- [Funkwhale](https://www.funkwhale.audio/)
|
||||
- [Gonic](https://github.com/sentriz/gonic)
|
||||
- [LMS](https://github.com/epoupon/lms)
|
||||
- [Nextcloud Music](https://apps.nextcloud.com/apps/music)
|
||||
- [Supysonic](https://github.com/spl0k/supysonic)
|
||||
- More (?)
|
||||
- [Navidrome](https://github.com/navidrome/navidrome)
|
||||
- [Jellyfin](https://github.com/jellyfin/jellyfin)
|
||||
- [OpenSubsonic](https://opensubsonic.netlify.app/) compatible servers, such as...
|
||||
- [Airsonic-Advanced](https://github.com/airsonic-advanced/airsonic-advanced)
|
||||
- [Ampache](https://ampache.org)
|
||||
- [Astiga](https://asti.ga/)
|
||||
- [Funkwhale](https://www.funkwhale.audio/)
|
||||
- [Gonic](https://github.com/sentriz/gonic)
|
||||
- [LMS](https://github.com/epoupon/lms)
|
||||
- [Nextcloud Music](https://apps.nextcloud.com/apps/music)
|
||||
- [Supysonic](https://github.com/spl0k/supysonic)
|
||||
- More (?)
|
||||
|
||||
### I have the issue "The SUID sandbox helper binary was found, but is not configured correctly" on Linux
|
||||
|
||||
@@ -152,9 +144,32 @@ Ubunutu 24.04 specifically introduced breaking changes that affect how namespace
|
||||
|
||||
## Development
|
||||
|
||||
Built and tested using Node `v16.15.0`.
|
||||
Built and tested using Node `v23.11.0`.
|
||||
|
||||
This project is built off of [electron-react-boilerplate](https://github.com/electron-react-boilerplate/electron-react-boilerplate) v4.6.0.
|
||||
This project is built off of [electron-vite](https://github.com/alex8088/electron-vite)
|
||||
|
||||
- `pnpm run dev` - Start the development server
|
||||
- `pnpm run dev:watch` - Start the development server in watch mode (for main / preload HMR)
|
||||
- `pnpm run start` - Starts the app in production preview mode
|
||||
- `pnpm run build` - Builds the app for desktop
|
||||
- `pnpm run build:electron` - Build the electron app (main, preload, and renderer)
|
||||
- `pnpm run build:remote` - Build the remote app (remote)
|
||||
- `pnpm run build:web` - Build the standalone web app (renderer)
|
||||
- `pnpm run package` - Package the project
|
||||
- `pnpm run package:dev` - Package the project for development
|
||||
- `pnpm run package:linux` - Package the project for Linux
|
||||
- `pnpm run package:mac` - Package the project for Mac
|
||||
- `pnpm run package:win` - Package the project for Windows
|
||||
- `pnpm run publish:linux` - Publish the project for Linux
|
||||
- `pnpm run publish:linux-arm64` - Publish the project for Linux ARM64
|
||||
- `pnpm run publish:mac` - Publish the project for Mac
|
||||
- `pnpm run publish:win` - Publish the project for Windows
|
||||
- `pnpm run typecheck` - Type check the project
|
||||
- `pnpm run typecheck:node` - Type check the project with tsconfig.node.json
|
||||
- `pnpm run typecheck:web` - Type check the project with tsconfig.web.json
|
||||
- `pnpm run lint` - Lint the project
|
||||
- `pnpm run lint:fix` - Lint the project and fix linting errors
|
||||
- `pnpm run i18next` - Generate i18n files
|
||||
|
||||
## Translation
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
provider: generic
|
||||
url: https://example.com/auto-updates
|
||||
updaterCacheDirName: feishin-updater
|
||||
@@ -0,0 +1,75 @@
|
||||
appId: org.jeffvli.feishin
|
||||
productName: Feishin
|
||||
artifactName: ${productName}-${version}-${os}-${arch}.${ext}
|
||||
electronVersion: 35.1.5
|
||||
directories:
|
||||
buildResources: assets
|
||||
files:
|
||||
- 'out/**/*'
|
||||
- 'package.json'
|
||||
extraResources:
|
||||
- assets/**
|
||||
asarUnpack:
|
||||
- resources/**
|
||||
win:
|
||||
target:
|
||||
- zip
|
||||
- nsis
|
||||
icon: assets/icons/icon.png
|
||||
nsis:
|
||||
shortcutName: ${productName}
|
||||
uninstallDisplayName: ${productName}
|
||||
createDesktopShortcut: always
|
||||
mac:
|
||||
target:
|
||||
target: default
|
||||
arch:
|
||||
- arm64
|
||||
- x64
|
||||
icon: assets/icons/icon.icns
|
||||
type: distribution
|
||||
hardenedRuntime: true
|
||||
entitlements: assets/entitlements.mac.plist
|
||||
entitlementsInherit: assets/entitlements.mac.plist
|
||||
gatekeeperAssess: false
|
||||
notarize: false
|
||||
dmg:
|
||||
contents: [{ x: 130, y: 220 }, { x: 410, y: 220, type: link, path: /Applications }]
|
||||
deb:
|
||||
depends:
|
||||
- libgssapi_krb5.so.2
|
||||
- libavahi-common.so.3
|
||||
- libavahi-client.so.3
|
||||
- libkrb5.so.3
|
||||
- libkrb5support.so.0
|
||||
- libkeyutils.so.1
|
||||
- libcups.so.2
|
||||
rpm:
|
||||
depends:
|
||||
- libgssapi_krb5.so.2
|
||||
- libavahi-common.so.3
|
||||
- libavahi-client.so.3
|
||||
- libkrb5.so.3
|
||||
- libkrb5support.so.0
|
||||
- libkeyutils.so.1
|
||||
- libcups.so.2
|
||||
freebsd:
|
||||
depends:
|
||||
- libgssapi_krb5.so.2
|
||||
- libavahi-common.so.3
|
||||
- libavahi-client.so.3
|
||||
- libkrb5.so.3
|
||||
- libkrb5support.so.0
|
||||
- libkeyutils.so.1
|
||||
- libcups.so.2
|
||||
linux:
|
||||
target:
|
||||
- AppImage
|
||||
- tar.xz
|
||||
category: AudioVideo;Audio;Player
|
||||
icon: assets/icons/icon.png
|
||||
npmRebuild: false
|
||||
publish:
|
||||
provider: github
|
||||
owner: jeffvli
|
||||
repo: feishin
|
||||
@@ -0,0 +1,66 @@
|
||||
import react from '@vitejs/plugin-react';
|
||||
import { externalizeDepsPlugin, UserConfig } from 'electron-vite';
|
||||
import { resolve } from 'path';
|
||||
import conditionalImportPlugin from 'vite-plugin-conditional-import';
|
||||
import dynamicImportPlugin from 'vite-plugin-dynamic-import';
|
||||
import { ViteEjsPlugin } from 'vite-plugin-ejs';
|
||||
|
||||
const currentOSEnv = process.platform;
|
||||
|
||||
const config: UserConfig = {
|
||||
main: {
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: ['source-map-support'],
|
||||
},
|
||||
sourcemap: true,
|
||||
},
|
||||
define: {
|
||||
'import.meta.env.IS_LINUX': JSON.stringify(currentOSEnv === 'linux'),
|
||||
'import.meta.env.IS_MACOS': JSON.stringify(currentOSEnv === 'darwin'),
|
||||
'import.meta.env.IS_WIN': JSON.stringify(currentOSEnv === 'win32'),
|
||||
},
|
||||
plugins: [
|
||||
externalizeDepsPlugin(),
|
||||
dynamicImportPlugin(),
|
||||
conditionalImportPlugin({
|
||||
currentEnv: currentOSEnv,
|
||||
envs: ['win32', 'linux', 'darwin'],
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'/@/main': resolve('src/main'),
|
||||
'/@/shared': resolve('src/shared'),
|
||||
},
|
||||
},
|
||||
},
|
||||
preload: {
|
||||
plugins: [externalizeDepsPlugin()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'/@/preload': resolve('src/preload'),
|
||||
'/@/shared': resolve('src/shared'),
|
||||
},
|
||||
},
|
||||
},
|
||||
renderer: {
|
||||
css: {
|
||||
modules: {
|
||||
generateScopedName: 'fs-[name]-[local]',
|
||||
localsConvention: 'camelCase',
|
||||
},
|
||||
},
|
||||
plugins: [react(), ViteEjsPlugin({ web: false })],
|
||||
resolve: {
|
||||
alias: {
|
||||
'/@/i18n': resolve('src/i18n'),
|
||||
'/@/remote': resolve('src/remote'),
|
||||
'/@/renderer': resolve('src/renderer'),
|
||||
'/@/shared': resolve('src/shared'),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,53 @@
|
||||
import eslintConfigPrettier from '@electron-toolkit/eslint-config-prettier';
|
||||
import tseslint from '@electron-toolkit/eslint-config-ts';
|
||||
import perfectionist from 'eslint-plugin-perfectionist';
|
||||
import eslintPluginReact from 'eslint-plugin-react';
|
||||
import eslintPluginReactHooks from 'eslint-plugin-react-hooks';
|
||||
import eslintPluginReactRefresh from 'eslint-plugin-react-refresh';
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ['**/node_modules', '**/dist', '**/out'] },
|
||||
tseslint.configs.recommended,
|
||||
perfectionist.configs['recommended-natural'],
|
||||
eslintPluginReact.configs.flat.recommended,
|
||||
eslintPluginReact.configs.flat['jsx-runtime'],
|
||||
{
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
plugins: {
|
||||
'react-hooks': eslintPluginReactHooks,
|
||||
'react-refresh': eslintPluginReactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...eslintPluginReactHooks.configs.recommended.rules,
|
||||
...eslintPluginReactRefresh.configs.vite.rules,
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/no-duplicate-enum-values': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
curly: ['error', 'all'],
|
||||
indent: [
|
||||
'error',
|
||||
'tab',
|
||||
{
|
||||
offsetTernaryExpressions: true,
|
||||
SwitchCase: 1,
|
||||
},
|
||||
],
|
||||
'no-unused-vars': 'off',
|
||||
'no-use-before-define': 'off',
|
||||
quotes: ['error', 'single'],
|
||||
'react-refresh/only-export-components': 'off',
|
||||
'react/display-name': 'off',
|
||||
semi: ['error', 'always'],
|
||||
'single-attribute-per-line': 'off',
|
||||
},
|
||||
},
|
||||
eslintConfigPrettier,
|
||||
);
|
||||
+1
-1
@@ -24,4 +24,4 @@ server {
|
||||
location ${PUBLIC_PATH}/settings.js {
|
||||
alias /etc/nginx/conf.d/settings.js;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
-40780
File diff suppressed because it is too large
Load Diff
+117
-327
@@ -1,297 +1,57 @@
|
||||
{
|
||||
"name": "feishin",
|
||||
"productName": "Feishin",
|
||||
"description": "Feishin music server",
|
||||
"version": "0.12.6",
|
||||
"scripts": {
|
||||
"build": "concurrently \"npm run build:main\" \"npm run build:renderer\" \"npm run build:remote\"",
|
||||
"build:main": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts",
|
||||
"build:remote": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.remote.prod.ts",
|
||||
"build:renderer": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.prod.ts",
|
||||
"build:web": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.web.prod.ts",
|
||||
"build:docker": "docker build -t jeffvli/feishin .",
|
||||
"rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir release/app",
|
||||
"lint": "concurrently \"npm run lint:code\" \"npm run lint:styles\"",
|
||||
"lint:code": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx --fix",
|
||||
"lint:styles": "npx stylelint **/*.tsx --fix",
|
||||
"package": "node --import tsx ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never",
|
||||
"package:pr": "node --import tsx ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never --win --mac --linux",
|
||||
"package:pr:macos": "node --import tsx ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never --mac",
|
||||
"package:pr:windows": "node --import tsx ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never --win",
|
||||
"package:pr:linux": "node --import tsx ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never --linux",
|
||||
"package:dev": "node --import tsx ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never --dir",
|
||||
"postinstall": "node --import tsx .erb/scripts/check-native-dep.js && electron-builder install-app-deps && cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts",
|
||||
"start": "node --import tsx ./.erb/scripts/check-port-in-use.js && npm run start:renderer",
|
||||
"start:main": "cross-env NODE_ENV=development NODE_OPTIONS=\"--import tsx\" electron -r ts-node/register/transpile-only ./src/main/main.ts",
|
||||
"start:preload": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.preload.dev.ts",
|
||||
"start:remote": "cross-env NODE_ENV=developemnt TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.remote.dev.ts",
|
||||
"start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts",
|
||||
"start:web": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.web.ts",
|
||||
"test": "jest",
|
||||
"prepare": "husky install",
|
||||
"i18next": "i18next -c src/i18n/i18next-parser.config.js",
|
||||
"prod:buildserver": "pwsh -c \"./scripts/server-build.ps1\"",
|
||||
"prod:publishserver": "pwsh -c \"./scripts/server-publish.ps1\""
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx}": [
|
||||
"cross-env NODE_ENV=development eslint --cache"
|
||||
],
|
||||
"*.json,.{eslintrc,prettierrc}": [
|
||||
"prettier --ignore-path .eslintignore --parser json --write"
|
||||
],
|
||||
"*.{css,scss}": [
|
||||
"prettier --ignore-path .eslintignore --single-quote --write"
|
||||
],
|
||||
"*.{html,md,yml}": [
|
||||
"prettier --ignore-path .eslintignore --single-quote --write"
|
||||
]
|
||||
},
|
||||
"build": {
|
||||
"productName": "Feishin",
|
||||
"appId": "org.jeffvli.feishin",
|
||||
"artifactName": "${productName}-${version}-${os}-${arch}.${ext}",
|
||||
"asar": true,
|
||||
"asarUnpack": "**\\*.{node,dll}",
|
||||
"files": [
|
||||
"dist",
|
||||
"node_modules",
|
||||
"package.json"
|
||||
],
|
||||
"afterSign": ".erb/scripts/notarize.js",
|
||||
"electronVersion": "36.1.0",
|
||||
"mac": {
|
||||
"target": {
|
||||
"target": "default",
|
||||
"arch": [
|
||||
"arm64",
|
||||
"x64"
|
||||
]
|
||||
},
|
||||
"icon": "assets/icons/icon.icns",
|
||||
"type": "distribution",
|
||||
"hardenedRuntime": true,
|
||||
"entitlements": "assets/entitlements.mac.plist",
|
||||
"entitlementsInherit": "assets/entitlements.mac.plist",
|
||||
"gatekeeperAssess": false
|
||||
},
|
||||
"dmg": {
|
||||
"contents": [
|
||||
{
|
||||
"x": 130,
|
||||
"y": 220
|
||||
},
|
||||
{
|
||||
"x": 410,
|
||||
"y": 220,
|
||||
"type": "link",
|
||||
"path": "/Applications"
|
||||
}
|
||||
]
|
||||
},
|
||||
"win": {
|
||||
"target": [
|
||||
"nsis",
|
||||
"zip"
|
||||
],
|
||||
"icon": "assets/icons/icon.ico"
|
||||
},
|
||||
"deb": {
|
||||
"depends": [
|
||||
"libgssapi_krb5.so.2",
|
||||
"libavahi-common.so.3",
|
||||
"libavahi-client.so.3",
|
||||
"libkrb5.so.3",
|
||||
"libkrb5support.so.0",
|
||||
"libkeyutils.so.1",
|
||||
"libcups.so.2"
|
||||
]
|
||||
},
|
||||
"rpm": {
|
||||
"depends": [
|
||||
"libgssapi_krb5.so.2",
|
||||
"libavahi-common.so.3",
|
||||
"libavahi-client.so.3",
|
||||
"libkrb5.so.3",
|
||||
"libkrb5support.so.0",
|
||||
"libkeyutils.so.1",
|
||||
"libcups.so.2"
|
||||
]
|
||||
},
|
||||
"freebsd": {
|
||||
"depends": [
|
||||
"libgssapi_krb5.so.2",
|
||||
"libavahi-common.so.3",
|
||||
"libavahi-client.so.3",
|
||||
"libkrb5.so.3",
|
||||
"libkrb5support.so.0",
|
||||
"libkeyutils.so.1",
|
||||
"libcups.so.2"
|
||||
]
|
||||
},
|
||||
"linux": {
|
||||
"target": [
|
||||
"AppImage",
|
||||
"tar.xz"
|
||||
],
|
||||
"icon": "assets/icons/icon.png",
|
||||
"category": "AudioVideo;Audio;Player"
|
||||
},
|
||||
"directories": {
|
||||
"app": "release/app",
|
||||
"buildResources": "assets",
|
||||
"output": "release/build"
|
||||
},
|
||||
"extraResources": [
|
||||
"./assets/**"
|
||||
],
|
||||
"publish": {
|
||||
"provider": "github",
|
||||
"owner": "jeffvli",
|
||||
"repo": "feishin"
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/jeffvli/feishin.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "jeffvli",
|
||||
"url": "https://github.com/jeffvli/"
|
||||
},
|
||||
"contributors": [],
|
||||
"license": "GPL-3.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/jeffvli/feishin/issues"
|
||||
},
|
||||
"version": "0.17.0",
|
||||
"description": "A modern self-hosted music player.",
|
||||
"keywords": [
|
||||
"subsonic",
|
||||
"navidrome",
|
||||
"airsonic",
|
||||
"jellyfin",
|
||||
"react",
|
||||
"electron"
|
||||
],
|
||||
"homepage": "https://github.com/jeffvli/feishin",
|
||||
"jest": {
|
||||
"testURL": "http://localhost/",
|
||||
"testEnvironment": "jsdom",
|
||||
"transform": {
|
||||
"\\.(ts|tsx|js|jsx)$": "ts-jest"
|
||||
},
|
||||
"moduleNameMapper": {
|
||||
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/.erb/mocks/fileMock.js",
|
||||
"\\.(css|less|sass|scss)$": "identity-obj-proxy"
|
||||
},
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"jsx",
|
||||
"ts",
|
||||
"tsx",
|
||||
"json"
|
||||
],
|
||||
"moduleDirectories": [
|
||||
"node_modules",
|
||||
"release/app/node_modules"
|
||||
],
|
||||
"testPathIgnorePatterns": [
|
||||
"release/app/dist"
|
||||
],
|
||||
"setupFiles": [
|
||||
"./.erb/scripts/check-build-exists.ts"
|
||||
]
|
||||
"bugs": {
|
||||
"url": "https://github.com/jeffvli/feishin/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron/rebuild": "^3.6.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "0.5.5",
|
||||
"@stylelint/postcss-css-in-js": "^0.38.0",
|
||||
"@teamsupercell/typings-for-css-modules-loader": "^2.5.1",
|
||||
"@testing-library/jest-dom": "^5.16.4",
|
||||
"@testing-library/react": "^13.0.0",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/electron-localshortcut": "^3.1.0",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/lodash": "^4.14.188",
|
||||
"@types/md5": "^2.3.2",
|
||||
"@types/node": "^17.0.23",
|
||||
"@types/react": "^18.0.25",
|
||||
"@types/react-dom": "^18.0.8",
|
||||
"@types/react-test-renderer": "^17.0.1",
|
||||
"@types/react-virtualized-auto-sizer": "^1.0.1",
|
||||
"@types/react-window": "^1.8.5",
|
||||
"@types/react-window-infinite-loader": "^1.0.6",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"@types/terser-webpack-plugin": "^5.0.4",
|
||||
"@types/webpack-bundle-analyzer": "^4.4.1",
|
||||
"@types/webpack-env": "^1.16.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"browserslist-config-erb": "^0.0.3",
|
||||
"chalk": "^4.1.2",
|
||||
"concurrently": "^7.1.0",
|
||||
"core-js": "^3.21.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^6.7.1",
|
||||
"css-minimizer-webpack-plugin": "^3.4.1",
|
||||
"detect-port": "^1.3.0",
|
||||
"electron": "^36.1.0",
|
||||
"electron-builder": "^24.13.3",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"electron-notarize": "^1.2.1",
|
||||
"electronmon": "^2.0.2",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-config-erb": "^4.0.3",
|
||||
"eslint-import-resolver-typescript": "^2.7.1",
|
||||
"eslint-import-resolver-webpack": "^0.13.2",
|
||||
"eslint-plugin-compat": "^4.2.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-jest": "^26.1.3",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-promise": "^6.0.0",
|
||||
"eslint-plugin-react": "^7.29.4",
|
||||
"eslint-plugin-react-hooks": "^4.4.0",
|
||||
"eslint-plugin-sort-keys-fix": "^1.1.2",
|
||||
"eslint-plugin-typescript-sort-keys": "^2.1.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"husky": "^7.0.4",
|
||||
"i18next-parser": "^9.0.2",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^27.5.1",
|
||||
"lint-staged": "^12.3.7",
|
||||
"mini-css-extract-plugin": "^2.6.0",
|
||||
"postcss-scss": "^4.0.4",
|
||||
"postcss-styled-syntax": "^0.5.0",
|
||||
"postcss-syntax": "^0.36.2",
|
||||
"prettier": "^3.3.3",
|
||||
"react-refresh": "^0.12.0",
|
||||
"react-refresh-typescript": "^2.0.4",
|
||||
"react-test-renderer": "^18.0.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"sass": "^1.49.11",
|
||||
"sass-loader": "^12.6.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"stylelint": "^15.10.3",
|
||||
"stylelint-config-css-modules": "^4.3.0",
|
||||
"stylelint-config-recess-order": "^4.3.0",
|
||||
"stylelint-config-standard": "^34.0.0",
|
||||
"stylelint-config-standard-scss": "^4.0.0",
|
||||
"stylelint-config-styled-components": "^0.1.1",
|
||||
"terser-webpack-plugin": "^5.3.1",
|
||||
"ts-jest": "^27.1.4",
|
||||
"ts-loader": "^9.2.8",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsconfig-paths-webpack-plugin": "^4.0.0",
|
||||
"tsx": "^4.16.2",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-styled-components": "^3.0.0",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.94.0",
|
||||
"webpack-bundle-analyzer": "^4.5.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.8.0",
|
||||
"webpack-merge": "^5.8.0"
|
||||
"license": "GPL-3.0",
|
||||
"author": {
|
||||
"name": "jeffvli",
|
||||
"url": "https://github.com/jeffvli/"
|
||||
},
|
||||
"main": "./out/main/index.js",
|
||||
"scripts": {
|
||||
"build": "pnpm run typecheck && pnpm run build:electron && pnpm run build:remote",
|
||||
"build:electron": "electron-vite build",
|
||||
"build:remote": "vite build --config remote.vite.config.ts",
|
||||
"build:web": "vite build --config web.vite.config.ts",
|
||||
"dev": "electron-vite dev",
|
||||
"dev:remote": "vite dev --config remote.vite.config.ts",
|
||||
"dev:watch": "electron-vite dev --watch",
|
||||
"i18next": "i18next -c src/i18n/i18next-parser.config.js",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"lint": "pnpm run lint-code && pnpm run lint-styles",
|
||||
"lint-code": "eslint --cache .",
|
||||
"lint-code:fix": "eslint --cache --fix .",
|
||||
"lint-styles": "stylelint 'src/**/*.{css,scss}'",
|
||||
"lint-styles:fix": "stylelint 'src/**/*.{css,scss}' --fix",
|
||||
"lint:fix": "pnpm run lint-code:fix && pnpm run lint-styles:fix",
|
||||
"package": "pnpm run build && electron-builder",
|
||||
"package:dev": "pnpm run build && electron-builder --dir",
|
||||
"package:linux": "pnpm run build && electron-builder --linux",
|
||||
"package:linux-arm64:pr": "pnpm run build && electron-builder --linux --arm64 --publish never",
|
||||
"package:linux:pr": "pnpm run build && electron-builder --linux --publish never",
|
||||
"package:mac": "pnpm run build && electron-builder --mac",
|
||||
"package:mac:pr": "pnpm run build && electron-builder --mac --publish never",
|
||||
"package:win": "pnpm run build && electron-builder --win",
|
||||
"package:win:pr": "pnpm run build && electron-builder --win --publish never",
|
||||
"publish:linux": "electron-builder --publish always --linux",
|
||||
"publish:linux-arm64": "electron-builder --publish always --linux --arm64",
|
||||
"publish:mac": "electron-builder --publish always --mac",
|
||||
"publish:win": "electron-builder --publish always --win",
|
||||
"start": "electron-vite preview",
|
||||
"typecheck": "pnpm run typecheck:node && pnpm run typecheck:web",
|
||||
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
|
||||
"typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ag-grid-community/client-side-row-model": "^28.2.1",
|
||||
@@ -299,14 +59,18 @@
|
||||
"@ag-grid-community/infinite-row-model": "^28.2.1",
|
||||
"@ag-grid-community/react": "^28.2.1",
|
||||
"@ag-grid-community/styles": "^28.2.1",
|
||||
"@emotion/react": "^11.10.4",
|
||||
"@mantine/core": "^6.0.17",
|
||||
"@mantine/dates": "^6.0.17",
|
||||
"@mantine/form": "^6.0.17",
|
||||
"@mantine/hooks": "^6.0.17",
|
||||
"@mantine/modals": "^6.0.17",
|
||||
"@mantine/notifications": "^6.0.17",
|
||||
"@mantine/utils": "^6.0.17",
|
||||
"@atlaskit/pragmatic-drag-and-drop": "1.4.0",
|
||||
"@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^2.1.0",
|
||||
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
|
||||
"@electron-toolkit/preload": "^3.0.1",
|
||||
"@electron-toolkit/utils": "^4.0.0",
|
||||
"@mantine/colors-generator": "^8.1.1",
|
||||
"@mantine/core": "^8.1.1",
|
||||
"@mantine/dates": "^8.1.1",
|
||||
"@mantine/form": "^8.1.1",
|
||||
"@mantine/hooks": "^8.1.1",
|
||||
"@mantine/modals": "^8.1.1",
|
||||
"@mantine/notifications": "^8.1.1",
|
||||
"@tanstack/react-query": "^4.32.1",
|
||||
"@tanstack/react-query-devtools": "^4.32.1",
|
||||
"@tanstack/react-query-persist-client": "^4.32.1",
|
||||
@@ -315,6 +79,7 @@
|
||||
"audiomotion-analyzer": "^4.5.0",
|
||||
"auto-text-size": "^0.2.3",
|
||||
"axios": "^1.6.0",
|
||||
"cheerio": "^1.0.0",
|
||||
"clsx": "^2.0.0",
|
||||
"cmdk": "^0.2.0",
|
||||
"dayjs": "^1.11.6",
|
||||
@@ -323,12 +88,10 @@
|
||||
"electron-localshortcut": "^3.2.1",
|
||||
"electron-log": "^5.1.1",
|
||||
"electron-store": "^8.1.0",
|
||||
"electron-updater": "^6.3.1",
|
||||
"electron-updater": "^6.3.9",
|
||||
"fast-average-color": "^9.3.0",
|
||||
"format-duration": "^2.0.0",
|
||||
"framer-motion": "^11.0.0",
|
||||
"fuse.js": "^6.6.2",
|
||||
"history": "^5.3.0",
|
||||
"i18next": "^21.10.0",
|
||||
"idb-keyval": "^6.2.1",
|
||||
"immer": "^9.0.21",
|
||||
@@ -336,53 +99,80 @@
|
||||
"lodash": "^4.17.21",
|
||||
"md5": "^2.3.0",
|
||||
"memoize-one": "^6.0.0",
|
||||
"motion": "^12.18.1",
|
||||
"mpris-service": "^2.1.2",
|
||||
"nanoid": "^3.3.3",
|
||||
"net": "^1.0.2",
|
||||
"node-mpv": "github:jeffvli/Node-MPV#32b4d64395289ad710c41d481d2707a7acfc228f",
|
||||
"overlayscrollbars": "^2.2.1",
|
||||
"overlayscrollbars-react": "^0.5.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"overlayscrollbars": "^2.11.1",
|
||||
"overlayscrollbars-react": "^0.5.6",
|
||||
"qs": "^6.14.0",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-error-boundary": "^3.1.4",
|
||||
"react-i18next": "^11.18.6",
|
||||
"react-icons": "^4.10.1",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-image": "^4.1.0",
|
||||
"react-loading-skeleton": "^3.5.0",
|
||||
"react-player": "^2.11.0",
|
||||
"react-router": "^6.16.0",
|
||||
"react-router-dom": "^6.16.0",
|
||||
"react-simple-img": "^3.0.0",
|
||||
"react-virtualized-auto-sizer": "^1.0.17",
|
||||
"react-window": "^1.8.9",
|
||||
"react-window-infinite-loader": "^1.0.9",
|
||||
"semver": "^7.5.4",
|
||||
"styled-components": "^6.0.8",
|
||||
"swiper": "^9.3.1",
|
||||
"use-sync-external-store": "^1.5.0",
|
||||
"ws": "^8.18.2",
|
||||
"zod": "^3.22.3",
|
||||
"zustand": "^4.3.9"
|
||||
"zustand": "^5.0.5"
|
||||
},
|
||||
"resolutions": {
|
||||
"styled-components": "^6",
|
||||
"entities": "2.2.0"
|
||||
"devDependencies": {
|
||||
"@electron-toolkit/eslint-config-prettier": "^3.0.0",
|
||||
"@electron-toolkit/eslint-config-ts": "^3.0.0",
|
||||
"@electron-toolkit/tsconfig": "^1.0.1",
|
||||
"@types/electron-localshortcut": "^3.1.0",
|
||||
"@types/lodash": "^4.17.18",
|
||||
"@types/md5": "^2.3.5",
|
||||
"@types/node": "^22.15.32",
|
||||
"@types/react": "^18.3.23",
|
||||
"@types/react-dom": "^18.3.7",
|
||||
"@types/react-window": "^1.8.5",
|
||||
"@types/react-window-infinite-loader": "^1.0.6",
|
||||
"@types/source-map-support": "^0.5.10",
|
||||
"@types/ws": "^8.18.1",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"concurrently": "^7.1.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"electron": "^35.1.5",
|
||||
"electron-builder": "^26.0.12",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"electron-vite": "^3.1.0",
|
||||
"eslint": "^9.24.0",
|
||||
"eslint-plugin-perfectionist": "^4.13.0",
|
||||
"eslint-plugin-prettier": "^5.4.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"i18next-parser": "^9.0.2",
|
||||
"postcss-preset-mantine": "^1.17.0",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-packagejson": "^2.5.14",
|
||||
"sass-embedded": "^1.89.0",
|
||||
"stylelint": "^16.14.1",
|
||||
"stylelint-config-css-modules": "^4.4.0",
|
||||
"stylelint-config-recess-order": "^7.1.0",
|
||||
"stylelint-config-standard": "^38.0.0",
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^6.3.5",
|
||||
"vite-plugin-conditional-import": "^0.1.7",
|
||||
"vite-plugin-dynamic-import": "^1.6.0",
|
||||
"vite-plugin-ejs": "^1.7.0"
|
||||
},
|
||||
"overrides": {
|
||||
"entities": "2.2.0"
|
||||
},
|
||||
"devEngines": {
|
||||
"runtime": {
|
||||
"name": "node",
|
||||
"version": ">=18.x",
|
||||
"onFail": "error"
|
||||
},
|
||||
"packageManager": {
|
||||
"name": "npm",
|
||||
"version": ">=7.x",
|
||||
"onFail": "error"
|
||||
}
|
||||
},
|
||||
"browserslist": [],
|
||||
"electronmon": {
|
||||
"patterns": [
|
||||
"!server",
|
||||
"!src/renderer"
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"electron",
|
||||
"esbuild"
|
||||
]
|
||||
}
|
||||
},
|
||||
"productName": "feishin"
|
||||
}
|
||||
|
||||
Generated
+9656
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'postcss-preset-mantine': {},
|
||||
},
|
||||
};
|
||||
Generated
-2351
File diff suppressed because it is too large
Load Diff
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"name": "feishin",
|
||||
"version": "0.12.6",
|
||||
"description": "",
|
||||
"main": "./dist/main/main.js",
|
||||
"author": {
|
||||
"name": "jeffvli",
|
||||
"url": "https://github.com/jeffvli/"
|
||||
},
|
||||
"scripts": {
|
||||
"electron-rebuild": "node -r ts-node/register ../../.erb/scripts/electron-rebuild.js",
|
||||
"link-modules": "node -r ts-node/register ../../.erb/scripts/link-modules.ts",
|
||||
"postinstall": "npm run electron-rebuild && npm run link-modules"
|
||||
},
|
||||
"dependencies": {
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
"mpris-service": "^2.1.2",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "36.1.0"
|
||||
},
|
||||
"license": "GPL-3.0"
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import react from '@vitejs/plugin-react';
|
||||
import path from 'path';
|
||||
import { defineConfig, normalizePath } from 'vite';
|
||||
import { ViteEjsPlugin } from 'vite-plugin-ejs';
|
||||
|
||||
import { version } from './package.json';
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
emptyOutDir: true,
|
||||
outDir: path.resolve(__dirname, './out/remote'),
|
||||
rollupOptions: {
|
||||
input: {
|
||||
favicon: normalizePath(path.resolve(__dirname, './assets/icons/favicon.ico')),
|
||||
index: normalizePath(path.resolve(__dirname, './src/remote/index.html')),
|
||||
manifest: normalizePath(path.resolve(__dirname, './src/remote/manifest.json')),
|
||||
remote: normalizePath(path.resolve(__dirname, './src/remote/index.tsx')),
|
||||
worker: normalizePath(path.resolve(__dirname, './src/remote/service-worker.ts')),
|
||||
},
|
||||
output: {
|
||||
assetFileNames: '[name].[ext]',
|
||||
chunkFileNames: '[name].js',
|
||||
entryFileNames: '[name].js',
|
||||
},
|
||||
},
|
||||
sourcemap: true,
|
||||
},
|
||||
css: {
|
||||
modules: {
|
||||
generateScopedName: 'fs-[name]-[local]',
|
||||
localsConvention: 'camelCase',
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
react(),
|
||||
ViteEjsPlugin({
|
||||
prod: process.env.NODE_ENV === 'production',
|
||||
root: normalizePath(path.resolve(__dirname, './src/remote')),
|
||||
version,
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'/@/i18n': path.resolve(__dirname, './src/i18n'),
|
||||
'/@/remote': path.resolve(__dirname, './src/remote'),
|
||||
'/@/renderer': path.resolve(__dirname, './src/renderer'),
|
||||
'/@/shared': path.resolve(__dirname, './src/shared'),
|
||||
},
|
||||
},
|
||||
root: path.resolve(__dirname, './src/remote'),
|
||||
});
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
@@ -1,9 +0,0 @@
|
||||
import '@testing-library/jest-dom';
|
||||
import { render } from '@testing-library/react';
|
||||
import { App } from '../renderer/app';
|
||||
|
||||
describe('App', () => {
|
||||
it('should render', () => {
|
||||
expect(render(<App />)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+33
-32
@@ -1,52 +1,53 @@
|
||||
import { PostProcessorModule, TOptions, StringMap } from 'i18next';
|
||||
import { PostProcessorModule, StringMap, TOptions } from 'i18next';
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
import cs from './locales/cs.json';
|
||||
import de from './locales/de.json';
|
||||
import en from './locales/en.json';
|
||||
import es from './locales/es.json';
|
||||
import fa from './locales/fa.json';
|
||||
import fi from './locales/fi.json';
|
||||
import fr from './locales/fr.json';
|
||||
import ja from './locales/ja.json';
|
||||
import pl from './locales/pl.json';
|
||||
import zhHans from './locales/zh-Hans.json';
|
||||
import de from './locales/de.json';
|
||||
import hu from './locales/hu.json';
|
||||
import id from './locales/id.json';
|
||||
import it from './locales/it.json';
|
||||
import ru from './locales/ru.json';
|
||||
import ptBr from './locales/pt-BR.json';
|
||||
import sr from './locales/sr.json';
|
||||
import sv from './locales/sv.json';
|
||||
import cs from './locales/cs.json';
|
||||
import ja from './locales/ja.json';
|
||||
import ko from './locales/ko.json';
|
||||
import nbNO from './locales/nb-NO.json';
|
||||
import nl from './locales/nl.json';
|
||||
import zhHant from './locales/zh-Hant.json';
|
||||
import fa from './locales/fa.json';
|
||||
import ko from './locales/ko.json';
|
||||
import pl from './locales/pl.json';
|
||||
import ptBr from './locales/pt-BR.json';
|
||||
import ru from './locales/ru.json';
|
||||
import sr from './locales/sr.json';
|
||||
import sv from './locales/sv.json';
|
||||
import ta from './locales/ta.json';
|
||||
import id from './locales/id.json';
|
||||
import fi from './locales/fi.json';
|
||||
import hu from './locales/hu.json';
|
||||
import zhHans from './locales/zh-Hans.json';
|
||||
import zhHant from './locales/zh-Hant.json';
|
||||
|
||||
const resources = {
|
||||
cs: { translation: cs },
|
||||
de: { translation: de },
|
||||
en: { translation: en },
|
||||
es: { translation: es },
|
||||
de: { translation: de },
|
||||
it: { translation: it },
|
||||
ru: { translation: ru },
|
||||
'pt-BR': { translation: ptBr },
|
||||
fa: { translation: fa },
|
||||
fi: { translation: fi },
|
||||
fr: { translation: fr },
|
||||
hu: { translation: hu },
|
||||
id: { translation: id },
|
||||
it: { translation: it },
|
||||
ja: { translation: ja },
|
||||
ko: { translation: ko },
|
||||
'nb-NO': { translation: nbNO },
|
||||
nl: { translation: nl },
|
||||
pl: { translation: pl },
|
||||
'zh-Hans': { translation: zhHans },
|
||||
'zh-Hant': { translation: zhHant },
|
||||
'pt-BR': { translation: ptBr },
|
||||
ru: { translation: ru },
|
||||
sr: { translation: sr },
|
||||
sv: { translation: sv },
|
||||
cs: { translation: cs },
|
||||
nl: { translation: nl },
|
||||
'nb-NO': { translation: nbNO },
|
||||
ta: { translation: ta },
|
||||
id: { translation: id },
|
||||
fi: { translation: fi },
|
||||
hu: { translation: hu },
|
||||
'zh-Hans': { translation: zhHans },
|
||||
'zh-Hant': { translation: zhHant },
|
||||
};
|
||||
|
||||
export const languages = [
|
||||
@@ -141,35 +142,34 @@ export const languages = [
|
||||
];
|
||||
|
||||
const lowerCasePostProcessor: PostProcessorModule = {
|
||||
type: 'postProcessor',
|
||||
name: 'lowerCase',
|
||||
process: (value: string) => {
|
||||
return value.toLocaleLowerCase();
|
||||
},
|
||||
type: 'postProcessor',
|
||||
};
|
||||
|
||||
const upperCasePostProcessor: PostProcessorModule = {
|
||||
type: 'postProcessor',
|
||||
name: 'upperCase',
|
||||
process: (value: string) => {
|
||||
return value.toLocaleUpperCase();
|
||||
},
|
||||
type: 'postProcessor',
|
||||
};
|
||||
|
||||
const titleCasePostProcessor: PostProcessorModule = {
|
||||
type: 'postProcessor',
|
||||
name: 'titleCase',
|
||||
process: (value: string) => {
|
||||
return value.replace(/\S\S*/g, (txt) => {
|
||||
return txt.charAt(0).toLocaleUpperCase() + txt.slice(1).toLowerCase();
|
||||
});
|
||||
},
|
||||
type: 'postProcessor',
|
||||
};
|
||||
|
||||
const ignoreSentenceCaseLanguages = ['de'];
|
||||
|
||||
const sentenceCasePostProcessor: PostProcessorModule = {
|
||||
type: 'postProcessor',
|
||||
name: 'sentenceCase',
|
||||
process: (value: string, _key: string, _options: TOptions<StringMap>, translator: any) => {
|
||||
const sentences = value.split('. ');
|
||||
@@ -185,6 +185,7 @@ const sentenceCasePostProcessor: PostProcessorModule = {
|
||||
})
|
||||
.join('. ');
|
||||
},
|
||||
type: 'postProcessor',
|
||||
};
|
||||
i18n.use(lowerCasePostProcessor)
|
||||
.use(upperCasePostProcessor)
|
||||
|
||||
@@ -5,7 +5,7 @@ module.exports = {
|
||||
createOldCatalogs: true,
|
||||
customValueTemplate: null,
|
||||
defaultNamespace: 'translation',
|
||||
defaultValue: function (locale, namespace, key, value) {
|
||||
defaultValue: function (locale, namespace, key) {
|
||||
return key;
|
||||
},
|
||||
failOnUpdate: false,
|
||||
|
||||
+34
-11
@@ -124,7 +124,7 @@
|
||||
"hotkey_toggleShuffle": "přepnutí náhodného přehrávání",
|
||||
"theme": "motiv",
|
||||
"playbackStyle_description": "nastavení způsobu přehrávání pro přehrávač zvuku",
|
||||
"discordRichPresence_description": "povolit stav přehrávání v {{discord}} rich presence. Klíče obrázků jsou: {{icon}}, {{playing}}, {{paused}} ",
|
||||
"discordRichPresence_description": "povolit stav přehrávání v {{discord}} rich presence. Klíče obrázků jsou: {{icon}}, {{playing}}, {{paused}}",
|
||||
"mpvExecutablePath": "cesta ke spustitelnému souboru mpv",
|
||||
"audioDevice": "zvukové zařízení",
|
||||
"hotkey_rate2": "hodnocení 2 hvězdami",
|
||||
@@ -171,7 +171,7 @@
|
||||
"hotkey_zoomOut": "oddálení",
|
||||
"hotkey_unfavoriteCurrentSong": "zrušení oblíbení u $t(common.currentSong)",
|
||||
"hotkey_rate0": "vymazání hodnocení",
|
||||
"discordApplicationId": "aplikační id pro {{discord}}",
|
||||
"discordApplicationId": "id aplikace pro {{discord}}",
|
||||
"applicationHotkeys_description": "nastavení klávesových zkratek aplikace. přepněte pole pro nastavení jako globální zkratku (pouze na počítači)",
|
||||
"floatingQueueArea_description": "zobrazit ikonu přejetí myší na pravé straně obrazovky pro zobrazení fronty",
|
||||
"hotkey_volumeMute": "ztlumení",
|
||||
@@ -257,7 +257,21 @@
|
||||
"translationTargetLanguage": "cílový jazyk překladu",
|
||||
"translationTargetLanguage_description": "cílový jazyk pro překlad",
|
||||
"lastfmApiKey": "klíč API {{lastfm}}",
|
||||
"lastfmApiKey_description": "klíč API pro {{lastfm}}. vyžadováno pro obaly alb"
|
||||
"lastfmApiKey_description": "klíč API pro {{lastfm}}. vyžadováno pro obaly alb",
|
||||
"discordServeImage": "načítat obrázky {{discord}} ze serveru",
|
||||
"discordServeImage_description": "sdílet obaly alb pro {{discord}} rich presence ze samotného serveru, dostupné pouze pro jellyfin a navidrome",
|
||||
"lastfm": "zobrazit odkazy na last.fm",
|
||||
"lastfm_description": "na stránkách umělců a alb zobrazit odkazy na last.fm",
|
||||
"musicbrainz": "zobrazit odkazy na musicbrainz",
|
||||
"musicbrainz_description": "na stránkách umělců a alb, kde existuje mbid, zobrazit odkazy na musicbrainz",
|
||||
"neteaseTranslation": "Povolit překlady NetEase",
|
||||
"neteaseTranslation_description": "Pokud je povoleno, načte a zobrazí přeložené texty ze služby NetEase, pokud jsou dostupné.",
|
||||
"preferLocalLyrics": "preferovat místní texty",
|
||||
"preferLocalLyrics_description": "preferovat místní texty před vzdálenými, pokud jsou dostupné",
|
||||
"discordPausedStatus": "zobrazit rich presence při pozastavení",
|
||||
"discordPausedStatus_description": "pokud je povoleno, bude při pozastavení přehrávače zobrazen stav",
|
||||
"preservePitch": "zachovat výšku",
|
||||
"preservePitch_description": "zachová výšku při úpravě rychlosti přehrávání"
|
||||
},
|
||||
"action": {
|
||||
"editPlaylist": "upravit $t(entity.playlist_one)",
|
||||
@@ -365,7 +379,7 @@
|
||||
"size": "velikost",
|
||||
"biography": "biografie",
|
||||
"note": "poznámka",
|
||||
"albumGain": "zisk (gain) alba",
|
||||
"albumGain": "gain alba",
|
||||
"albumPeak": "vrchol alba",
|
||||
"close": "zavřít",
|
||||
"mbid": "ID MusicBrainz",
|
||||
@@ -375,14 +389,20 @@
|
||||
"codec": "kodek",
|
||||
"trackPeak": "vrchol skladby",
|
||||
"preview": "náhled",
|
||||
"translation": "překlad"
|
||||
"translation": "překlad",
|
||||
"additionalParticipants": "další přispívající",
|
||||
"tags": "štítky",
|
||||
"viewReleaseNotes": "zobrazit seznam změn",
|
||||
"newVersion": "byla nainstalována nová verze ({{version}})"
|
||||
},
|
||||
"table": {
|
||||
"config": {
|
||||
"view": {
|
||||
"card": "karta",
|
||||
"table": "tabulka",
|
||||
"poster": "plakát"
|
||||
"poster": "plakát",
|
||||
"list": "seznam",
|
||||
"grid": "mřížka"
|
||||
},
|
||||
"general": {
|
||||
"displayType": "typ zobrazení",
|
||||
@@ -474,7 +494,8 @@
|
||||
"loginRateError": "příliš mnoho pokusů o přihlášení, zkuste to znovu za pár vteřin",
|
||||
"badAlbum": "tuto stránku vidíte, protože tato skladba není součástí alba. tento problém může nastat, pokud máte skladbu na nejvyšší úrovni vaší složky s hudbou. jellyfin seskupuje skladby pouze, pokud se nacházejí ve složce.",
|
||||
"networkError": "vyskytla se chyba sítě",
|
||||
"openError": "nepodařilo se otevřít soubor"
|
||||
"openError": "nepodařilo se otevřít soubor",
|
||||
"badValue": "neplatná možnost „{{value}}“. tato možnost již neexistuje"
|
||||
},
|
||||
"filter": {
|
||||
"mostPlayed": "nejvíce přehráváno",
|
||||
@@ -533,7 +554,8 @@
|
||||
"home": "$t(common.home)",
|
||||
"artists": "$t(entity.artist_other)",
|
||||
"albumArtists": "$t(entity.albumArtist_other)",
|
||||
"shared": "$t(entity.playlist_other) sdíleny"
|
||||
"shared": "$t(entity.playlist_other) sdíleny",
|
||||
"myLibrary": "moje knihovna"
|
||||
},
|
||||
"fullscreenPlayer": {
|
||||
"config": {
|
||||
@@ -709,7 +731,8 @@
|
||||
},
|
||||
"queryEditor": {
|
||||
"input_optionMatchAll": "shoda všeho",
|
||||
"input_optionMatchAny": "shoda libovolného"
|
||||
"input_optionMatchAny": "shoda libovolného",
|
||||
"title": "editor dotazů"
|
||||
},
|
||||
"lyricSearch": {
|
||||
"input_name": "$t(common.name)",
|
||||
@@ -747,8 +770,8 @@
|
||||
"folderWithCount_few": "{{count}} složky",
|
||||
"folderWithCount_other": "{{count}} složek",
|
||||
"albumArtist_one": "umělec alba",
|
||||
"albumArtist_few": "umělci alba",
|
||||
"albumArtist_other": "umělců alba",
|
||||
"albumArtist_few": "umělci alb",
|
||||
"albumArtist_other": "umělci alb",
|
||||
"track_one": "skladba",
|
||||
"track_few": "skladby",
|
||||
"track_other": "skladby",
|
||||
|
||||
@@ -113,7 +113,9 @@
|
||||
"trackPeak": "Track-Spitzenpegel",
|
||||
"codec": "Codec",
|
||||
"albumPeak": "Album-Spitzenpegel",
|
||||
"albumGain": "Album-Pegelverstärkung"
|
||||
"albumGain": "Album-Pegelverstärkung",
|
||||
"tags": "tags",
|
||||
"viewReleaseNotes": "Release Notes anzeigen"
|
||||
},
|
||||
"error": {
|
||||
"remotePortWarning": "Starten Sie den Server neu, um den neuen Port anzuwenden",
|
||||
@@ -237,7 +239,8 @@
|
||||
"description": "Beschreibung",
|
||||
"setExpiration": "Ablaufdatum setzen",
|
||||
"expireInvalid": "Ablaufdatum muss in der Zukunft liegen",
|
||||
"allowDownloading": "Herunterladen zulassen"
|
||||
"allowDownloading": "Herunterladen zulassen",
|
||||
"success": "Link in die Zwischenablage kopiert (oder hier klicken um zu öffnen)"
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
@@ -429,7 +432,8 @@
|
||||
"home": "$t(common.home)",
|
||||
"artists": "$t(entity.artist_other)",
|
||||
"albumArtists": "$t(entity.albumArtist_other)",
|
||||
"shared": "$t(entity.playlist_other) geteilt"
|
||||
"shared": "$t(entity.playlist_other) geteilt",
|
||||
"myLibrary": "meine bibliothek"
|
||||
},
|
||||
"setting": {
|
||||
"playbackTab": "Wiedergabe",
|
||||
@@ -516,7 +520,7 @@
|
||||
"playSimilarSongs": "Ähnliche Lieder abspielen"
|
||||
},
|
||||
"setting": {
|
||||
"audioDevice_description": "Wählen Sie das Audiogerät aus, das für die Wiedergabe verwendet werden soll (nur Webplayer).",
|
||||
"audioDevice_description": "Wählen Sie das Audiogerät aus, das für die Wiedergabe verwendet werden soll (nur Webplayer)",
|
||||
"audioExclusiveMode": "Audio-Exklusivmodus",
|
||||
"audioDevice": "Audiogerät",
|
||||
"accentColor": "Akzentfarbe",
|
||||
@@ -670,12 +674,23 @@
|
||||
"windowBarStyle_description": "Wähle den Stil der Windows-Leiste",
|
||||
"hotkey_toggleCurrentSongFavorite": "$t(common.currentSong) zu Favoriten hinzufügen",
|
||||
"clearQueryCache_description": "\"Weiches\" Zurücksetzen. Dies wird Playlisten, Musik-Metadaten und gespeicherte Liedtexte zurücksetzen, Zugangsinformationen und zwischengespeicherte Bilder werden behalten",
|
||||
"discordRichPresence_description": "Zeige deinen Wiedergabe-Status in {{discord}} als rich presence an. Angezeigte Bilder sind: {{icon}}, {{playing}}, und {{paused}} ",
|
||||
"discordRichPresence_description": "Zeige deinen Wiedergabe-Status in {{discord}} als rich presence an. Angezeigte Bilder sind: {{icon}}, {{playing}}, und {{paused}}",
|
||||
"clearCache": "Browser-Zwischenspeicher löschen",
|
||||
"clearQueryCache": "feishins Zwischenspeicher leeren",
|
||||
"clearCache_description": "Hartes Zurücksetzen. Neben feishins Zwischenspeicher wird auch der des Browsers gelöscht (Bilder und andere Daten). Zugangsinformationen und Einstellungen werden behalten",
|
||||
"sidePlayQueueStyle": "Wiedergabelistenstil in der Seitenleiste",
|
||||
"zoom_description": "Setzt den Zoom (in %) für das Programm",
|
||||
"zoom": "Zoom"
|
||||
"zoom": "Zoom",
|
||||
"albumBackground": "Album Hintergrund",
|
||||
"customCss": "Benutzerdefiniert css",
|
||||
"homeConfiguration": "Startseite Konfiguration",
|
||||
"lastfmApiKey": "{{lastfm}} API-Schlüssel",
|
||||
"lastfmApiKey_description": "Der API-Schlüssel für {{lastfm}}. wird für benötigt",
|
||||
"discordListening": "Status als hört zu anzeigen",
|
||||
"discordListening_description": "Status als hört zu statt als spielt anzeigen",
|
||||
"lastfm": "zeige last.fm links",
|
||||
"lastfm_description": "zeige links zu last.fm auf dem Künstler/Album-Seiten",
|
||||
"musicbrainz": "Zeig musicbrainz links",
|
||||
"customCssEnable": "aktiviere Benutzerdefinierte css"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
"action_one": "action",
|
||||
"action_other": "actions",
|
||||
"add": "add",
|
||||
"additionalParticipants": "additional participants",
|
||||
"newVersion": "a new version has been installed ({{version}})",
|
||||
"viewReleaseNotes": "view release notes",
|
||||
"albumGain": "album gain",
|
||||
"albumPeak": "album peak",
|
||||
"areYouSure": "are you sure?",
|
||||
@@ -106,6 +109,7 @@
|
||||
"share": "share",
|
||||
"size": "size",
|
||||
"sortOrder": "order",
|
||||
"tags": "tags",
|
||||
"title": "title",
|
||||
"trackNumber": "track",
|
||||
"trackGain": "track gain",
|
||||
@@ -158,6 +162,7 @@
|
||||
"audioDeviceFetchError": "an error occurred when trying to get audio devices",
|
||||
"authenticationFailed": "authentication failed",
|
||||
"badAlbum": "you are seeing this page because this song is not part of an album. you are most likely seeing this issue if you have a song at the top level of your music folder. jellyfin only groups tracks if they are in a folder.",
|
||||
"badValue": "invalid option \"{{value}}\". this value no longer exists",
|
||||
"credentialsRequired": "credentials required",
|
||||
"endpointNotImplementedError": "endpoint {{endpoint}} is not implemented for {{serverType}}",
|
||||
"genericError": "an error occurred",
|
||||
@@ -265,6 +270,7 @@
|
||||
"title": "lyric search"
|
||||
},
|
||||
"queryEditor": {
|
||||
"title": "query editor",
|
||||
"input_optionMatchAll": "match all",
|
||||
"input_optionMatchAny": "match any"
|
||||
},
|
||||
@@ -418,6 +424,7 @@
|
||||
"folders": "$t(entity.folder_other)",
|
||||
"genres": "$t(entity.genre_other)",
|
||||
"home": "$t(common.home)",
|
||||
"myLibrary": "my library",
|
||||
"nowPlaying": "now playing",
|
||||
"playlists": "$t(entity.playlist_other)",
|
||||
"search": "$t(common.search)",
|
||||
@@ -507,12 +514,16 @@
|
||||
"disableLibraryUpdateOnStartup": "disable checking for new versions on startup",
|
||||
"discordApplicationId": "{{discord}} application id",
|
||||
"discordApplicationId_description": "the application id for {{discord}} rich presence (defaults to {{defaultId}})",
|
||||
"discordPausedStatus": "show rich presence when paused",
|
||||
"discordPausedStatus_description": "when enabled, status will show when player is paused",
|
||||
"discordIdleStatus": "show rich presence idle status",
|
||||
"discordIdleStatus_description": "when enabled, update status while player is idle",
|
||||
"discordListening": "show status as listening",
|
||||
"discordListening_description": "show status as listening instead of playing",
|
||||
"discordRichPresence": "{{discord}} rich presence",
|
||||
"discordRichPresence_description": "enable playback status in {{discord}} rich presence. Image keys are: {{icon}}, {{playing}}, and {{paused}} ",
|
||||
"discordRichPresence_description": "enable playback status in {{discord}} rich presence. Image keys are: {{icon}}, {{playing}}, and {{paused}}",
|
||||
"discordServeImage": "serve {{discord}} images from server",
|
||||
"discordServeImage_description": "share cover art for {{discord}} rich presence from server itself, only available for jellyfin and navidrome",
|
||||
"discordUpdateInterval": "{{discord}} rich presence update interval",
|
||||
"discordUpdateInterval_description": "the time in seconds between each update (minimum 15 seconds)",
|
||||
"doubleClickBehavior": "queue all searched tracks when double clicking",
|
||||
@@ -527,6 +538,8 @@
|
||||
"floatingQueueArea_description": "display a hover icon on the right side of the screen to view the play queue",
|
||||
"followLyric": "follow current lyric",
|
||||
"followLyric_description": "scroll the lyric to the current playing position",
|
||||
"preferLocalLyrics": "prefer local lyrics",
|
||||
"preferLocalLyrics_description": "prefer local lyrics over remote lyrics when available",
|
||||
"font": "font",
|
||||
"font_description": "sets the font to use for the application",
|
||||
"fontType": "font type",
|
||||
@@ -582,6 +595,8 @@
|
||||
"imageAspectRatio_description": "if enabled, cover art will be shown using their native aspect ratio. for art that is not 1:1, the remaining space will be empty",
|
||||
"language": "language",
|
||||
"language_description": "sets the language for the application ($t(common.restartRequired))",
|
||||
"lastfm": "show last.fm links",
|
||||
"lastfm_description": "show links to last.fm on artist/album pages",
|
||||
"lastfmApiKey": "{{lastfm}} API key",
|
||||
"lastfmApiKey_description": "the API key for {{lastfm}}. required for cover art",
|
||||
"lyricFetch": "fetch lyrics from the internet",
|
||||
@@ -600,6 +615,10 @@
|
||||
"mpvExecutablePath_description": "sets the path to the mpv executable. if left empty, the default path will be used",
|
||||
"mpvExtraParameters": "mpv parameters",
|
||||
"mpvExtraParameters_help": "one per line",
|
||||
"musicbrainz": "show musicbrainz links",
|
||||
"musicbrainz_description": "show links to musicbrainz on artist/album pages, where mbid exists",
|
||||
"neteaseTranslation": "Enable NetEase translations",
|
||||
"neteaseTranslation_description": "When enabled, fetches and displays translated lyrics from NetEase if available.",
|
||||
"passwordStore": "passwords/secret store",
|
||||
"passwordStore_description": "what password/secret store to use. change this if you are having issues storing passwords.",
|
||||
"playbackStyle": "playback style",
|
||||
@@ -688,6 +707,8 @@
|
||||
"volumeWidth_description": "the width of the volume slider",
|
||||
"webAudio": "use web audio",
|
||||
"webAudio_description": "use web audio. this enables advanced features like replaygain. disable if you experience otherwise",
|
||||
"preservePitch": "preserve pitch",
|
||||
"preservePitch_description": "preserves pitch when modifying playback speed",
|
||||
"windowBarStyle": "window bar style",
|
||||
"windowBarStyle_description": "select the style of the window bar",
|
||||
"zoom": "zoom percentage",
|
||||
@@ -763,6 +784,8 @@
|
||||
},
|
||||
"view": {
|
||||
"card": "card",
|
||||
"grid": "grid",
|
||||
"list": "list",
|
||||
"poster": "poster",
|
||||
"table": "table"
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
"hotkey_toggleShuffle": "alterna aleatorio",
|
||||
"theme": "tema",
|
||||
"playbackStyle_description": "selecciona el estilo de reproducción a usar por el reproductor de audio",
|
||||
"discordRichPresence_description": "activa el estado de reproducción en el estado de actividad de {{discord}}. Las teclas de imagen son: {{icon}}, {{playing}}, y {{paused}} ",
|
||||
"discordRichPresence_description": "activa el estado de reproducción en el estado de actividad de {{discord}}. Las teclas de imagen son: {{icon}}, {{playing}}, y {{paused}}",
|
||||
"mpvExecutablePath": "ruta del ejecutable mpv",
|
||||
"audioDevice": "dispositivo de audio",
|
||||
"hotkey_rate2": "calificar con 2 estrellas",
|
||||
@@ -257,7 +257,21 @@
|
||||
"translationTargetLanguage": "idioma final de la traducción",
|
||||
"translationTargetLanguage_description": "lengua de destino de la traducción",
|
||||
"lastfmApiKey_description": "la clave API para {{lastfm}}. Requerida para la portada",
|
||||
"lastfmApiKey": "Clave API para {{lastfm}}"
|
||||
"lastfmApiKey": "Clave API para {{lastfm}}",
|
||||
"discordServeImage": "Servir imágenes de {{discord}} desde el servidor",
|
||||
"discordServeImage_description": "Comparte el arte de la portada para el estado de actividad de {{discord}} desde el propio servidor, solo disponible para Jellyfin y Navidrome",
|
||||
"lastfm": "Mostrar enlaces de last.fm",
|
||||
"lastfm_description": "Muestra enlaces a last.fm en las páginas de artistas/álbumes",
|
||||
"musicbrainz": "Mostrar enlaces de MusicBrainz",
|
||||
"musicbrainz_description": "Muestra enlaces a MusicBrainz en las páginas de artistas/álbumes, donde exista mbid",
|
||||
"neteaseTranslation": "Activar traducciones de NetEase",
|
||||
"neteaseTranslation_description": "Cuando se habilita, busca y muestra letras traducidas desde NetEase si está disponible.",
|
||||
"preferLocalLyrics_description": "Prefiere letras locales sobre letras remotas cuando esté disponible",
|
||||
"preferLocalLyrics": "Preferir letras locales",
|
||||
"discordPausedStatus": "Mostrar estado de actividad cuando esté en pausa",
|
||||
"discordPausedStatus_description": "Cuando está activado, el estado mostrará cuando el reproductor esté en pausa",
|
||||
"preservePitch": "Mantener el tono",
|
||||
"preservePitch_description": "Mantiene el tono cuando se modifica la velocidad de reproducción"
|
||||
},
|
||||
"action": {
|
||||
"editPlaylist": "editar $t(entity.playlist_one)",
|
||||
@@ -375,7 +389,11 @@
|
||||
"share": "Compartir",
|
||||
"trackGain": "Ganancia de pista",
|
||||
"preview": "Vista previa",
|
||||
"translation": "traducción"
|
||||
"translation": "traducción",
|
||||
"additionalParticipants": "Participantes adicionales",
|
||||
"tags": "Etiquetas",
|
||||
"newVersion": "Una nueva versión ha sido instalada ({{version}})",
|
||||
"viewReleaseNotes": "Ver notas de lanzamiento"
|
||||
},
|
||||
"error": {
|
||||
"remotePortWarning": "reiniciar el servidor para aplicar el nuevo puerto",
|
||||
@@ -399,7 +417,8 @@
|
||||
"loginRateError": "demasiados intentos de inicio de sesión, por favor inténtalo en unos segundos",
|
||||
"badAlbum": "Estás viendo esta página porque esta canción no forma parte de un álbum. Este problema puede ocurrir si tienes una canción en el nivel superior de tu carpeta de música. Jellyfin solo agrupa pistas si están en una carpeta.",
|
||||
"networkError": "Ocurrió un error de red",
|
||||
"openError": "No se pudo abrir el archivo"
|
||||
"openError": "No se pudo abrir el archivo",
|
||||
"badValue": "Opción inválida \"{{value}}\". Este valor ya no existe"
|
||||
},
|
||||
"filter": {
|
||||
"mostPlayed": "más reproducido",
|
||||
@@ -458,7 +477,8 @@
|
||||
"home": "$t(common.home)",
|
||||
"artists": "$t(entity.artist_other)",
|
||||
"albumArtists": "$t(entity.albumArtist_other)",
|
||||
"shared": "compartido $t(entity.playlist_other)"
|
||||
"shared": "compartido $t(entity.playlist_other)",
|
||||
"myLibrary": "Mi biblioteca"
|
||||
},
|
||||
"appMenu": {
|
||||
"selectServer": "seleccionar servidor",
|
||||
@@ -644,7 +664,8 @@
|
||||
},
|
||||
"queryEditor": {
|
||||
"input_optionMatchAll": "coincidir todos",
|
||||
"input_optionMatchAny": "coincidir cualquiera"
|
||||
"input_optionMatchAny": "coincidir cualquiera",
|
||||
"title": "Editor de consultas"
|
||||
},
|
||||
"shareItem": {
|
||||
"createFailed": "No se pudo crear el recurso compartido (¿está habilitado el uso compartido?)",
|
||||
@@ -726,7 +747,9 @@
|
||||
"view": {
|
||||
"card": "tarjeta",
|
||||
"table": "tabla",
|
||||
"poster": "cartel"
|
||||
"poster": "cartel",
|
||||
"list": "Lista",
|
||||
"grid": "Cuadrícula"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -88,7 +88,11 @@
|
||||
"albumGain": "albumin vahvistus (gain)",
|
||||
"albumPeak": "albumin huippu (peak)",
|
||||
"trackGain": "raidan vahvistus (gain)",
|
||||
"trackPeak": "kappaleen huippu (peak)"
|
||||
"trackPeak": "kappaleen huippu (peak)",
|
||||
"additionalParticipants": "muut osallistujat",
|
||||
"tags": "tägit",
|
||||
"newVersion": "uusi versio on asennettu ({{version}})",
|
||||
"viewReleaseNotes": "katsele julkaisutietoja"
|
||||
},
|
||||
"entity": {
|
||||
"album_one": "albumi",
|
||||
@@ -173,7 +177,8 @@
|
||||
"localFontAccessDenied": "paikallisiin fontteihin pääsy on kielletty",
|
||||
"playbackError": "mediaa toistaessa tapahtui virhe",
|
||||
"remotePortWarning": "käynnistä palvelin uudestaan ottaaksesi uuden portin käyttöön",
|
||||
"endpointNotImplementedError": "päätepiste {{endpoint}} ei ole toteutettu {{serverType}} varten"
|
||||
"endpointNotImplementedError": "päätepiste {{endpoint}} ei ole toteutettu {{serverType}} varten",
|
||||
"badValue": "kelpaamaton optio \"{{value}}\". tätä arvoa ei ole enää olemassa"
|
||||
},
|
||||
"filter": {
|
||||
"album": "$t(entity.album_one)",
|
||||
@@ -276,7 +281,8 @@
|
||||
},
|
||||
"queryEditor": {
|
||||
"input_optionMatchAny": "sovita joku",
|
||||
"input_optionMatchAll": "sovita kaikki"
|
||||
"input_optionMatchAll": "sovita kaikki",
|
||||
"title": "kyselyeditori"
|
||||
}
|
||||
},
|
||||
"setting": {
|
||||
@@ -356,7 +362,7 @@
|
||||
"doubleClickBehavior": "lisää kaikki haetut kappaleet soittojonoon tuplaklikkauksella",
|
||||
"discordUpdateInterval_description": "päivitysväli sekunnteina (vähintään 15 sekunttia)",
|
||||
"discordRichPresence": "{{discord}} rich presence",
|
||||
"discordRichPresence_description": "ota toiston tila käyttöön {{discord}}n rich presence-toiminnossa. Kuvakkeiden avaimet ovat {{icon}}, {{playing}} ja {{paused}}. ",
|
||||
"discordRichPresence_description": "ota toiston tila käyttöön {{discord}}n rich presence-toiminnossa. Kuvakkeiden avaimet ovat {{icon}}, {{playing}} ja {{paused}}",
|
||||
"discordUpdateInterval": "{{discord}} rich presencen päivitysväli",
|
||||
"enableRemote": "aktivoi etäohjauspalvelin",
|
||||
"externalLinks_description": "ottaa ulkoiset linkit (Last.fm, MusicBrainz) artistien/albumien sivuilla",
|
||||
@@ -504,7 +510,21 @@
|
||||
"webAudio_description": "käytä web-ääntä. tämä mahdollistaa edistyneet ominaisuudet, kuten replaygainin. poista käytöstä, jos koet ongelmia",
|
||||
"startMinimized": "käynnistä pienennettynä",
|
||||
"useSystemTheme": "käytä järjestelmän teemaa",
|
||||
"volumeWheelStep": "äänenvoimakkuusrullan askel"
|
||||
"volumeWheelStep": "äänenvoimakkuusrullan askel",
|
||||
"discordServeImage": "jaa {{discord}} kuvat palvelimelta",
|
||||
"discordServeImage_description": "jaa kansikuvat {{discord}}n rich presenceä varten suoraan palvelimelta. saatavilla vain jellyfinille ja navidromelle",
|
||||
"musicbrainz_description": "näytä linkit musicbrainz sivulle artistin/albumin sivuilla, jos musicbrainz-id löytyy",
|
||||
"lastfm": "näytä last.fm linkit",
|
||||
"lastfm_description": "näytä linkit last.fm sivulle artistin/albumin sivuilla",
|
||||
"musicbrainz": "näytä musicbrainz linkit",
|
||||
"neteaseTranslation": "Ota NetEasen käännökset käyttöön",
|
||||
"neteaseTranslation_description": "Käytöss ollessa noutaa ja näyttää käännetyt sanat NetEasesta, jos ne ovat saatavilla.",
|
||||
"preferLocalLyrics_description": "suosi paikallisia sanoituksia ulkoisten sijasta, kun saatavilla",
|
||||
"preferLocalLyrics": "suosi paikallisia sanoituksia",
|
||||
"discordPausedStatus": "näytä rich presence tauotettuna",
|
||||
"discordPausedStatus_description": "ollessak käytössä, status näyttää milloin soitin on tautotettuna",
|
||||
"preservePitch": "säilytä sävelkorkeus",
|
||||
"preservePitch_description": "säilytä sävelkorkeus toistonopeutta muokatessa"
|
||||
},
|
||||
"page": {
|
||||
"itemDetail": {
|
||||
@@ -573,7 +593,8 @@
|
||||
"home": "$t(common.home)",
|
||||
"nowPlaying": "nyt soi",
|
||||
"playlists": "$t(entity.playlist_other)",
|
||||
"search": "$t(common.search)"
|
||||
"search": "$t(common.search)",
|
||||
"myLibrary": "oma kirjasto"
|
||||
},
|
||||
"setting": {
|
||||
"generalTab": "yleinen",
|
||||
@@ -734,7 +755,9 @@
|
||||
"view": {
|
||||
"table": "taulukko",
|
||||
"card": "kortti",
|
||||
"poster": "juliste"
|
||||
"poster": "juliste",
|
||||
"grid": "ruudukko",
|
||||
"list": "lista"
|
||||
}
|
||||
},
|
||||
"column": {
|
||||
|
||||
@@ -148,7 +148,11 @@
|
||||
"trackGain": "gain de la piste",
|
||||
"trackPeak": "crête de la piste",
|
||||
"codec": "codec",
|
||||
"translation": "traduction"
|
||||
"translation": "traduction",
|
||||
"additionalParticipants": "participants additionnels",
|
||||
"tags": "tags",
|
||||
"newVersion": "une nouvelle version vient d'être installé ({{version}})",
|
||||
"viewReleaseNotes": "voir la note de version"
|
||||
},
|
||||
"error": {
|
||||
"remotePortWarning": "redémarrer le serveur pour appliquer le nouveau port",
|
||||
@@ -172,7 +176,8 @@
|
||||
"loginRateError": "trop de tentative de connexion, merci de réessayer dans quelques secondes",
|
||||
"openError": "impossible d'ouvrir le fichier",
|
||||
"networkError": "une erreur de réseau est survenue",
|
||||
"badAlbum": "vous voyez cette page parce que cette chanson ne fait pas parti d'un album. vous rencontrez probablement cette erreur si vous avez une chanson qui n'est pas dans votre répertoire de musique. jellyfin gère les chansons uniquement si elles sont dans un sous-dossier, qui est lui-même dans un dossier \"Musique(s)\"."
|
||||
"badAlbum": "vous voyez cette page parce que cette chanson ne fait pas parti d'un album. vous rencontrez probablement cette erreur si vous avez une chanson qui n'est pas dans votre répertoire de musique. jellyfin gère les chansons uniquement si elles sont dans un sous-dossier, qui est lui-même dans un dossier \"Musique(s)\".",
|
||||
"badValue": "option {{value}} invalide. Cette valeur n'existe plus"
|
||||
},
|
||||
"filter": {
|
||||
"mostPlayed": "plus joués",
|
||||
@@ -231,7 +236,8 @@
|
||||
"home": "$t(common.home)",
|
||||
"artists": "$t(entity.artist_other)",
|
||||
"albumArtists": "$t(entity.albumArtist_other)",
|
||||
"shared": "partagé $t(entity.playlist_other)"
|
||||
"shared": "partagé $t(entity.playlist_other)",
|
||||
"myLibrary": "ma bibliothèque"
|
||||
},
|
||||
"fullscreenPlayer": {
|
||||
"config": {
|
||||
@@ -443,7 +449,7 @@
|
||||
"playbackStyle": "style de lecture",
|
||||
"hotkey_toggleShuffle": "basculer la lecture aléatoire",
|
||||
"playbackStyle_description": "sélectionnez le style de lecture à utiliser pour le lecteur audio",
|
||||
"discordRichPresence_description": "active l'état de lecteur dans le status d'activité {{discord}}. Les images clés sont : {{icon}}, {{playing}}, et {{paused}} ",
|
||||
"discordRichPresence_description": "active l'état de lecteur dans le status d'activité {{discord}}. Les images clés sont : {{icon}}, {{playing}}, et {{paused}}",
|
||||
"mpvExecutablePath": "chemin de l'exécutable mpv",
|
||||
"hotkey_rate2": "noter 2 étoiles",
|
||||
"playButtonBehavior_description": "définit le comportement par défaut du bouton play, lors de l'ajout de chanson à la file d'attente",
|
||||
@@ -593,7 +599,21 @@
|
||||
"doubleClickBehavior_description": "si vrai, toutes les pistes correspondantes dans une recherche de piste seront mises en file d'attente. sinon, seule celle sur laquelle vous avez cliqué sera mise en file d'attente",
|
||||
"albumBackgroundBlur": "taille du flou de l'image d'arrière-plan de l'album",
|
||||
"lastfmApiKey": "clé API {{lastfm}}",
|
||||
"lastfmApiKey_description": "la clé API pour {{lastfm}} est requise pour la pochette d'album"
|
||||
"lastfmApiKey_description": "la clé API pour {{lastfm}} . requise pour la pochette d'album",
|
||||
"discordServeImage": "servir l'image {{discord}} depuis le serveur",
|
||||
"discordServeImage_description": "partage pochette du status d'activité {{discord}} depuis le serveur lui même, disponible uniquement pour jellyfin et navidrome",
|
||||
"lastfm": "affiche les liens de last.fm",
|
||||
"musicbrainz_description": "affiches les liens vers musicbrainz sur les pages des artistes/albums, quand mbid existes",
|
||||
"lastfm_description": "affiche les liens vers last.fm sur les pages des artistes/albums",
|
||||
"musicbrainz": "affiches les liens musicbrainz",
|
||||
"neteaseTranslation": "Activer les traductions NetEase",
|
||||
"neteaseTranslation_description": "Lorsque cette option est activée, récupère et affiche les paroles traduites de NetEase si elles sont disponibles.",
|
||||
"preferLocalLyrics_description": "privilégier les paroles locales aux paroles distantes lorsqu'elles sont disponibles",
|
||||
"preferLocalLyrics": "privilégier les paroles locales",
|
||||
"discordPausedStatus_description": "quand activé, le status s'affichera lorsque le lecteur est en pause",
|
||||
"discordPausedStatus": "afficher le status d'activité en pause",
|
||||
"preservePitch": "préserver la hauteur",
|
||||
"preservePitch_description": "préserver la hauteur lors du changement de la vitesse de lecture"
|
||||
},
|
||||
"form": {
|
||||
"deletePlaylist": {
|
||||
@@ -634,7 +654,8 @@
|
||||
},
|
||||
"queryEditor": {
|
||||
"input_optionMatchAll": "correspondre à tous",
|
||||
"input_optionMatchAny": "correspondre à n'importe quel"
|
||||
"input_optionMatchAny": "correspondre à n'importe quel",
|
||||
"title": "éditeur de requête"
|
||||
},
|
||||
"editPlaylist": {
|
||||
"title": "modifier $t(entity.playlist_one)",
|
||||
@@ -724,7 +745,9 @@
|
||||
"view": {
|
||||
"table": "liste",
|
||||
"poster": "poster",
|
||||
"card": "Carte"
|
||||
"card": "Carte",
|
||||
"grid": "grille",
|
||||
"list": "liste"
|
||||
},
|
||||
"label": {
|
||||
"releaseDate": "date de sortie",
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
"remotePortWarning": "indítsd újra a szervert az új PORT használatához",
|
||||
"genericError": "hiba történt",
|
||||
"endpointNotImplementedError": "a(z) {{endpoint}} végpont nincs implementálva a következőhöz: {{serverType}}",
|
||||
"badAlbum": "azért látod ezt az oldalt mert ez a zeneszám nem része egy albumnak. ez általában akkor történik amikor egy szám a zenekönyvtárad gyökerébe kerül. a Jellyfin csak mappákba rendezett számokat csoportosít",
|
||||
"badAlbum": "azért látod ezt az oldalt mert ez a zeneszám nem része egy albumnak. ez általában akkor történik amikor egy szám a zenekönyvtárad gyökerébe kerül. a Jellyfin csak mappákba rendezett számokat csoportosít.",
|
||||
"loginRateError": "túl sok bejelentkezési kísérlet, kérlek próbáld újra pár másodperc múlva",
|
||||
"mpvRequired": "MPV szükséges",
|
||||
"invalidServer": "érvénytelen szerver",
|
||||
|
||||
@@ -491,7 +491,7 @@
|
||||
"discordListening": "Tampilkan status sebagai mendengarkan",
|
||||
"discordListening_description": "tampilkan status sebagai mendengarkan alih-alih bermain",
|
||||
"discordRichPresence": "status aktivitas {{discord}}",
|
||||
"discordRichPresence_description": "aktifkan status pemutaran di status aktivitas {{discord}}. Gambar tombol adalah: {{icon}}, {{playing}}, dan {{paused}} ",
|
||||
"discordRichPresence_description": "aktifkan status pemutaran di status aktivitas {{discord}}. Gambar tombol adalah: {{icon}}, {{playing}}, dan {{paused}}",
|
||||
"discordUpdateInterval": "interval pembaruan status aktivitas {{discord}}",
|
||||
"discordUpdateInterval_description": "waktu dalam detik antara setiap pembaruan (minimal 15 detik)",
|
||||
"doubleClickBehavior": "masukkan semua lagu yang dicari saat mengklik dua kali",
|
||||
|
||||
@@ -209,7 +209,7 @@
|
||||
"hotkey_toggleShuffle": "attiva/disattiva mescolamento",
|
||||
"theme": "tema",
|
||||
"playbackStyle_description": "selezione lo stile di riproduzione da usare per il player audio",
|
||||
"discordRichPresence_description": "abilita lo status del playback nello stato attività di {{discord}}. Le chiavi immagine sono: {{icon}}, {{playing}} e {{paused}} ",
|
||||
"discordRichPresence_description": "abilita lo status del playback nello stato attività di {{discord}}. Le chiavi immagine sono: {{icon}}, {{playing}} e {{paused}}",
|
||||
"mpvExecutablePath": "percorso eseguibile mpv",
|
||||
"audioDevice": "device audio",
|
||||
"hotkey_rate2": "voto 2 stelle",
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
"hotkey_toggleShuffle": "シャッフルの切り替え",
|
||||
"theme": "テーマ",
|
||||
"playbackStyle_description": "オーディオプレーヤーに使用する再生スタイルを選択します",
|
||||
"discordRichPresence_description": "{{discord}} のRich Presenceに再生ステータスを表示するようにします。画像キー: {{icon}}, {{playing}}, {{paused}} ",
|
||||
"discordRichPresence_description": "{{discord}} のRich Presenceに再生ステータスを表示するようにします。画像キー: {{icon}}, {{playing}}, {{paused}}",
|
||||
"mpvExecutablePath": "mpv 実行ファイルパス",
|
||||
"audioDevice": "オーディオデバイス",
|
||||
"hotkey_rate2": "2つ星で評価",
|
||||
|
||||
@@ -533,7 +533,7 @@
|
||||
"crossfadeDuration_description": "ustaw czas trwania efektu przenikania",
|
||||
"language": "język",
|
||||
"hotkey_toggleShuffle": "przełącz kolejność losową",
|
||||
"discordRichPresence_description": "włącz status odtwarzania w {{discord}} (rich presence). Dzięki temu będą wyświetlane informacje takie jak: {{icon}}, {{playing}} i {{paused}}. ",
|
||||
"discordRichPresence_description": "włącz status odtwarzania w {{discord}} (rich presence). Dzięki temu będą wyświetlane informacje takie jak: {{icon}}, {{playing}} i {{paused}}",
|
||||
"audioDevice": "urządzenia dźwiękowe",
|
||||
"hotkey_rate2": "oceń na 2 gwiazdki",
|
||||
"exitToTray": "zamknij do zasobnika",
|
||||
|
||||
@@ -91,7 +91,9 @@
|
||||
"albumGain": "ganho do álbum",
|
||||
"trackPeak": "pico da faixa",
|
||||
"albumPeak": "pico do álbum",
|
||||
"trackGain": "ganho da faixa"
|
||||
"trackGain": "ganho da faixa",
|
||||
"additionalParticipants": "participantes adicionais",
|
||||
"tags": "tags"
|
||||
},
|
||||
"action": {
|
||||
"goToPage": "vá para página",
|
||||
@@ -205,7 +207,16 @@
|
||||
"buttonSize_description": "o tamanho dos botões da barra de reprodução",
|
||||
"albumBackgroundBlur": "tamanho de desfoque da imagem de fundo do álbum",
|
||||
"albumBackgroundBlur_description": "ajusta a quantidade de desfoque aplicada para a imagem de fundo do álbum",
|
||||
"albumBackground": "imagem de fundo do álbum"
|
||||
"albumBackground": "imagem de fundo do álbum",
|
||||
"contextMenu_description": "permite esconder itens exibidos no menu quando você clica em um item com o botão direito. itens não selecionados serão escondidos",
|
||||
"customCssEnable": "habilitar css customizado",
|
||||
"customCssEnable_description": "permite escrever css customizado.",
|
||||
"crossfadeDuration": "duraçao de crossfade",
|
||||
"customCss": "css customizado",
|
||||
"crossfadeDuration_description": "define a duração do efeito crossfade",
|
||||
"customCssNotice": "Aviso: apesar de existir alguma higienização (url() e content: não são permitidas), o uso de CSS personalizado ainda pode representar riscos ao alterar a interface.",
|
||||
"crossfadeStyle": "estilo do crossfade",
|
||||
"crossfadeStyle_description": "seleciona qual estilo de crossfade usado no player de áudio"
|
||||
},
|
||||
"table": {
|
||||
"config": {
|
||||
@@ -524,6 +535,7 @@
|
||||
"loginRateError": "muitas tentativas de login, tente novamente em alguns segundos",
|
||||
"badAlbum": "você está vendo este erro por que está música não é parte de algum album. um motivo comum para você estar vendo este erro é se a sua música estiver na raiz da sua pasta de músicas. o jellyfin apenas agrupa as músicas se elas estiveram na mesma pasta.",
|
||||
"networkError": "ocorreu um erro na internet",
|
||||
"openError": "não foi possível abrir o arquivo"
|
||||
"openError": "não foi possível abrir o arquivo",
|
||||
"badValue": "opção inválida \"{{value}}\". este valor não existe no momento"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
"confirm": "подтвердить",
|
||||
"resetToDefault": "сбросить настройки",
|
||||
"home": "главная",
|
||||
"comingSoon": "скоро...",
|
||||
"comingSoon": "скоро…",
|
||||
"reset": "сбросить",
|
||||
"channel_one": "канал",
|
||||
"channel_few": "канала",
|
||||
@@ -333,7 +333,7 @@
|
||||
"next": "следующий",
|
||||
"shuffle": "перемешать",
|
||||
"playbackFetchNoResults": "песни не найдены",
|
||||
"playbackFetchInProgress": "загрузка песен..",
|
||||
"playbackFetchInProgress": "загрузка песен…",
|
||||
"addNext": "воспроизвести следующим",
|
||||
"playbackSpeed": "скорость воспроизведения",
|
||||
"playbackFetchCancel": "пожалуйста, подождите немного... закройте уведомление для отмены",
|
||||
@@ -759,7 +759,7 @@
|
||||
"artistConfiguration": "конфигурация страницы альбомов исполнителей",
|
||||
"artistConfiguration_description": "позволяет настроить видимость и порядок элементов на странице альбомов исполнителей",
|
||||
"fontType_description": "встроенный позволяет выбрать один из шрифтов, предоставляемых Feishin. системный позволяет выбрать любой шрифт, предоставляемый вашей операционной системой. пользовательский позволяет выбрать свой собственный шрифт",
|
||||
"discordRichPresence_description": "включить статус воспроизведения в статус профиля в {{discord}}. Ключи изображений: {{icon}}, {{playing}} и {{paused}} ",
|
||||
"discordRichPresence_description": "включить статус воспроизведения в статус профиля в {{discord}}. Ключи изображений: {{icon}}, {{playing}} и {{paused}}",
|
||||
"lyricOffset": "синхронизация текста треков (мс)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
"hotkey_localSearch": "pretraživanje na stranici",
|
||||
"hotkey_toggleQueue": "promeni listu za reprodukciju",
|
||||
"zoom_description": "postavlja stepen zumiranja za aplikaciju",
|
||||
"remotePassword_description": "postavlja lozinku za daljinsku kontrolu servera. Ove informacije se prenose nezaštićeno, pa biste trebali koristiti jedinstvenu lozinku koja vam nije važna.",
|
||||
"remotePassword_description": "postavlja lozinku za daljinsku kontrolu servera. Ove informacije se prenose nezaštićeno, pa biste trebali koristiti jedinstvenu lozinku koja vam nije važna",
|
||||
"hotkey_rate5": "oceni sa 5 zvezdica",
|
||||
"hotkey_playbackPrevious": "prethodna pesma",
|
||||
"showSkipButtons_description": "prikaži ili sakrij dugmad za preskakanje na traci za reprodukciju",
|
||||
@@ -122,7 +122,7 @@
|
||||
"hotkey_toggleShuffle": "promeni slučajan redosled",
|
||||
"theme": "tema",
|
||||
"playbackStyle_description": "izaberite stil reprodukcije za audio plejer",
|
||||
"discordRichPresence_description": "omogućava status reprodukcije u {{discord}} bogatom prikazu. Ključevi slika su: {{icon}}, {{playing}}, i {{paused}} ",
|
||||
"discordRichPresence_description": "omogućava status reprodukcije u {{discord}} bogatom prikazu. Ključevi slika su: {{icon}}, {{playing}}, i {{paused}}",
|
||||
"mpvExecutablePath": "putanja do mpv izvršne datoteke",
|
||||
"audioDevice": "audio uređaj",
|
||||
"hotkey_rate2": "oceni sa 2 zvezdice",
|
||||
@@ -158,7 +158,7 @@
|
||||
"useSystemTheme_description": "prati sistemski određene postavke za svetlu ili tamnu temu",
|
||||
"playButtonBehavior_optionAddNext": "$t(player.addNext)",
|
||||
"lyricFetch_description": "preuzimanje tekstova sa različitih izvora na internetu",
|
||||
"lyricFetchProvider_description": "izaberite pružatelje tekstova za preuzimanje. Redosled pružatelja je redosled upita.",
|
||||
"lyricFetchProvider_description": "izaberite pružatelje tekstova za preuzimanje. Redosled pružatelja je redosled upita",
|
||||
"globalMediaHotkeys_description": "omogućava ili onemogućava korišćenje medijskih tastera sistema za kontrolu reprodukcije",
|
||||
"customFontPath": "prilagođena putanja fonta",
|
||||
"followLyric": "prati trenutni tekst pesme",
|
||||
|
||||
@@ -224,7 +224,7 @@
|
||||
"input_password": "கடவுச்சொல்",
|
||||
"error_savePassword": "கடவுச்சொல்லை சேமிக்க முயற்சிக்கும்போது பிழை ஏற்பட்டது",
|
||||
"ignoreCors": "CORS ஐ புறக்கணிக்கவும் ($ t (Common.RestartRequired))",
|
||||
"ignoreSsl": "SSL ஐ புறக்கணிக்கவும் ($ t (பொதுவானது.",
|
||||
"ignoreSsl": "SSL ஐ புறக்கணிக்கவும் ($ t (பொதுவானது",
|
||||
"input_legacyAuthentication": "மரபு அங்கீகாரத்தை இயக்கவும்",
|
||||
"input_name": "சேவையக பெயர்",
|
||||
"input_savePassword": "கடவுச்சொல்லைச் சேமிக்கவும்",
|
||||
@@ -521,7 +521,7 @@
|
||||
"hotkey_volumeMute": "தொகுதி முடக்கு",
|
||||
"hotkey_volumeUp": "தொகுதி",
|
||||
"language": "மொழி",
|
||||
"language_description": "பயன்பாட்டிற்கான மொழியை அமைக்கிறது ($ t (பொதுவானது.",
|
||||
"language_description": "பயன்பாட்டிற்கான மொழியை அமைக்கிறது ($ t (பொதுவானது",
|
||||
"lastfmApiKey": "{{lastfm}} பநிஇ key",
|
||||
"lastfmApiKey_description": "{{lastfm} க்கு க்கான பநிஇ விசை. கவர் கலைக்கு தேவை",
|
||||
"lyricFetch": "இணையத்திலிருந்து வரிகளை பெறுங்கள்",
|
||||
@@ -615,7 +615,7 @@
|
||||
"discordIdleStatus_description": "இயக்கப்பட்டால், பிளேயர் சும்மா இருக்கும்போது நிலையைப் புதுப்பிக்கவும்",
|
||||
"discordListening_description": "விளையாடுவதற்குப் பதிலாக கேட்பது என்று அந்த நிலையைக் காட்டுங்கள்",
|
||||
"discordRichPresence": "{{discord}} பணக்கார இருப்பு",
|
||||
"discordRichPresence_description": "{{discord}} பணக்கார இருப்பில் பின்னணி நிலையை இயக்கவும். பட விசைகள்: {{icon}}, {{playing}}, மற்றும் {{paused}} ",
|
||||
"discordRichPresence_description": "{{discord}} பணக்கார இருப்பில் பின்னணி நிலையை இயக்கவும். பட விசைகள்: {{icon}}, {{playing}}, மற்றும் {{paused}}",
|
||||
"customCss_description": "தனிப்பயன் சிஎச்எச் உள்ளடக்கம். குறிப்பு: உள்ளடக்கம் மற்றும் தொலைநிலை முகவரி கள் அனுமதிக்கப்படாத பண்புகள். உங்கள் உள்ளடக்கத்தின் முன்னோட்டம் கீழே காட்டப்பட்டுள்ளது. நீங்கள் அமைக்காத கூடுதல் புலங்கள் சுத்திகரிப்பு காரணமாக உள்ளன.",
|
||||
"doubleClickBehavior": "இரட்டை சொடுக்கு செய்யும் போது தேடப்பட்ட அனைத்து தடங்களையும் வரிசைப்படுத்தவும்",
|
||||
"doubleClickBehavior_description": "உண்மை என்றால், தட தேடலில் பொருந்தக்கூடிய அனைத்து தடங்களும் வரிசையில் நிற்கப்படும். இல்லையெனில், சொடுக்கு செய்யப்பட்ட ஒன்று மட்டுமே வரிசையில் நிற்கப்படும்",
|
||||
@@ -705,14 +705,14 @@
|
||||
"rowIndex": "வரிசை அட்டவணை",
|
||||
"size": "$ t (common.size)",
|
||||
"trackNumber": "ட்ராக் எண்",
|
||||
"year": "$ t (பொதுவானது.",
|
||||
"year": "$ t (பொதுவானது",
|
||||
"lastPlayed": "கடைசியாக விளையாடியது",
|
||||
"note": "$ t (பொதுவானது. குறிப்பு)",
|
||||
"owner": "$ t (பொதுவானவர்)",
|
||||
"actions": "$ t (common.action_other)",
|
||||
"albumArtist": "$ t (entity.albumartist_one)",
|
||||
"discNumber": "வட்டு எண்",
|
||||
"duration": "$ t (பொதுவானது.",
|
||||
"duration": "$ t (பொதுவானது",
|
||||
"favorite": "$ t (common.foavorite)",
|
||||
"genre": "$ t (entity.genre_one)",
|
||||
"path": "$ t (common.path)",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user