mirror of
https://github.com/morpheus65535/bazarr.git
synced 2025-04-24 06:37:16 -04:00
Merge branch 'refs/heads/development' into non-hi-only
This commit is contained in:
commit
d3301a210f
221 changed files with 4786 additions and 1206 deletions
|
@ -8,6 +8,8 @@ from app.database import TableShows, TableMovies, database, select
|
|||
|
||||
from ..utils import authenticate
|
||||
|
||||
import textdistance
|
||||
|
||||
api_ns_system_searches = Namespace('System Searches', description='Search for series or movies by name')
|
||||
|
||||
|
||||
|
@ -61,4 +63,6 @@ class Searches(Resource):
|
|||
|
||||
results.append(result)
|
||||
|
||||
# sort results by how closely they match the query
|
||||
results = sorted(results, key=lambda x: textdistance.hamming.distance(query, x['title']))
|
||||
return results
|
||||
|
|
|
@ -29,6 +29,7 @@ from dogpile.cache.api import NO_VALUE
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LegendasdivxSubtitle(Subtitle):
|
||||
"""Legendasdivx Subtitle."""
|
||||
provider_name = 'legendasdivx'
|
||||
|
@ -69,10 +70,12 @@ class LegendasdivxSubtitle(Subtitle):
|
|||
self.wrong_fps = True
|
||||
|
||||
if self.skip_wrong_fps:
|
||||
logger.debug("Legendasdivx :: Skipping subtitle due to FPS mismatch (expected: %s, got: %s)", video.fps, self.sub_frame_rate)
|
||||
logger.debug("Legendasdivx :: Skipping subtitle due to FPS mismatch (expected: %s, got: %s)", video.fps,
|
||||
self.sub_frame_rate)
|
||||
# not a single match :)
|
||||
return set()
|
||||
logger.debug("Legendasdivx :: Frame rate mismatch (expected: %s, got: %s, but continuing...)", video.fps, self.sub_frame_rate)
|
||||
logger.debug("Legendasdivx :: Frame rate mismatch (expected: %s, got: %s, but continuing...)", video.fps,
|
||||
self.sub_frame_rate)
|
||||
|
||||
description = sanitize(self.description)
|
||||
|
||||
|
@ -112,6 +115,11 @@ class LegendasdivxSubtitle(Subtitle):
|
|||
matches.update(['season'])
|
||||
if video.episode and 'e{:02d}'.format(video.episode) in description:
|
||||
matches.update(['episode'])
|
||||
# All the search is already based on the series_imdb_id when present in the video and controlled via the
|
||||
# the legendasdivx backend it, so if there is a result, it matches, either inside of a pack or a specific
|
||||
# series and episode, so we can assume the season and episode matches.
|
||||
if video.series_imdb_id:
|
||||
matches.update(['series', 'series_imdb_id', 'season', 'episode'])
|
||||
|
||||
# release_group
|
||||
if video.release_group and sanitize_release_group(video.release_group) in sanitize_release_group(description):
|
||||
|
@ -121,6 +129,7 @@ class LegendasdivxSubtitle(Subtitle):
|
|||
|
||||
return matches
|
||||
|
||||
|
||||
class LegendasdivxProvider(Provider):
|
||||
"""Legendasdivx Provider."""
|
||||
languages = {Language('por', 'BR')} | {Language('por')}
|
||||
|
@ -135,7 +144,7 @@ class LegendasdivxProvider(Provider):
|
|||
'Referer': 'https://www.legendasdivx.pt'
|
||||
}
|
||||
loginpage = site + '/forum/ucp.php?mode=login'
|
||||
searchurl = site + '/modules.php?name=Downloads&file=jz&d_op=search&op=_jz00&query={query}'
|
||||
searchurl = site + '/modules.php?name=Downloads&file=jz&d_op={d_op}&op={op}&query={query}&temporada={season}&episodio={episode}&imdb={imdbid}'
|
||||
download_link = site + '/modules.php{link}'
|
||||
|
||||
def __init__(self, username, password, skip_wrong_fps=True):
|
||||
|
@ -186,7 +195,8 @@ class LegendasdivxProvider(Provider):
|
|||
res = self.session.post(self.loginpage, data)
|
||||
res.raise_for_status()
|
||||
# make sure we're logged in
|
||||
logger.debug('Legendasdivx.pt :: Logged in successfully: PHPSESSID: %s', self.session.cookies.get_dict()['PHPSESSID'])
|
||||
logger.debug('Legendasdivx.pt :: Logged in successfully: PHPSESSID: %s',
|
||||
self.session.cookies.get_dict()['PHPSESSID'])
|
||||
cj = self.session.cookies.copy()
|
||||
store_cks = ("PHPSESSID", "phpbb3_2z8zs_sid", "phpbb3_2z8zs_k", "phpbb3_2z8zs_u", "lang")
|
||||
for cn in iter(self.session.cookies.keys()):
|
||||
|
@ -252,7 +262,7 @@ class LegendasdivxProvider(Provider):
|
|||
continue
|
||||
|
||||
# get subtitle uploader
|
||||
sub_header = _subbox.find("div", {"class" :"sub_header"})
|
||||
sub_header = _subbox.find("div", {"class": "sub_header"})
|
||||
uploader = sub_header.find("a").text if sub_header else 'anonymous'
|
||||
|
||||
exact_match = False
|
||||
|
@ -278,12 +288,24 @@ class LegendasdivxProvider(Provider):
|
|||
|
||||
subtitles = []
|
||||
|
||||
# Set the default search criteria
|
||||
d_op = 'search'
|
||||
op = '_jz00'
|
||||
|
||||
lang_filter_key = 'form_cat'
|
||||
|
||||
if isinstance(video, Movie):
|
||||
querytext = video.imdb_id if video.imdb_id else video.title
|
||||
|
||||
if isinstance(video, Episode):
|
||||
querytext = '%22{}%20S{:02d}E{:02d}%22'.format(video.series, video.season, video.episode)
|
||||
querytext = quote(querytext.lower())
|
||||
# Overwrite the parameters to refine via imdb_id
|
||||
if video.series_imdb_id:
|
||||
querytext = '&faz=pesquisa_episodio'
|
||||
lang_filter_key = 'idioma'
|
||||
d_op = 'jz_00'
|
||||
op = ''
|
||||
else:
|
||||
querytext = '%22{}%22%20S{:02d}E{:02d}'.format(video.series, video.season, video.episode)
|
||||
querytext = quote(querytext.lower())
|
||||
|
||||
# language query filter
|
||||
if not isinstance(languages, (tuple, list, set)):
|
||||
|
@ -293,21 +315,30 @@ class LegendasdivxProvider(Provider):
|
|||
logger.debug("Legendasdivx.pt :: searching for %s subtitles.", language)
|
||||
language_id = language.opensubtitles
|
||||
if 'por' in language_id:
|
||||
lang_filter = '&form_cat=28'
|
||||
lang_filter = '&{}=28'.format(lang_filter_key)
|
||||
elif 'pob' in language_id:
|
||||
lang_filter = '&form_cat=29'
|
||||
lang_filter = '&{}=29'.format(lang_filter_key)
|
||||
else:
|
||||
lang_filter = ''
|
||||
|
||||
querytext = querytext + lang_filter if lang_filter else querytext
|
||||
|
||||
search_url = _searchurl.format(
|
||||
query=querytext,
|
||||
season=video.season,
|
||||
episode=video.episode,
|
||||
imdbid=video.series_imdb_id.replace('tt', '') if video.series_imdb_id else None,
|
||||
op=op,
|
||||
d_op=d_op,
|
||||
)
|
||||
|
||||
try:
|
||||
# sleep for a 1 second before another request
|
||||
sleep(1)
|
||||
searchLimitReached = False
|
||||
self.headers['Referer'] = self.site + '/index.php'
|
||||
self.session.headers.update(self.headers)
|
||||
res = self.session.get(_searchurl.format(query=querytext), allow_redirects=False)
|
||||
res = self.session.get(search_url, allow_redirects=False)
|
||||
res.raise_for_status()
|
||||
if res.status_code == 200 and "<!--pesquisas:" in res.text:
|
||||
searches_count_groups = re.search(r'<!--pesquisas: (\d*)-->', res.text)
|
||||
|
@ -327,7 +358,7 @@ class LegendasdivxProvider(Provider):
|
|||
querytext = re.sub(r"(e|E)(\d{2})", "", querytext)
|
||||
# sleep for a 1 second before another request
|
||||
sleep(1)
|
||||
res = self.session.get(_searchurl.format(query=querytext), allow_redirects=False)
|
||||
res = self.session.get(search_url, allow_redirects=False)
|
||||
res.raise_for_status()
|
||||
if res.status_code == 200 and "<!--pesquisas:" in res.text:
|
||||
searches_count_groups = re.search(r'<!--pesquisas: (\d*)-->', res.text)
|
||||
|
@ -340,9 +371,11 @@ class LegendasdivxProvider(Provider):
|
|||
if searches_count >= self.SAFE_SEARCH_LIMIT:
|
||||
searchLimitReached = True
|
||||
if (res.status_code == 200 and "A legenda não foi encontrada" in res.text):
|
||||
logger.warning('Legendasdivx.pt :: query {0} return no results for language {1}(for series and season only).'.format(querytext, language_id))
|
||||
logger.warning(
|
||||
'Legendasdivx.pt :: query {0} return no results for language {1}(for series and season only).'.format(
|
||||
querytext, language_id))
|
||||
continue
|
||||
if res.status_code == 302: # got redirected to login page.
|
||||
if res.status_code == 302: # got redirected to login page.
|
||||
# seems that our session cookies are no longer valid... clean them from cache
|
||||
region.delete("legendasdivx_cookies2")
|
||||
logger.debug("Legendasdivx.pt :: Logging in again. Cookies have expired!")
|
||||
|
@ -350,7 +383,7 @@ class LegendasdivxProvider(Provider):
|
|||
self.login()
|
||||
# sleep for a 1 second before another request
|
||||
sleep(1)
|
||||
res = self.session.get(_searchurl.format(query=querytext))
|
||||
res = self.session.get(search_url, allow_redirects=False)
|
||||
res.raise_for_status()
|
||||
if res.status_code == 200 and "<!--pesquisas:" in res.text:
|
||||
searches_count_groups = re.search(r'<!--pesquisas: (\d*)-->', res.text)
|
||||
|
@ -394,9 +427,9 @@ class LegendasdivxProvider(Provider):
|
|||
|
||||
# more pages?
|
||||
if num_pages > 1:
|
||||
for num_page in range(2, num_pages+1):
|
||||
for num_page in range(2, num_pages + 1):
|
||||
sleep(1) # another 1 sec before requesting...
|
||||
_search_next = self.searchurl.format(query=querytext) + "&page={0}".format(str(num_page))
|
||||
_search_next = search_url + "&page={0}".format(str(num_page))
|
||||
logger.debug("Legendasdivx.pt :: Moving on to next page: %s", _search_next)
|
||||
# sleep for a 1 second before another request
|
||||
sleep(1)
|
||||
|
@ -409,7 +442,7 @@ class LegendasdivxProvider(Provider):
|
|||
|
||||
def list_subtitles(self, video, languages):
|
||||
return self.query(video, languages)
|
||||
|
||||
|
||||
@reinitialize_on_error((RequestException,), attempts=1)
|
||||
def download_subtitle(self, subtitle):
|
||||
|
||||
|
@ -478,7 +511,8 @@ class LegendasdivxProvider(Provider):
|
|||
if isinstance(subtitle.video, Episode):
|
||||
if all(key in _guess for key in ('season', 'episode')):
|
||||
logger.debug("Legendasdivx.pt :: guessing %s", name)
|
||||
logger.debug("Legendasdivx.pt :: subtitle S%sE%s video S%sE%s", _guess['season'], _guess['episode'], subtitle.video.season, subtitle.video.episode)
|
||||
logger.debug("Legendasdivx.pt :: subtitle S%sE%s video S%sE%s", _guess['season'], _guess['episode'],
|
||||
subtitle.video.season, subtitle.video.episode)
|
||||
|
||||
if subtitle.video.episode != _guess['episode'] or subtitle.video.season != _guess['season']:
|
||||
logger.debug('Legendasdivx.pt :: subtitle does not match video, skipping')
|
||||
|
|
|
@ -13,7 +13,7 @@ import pysrt
|
|||
import pysubs2
|
||||
from bs4 import UnicodeDammit
|
||||
from pysubs2 import SSAStyle
|
||||
from pysubs2.subrip import parse_tags, MAX_REPRESENTABLE_TIME
|
||||
from pysubs2.formats.subrip import parse_tags, MAX_REPRESENTABLE_TIME
|
||||
from pysubs2.time import ms_to_times
|
||||
from subzero.modification import SubtitleModifications
|
||||
from subzero.language import Language
|
||||
|
|
|
@ -2,6 +2,13 @@
|
|||
"rules": {
|
||||
"no-console": "error",
|
||||
"camelcase": "warn",
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": ["..*"]
|
||||
}
|
||||
],
|
||||
"simple-import-sort/imports": "error",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-empty-function": "warn",
|
||||
"@typescript-eslint/no-empty-interface": "off",
|
||||
|
@ -13,7 +20,7 @@
|
|||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"plugins": ["testing-library"],
|
||||
"plugins": ["testing-library", "simple-import-sort"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
|
@ -21,6 +28,43 @@
|
|||
"**/?(*.)+(spec|test).[jt]s?(x)"
|
||||
],
|
||||
"extends": ["plugin:testing-library/react"]
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {
|
||||
"simple-import-sort/imports": [
|
||||
"error",
|
||||
{
|
||||
"groups": [
|
||||
[
|
||||
// React Packages
|
||||
"^react",
|
||||
// Mantine Packages
|
||||
"^@mantine/",
|
||||
// Vendor Packages
|
||||
"^(\\w|@\\w)",
|
||||
// Side Effect Imports
|
||||
"^\\u0000",
|
||||
// Internal Packages
|
||||
"^@/\\w",
|
||||
// Parent Imports
|
||||
"^\\.\\.(?!/?$)",
|
||||
"^\\.\\./?$",
|
||||
// Relative Imports
|
||||
"^\\./(?=.*/)(?!/?$)",
|
||||
"^\\.(?!/?$)",
|
||||
"^\\./?$",
|
||||
// Style Imports
|
||||
"^.+\\.?(css)$"
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": "latest"
|
||||
}
|
||||
}
|
||||
|
|
37
frontend/package-lock.json
generated
37
frontend/package-lock.json
generated
|
@ -19,7 +19,7 @@
|
|||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-query": "^3.39.3",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"react-router-dom": "^6.23.1",
|
||||
"socket.io-client": "^4.7.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -45,6 +45,7 @@
|
|||
"eslint": "^8.57.0",
|
||||
"eslint-config-react-app": "^7.0.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-simple-import-sort": "^12.1.0",
|
||||
"eslint-plugin-testing-library": "^6.2.0",
|
||||
"husky": "^9.0.11",
|
||||
"jsdom": "^24.0.0",
|
||||
|
@ -3111,9 +3112,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz",
|
||||
"integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==",
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz",
|
||||
"integrity": "sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
|
@ -6101,6 +6102,16 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-simple-import-sort": {
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.0.tgz",
|
||||
"integrity": "sha512-Y2fqAfC11TcG/WP3TrI1Gi3p3nc8XJyEOJYHyEPEGI/UAgNx6akxxlX74p7SbAQdLcgASKhj8M0GKvH3vq/+ig==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"eslint": ">=5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-testing-library": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-6.2.0.tgz",
|
||||
|
@ -8926,11 +8937,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "6.22.3",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz",
|
||||
"integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==",
|
||||
"version": "6.23.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.1.tgz",
|
||||
"integrity": "sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.15.3"
|
||||
"@remix-run/router": "1.16.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
|
@ -8940,12 +8951,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "6.22.3",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz",
|
||||
"integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==",
|
||||
"version": "6.23.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz",
|
||||
"integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.15.3",
|
||||
"react-router": "6.22.3"
|
||||
"@remix-run/router": "1.16.1",
|
||||
"react-router": "6.23.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-query": "^3.39.3",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"react-router-dom": "^6.23.1",
|
||||
"socket.io-client": "^4.7.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -49,6 +49,7 @@
|
|||
"eslint": "^8.57.0",
|
||||
"eslint-config-react-app": "^7.0.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-simple-import-sort": "^12.1.0",
|
||||
"eslint-plugin-testing-library": "^6.2.0",
|
||||
"husky": "^9.0.11",
|
||||
"jsdom": "^24.0.0",
|
||||
|
@ -72,6 +73,7 @@
|
|||
"build": "vite build",
|
||||
"build:ci": "vite build -m development",
|
||||
"check": "eslint --ext .ts,.tsx src",
|
||||
"check:fix": "eslint --ext .ts,.tsx src --fix",
|
||||
"check:ts": "tsc --noEmit --incremental false",
|
||||
"check:fmt": "prettier -c .",
|
||||
"test": "vitest",
|
||||
|
|
|
@ -1,14 +1,4 @@
|
|||
import { useSystem, useSystemSettings } from "@/apis/hooks";
|
||||
import { Action, Search } from "@/components";
|
||||
import { useNavbar } from "@/contexts/Navbar";
|
||||
import { useIsOnline } from "@/contexts/Online";
|
||||
import { Environment, useGotoHomepage } from "@/utilities";
|
||||
import {
|
||||
faArrowRotateLeft,
|
||||
faGear,
|
||||
faPowerOff,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { FunctionComponent } from "react";
|
||||
import {
|
||||
Anchor,
|
||||
AppShell,
|
||||
|
@ -19,7 +9,17 @@ import {
|
|||
Group,
|
||||
Menu,
|
||||
} from "@mantine/core";
|
||||
import { FunctionComponent } from "react";
|
||||
import {
|
||||
faArrowRotateLeft,
|
||||
faGear,
|
||||
faPowerOff,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useSystem, useSystemSettings } from "@/apis/hooks";
|
||||
import { Action, Search } from "@/components";
|
||||
import { useNavbar } from "@/contexts/Navbar";
|
||||
import { useIsOnline } from "@/contexts/Online";
|
||||
import { Environment, useGotoHomepage } from "@/utilities";
|
||||
import styles from "./Header.module.scss";
|
||||
|
||||
const AppHeader: FunctionComponent = () => {
|
||||
|
@ -52,7 +52,7 @@ const AppHeader: FunctionComponent = () => {
|
|||
size="sm"
|
||||
hiddenFrom="sm"
|
||||
></Burger>
|
||||
<Badge size="lg" radius="sm">
|
||||
<Badge size="lg" radius="sm" variant="brand">
|
||||
Bazarr
|
||||
</Badge>
|
||||
</Group>
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
import { Action } from "@/components";
|
||||
import { useNavbar } from "@/contexts/Navbar";
|
||||
import { useRouteItems } from "@/Router";
|
||||
import { CustomRouteObject, Route } from "@/Router/type";
|
||||
import { BuildKey, pathJoin } from "@/utilities";
|
||||
import { LOG } from "@/utilities/console";
|
||||
import {
|
||||
faHeart,
|
||||
faMoon,
|
||||
faSun,
|
||||
IconDefinition,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import React, {
|
||||
createContext,
|
||||
FunctionComponent,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import { matchPath, NavLink, RouteObject, useLocation } from "react-router-dom";
|
||||
import {
|
||||
Anchor,
|
||||
AppShell,
|
||||
|
@ -24,16 +20,20 @@ import {
|
|||
useMantineColorScheme,
|
||||
} from "@mantine/core";
|
||||
import { useHover } from "@mantine/hooks";
|
||||
import {
|
||||
faHeart,
|
||||
faMoon,
|
||||
faSun,
|
||||
IconDefinition,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import clsx from "clsx";
|
||||
import React, {
|
||||
createContext,
|
||||
FunctionComponent,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import { matchPath, NavLink, RouteObject, useLocation } from "react-router-dom";
|
||||
import { Action } from "@/components";
|
||||
import { useNavbar } from "@/contexts/Navbar";
|
||||
import { useRouteItems } from "@/Router";
|
||||
import { CustomRouteObject, Route } from "@/Router/type";
|
||||
import { BuildKey, pathJoin } from "@/utilities";
|
||||
import { LOG } from "@/utilities/console";
|
||||
import styles from "./Navbar.module.scss";
|
||||
|
||||
const Selection = createContext<{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { FunctionComponent, PropsWithChildren } from "react";
|
||||
import {
|
||||
ActionIcon,
|
||||
AppShell,
|
||||
|
@ -5,16 +6,17 @@ import {
|
|||
Button,
|
||||
createTheme,
|
||||
MantineProvider,
|
||||
Pagination,
|
||||
} from "@mantine/core";
|
||||
import { FunctionComponent, PropsWithChildren } from "react";
|
||||
import ThemeLoader from "@/App/ThemeLoader";
|
||||
import "@mantine/core/styles.layer.css";
|
||||
import "@mantine/notifications/styles.layer.css";
|
||||
import styleVars from "@/assets/_variables.module.scss";
|
||||
import buttonClasses from "@/assets/button.module.scss";
|
||||
import actionIconClasses from "@/assets/action_icon.module.scss";
|
||||
import appShellClasses from "@/assets/app_shell.module.scss";
|
||||
import badgeClasses from "@/assets/badge.module.scss";
|
||||
import buttonClasses from "@/assets/button.module.scss";
|
||||
import paginationClasses from "@/assets/pagination.module.scss";
|
||||
|
||||
const themeProvider = createTheme({
|
||||
fontFamily: "Roboto, open sans, Helvetica Neue, Helvetica, Arial, sans-serif",
|
||||
|
@ -46,6 +48,9 @@ const themeProvider = createTheme({
|
|||
Button: Button.extend({
|
||||
classNames: buttonClasses,
|
||||
}),
|
||||
Pagination: Pagination.extend({
|
||||
classNames: paginationClasses,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { render } from "@/tests";
|
||||
import { describe, it } from "vitest";
|
||||
import { render } from "@/tests";
|
||||
import App from ".";
|
||||
|
||||
describe("App", () => {
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { FunctionComponent, useEffect, useState } from "react";
|
||||
import { Outlet, useNavigate } from "react-router-dom";
|
||||
import { AppShell } from "@mantine/core";
|
||||
import { useWindowEvent } from "@mantine/hooks";
|
||||
import { showNotification } from "@mantine/notifications";
|
||||
import AppNavbar from "@/App/Navbar";
|
||||
import { RouterNames } from "@/Router/RouterNames";
|
||||
import ErrorBoundary from "@/components/ErrorBoundary";
|
||||
import NavbarProvider from "@/contexts/Navbar";
|
||||
import OnlineProvider from "@/contexts/Online";
|
||||
import { notification } from "@/modules/task";
|
||||
import CriticalError from "@/pages/errors/CriticalError";
|
||||
import { RouterNames } from "@/Router/RouterNames";
|
||||
import { Environment } from "@/utilities";
|
||||
import { AppShell } from "@mantine/core";
|
||||
import { useWindowEvent } from "@mantine/hooks";
|
||||
import { showNotification } from "@mantine/notifications";
|
||||
import { FunctionComponent, useEffect, useState } from "react";
|
||||
import { Outlet, useNavigate } from "react-router-dom";
|
||||
import AppHeader from "./Header";
|
||||
import styleVars from "@/assets/_variables.module.scss";
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useSystemSettings } from "@/apis/hooks";
|
||||
import { LoadingOverlay } from "@mantine/core";
|
||||
import { FunctionComponent, useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { LoadingOverlay } from "@mantine/core";
|
||||
import { useSystemSettings } from "@/apis/hooks";
|
||||
|
||||
const Redirector: FunctionComponent = () => {
|
||||
const { data } = useSystemSettings();
|
||||
|
|
|
@ -1,11 +1,29 @@
|
|||
import App from "@/App";
|
||||
import {
|
||||
createContext,
|
||||
FunctionComponent,
|
||||
lazy,
|
||||
useContext,
|
||||
useMemo,
|
||||
} from "react";
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
import {
|
||||
faClock,
|
||||
faCogs,
|
||||
faExclamationTriangle,
|
||||
faFileExcel,
|
||||
faFilm,
|
||||
faLaptop,
|
||||
faPlay,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { useBadges } from "@/apis/hooks";
|
||||
import { useEnabledStatus } from "@/apis/hooks/site";
|
||||
import App from "@/App";
|
||||
import { Lazy } from "@/components/async";
|
||||
import Authentication from "@/pages/Authentication";
|
||||
import BlacklistMoviesView from "@/pages/Blacklist/Movies";
|
||||
import BlacklistSeriesView from "@/pages/Blacklist/Series";
|
||||
import Episodes from "@/pages/Episodes";
|
||||
import NotFound from "@/pages/errors/NotFound";
|
||||
import MoviesHistoryView from "@/pages/History/Movies";
|
||||
import SeriesHistoryView from "@/pages/History/Series";
|
||||
import MovieView from "@/pages/Movies";
|
||||
|
@ -30,25 +48,7 @@ import SystemReleasesView from "@/pages/System/Releases";
|
|||
import SystemTasksView from "@/pages/System/Tasks";
|
||||
import WantedMoviesView from "@/pages/Wanted/Movies";
|
||||
import WantedSeriesView from "@/pages/Wanted/Series";
|
||||
import NotFound from "@/pages/errors/NotFound";
|
||||
import { Environment } from "@/utilities";
|
||||
import {
|
||||
faClock,
|
||||
faCogs,
|
||||
faExclamationTriangle,
|
||||
faFileExcel,
|
||||
faFilm,
|
||||
faLaptop,
|
||||
faPlay,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import {
|
||||
FunctionComponent,
|
||||
createContext,
|
||||
lazy,
|
||||
useContext,
|
||||
useMemo,
|
||||
} from "react";
|
||||
import { RouterProvider, createBrowserRouter } from "react-router-dom";
|
||||
import Redirector from "./Redirector";
|
||||
import { RouterNames } from "./RouterNames";
|
||||
import { CustomRouteObject } from "./type";
|
||||
|
|
2
frontend/src/Router/type.d.ts
vendored
2
frontend/src/Router/type.d.ts
vendored
|
@ -1,5 +1,5 @@
|
|||
import { IconDefinition } from "@fortawesome/free-solid-svg-icons";
|
||||
import { RouteObject } from "react-router-dom";
|
||||
import { IconDefinition } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
declare namespace Route {
|
||||
export type Item = {
|
||||
|
|
|
@ -4,9 +4,9 @@ import {
|
|||
useQuery,
|
||||
useQueryClient,
|
||||
} from "react-query";
|
||||
import { usePaginationQuery } from "../queries/hooks";
|
||||
import { QueryKeys } from "../queries/keys";
|
||||
import api from "../raw";
|
||||
import { usePaginationQuery } from "@/apis/queries/hooks";
|
||||
import { QueryKeys } from "@/apis/queries/keys";
|
||||
import api from "@/apis/raw";
|
||||
|
||||
const cacheEpisodes = (client: QueryClient, episodes: Item.Episode[]) => {
|
||||
episodes.forEach((item) => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useQuery } from "react-query";
|
||||
import { QueryKeys } from "../queries/keys";
|
||||
import api from "../raw";
|
||||
import { QueryKeys } from "@/apis/queries/keys";
|
||||
import api from "@/apis/raw";
|
||||
|
||||
export function useHistoryStats(
|
||||
time: History.TimeFrameOptions,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useQuery } from "react-query";
|
||||
import { QueryKeys } from "../queries/keys";
|
||||
import api from "../raw";
|
||||
import { QueryKeys } from "@/apis/queries/keys";
|
||||
import api from "@/apis/raw";
|
||||
|
||||
export function useLanguages(history?: boolean) {
|
||||
return useQuery(
|
||||
|
|
|
@ -4,9 +4,9 @@ import {
|
|||
useQuery,
|
||||
useQueryClient,
|
||||
} from "react-query";
|
||||
import { usePaginationQuery } from "../queries/hooks";
|
||||
import { QueryKeys } from "../queries/keys";
|
||||
import api from "../raw";
|
||||
import { usePaginationQuery } from "@/apis/queries/hooks";
|
||||
import { QueryKeys } from "@/apis/queries/keys";
|
||||
import api from "@/apis/raw";
|
||||
|
||||
const cacheMovies = (client: QueryClient, movies: Item.Movie[]) => {
|
||||
movies.forEach((item) => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
import { QueryKeys } from "../queries/keys";
|
||||
import api from "../raw";
|
||||
import { QueryKeys } from "@/apis/queries/keys";
|
||||
import api from "@/apis/raw";
|
||||
|
||||
export function useSystemProviders(history?: boolean) {
|
||||
return useQuery(
|
||||
|
|
|
@ -4,9 +4,9 @@ import {
|
|||
useQuery,
|
||||
useQueryClient,
|
||||
} from "react-query";
|
||||
import { usePaginationQuery } from "../queries/hooks";
|
||||
import { QueryKeys } from "../queries/keys";
|
||||
import api from "../raw";
|
||||
import { usePaginationQuery } from "@/apis/queries/hooks";
|
||||
import { QueryKeys } from "@/apis/queries/keys";
|
||||
import api from "@/apis/raw";
|
||||
|
||||
function cacheSeries(client: QueryClient, series: Item.Series[]) {
|
||||
series.forEach((item) => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useIsMutating } from "react-query";
|
||||
import { QueryKeys } from "../queries/keys";
|
||||
import { QueryKeys } from "@/apis/queries/keys";
|
||||
|
||||
export function useIsAnyActionRunning() {
|
||||
return useIsMutating([QueryKeys.Actions]) > 0;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
import { QueryKeys } from "../queries/keys";
|
||||
import api from "../raw";
|
||||
import { QueryKeys } from "@/apis/queries/keys";
|
||||
import api from "@/apis/raw";
|
||||
|
||||
export function useSubtitleAction() {
|
||||
const client = useQueryClient();
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { Environment } from "@/utilities";
|
||||
import { setAuthenticated } from "@/utilities/event";
|
||||
import { useMemo } from "react";
|
||||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
import { QueryKeys } from "../queries/keys";
|
||||
import api from "../raw";
|
||||
import { QueryKeys } from "@/apis/queries/keys";
|
||||
import api from "@/apis/raw";
|
||||
import { Environment } from "@/utilities";
|
||||
import { setAuthenticated } from "@/utilities/event";
|
||||
|
||||
export function useBadges() {
|
||||
return useQuery(
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { GetItemId, useOnValueChange } from "@/utilities";
|
||||
import { usePageSize } from "@/utilities/storage";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
QueryKey,
|
||||
UseQueryResult,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
UseQueryResult,
|
||||
} from "react-query";
|
||||
import { GetItemId, useOnValueChange } from "@/utilities";
|
||||
import { usePageSize } from "@/utilities/storage";
|
||||
import { QueryKeys } from "./keys";
|
||||
|
||||
export type UsePaginationQueryResult<T extends object> = UseQueryResult<
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import socketio from "@/modules/socketio";
|
||||
import { notification } from "@/modules/task";
|
||||
import { LOG } from "@/utilities/console";
|
||||
import { setAuthenticated } from "@/utilities/event";
|
||||
import { showNotification } from "@mantine/notifications";
|
||||
import Axios, { AxiosError, AxiosInstance, CancelTokenSource } from "axios";
|
||||
import { Environment } from "../../utilities";
|
||||
import socketio from "@/modules/socketio";
|
||||
import { notification } from "@/modules/task";
|
||||
import { Environment } from "@/utilities";
|
||||
import { LOG } from "@/utilities/console";
|
||||
import { setAuthenticated } from "@/utilities/event";
|
||||
|
||||
function GetErrorMessage(data: unknown, defaultMsg = "Unknown error"): string {
|
||||
if (typeof data === "string") {
|
||||
|
|
|
@ -9,6 +9,42 @@ $color-brand-7: #ae3ec9;
|
|||
$color-brand-8: #9c36b5;
|
||||
$color-brand-9: #862e9c;
|
||||
|
||||
// Based on Mantine Cyan
|
||||
$color-highlight-0: #e3fafc;
|
||||
$color-highlight-1: #c5f6fa;
|
||||
$color-highlight-2: #99e9f2;
|
||||
$color-highlight-3: #66d9e8;
|
||||
$color-highlight-4: #3bc9db;
|
||||
$color-highlight-5: #22b8cf;
|
||||
$color-highlight-6: #15aabf;
|
||||
$color-highlight-7: #1098ad;
|
||||
$color-highlight-8: #0c8599;
|
||||
$color-highlight-9: #0b7285;
|
||||
|
||||
// Based on Mantine Yellow
|
||||
$color-warning-0: #fff9db;
|
||||
$color-warning-1: #fff3bf;
|
||||
$color-warning-2: #ffec99;
|
||||
$color-warning-3: #ffe066;
|
||||
$color-warning-4: #ffd43b;
|
||||
$color-warning-5: #fcc419;
|
||||
$color-warning-6: #fab005;
|
||||
$color-warning-7: #f59f00;
|
||||
$color-warning-8: #f08c00;
|
||||
$color-warning-9: #e67700;
|
||||
|
||||
// Based on Mantine Gray
|
||||
$color-disabled-0: #f8f9fa;
|
||||
$color-disabled-1: #f1f3f5;
|
||||
$color-disabled-2: #e9ecef;
|
||||
$color-disabled-3: #dee2e6;
|
||||
$color-disabled-4: #ced4da;
|
||||
$color-disabled-5: #adb5bd;
|
||||
$color-disabled-6: #868e96;
|
||||
$color-disabled-7: #495057;
|
||||
$color-disabled-8: #343a40;
|
||||
$color-disabled-9: #212529;
|
||||
|
||||
$header-height: 64px;
|
||||
|
||||
:global {
|
||||
|
|
|
@ -1,14 +1,25 @@
|
|||
@layer mantine {
|
||||
.root {
|
||||
background-color: transparent;
|
||||
|
||||
&[data-variant="light"] {
|
||||
color: var(--mantine-color-dark-0);
|
||||
}
|
||||
|
||||
&[data-variant="dark"] {
|
||||
--ai-bg: transparent;
|
||||
--ai-hover: darken(var(--mantine-color-grape-light), 0.2);
|
||||
}
|
||||
|
||||
@include light {
|
||||
&[data-variant="light"] {
|
||||
background-color: var(--mantine-color-gray-1);
|
||||
color: var(--mantine-color-dark-2);
|
||||
}
|
||||
|
||||
&[data-variant="dark"] {
|
||||
--ai-color: var(--mantine-color-dark-filled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
.main {
|
||||
@include dark {
|
||||
background-color: rgb(26, 27, 30);
|
||||
@layer mantine {
|
||||
.main {
|
||||
@include dark {
|
||||
background-color: var(--mantine-color-dark-8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,40 @@
|
|||
.root {
|
||||
background-color: var(--mantine-color-grape-light);
|
||||
@layer mantine {
|
||||
.root {
|
||||
background-color: transparentize($color-brand-6, 0.8);
|
||||
|
||||
@include light {
|
||||
color: var(--mantine-color-dark-filled);
|
||||
background-color: var(--mantine-color-grape-light);
|
||||
&[data-variant="warning"] {
|
||||
color: lighten($color-warning-2, 1);
|
||||
background-color: transparentize($color-warning-6, 0.8);
|
||||
}
|
||||
|
||||
&[data-variant="highlight"] {
|
||||
color: lighten($color-highlight-2, 1);
|
||||
background-color: transparentize($color-highlight-5, 0.8);
|
||||
}
|
||||
|
||||
&[data-variant="disabled"] {
|
||||
color: lighten($color-disabled-0, 1);
|
||||
background-color: transparentize($color-disabled-7, 0.8);
|
||||
}
|
||||
|
||||
@include light {
|
||||
color: $color-brand-6;
|
||||
background-color: transparentize($color-brand-3, 0.8);
|
||||
|
||||
&[data-variant="warning"] {
|
||||
color: darken($color-warning-7, 1);
|
||||
background-color: transparentize($color-warning-6, 0.8);
|
||||
}
|
||||
|
||||
&[data-variant="disabled"] {
|
||||
color: darken($color-disabled-6, 1);
|
||||
background-color: transparentize($color-disabled-4, 0.8);
|
||||
}
|
||||
|
||||
&[data-variant="highlight"] {
|
||||
color: darken($color-highlight-6, 1);
|
||||
background-color: transparentize($color-highlight-5, 0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,4 +9,10 @@
|
|||
color: var(--mantine-color-red-0);
|
||||
}
|
||||
}
|
||||
|
||||
.root:disabled {
|
||||
@include dark {
|
||||
color: var(--mantine-color-dark-9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
3
frontend/src/assets/pagination.module.scss
Normal file
3
frontend/src/assets/pagination.module.scss
Normal file
|
@ -0,0 +1,3 @@
|
|||
.control {
|
||||
--pagination-active-bg: var(--mantine-color-brand-filled);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import UIError from "@/pages/errors/UIError";
|
||||
import { Component, PropsWithChildren } from "react";
|
||||
import UIError from "@/pages/errors/UIError";
|
||||
|
||||
interface State {
|
||||
error: Error | null;
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { useServerSearch } from "@/apis/hooks";
|
||||
import { useDebouncedValue } from "@/utilities";
|
||||
import { faSearch } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { FunctionComponent, useMemo, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import {
|
||||
Anchor,
|
||||
Autocomplete,
|
||||
ComboboxItem,
|
||||
OptionsFilter,
|
||||
} from "@mantine/core";
|
||||
import { FunctionComponent, useMemo, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { faSearch } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useServerSearch } from "@/apis/hooks";
|
||||
import { useDebouncedValue } from "@/utilities";
|
||||
import styles from "./Search.module.scss";
|
||||
|
||||
type SearchResultItem = {
|
||||
|
@ -19,7 +19,7 @@ type SearchResultItem = {
|
|||
|
||||
function useSearch(query: string) {
|
||||
const debouncedQuery = useDebouncedValue(query, 500);
|
||||
const { data } = useServerSearch(debouncedQuery, debouncedQuery.length > 0);
|
||||
const { data } = useServerSearch(debouncedQuery, debouncedQuery.length >= 0);
|
||||
|
||||
return useMemo<SearchResultItem[]>(
|
||||
() =>
|
||||
|
@ -32,7 +32,6 @@ function useSearch(query: string) {
|
|||
} else {
|
||||
throw new Error("Unknown search result");
|
||||
}
|
||||
|
||||
return {
|
||||
value: `${v.title} (${v.year})`,
|
||||
link,
|
||||
|
@ -92,6 +91,8 @@ const Search: FunctionComponent = () => {
|
|||
size="sm"
|
||||
data={results}
|
||||
value={query}
|
||||
scrollAreaProps={{ type: "auto" }}
|
||||
maxDropdownHeight={400}
|
||||
onChange={setQuery}
|
||||
onBlur={() => setQuery("")}
|
||||
filter={optionsFilter}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { BuildKey } from "@/utilities";
|
||||
import { FunctionComponent } from "react";
|
||||
import { Group, List, Popover, Stack, Text } from "@mantine/core";
|
||||
import { useHover } from "@mantine/hooks";
|
||||
import {
|
||||
faCheck,
|
||||
faCheckCircle,
|
||||
|
@ -7,9 +9,7 @@ import {
|
|||
faTimes,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Group, List, Popover, Stack, Text } from "@mantine/core";
|
||||
import { useHover } from "@mantine/hooks";
|
||||
import { FunctionComponent } from "react";
|
||||
import { BuildKey } from "@/utilities";
|
||||
|
||||
interface StateIconProps {
|
||||
matches: string[];
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
import { useSubtitleAction } from "@/apis/hooks";
|
||||
import { ColorToolModal } from "@/components/forms/ColorToolForm";
|
||||
import { FrameRateModal } from "@/components/forms/FrameRateForm";
|
||||
import { TimeOffsetModal } from "@/components/forms/TimeOffsetForm";
|
||||
import { TranslationModal } from "@/components/forms/TranslationForm";
|
||||
import { useModals } from "@/modules/modals";
|
||||
import { ModalComponent } from "@/modules/modals/WithModal";
|
||||
import { task } from "@/modules/task";
|
||||
import { FunctionComponent, ReactElement, useCallback, useMemo } from "react";
|
||||
import { Divider, List, Menu, MenuProps, ScrollArea } from "@mantine/core";
|
||||
import {
|
||||
faClock,
|
||||
faCode,
|
||||
|
@ -23,8 +17,14 @@ import {
|
|||
IconDefinition,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Divider, List, Menu, MenuProps, ScrollArea } from "@mantine/core";
|
||||
import { FunctionComponent, ReactElement, useCallback, useMemo } from "react";
|
||||
import { useSubtitleAction } from "@/apis/hooks";
|
||||
import { ColorToolModal } from "@/components/forms/ColorToolForm";
|
||||
import { FrameRateModal } from "@/components/forms/FrameRateForm";
|
||||
import { TimeOffsetModal } from "@/components/forms/TimeOffsetForm";
|
||||
import { TranslationModal } from "@/components/forms/TranslationForm";
|
||||
import { useModals } from "@/modules/modals";
|
||||
import { ModalComponent } from "@/modules/modals/WithModal";
|
||||
import { task } from "@/modules/task";
|
||||
import { SyncSubtitleModal } from "./forms/SyncSubtitleForm";
|
||||
|
||||
export interface ToolOptions {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { FunctionComponent, ReactElement } from "react";
|
||||
import { Tooltip, TooltipProps } from "@mantine/core";
|
||||
import { useHover } from "@mantine/hooks";
|
||||
import { isNull, isUndefined } from "lodash";
|
||||
import { FunctionComponent, ReactElement } from "react";
|
||||
|
||||
interface TextPopoverProps {
|
||||
children: ReactElement;
|
||||
|
@ -21,7 +21,12 @@ const TextPopover: FunctionComponent<TextPopoverProps> = ({
|
|||
}
|
||||
|
||||
return (
|
||||
<Tooltip opened={hovered} label={text} {...tooltip}>
|
||||
<Tooltip
|
||||
opened={hovered}
|
||||
label={text}
|
||||
{...tooltip}
|
||||
style={{ textWrap: "pretty" }}
|
||||
>
|
||||
<div ref={ref}>{children}</div>
|
||||
</Tooltip>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { LoadingOverlay } from "@mantine/core";
|
||||
import { FunctionComponent, PropsWithChildren, Suspense } from "react";
|
||||
import { LoadingOverlay } from "@mantine/core";
|
||||
|
||||
const Lazy: FunctionComponent<PropsWithChildren> = ({ children }) => {
|
||||
return <Suspense fallback={<LoadingOverlay visible />}>{children}</Suspense>;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useCallback, useState } from "react";
|
||||
import { UseMutationResult } from "react-query";
|
||||
import { Action } from "../inputs";
|
||||
import { ActionProps } from "../inputs/Action";
|
||||
import { Action } from "@/components/inputs";
|
||||
import { ActionProps } from "@/components/inputs/Action";
|
||||
|
||||
type MutateActionProps<DATA, VAR> = Omit<
|
||||
ActionProps,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Button, ButtonProps } from "@mantine/core";
|
||||
import { useCallback, useState } from "react";
|
||||
import { UseMutationResult } from "react-query";
|
||||
import { Button, ButtonProps } from "@mantine/core";
|
||||
|
||||
type MutateButtonProps<DATA, VAR> = Omit<
|
||||
ButtonProps,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { LoadingProvider } from "@/contexts";
|
||||
import { LoadingOverlay } from "@mantine/core";
|
||||
import { FunctionComponent, ReactNode } from "react";
|
||||
import { UseQueryResult } from "react-query";
|
||||
import { LoadingOverlay } from "@mantine/core";
|
||||
import { LoadingProvider } from "@/contexts";
|
||||
|
||||
interface QueryOverlayProps {
|
||||
result: UseQueryResult<unknown, unknown>;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BuildKey } from "@/utilities";
|
||||
import { Badge, BadgeProps, Group, GroupProps } from "@mantine/core";
|
||||
import { FunctionComponent } from "react";
|
||||
import { Badge, BadgeProps, Group, GroupProps } from "@mantine/core";
|
||||
import { BuildKey } from "@/utilities";
|
||||
|
||||
export type AudioListProps = GroupProps & {
|
||||
audios: Language.Info[];
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { FunctionComponent } from "react";
|
||||
import { Tooltip } from "@mantine/core";
|
||||
import {
|
||||
faClock,
|
||||
faClosedCaptioning,
|
||||
|
@ -9,8 +11,6 @@ import {
|
|||
faUser,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Tooltip } from "@mantine/core";
|
||||
import { FunctionComponent } from "react";
|
||||
|
||||
enum HistoryAction {
|
||||
Delete = 0,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { render, screen } from "@/tests";
|
||||
import { describe, it } from "vitest";
|
||||
import { render, screen } from "@/tests";
|
||||
import { Language } from ".";
|
||||
|
||||
describe("Language text", () => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BuildKey } from "@/utilities";
|
||||
import { Badge, Group, Text, TextProps } from "@mantine/core";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Badge, Group, Text, TextProps } from "@mantine/core";
|
||||
import { BuildKey } from "@/utilities";
|
||||
|
||||
type LanguageTextProps = TextProps & {
|
||||
value: Language.Info;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useLanguageProfiles } from "@/apis/hooks";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { useLanguageProfiles } from "@/apis/hooks";
|
||||
|
||||
interface Props {
|
||||
index: number | null;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { FunctionComponent, useMemo } from "react";
|
||||
import { useLanguages } from "@/apis/hooks";
|
||||
import { Selector, SelectorProps } from "@/components/inputs";
|
||||
import { useSelectorOptions } from "@/utilities";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
|
||||
interface LanguageSelectorProps
|
||||
extends Omit<SelectorProps<Language.Server>, "options" | "getkey"> {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { FunctionComponent } from "react";
|
||||
import { Button, Divider, Stack } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { useSubtitleAction } from "@/apis/hooks";
|
||||
import { Selector, SelectorOption } from "@/components";
|
||||
import { useModals, withModal } from "@/modules/modals";
|
||||
import { task } from "@/modules/task";
|
||||
import FormUtils from "@/utilities/form";
|
||||
import { Button, Divider, Stack } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { FunctionComponent } from "react";
|
||||
|
||||
const TaskName = "Changing Color";
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { FunctionComponent } from "react";
|
||||
import { Button, Divider, Group, NumberInput, Stack } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { useSubtitleAction } from "@/apis/hooks";
|
||||
import { useModals, withModal } from "@/modules/modals";
|
||||
import { task } from "@/modules/task";
|
||||
import FormUtils from "@/utilities/form";
|
||||
import { Button, Divider, Group, NumberInput, Stack } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { FunctionComponent } from "react";
|
||||
|
||||
const TaskName = "Changing Frame Rate";
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { FunctionComponent, useMemo } from "react";
|
||||
import { UseMutationResult } from "react-query";
|
||||
import { Button, Divider, Group, LoadingOverlay, Stack } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { useLanguageProfiles } from "@/apis/hooks";
|
||||
import { MultiSelector, Selector } from "@/components/inputs";
|
||||
import { useModals, withModal } from "@/modules/modals";
|
||||
import { GetItemId, useSelectorOptions } from "@/utilities";
|
||||
import { Button, Divider, Group, LoadingOverlay, Stack } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { UseMutationResult } from "react-query";
|
||||
|
||||
interface Props {
|
||||
mutation: UseMutationResult<void, unknown, FormType.ModifyItem, unknown>;
|
||||
|
|
|
@ -1,20 +1,5 @@
|
|||
import { useMovieSubtitleModification } from "@/apis/hooks";
|
||||
import { useModals, withModal } from "@/modules/modals";
|
||||
import { TaskGroup, task } from "@/modules/task";
|
||||
import { useArrayAction, useSelectorOptions } from "@/utilities";
|
||||
import FormUtils from "@/utilities/form";
|
||||
import {
|
||||
useLanguageProfileBy,
|
||||
useProfileItemsToLanguages,
|
||||
} from "@/utilities/languages";
|
||||
import {
|
||||
faCheck,
|
||||
faCircleNotch,
|
||||
faInfoCircle,
|
||||
faTimes,
|
||||
faTrash,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { FunctionComponent, useEffect, useMemo } from "react";
|
||||
import { Column } from "react-table";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
|
@ -24,12 +9,27 @@ import {
|
|||
Text,
|
||||
} from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import {
|
||||
faCheck,
|
||||
faCircleNotch,
|
||||
faInfoCircle,
|
||||
faTimes,
|
||||
faTrash,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { isString } from "lodash";
|
||||
import { FunctionComponent, useEffect, useMemo } from "react";
|
||||
import { Column } from "react-table";
|
||||
import TextPopover from "../TextPopover";
|
||||
import { Action, Selector } from "../inputs";
|
||||
import { SimpleTable } from "../tables";
|
||||
import { useMovieSubtitleModification } from "@/apis/hooks";
|
||||
import { Action, Selector } from "@/components/inputs";
|
||||
import { SimpleTable } from "@/components/tables";
|
||||
import TextPopover from "@/components/TextPopover";
|
||||
import { useModals, withModal } from "@/modules/modals";
|
||||
import { task, TaskGroup } from "@/modules/task";
|
||||
import { useArrayAction, useSelectorOptions } from "@/utilities";
|
||||
import FormUtils from "@/utilities/form";
|
||||
import {
|
||||
useLanguageProfileBy,
|
||||
useProfileItemsToLanguages,
|
||||
} from "@/utilities/languages";
|
||||
|
||||
type SubtitleFile = {
|
||||
file: File;
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
import { Action, Selector, SelectorOption, SimpleTable } from "@/components";
|
||||
import { useModals, withModal } from "@/modules/modals";
|
||||
import { useArrayAction, useSelectorOptions } from "@/utilities";
|
||||
import { LOG } from "@/utilities/console";
|
||||
import FormUtils from "@/utilities/form";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FunctionComponent, useCallback, useMemo } from "react";
|
||||
import { Column } from "react-table";
|
||||
import {
|
||||
Accordion,
|
||||
Button,
|
||||
|
@ -15,9 +11,13 @@ import {
|
|||
TextInput,
|
||||
} from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { FunctionComponent, useCallback, useMemo } from "react";
|
||||
import { Column } from "react-table";
|
||||
import ChipInput from "../inputs/ChipInput";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { Action, Selector, SelectorOption, SimpleTable } from "@/components";
|
||||
import ChipInput from "@/components/inputs/ChipInput";
|
||||
import { useModals, withModal } from "@/modules/modals";
|
||||
import { useArrayAction, useSelectorOptions } from "@/utilities";
|
||||
import { LOG } from "@/utilities/console";
|
||||
import FormUtils from "@/utilities/form";
|
||||
import styles from "./ProfileEditForm.module.scss";
|
||||
|
||||
export const anyCutoff = 65535;
|
||||
|
|
|
@ -1,24 +1,5 @@
|
|||
import {
|
||||
useEpisodesBySeriesId,
|
||||
useEpisodeSubtitleModification,
|
||||
useSubtitleInfos,
|
||||
} from "@/apis/hooks";
|
||||
import { useModals, withModal } from "@/modules/modals";
|
||||
import { task, TaskGroup } from "@/modules/task";
|
||||
import { useArrayAction, useSelectorOptions } from "@/utilities";
|
||||
import FormUtils from "@/utilities/form";
|
||||
import {
|
||||
useLanguageProfileBy,
|
||||
useProfileItemsToLanguages,
|
||||
} from "@/utilities/languages";
|
||||
import {
|
||||
faCheck,
|
||||
faCircleNotch,
|
||||
faInfoCircle,
|
||||
faTimes,
|
||||
faTrash,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { FunctionComponent, useEffect, useMemo } from "react";
|
||||
import { Column } from "react-table";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
|
@ -28,12 +9,31 @@ import {
|
|||
Text,
|
||||
} from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import {
|
||||
faCheck,
|
||||
faCircleNotch,
|
||||
faInfoCircle,
|
||||
faTimes,
|
||||
faTrash,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { isString } from "lodash";
|
||||
import { FunctionComponent, useEffect, useMemo } from "react";
|
||||
import { Column } from "react-table";
|
||||
import { Action, Selector } from "../inputs";
|
||||
import { SimpleTable } from "../tables";
|
||||
import TextPopover from "../TextPopover";
|
||||
import {
|
||||
useEpisodesBySeriesId,
|
||||
useEpisodeSubtitleModification,
|
||||
useSubtitleInfos,
|
||||
} from "@/apis/hooks";
|
||||
import { Action, Selector } from "@/components/inputs";
|
||||
import { SimpleTable } from "@/components/tables";
|
||||
import TextPopover from "@/components/TextPopover";
|
||||
import { useModals, withModal } from "@/modules/modals";
|
||||
import { task, TaskGroup } from "@/modules/task";
|
||||
import { useArrayAction, useSelectorOptions } from "@/utilities";
|
||||
import FormUtils from "@/utilities/form";
|
||||
import {
|
||||
useLanguageProfileBy,
|
||||
useProfileItemsToLanguages,
|
||||
} from "@/utilities/languages";
|
||||
|
||||
type SubtitleFile = {
|
||||
file: File;
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
/* eslint-disable camelcase */
|
||||
|
||||
import { FunctionComponent } from "react";
|
||||
import { Alert, Button, Checkbox, Divider, Stack, Text } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { faInfoCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
useRefTracksByEpisodeId,
|
||||
useRefTracksByMovieId,
|
||||
useSubtitleAction,
|
||||
} from "@/apis/hooks";
|
||||
import { GroupedSelector, Selector } from "@/components/inputs";
|
||||
import { useModals, withModal } from "@/modules/modals";
|
||||
import { task } from "@/modules/task";
|
||||
import { syncMaxOffsetSecondsOptions } from "@/pages/Settings/Subtitles/options";
|
||||
import { toPython } from "@/utilities";
|
||||
import { faInfoCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Alert, Button, Checkbox, Divider, Stack, Text } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { FunctionComponent } from "react";
|
||||
import { GroupedSelector, Selector } from "../inputs";
|
||||
|
||||
const TaskName = "Syncing Subtitle";
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { FunctionComponent } from "react";
|
||||
import { Button, Divider, Group, NumberInput, Stack } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { faMinus, faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useSubtitleAction } from "@/apis/hooks";
|
||||
import { useModals, withModal } from "@/modules/modals";
|
||||
import { task } from "@/modules/task";
|
||||
import FormUtils from "@/utilities/form";
|
||||
import { faMinus, faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Button, Divider, Group, NumberInput, Stack } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { FunctionComponent } from "react";
|
||||
|
||||
const TaskName = "Changing Time";
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Alert, Button, Divider, Stack } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { isObject } from "lodash";
|
||||
import { useSubtitleAction } from "@/apis/hooks";
|
||||
import { Selector } from "@/components/inputs";
|
||||
import { useModals, withModal } from "@/modules/modals";
|
||||
import { task } from "@/modules/task";
|
||||
import { useSelectorOptions } from "@/utilities";
|
||||
import FormUtils from "@/utilities/form";
|
||||
import { useEnabledLanguages } from "@/utilities/languages";
|
||||
import { Alert, Button, Divider, Stack } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { isObject } from "lodash";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Selector } from "../inputs";
|
||||
|
||||
const TaskName = "Translating Subtitles";
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { render, screen } from "@/tests";
|
||||
import { faStickyNote } from "@fortawesome/free-regular-svg-icons";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, it, vitest } from "vitest";
|
||||
import { render, screen } from "@/tests";
|
||||
import Action from "./Action";
|
||||
|
||||
const testLabel = "Test Label";
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { IconDefinition } from "@fortawesome/fontawesome-common-types";
|
||||
import {
|
||||
FontAwesomeIcon,
|
||||
FontAwesomeIconProps,
|
||||
} from "@fortawesome/react-fontawesome";
|
||||
import { forwardRef } from "react";
|
||||
import {
|
||||
ActionIcon,
|
||||
ActionIconProps,
|
||||
Tooltip,
|
||||
TooltipProps,
|
||||
} from "@mantine/core";
|
||||
import { forwardRef } from "react";
|
||||
import { IconDefinition } from "@fortawesome/fontawesome-common-types";
|
||||
import {
|
||||
FontAwesomeIcon,
|
||||
FontAwesomeIconProps,
|
||||
} from "@fortawesome/react-fontawesome";
|
||||
|
||||
export type ActionProps = MantineComp<ActionIconProps, "button"> & {
|
||||
icon: IconDefinition;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { render, screen } from "@/tests";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, it, vitest } from "vitest";
|
||||
import { render, screen } from "@/tests";
|
||||
import ChipInput from "./ChipInput";
|
||||
|
||||
describe("ChipInput", () => {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { FunctionComponent } from "react";
|
||||
import { Group, Stack, Text } from "@mantine/core";
|
||||
import { Dropzone } from "@mantine/dropzone";
|
||||
import {
|
||||
faArrowUp,
|
||||
faFileCirclePlus,
|
||||
faXmark,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Group, Stack, Text } from "@mantine/core";
|
||||
import { Dropzone } from "@mantine/dropzone";
|
||||
import { FunctionComponent } from "react";
|
||||
import styles from "./DropContent.module.scss";
|
||||
|
||||
export const DropContent: FunctionComponent = () => {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { useFileSystem } from "@/apis/hooks";
|
||||
import { faFolder } from "@fortawesome/free-regular-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { FunctionComponent, useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
Autocomplete,
|
||||
AutocompleteProps,
|
||||
ComboboxItem,
|
||||
OptionsFilter,
|
||||
} from "@mantine/core";
|
||||
import { FunctionComponent, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { faFolder } from "@fortawesome/free-regular-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useFileSystem } from "@/apis/hooks";
|
||||
|
||||
// TODO: use fortawesome icons
|
||||
const backKey = "⏎ Back";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { render, screen } from "@/tests";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, it, vitest } from "vitest";
|
||||
import { render, screen } from "@/tests";
|
||||
import { Selector, SelectorOption } from "./Selector";
|
||||
|
||||
const selectorName = "Test Selections";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { LOG } from "@/utilities/console";
|
||||
import { useCallback, useMemo, useRef } from "react";
|
||||
import {
|
||||
ComboboxItem,
|
||||
ComboboxParsedItemGroup,
|
||||
|
@ -8,7 +8,7 @@ import {
|
|||
SelectProps,
|
||||
} from "@mantine/core";
|
||||
import { isNull, isUndefined } from "lodash";
|
||||
import { useCallback, useMemo, useRef } from "react";
|
||||
import { LOG } from "@/utilities/console";
|
||||
|
||||
export type SelectorOption<T> = Override<
|
||||
{
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
/* eslint-disable camelcase */
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Column } from "react-table";
|
||||
import { Badge, Center, Text } from "@mantine/core";
|
||||
import { faFileExcel, faInfoCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
useEpisodeAddBlacklist,
|
||||
useEpisodeHistory,
|
||||
useMovieAddBlacklist,
|
||||
useMovieHistory,
|
||||
} from "@/apis/hooks";
|
||||
import { PageTable } from "@/components";
|
||||
import MutateAction from "@/components/async/MutateAction";
|
||||
import QueryOverlay from "@/components/async/QueryOverlay";
|
||||
import { HistoryIcon } from "@/components/bazarr";
|
||||
import Language from "@/components/bazarr/Language";
|
||||
import StateIcon from "@/components/StateIcon";
|
||||
import TextPopover from "@/components/TextPopover";
|
||||
import { withModal } from "@/modules/modals";
|
||||
import { faFileExcel, faInfoCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Badge, Center, Text } from "@mantine/core";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Column } from "react-table";
|
||||
import { PageTable } from "..";
|
||||
import TextPopover from "../TextPopover";
|
||||
import MutateAction from "../async/MutateAction";
|
||||
import QueryOverlay from "../async/QueryOverlay";
|
||||
import { HistoryIcon } from "../bazarr";
|
||||
import Language from "../bazarr/Language";
|
||||
|
||||
interface MovieHistoryViewProps {
|
||||
movie: Item.Movie;
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
import { withModal } from "@/modules/modals";
|
||||
import { task, TaskGroup } from "@/modules/task";
|
||||
import { GetItemId } from "@/utilities";
|
||||
import {
|
||||
faCaretDown,
|
||||
faDownload,
|
||||
faInfoCircle,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { UseQueryResult } from "react-query";
|
||||
import { Column } from "react-table";
|
||||
import {
|
||||
Alert,
|
||||
Anchor,
|
||||
|
@ -18,13 +12,19 @@ import {
|
|||
Stack,
|
||||
Text,
|
||||
} from "@mantine/core";
|
||||
import {
|
||||
faCaretDown,
|
||||
faDownload,
|
||||
faInfoCircle,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { isString } from "lodash";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { UseQueryResult } from "react-query";
|
||||
import { Column } from "react-table";
|
||||
import { Action, PageTable } from "..";
|
||||
import Language from "../bazarr/Language";
|
||||
import StateIcon from "../StateIcon";
|
||||
import { Action, PageTable } from "@/components";
|
||||
import Language from "@/components/bazarr/Language";
|
||||
import StateIcon from "@/components/StateIcon";
|
||||
import { withModal } from "@/modules/modals";
|
||||
import { task, TaskGroup } from "@/modules/task";
|
||||
import { GetItemId } from "@/utilities";
|
||||
|
||||
type SupportType = Item.Movie | Item.Episode;
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { FunctionComponent, useMemo, useState } from "react";
|
||||
import { Column, useRowSelect } from "react-table";
|
||||
import { Badge, Button, Divider, Group, Stack, Text } from "@mantine/core";
|
||||
import Language from "@/components/bazarr/Language";
|
||||
import SubtitleToolsMenu from "@/components/SubtitleToolsMenu";
|
||||
import { SimpleTable } from "@/components/tables";
|
||||
import { useCustomSelection } from "@/components/tables/plugins";
|
||||
import { withModal } from "@/modules/modals";
|
||||
import { isMovie } from "@/utilities";
|
||||
import { Badge, Button, Divider, Group, Stack, Text } from "@mantine/core";
|
||||
import { FunctionComponent, useMemo, useState } from "react";
|
||||
import { Column, useRowSelect } from "react-table";
|
||||
|
||||
type SupportType = Item.Episode | Item.Movie;
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { useIsLoading } from "@/contexts";
|
||||
import { usePageSize } from "@/utilities/storage";
|
||||
import { Box, Skeleton, Table, Text } from "@mantine/core";
|
||||
import { ReactNode, useMemo } from "react";
|
||||
import { HeaderGroup, Row, TableInstance } from "react-table";
|
||||
import { Box, Skeleton, Table, Text } from "@mantine/core";
|
||||
import { useIsLoading } from "@/contexts";
|
||||
import { usePageSize } from "@/utilities/storage";
|
||||
import styles from "./BaseTable.module.scss";
|
||||
|
||||
export type BaseTableProps<T extends object> = TableInstance<T> & {
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
import { faChevronCircleRight } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Box, Text, Table } from "@mantine/core";
|
||||
import {
|
||||
Cell,
|
||||
HeaderGroup,
|
||||
|
@ -9,6 +6,9 @@ import {
|
|||
useGroupBy,
|
||||
useSortBy,
|
||||
} from "react-table";
|
||||
import { Box, Table, Text } from "@mantine/core";
|
||||
import { faChevronCircleRight } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import SimpleTable, { SimpleTableProps } from "./SimpleTable";
|
||||
|
||||
function renderCell<T extends object = object>(cell: Cell<T>, row: Row<T>) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { useIsLoading } from "@/contexts";
|
||||
import { Group, Pagination, Text } from "@mantine/core";
|
||||
import { FunctionComponent, useEffect } from "react";
|
||||
import { Group, Pagination, Text } from "@mantine/core";
|
||||
import { useIsLoading } from "@/contexts";
|
||||
|
||||
interface Props {
|
||||
count: number;
|
||||
index: number;
|
||||
|
@ -28,7 +29,7 @@ const PageControl: FunctionComponent<Props> = ({
|
|||
}, [total, goto]);
|
||||
|
||||
return (
|
||||
<Group p={16} justify="apart">
|
||||
<Group p={16} justify="space-between">
|
||||
<Text size="sm">
|
||||
Show {start} to {end} of {total} entries
|
||||
</Text>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { ScrollToTop } from "@/utilities";
|
||||
import { usePageSize } from "@/utilities/storage";
|
||||
import { useEffect } from "react";
|
||||
import { usePagination, useTable } from "react-table";
|
||||
import { ScrollToTop } from "@/utilities";
|
||||
import { usePageSize } from "@/utilities/storage";
|
||||
import BaseTable from "./BaseTable";
|
||||
import PageControl from "./PageControl";
|
||||
import { SimpleTableProps } from "./SimpleTable";
|
||||
import { useDefaultSettings } from "./plugins";
|
||||
import { SimpleTableProps } from "./SimpleTable";
|
||||
|
||||
type Props<T extends object> = SimpleTableProps<T> & {
|
||||
autoScroll?: boolean;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useEffect } from "react";
|
||||
import { UsePaginationQueryResult } from "@/apis/queries/hooks";
|
||||
import { LoadingProvider } from "@/contexts";
|
||||
import { ScrollToTop } from "@/utilities";
|
||||
import { useEffect } from "react";
|
||||
import PageControl from "./PageControl";
|
||||
import SimpleTable, { SimpleTableProps } from "./SimpleTable";
|
||||
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { Checkbox as MantineCheckbox } from "@mantine/core";
|
||||
import { forwardRef, useEffect, useRef } from "react";
|
||||
import {
|
||||
CellProps,
|
||||
Column,
|
||||
ColumnInstance,
|
||||
ensurePluginOrder,
|
||||
HeaderProps,
|
||||
Hooks,
|
||||
MetaBase,
|
||||
TableInstance,
|
||||
TableToggleCommonProps,
|
||||
ensurePluginOrder,
|
||||
} from "react-table";
|
||||
import { Checkbox as MantineCheckbox } from "@mantine/core";
|
||||
|
||||
const pluginName = "useCustomSelection";
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { usePageSize } from "@/utilities/storage";
|
||||
import { Hooks, TableOptions } from "react-table";
|
||||
import { usePageSize } from "@/utilities/storage";
|
||||
|
||||
const pluginName = "useLocalSettings";
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Button, ButtonProps, Text } from "@mantine/core";
|
||||
import {
|
||||
ComponentProps,
|
||||
FunctionComponent,
|
||||
|
@ -8,6 +5,9 @@ import {
|
|||
useCallback,
|
||||
useState,
|
||||
} from "react";
|
||||
import { Button, ButtonProps, Text } from "@mantine/core";
|
||||
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
type ToolboxButtonProps = Omit<ButtonProps, "color" | "variant" | "leftIcon"> &
|
||||
Omit<ComponentProps<"button">, "ref"> & {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
.group {
|
||||
@include light {
|
||||
color: var(--mantine-color-gray-3);
|
||||
background-color: var(--mantine-color-gray-3);
|
||||
}
|
||||
|
||||
@include dark {
|
||||
color: var(--mantine-color-dark-5);
|
||||
background-color: var(--mantine-color-dark-5);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Group } from "@mantine/core";
|
||||
import { FunctionComponent, PropsWithChildren } from "react";
|
||||
import { Group } from "@mantine/core";
|
||||
import ToolboxButton, { ToolboxMutateButton } from "./Button";
|
||||
import styles from "./Toolbox.module.scss";
|
||||
|
||||
|
@ -10,7 +10,7 @@ declare type ToolboxComp = FunctionComponent<PropsWithChildren> & {
|
|||
|
||||
const Toolbox: ToolboxComp = ({ children }) => {
|
||||
return (
|
||||
<Group p={12} justify="apart" className={styles.group}>
|
||||
<Group p={12} justify="space-between" className={styles.group}>
|
||||
{children}
|
||||
</Group>
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { Router } from "./Router";
|
||||
import { AllProviders } from "./providers";
|
||||
import { Router } from "./Router";
|
||||
|
||||
const container = document.getElementById("root");
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { FunctionComponent, PropsWithChildren, useMemo } from "react";
|
||||
import {
|
||||
ModalsProvider as MantineModalsProvider,
|
||||
ModalsProviderProps as MantineModalsProviderProps,
|
||||
} from "@mantine/modals";
|
||||
import { FunctionComponent, PropsWithChildren, useMemo } from "react";
|
||||
import { ModalComponent, StaticModals } from "./WithModal";
|
||||
|
||||
const DefaultModalProps: MantineModalsProviderProps["modalProps"] = {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
|
||||
import { createContext, FunctionComponent } from "react";
|
||||
import { ContextModalProps } from "@mantine/modals";
|
||||
import { ModalSettings } from "@mantine/modals/lib/context";
|
||||
import { createContext, FunctionComponent } from "react";
|
||||
|
||||
export type ModalComponent<P extends Record<string, unknown> = {}> =
|
||||
FunctionComponent<ContextModalProps<P>> & {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import { useCallback, useContext, useMemo } from "react";
|
||||
import { useModals as useMantineModals } from "@mantine/modals";
|
||||
import { ModalSettings } from "@mantine/modals/lib/context";
|
||||
import { useCallback, useContext, useMemo } from "react";
|
||||
import { ModalComponent, ModalIdContext } from "./WithModal";
|
||||
|
||||
export function useModals() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useEffect } from "react";
|
||||
import { LOG } from "@/utilities/console";
|
||||
import Socketio from ".";
|
||||
import { LOG } from "../../utilities/console";
|
||||
|
||||
export function useSocketIOReducer(reducer: SocketIO.Reducer) {
|
||||
useEffect(() => {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { debounce, forIn, remove, uniq } from "lodash";
|
||||
import { onlineManager } from "react-query";
|
||||
import { Socket, io } from "socket.io-client";
|
||||
import { Environment, isDevEnv, isTestEnv } from "../../utilities";
|
||||
import { ENSURE, GROUP, LOG } from "../../utilities/console";
|
||||
import { debounce, forIn, remove, uniq } from "lodash";
|
||||
import { io, Socket } from "socket.io-client";
|
||||
import { Environment, isDevEnv, isTestEnv } from "@/utilities";
|
||||
import { ENSURE, GROUP, LOG } from "@/utilities/console";
|
||||
import { createDefaultReducer } from "./reducer";
|
||||
|
||||
class SocketIOClient {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { cleanNotifications, showNotification } from "@mantine/notifications";
|
||||
import queryClient from "@/apis/queries";
|
||||
import { QueryKeys } from "@/apis/queries/keys";
|
||||
import { notification, task } from "@/modules/task";
|
||||
import { LOG } from "@/utilities/console";
|
||||
import { setCriticalError, setOnlineStatus } from "@/utilities/event";
|
||||
import { cleanNotifications, showNotification } from "@mantine/notifications";
|
||||
import { notification, task } from "../task";
|
||||
|
||||
export function createDefaultReducer(): SocketIO.Reducer[] {
|
||||
return [
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { LOG } from "@/utilities/console";
|
||||
import {
|
||||
hideNotification,
|
||||
showNotification,
|
||||
updateNotification,
|
||||
} from "@mantine/notifications";
|
||||
import { uniqueId } from "lodash";
|
||||
import { LOG } from "@/utilities/console";
|
||||
import { notification } from "./notification";
|
||||
|
||||
class TaskDispatcher {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { render, screen } from "@/tests";
|
||||
import { describe, it } from "vitest";
|
||||
import { render, screen } from "@/tests";
|
||||
import Authentication from "./Authentication";
|
||||
|
||||
describe("Authentication", () => {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { useSystem } from "@/apis/hooks";
|
||||
import { Environment } from "@/utilities";
|
||||
import { FunctionComponent } from "react";
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
|
@ -11,7 +10,8 @@ import {
|
|||
TextInput,
|
||||
} from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { FunctionComponent } from "react";
|
||||
import { useSystem } from "@/apis/hooks";
|
||||
import { Environment } from "@/utilities";
|
||||
|
||||
const Authentication: FunctionComponent = () => {
|
||||
const { login } = useSystem();
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { FunctionComponent } from "react";
|
||||
import { Container, Stack } from "@mantine/core";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import {
|
||||
useMovieBlacklist,
|
||||
useMovieDeleteBlacklist,
|
||||
} from "@/apis/hooks/movies";
|
||||
import { Toolbox } from "@/components";
|
||||
import { QueryOverlay } from "@/components/async";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { Container, Stack } from "@mantine/core";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { FunctionComponent } from "react";
|
||||
import Table from "./table";
|
||||
|
||||
const BlacklistMoviesView: FunctionComponent = () => {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Column } from "react-table";
|
||||
import { Anchor, Text } from "@mantine/core";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { useMovieDeleteBlacklist } from "@/apis/hooks";
|
||||
import { PageTable } from "@/components";
|
||||
import MutateAction from "@/components/async/MutateAction";
|
||||
import Language from "@/components/bazarr/Language";
|
||||
import TextPopover from "@/components/TextPopover";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { Anchor, Text } from "@mantine/core";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Column } from "react-table";
|
||||
|
||||
interface Props {
|
||||
blacklist: readonly Blacklist.Movie[];
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { FunctionComponent } from "react";
|
||||
import { Container, Stack } from "@mantine/core";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { useEpisodeBlacklist, useEpisodeDeleteBlacklist } from "@/apis/hooks";
|
||||
import { Toolbox } from "@/components";
|
||||
import { QueryOverlay } from "@/components/async";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { Container, Stack } from "@mantine/core";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { FunctionComponent } from "react";
|
||||
import Table from "./table";
|
||||
|
||||
const BlacklistSeriesView: FunctionComponent = () => {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Column } from "react-table";
|
||||
import { Anchor, Text } from "@mantine/core";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { useEpisodeDeleteBlacklist } from "@/apis/hooks";
|
||||
import { PageTable } from "@/components";
|
||||
import MutateAction from "@/components/async/MutateAction";
|
||||
import Language from "@/components/bazarr/Language";
|
||||
import TextPopover from "@/components/TextPopover";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { Anchor, Text } from "@mantine/core";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Column } from "react-table";
|
||||
|
||||
interface Props {
|
||||
blacklist: readonly Blacklist.Episode[];
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { FunctionComponent, useMemo, useState } from "react";
|
||||
import { Badge, MantineColor, Tooltip } from "@mantine/core";
|
||||
import { useEpisodeSubtitleModification } from "@/apis/hooks";
|
||||
import Language from "@/components/bazarr/Language";
|
||||
import SubtitleToolsMenu from "@/components/SubtitleToolsMenu";
|
||||
import { task, TaskGroup } from "@/modules/task";
|
||||
import { Badge, MantineColor, Tooltip } from "@mantine/core";
|
||||
import { FunctionComponent, useMemo, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
seriesId: number;
|
||||
|
@ -24,13 +24,13 @@ export const Subtitle: FunctionComponent<Props> = ({
|
|||
|
||||
const disabled = subtitle.path === null;
|
||||
|
||||
const color: MantineColor | undefined = useMemo(() => {
|
||||
const variant: MantineColor | undefined = useMemo(() => {
|
||||
if (opened && !disabled) {
|
||||
return "cyan";
|
||||
return "highlight";
|
||||
} else if (missing) {
|
||||
return "yellow";
|
||||
return "warning";
|
||||
} else if (disabled) {
|
||||
return "gray";
|
||||
return "disabled";
|
||||
}
|
||||
}, [disabled, missing, opened]);
|
||||
|
||||
|
@ -50,7 +50,7 @@ export const Subtitle: FunctionComponent<Props> = ({
|
|||
}, [episodeId, subtitle.code2, subtitle.path]);
|
||||
|
||||
const ctx = (
|
||||
<Badge color={color}>
|
||||
<Badge variant={variant}>
|
||||
<Language.Text value={subtitle} long={false}></Language.Text>
|
||||
</Badge>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,26 @@
|
|||
import { RouterNames } from "@/Router/RouterNames";
|
||||
import {
|
||||
FunctionComponent,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { Container, Group, Stack } from "@mantine/core";
|
||||
import { Dropzone } from "@mantine/dropzone";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { showNotification } from "@mantine/notifications";
|
||||
import {
|
||||
faAdjust,
|
||||
faBriefcase,
|
||||
faCircleChevronDown,
|
||||
faCircleChevronRight,
|
||||
faCloudUploadAlt,
|
||||
faHdd,
|
||||
faSearch,
|
||||
faSync,
|
||||
faWrench,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import {
|
||||
useEpisodesBySeriesId,
|
||||
useIsAnyActionRunning,
|
||||
|
@ -12,32 +34,10 @@ import { ItemEditModal } from "@/components/forms/ItemEditForm";
|
|||
import { SeriesUploadModal } from "@/components/forms/SeriesUploadForm";
|
||||
import { SubtitleToolsModal } from "@/components/modals";
|
||||
import { useModals } from "@/modules/modals";
|
||||
import { TaskGroup, notification, task } from "@/modules/task";
|
||||
import { notification, task, TaskGroup } from "@/modules/task";
|
||||
import ItemOverview from "@/pages/views/ItemOverview";
|
||||
import { RouterNames } from "@/Router/RouterNames";
|
||||
import { useLanguageProfileBy } from "@/utilities/languages";
|
||||
import {
|
||||
faAdjust,
|
||||
faBriefcase,
|
||||
faCircleChevronDown,
|
||||
faCircleChevronRight,
|
||||
faCloudUploadAlt,
|
||||
faHdd,
|
||||
faSearch,
|
||||
faSync,
|
||||
faWrench,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { Container, Group, Stack } from "@mantine/core";
|
||||
import { Dropzone } from "@mantine/dropzone";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { showNotification } from "@mantine/notifications";
|
||||
import {
|
||||
FunctionComponent,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import Table from "./table";
|
||||
|
||||
const SeriesEpisodesView: FunctionComponent = () => {
|
||||
|
|
|
@ -1,21 +1,3 @@
|
|||
import { useDownloadEpisodeSubtitles, useEpisodesProvider } from "@/apis/hooks";
|
||||
import { useShowOnlyDesired } from "@/apis/hooks/site";
|
||||
import { Action, GroupTable } from "@/components";
|
||||
import TextPopover from "@/components/TextPopover";
|
||||
import { AudioList } from "@/components/bazarr";
|
||||
import { EpisodeHistoryModal } from "@/components/modals";
|
||||
import { EpisodeSearchModal } from "@/components/modals/ManualSearchModal";
|
||||
import { useModals } from "@/modules/modals";
|
||||
import { BuildKey, filterSubtitleBy } from "@/utilities";
|
||||
import { useProfileItemsToLanguages } from "@/utilities/languages";
|
||||
import { faBookmark as farBookmark } from "@fortawesome/free-regular-svg-icons";
|
||||
import {
|
||||
faBookmark,
|
||||
faHistory,
|
||||
faUser,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Group, Text } from "@mantine/core";
|
||||
import {
|
||||
FunctionComponent,
|
||||
useCallback,
|
||||
|
@ -24,6 +6,24 @@ import {
|
|||
useRef,
|
||||
} from "react";
|
||||
import { Column, TableInstance } from "react-table";
|
||||
import { Group, Text } from "@mantine/core";
|
||||
import { faBookmark as farBookmark } from "@fortawesome/free-regular-svg-icons";
|
||||
import {
|
||||
faBookmark,
|
||||
faHistory,
|
||||
faUser,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useDownloadEpisodeSubtitles, useEpisodesProvider } from "@/apis/hooks";
|
||||
import { useShowOnlyDesired } from "@/apis/hooks/site";
|
||||
import { Action, GroupTable } from "@/components";
|
||||
import { AudioList } from "@/components/bazarr";
|
||||
import { EpisodeHistoryModal } from "@/components/modals";
|
||||
import { EpisodeSearchModal } from "@/components/modals/ManualSearchModal";
|
||||
import TextPopover from "@/components/TextPopover";
|
||||
import { useModals } from "@/modules/modals";
|
||||
import { BuildKey, filterSubtitleBy } from "@/utilities";
|
||||
import { useProfileItemsToLanguages } from "@/utilities/languages";
|
||||
import { Subtitle } from "./components";
|
||||
|
||||
interface Props {
|
||||
|
@ -169,7 +169,7 @@ const Table: FunctionComponent<Props> = ({
|
|||
<Action
|
||||
label="Manual Search"
|
||||
disabled={disabled}
|
||||
color="dark"
|
||||
variant="dark"
|
||||
onClick={() => {
|
||||
modals.openContextModal(EpisodeSearchModal, {
|
||||
item: row.original,
|
||||
|
@ -182,7 +182,7 @@ const Table: FunctionComponent<Props> = ({
|
|||
<Action
|
||||
label="History"
|
||||
disabled={disabled}
|
||||
color="dark"
|
||||
variant="dark"
|
||||
onClick={() => {
|
||||
modals.openContextModal(
|
||||
EpisodeHistoryModal,
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
/* eslint-disable camelcase */
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Column } from "react-table";
|
||||
import { Anchor, Badge, Text } from "@mantine/core";
|
||||
import {
|
||||
faFileExcel,
|
||||
faInfoCircle,
|
||||
faRecycle,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useMovieAddBlacklist, useMovieHistoryPagination } from "@/apis/hooks";
|
||||
import { MutateAction } from "@/components/async";
|
||||
import { HistoryIcon } from "@/components/bazarr";
|
||||
|
@ -6,16 +16,6 @@ import Language from "@/components/bazarr/Language";
|
|||
import StateIcon from "@/components/StateIcon";
|
||||
import TextPopover from "@/components/TextPopover";
|
||||
import HistoryView from "@/pages/views/HistoryView";
|
||||
import {
|
||||
faFileExcel,
|
||||
faInfoCircle,
|
||||
faRecycle,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Anchor, Badge, Text } from "@mantine/core";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Column } from "react-table";
|
||||
|
||||
const MoviesHistoryView: FunctionComponent = () => {
|
||||
const columns: Column<History.Movie>[] = useMemo<Column<History.Movie>[]>(
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
/* eslint-disable camelcase */
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Column } from "react-table";
|
||||
import { Anchor, Badge, Text } from "@mantine/core";
|
||||
import {
|
||||
faFileExcel,
|
||||
faInfoCircle,
|
||||
faRecycle,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
useEpisodeAddBlacklist,
|
||||
useEpisodeHistoryPagination,
|
||||
|
@ -9,16 +19,6 @@ import Language from "@/components/bazarr/Language";
|
|||
import StateIcon from "@/components/StateIcon";
|
||||
import TextPopover from "@/components/TextPopover";
|
||||
import HistoryView from "@/pages/views/HistoryView";
|
||||
import {
|
||||
faFileExcel,
|
||||
faInfoCircle,
|
||||
faRecycle,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Anchor, Badge, Text } from "@mantine/core";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Column } from "react-table";
|
||||
|
||||
const SeriesHistoryView: FunctionComponent = () => {
|
||||
const columns: Column<History.Episode>[] = useMemo<Column<History.Episode>[]>(
|
||||
|
|
|
@ -1,15 +1,7 @@
|
|||
import {
|
||||
useHistoryStats,
|
||||
useLanguages,
|
||||
useSystemProviders,
|
||||
} from "@/apis/hooks";
|
||||
import { Selector, Toolbox } from "@/components";
|
||||
import { QueryOverlay } from "@/components/async";
|
||||
import { useSelectorOptions } from "@/utilities";
|
||||
import { FunctionComponent, useMemo, useState } from "react";
|
||||
import { Box, Container, SimpleGrid, useMantineTheme } from "@mantine/core";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { merge } from "lodash";
|
||||
import { FunctionComponent, useMemo, useState } from "react";
|
||||
import {
|
||||
Bar,
|
||||
BarChart,
|
||||
|
@ -20,6 +12,14 @@ import {
|
|||
XAxis,
|
||||
YAxis,
|
||||
} from "recharts";
|
||||
import {
|
||||
useHistoryStats,
|
||||
useLanguages,
|
||||
useSystemProviders,
|
||||
} from "@/apis/hooks";
|
||||
import { Selector, Toolbox } from "@/components";
|
||||
import { QueryOverlay } from "@/components/async";
|
||||
import { useSelectorOptions } from "@/utilities";
|
||||
import { actionOptions, timeFrameOptions } from "./options";
|
||||
import styles from "./HistoryStats.module.scss";
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { renderTest, RenderTestCase } from "@/tests/render";
|
||||
import HistoryStats from "./Statistics/HistoryStats";
|
||||
import MoviesHistoryView from "./Movies";
|
||||
import SeriesHistoryView from "./Series";
|
||||
import HistoryStats from "./Statistics/HistoryStats";
|
||||
|
||||
const cases: RenderTestCase[] = [
|
||||
{
|
||||
|
|
|
@ -1,4 +1,21 @@
|
|||
import { RouterNames } from "@/Router/RouterNames";
|
||||
import { FunctionComponent, useCallback, useRef } from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { Container, Group, Menu, Stack } from "@mantine/core";
|
||||
import { Dropzone } from "@mantine/dropzone";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { showNotification } from "@mantine/notifications";
|
||||
import {
|
||||
faCloudUploadAlt,
|
||||
faEllipsis,
|
||||
faHistory,
|
||||
faSearch,
|
||||
faSync,
|
||||
faToolbox,
|
||||
faUser,
|
||||
faWrench,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { isNumber } from "lodash";
|
||||
import {
|
||||
useDownloadMovieSubtitles,
|
||||
useIsMovieActionRunning,
|
||||
|
@ -16,27 +33,10 @@ import { MovieUploadModal } from "@/components/forms/MovieUploadForm";
|
|||
import { MovieHistoryModal, SubtitleToolsModal } from "@/components/modals";
|
||||
import { MovieSearchModal } from "@/components/modals/ManualSearchModal";
|
||||
import { useModals } from "@/modules/modals";
|
||||
import { TaskGroup, notification, task } from "@/modules/task";
|
||||
import { notification, task, TaskGroup } from "@/modules/task";
|
||||
import ItemOverview from "@/pages/views/ItemOverview";
|
||||
import { RouterNames } from "@/Router/RouterNames";
|
||||
import { useLanguageProfileBy } from "@/utilities/languages";
|
||||
import {
|
||||
faCloudUploadAlt,
|
||||
faEllipsis,
|
||||
faHistory,
|
||||
faSearch,
|
||||
faSync,
|
||||
faToolbox,
|
||||
faUser,
|
||||
faWrench,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Container, Group, Menu, Stack } from "@mantine/core";
|
||||
import { Dropzone } from "@mantine/dropzone";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { showNotification } from "@mantine/notifications";
|
||||
import { isNumber } from "lodash";
|
||||
import { FunctionComponent, useCallback, useRef } from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import Table from "./table";
|
||||
|
||||
const MovieDetailView: FunctionComponent = () => {
|
||||
|
@ -198,7 +198,6 @@ const MovieDetailView: FunctionComponent = () => {
|
|||
<Menu.Target>
|
||||
<Action
|
||||
label="More Actions"
|
||||
color="dark"
|
||||
icon={faEllipsis}
|
||||
disabled={hasTask}
|
||||
/>
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Column } from "react-table";
|
||||
import { Badge, Text, TextProps } from "@mantine/core";
|
||||
import { faEllipsis, faSearch } from "@fortawesome/free-solid-svg-icons";
|
||||
import { isString } from "lodash";
|
||||
import { useMovieSubtitleModification } from "@/apis/hooks";
|
||||
import { useShowOnlyDesired } from "@/apis/hooks/site";
|
||||
import { Action, SimpleTable } from "@/components";
|
||||
|
@ -6,11 +11,6 @@ import SubtitleToolsMenu from "@/components/SubtitleToolsMenu";
|
|||
import { task, TaskGroup } from "@/modules/task";
|
||||
import { filterSubtitleBy } from "@/utilities";
|
||||
import { useProfileItemsToLanguages } from "@/utilities/languages";
|
||||
import { faEllipsis, faSearch } from "@fortawesome/free-solid-svg-icons";
|
||||
import { Badge, Text, TextProps } from "@mantine/core";
|
||||
import { isString } from "lodash";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Column } from "react-table";
|
||||
|
||||
const missingText = "Missing Subtitles";
|
||||
|
||||
|
@ -161,7 +161,7 @@ const Table: FunctionComponent<Props> = ({ movie, profile, disabled }) => {
|
|||
<Action
|
||||
label="Subtitle Actions"
|
||||
disabled={isSubtitleTrack(path)}
|
||||
color="dark"
|
||||
variant="dark"
|
||||
icon={faEllipsis}
|
||||
></Action>
|
||||
</SubtitleToolsMenu>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Column } from "react-table";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { useMovieModification, useMovies } from "@/apis/hooks";
|
||||
import { QueryOverlay } from "@/components/async";
|
||||
import { AudioList } from "@/components/bazarr";
|
||||
import LanguageProfileName from "@/components/bazarr/LanguageProfile";
|
||||
import MassEditor from "@/pages/views/MassEditor";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Column } from "react-table";
|
||||
|
||||
const MovieMassEditor: FunctionComponent = () => {
|
||||
const query = useMovies();
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Column } from "react-table";
|
||||
import { Anchor, Badge, Container } from "@mantine/core";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { faBookmark as farBookmark } from "@fortawesome/free-regular-svg-icons";
|
||||
import { faBookmark, faWrench } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useMovieModification, useMoviesPagination } from "@/apis/hooks";
|
||||
import { Action } from "@/components";
|
||||
import { AudioList } from "@/components/bazarr";
|
||||
|
@ -7,14 +15,6 @@ import { ItemEditModal } from "@/components/forms/ItemEditForm";
|
|||
import { useModals } from "@/modules/modals";
|
||||
import ItemView from "@/pages/views/ItemView";
|
||||
import { BuildKey } from "@/utilities";
|
||||
import { faBookmark as farBookmark } from "@fortawesome/free-regular-svg-icons";
|
||||
import { faBookmark, faWrench } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Anchor, Badge, Container } from "@mantine/core";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Column } from "react-table";
|
||||
|
||||
const MovieView: FunctionComponent = () => {
|
||||
const query = useMoviesPagination();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue