mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 12:30:12 +02:00
Compare commits
143 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 |
+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
-40779
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.13.0",
|
||||
"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
-2352
File diff suppressed because it is too large
Load Diff
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"name": "feishin",
|
||||
"version": "0.13.0",
|
||||
"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"
|
||||
},
|
||||
"resolutions": {
|
||||
"xml2js": "0.5.0"
|
||||
},
|
||||
"overrides": {
|
||||
"xml2js": "0.5.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,
|
||||
|
||||
@@ -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í",
|
||||
@@ -259,7 +259,19 @@
|
||||
"lastfmApiKey": "klíč API {{lastfm}}",
|
||||
"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"
|
||||
"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)",
|
||||
@@ -367,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",
|
||||
@@ -379,14 +391,18 @@
|
||||
"preview": "náhled",
|
||||
"translation": "překlad",
|
||||
"additionalParticipants": "další přispívající",
|
||||
"tags": "štítky"
|
||||
"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í",
|
||||
@@ -538,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": {
|
||||
@@ -714,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)",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
"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?",
|
||||
@@ -268,6 +270,7 @@
|
||||
"title": "lyric search"
|
||||
},
|
||||
"queryEditor": {
|
||||
"title": "query editor",
|
||||
"input_optionMatchAll": "match all",
|
||||
"input_optionMatchAny": "match any"
|
||||
},
|
||||
@@ -421,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)",
|
||||
@@ -510,12 +514,14 @@
|
||||
"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",
|
||||
@@ -532,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",
|
||||
@@ -587,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",
|
||||
@@ -605,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",
|
||||
@@ -693,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",
|
||||
@@ -768,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",
|
||||
@@ -259,7 +259,19 @@
|
||||
"lastfmApiKey_description": "la clave API para {{lastfm}}. Requerida para la portada",
|
||||
"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"
|
||||
"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)",
|
||||
@@ -379,7 +391,9 @@
|
||||
"preview": "Vista previa",
|
||||
"translation": "traducción",
|
||||
"additionalParticipants": "Participantes adicionales",
|
||||
"tags": "Etiquetas"
|
||||
"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",
|
||||
@@ -463,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",
|
||||
@@ -649,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?)",
|
||||
@@ -731,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",
|
||||
@@ -506,7 +512,19 @@
|
||||
"useSystemTheme": "käytä järjestelmän teemaa",
|
||||
"volumeWheelStep": "äänenvoimakkuusrullan askel",
|
||||
"discordServeImage": "jaa {{discord}} kuvat palvelimelta",
|
||||
"discordServeImage_description": "jaa kansikuvat {{discord}}n rich presenceä varten suoraan palvelimelta. saatavilla vain jellyfinille ja navidromelle"
|
||||
"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": {
|
||||
@@ -575,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",
|
||||
@@ -736,7 +755,9 @@
|
||||
"view": {
|
||||
"table": "taulukko",
|
||||
"card": "kortti",
|
||||
"poster": "juliste"
|
||||
"poster": "juliste",
|
||||
"grid": "ruudukko",
|
||||
"list": "lista"
|
||||
}
|
||||
},
|
||||
"column": {
|
||||
|
||||
@@ -150,7 +150,9 @@
|
||||
"codec": "codec",
|
||||
"translation": "traduction",
|
||||
"additionalParticipants": "participants additionnels",
|
||||
"tags": "tags"
|
||||
"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",
|
||||
@@ -234,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": {
|
||||
@@ -446,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",
|
||||
@@ -598,7 +601,19 @@
|
||||
"lastfmApiKey": "clé API {{lastfm}}",
|
||||
"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"
|
||||
"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": {
|
||||
@@ -639,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)",
|
||||
@@ -729,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