Merge remote-tracking branch 'origin/develop'
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good Details

This commit is contained in:
Timothy Warren 2023-03-17 09:17:23 -04:00
commit 5076657b38
267 changed files with 11161 additions and 8999 deletions

6
.gitignore vendored
View File

@ -150,4 +150,8 @@ public/mal_mappings.json
.is-dev
tmp
tmp
tools/vendor/
tools/phinx/vendor/
/.php-cs-fixer.php
/.php-cs-fixer.cache

528
.php-cs-fixer.dist.php Normal file
View File

@ -0,0 +1,528 @@
<?php declare(strict_types=1);
use Nexus\CsConfig\Factory;
use PhpCsFixer\{Config, Finder};
$finder = Finder::create()
->in([
__DIR__,
__DIR__ . '/app',
__DIR__ . '/tools',
])
->exclude([
'apidocs',
'build',
'coverage',
'frontEndSrc',
'phinx',
'public',
'tools',
'tmp',
'vendor',
'views',
'templates',
]);
return (new Config())
->setRiskyAllowed(TRUE)
->setFinder($finder)
->setIndent(' ')
->setRules([
'align_multiline_comment' => false,
'array_indentation' => true,
'array_push' => true,
'array_syntax' => ['syntax' => 'short'],
'assign_null_coalescing_to_coalesce_equal' => true,
'backtick_to_shell_exec' => true,
'binary_operator_spaces' => [
'default' => 'single_space',
'operators' => [
'=' => NULL,
'&' => NULL,
]
],
'blank_line_after_namespace' => true,
'blank_line_after_opening_tag' => false,
'blank_line_before_statement' => [
'statements' => [
'case',
'continue',
'declare',
'default',
'do',
'exit',
'for',
'foreach',
'goto',
'return',
'switch',
'throw',
'try',
'while',
'yield',
'yield_from',
],
],
'braces' => [
'allow_single_line_anonymous_class_with_empty_body' => true,
'allow_single_line_closure' => true,
'position_after_anonymous_constructs' => 'same',
'position_after_control_structures' => 'next',
'position_after_functions_and_oop_constructs' => 'next',
],
'cast_spaces' => ['space' => 'single'],
'class_attributes_separation' => [
'elements' => [
'const' => 'none',
'property' => 'none',
'method' => 'one',
'trait_import' => 'none',
],
],
'class_definition' => [
'multi_line_extends_each_single_line' => true,
'single_item_single_line' => true,
'single_line' => true,
'space_before_parenthesis' => true,
],
'class_reference_name_casing' => true,
'clean_namespace' => true,
'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,
'combine_nested_dirname' => true,
'comment_to_phpdoc' => [
'ignored_tags' => [
'todo',
'codeCoverageIgnore',
'codeCoverageIgnoreStart',
'codeCoverageIgnoreEnd',
'phpstan-ignore-line',
'phpstan-ignore-next-line',
],
],
'compact_nullable_typehint' => true,
'concat_space' => ['spacing' => 'one'],
'constant_case' => ['case' => 'upper'],
'control_structure_continuation_position' => ['position' => 'next_line'],
'date_time_immutable' => false,
'declare_equal_normalize' => ['space' => 'none'],
'declare_parentheses' => true,
'declare_strict_types' => true,
'dir_constant' => true,
'doctrine_annotation_array_assignment' => false,
'doctrine_annotation_braces' => false,
'doctrine_annotation_indentation' => false,
'doctrine_annotation_spaces' => false,
'echo_tag_syntax' => [
'format' => 'short',
'long_function' => 'echo',
'shorten_simple_statements_only' => false,
],
'elseif' => true,
'empty_loop_body' => ['style' => 'braces'],
'empty_loop_condition' => ['style' => 'while'],
'encoding' => true,
'error_suppression' => [
'mute_deprecation_error' => true,
'noise_remaining_usages' => false,
'noise_remaining_usages_exclude' => [],
],
'escape_implicit_backslashes' => [
'double_quoted' => true,
'heredoc_syntax' => true,
'single_quoted' => false,
],
'explicit_indirect_variable' => true,
'explicit_string_variable' => true,
'final_class' => false,
'final_internal_class' => [
'annotation_exclude' => ['@no-final'],
'annotation_include' => ['@internal'],
'consider_absent_docblock_as_internal_class' => false,
],
'final_public_method_for_abstract_class' => false,
'fopen_flag_order' => true,
'fopen_flags' => ['b_mode' => true],
'full_opening_tag' => true,
'fully_qualified_strict_types' => true,
'function_declaration' => ['closure_function_spacing' => 'one'],
'function_to_constant' => [
'functions' => [
'get_called_class',
'get_class',
'get_class_this',
'php_sapi_name',
'phpversion',
'pi',
],
],
'function_typehint_space' => true,
'general_phpdoc_annotation_remove' => false,
'general_phpdoc_tag_rename' => false,
'get_class_to_class_keyword' => false,
'global_namespace_import' => [
'import_constants' => true,
'import_functions' => true,
'import_classes' => true,
],
'group_import' => true,
'header_comment' => false, // false by default
'heredoc_indentation' => ['indentation' => 'start_plus_one'],
'heredoc_to_nowdoc' => true,
'implode_call' => true,
'include' => true,
'increment_style' => ['style' => 'post'],
'indentation_type' => true,
'integer_literal_case' => true,
'is_null' => true,
'lambda_not_used_import' => true,
'line_ending' => true,
'linebreak_after_opening_tag' => false,
'list_syntax' => ['syntax' => 'short'],
'logical_operators' => true,
'lowercase_cast' => true,
'lowercase_keywords' => true,
'lowercase_static_reference' => true,
'magic_constant_casing' => true,
'magic_method_casing' => true,
'mb_str_functions' => false,
'method_argument_space' => [
'after_heredoc' => false,
'keep_multiple_spaces_after_comma' => false,
'on_multiline' => 'ensure_fully_multiline',
],
'method_chaining_indentation' => true,
'modernize_strpos' => false, // requires 8.0+
'modernize_types_casting' => true,
'multiline_comment_opening_closing' => true,
'multiline_whitespace_before_semicolons' => ['strategy' => 'no_multi_line'],
'native_constant_invocation' => false,
'native_function_casing' => true,
'native_function_invocation' => false,
'native_function_type_declaration_casing' => true,
'new_with_braces' => true,
'no_alias_functions' => ['sets' => ['@all']],
'no_alias_language_construct_call' => true,
'no_alternative_syntax' => ['fix_non_monolithic_code' => false],
'no_binary_string' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_blank_lines_before_namespace' => false, // conflicts with `single_blank_line_before_namespace`
'no_break_comment' => ['comment_text' => 'no break'],
'no_closing_tag' => true,
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_blank_lines' => ['tokens' => ['extra']],
'no_homoglyph_names' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_mixed_echo_print' => ['use' => 'echo'],
'no_multiline_whitespace_around_double_arrow' => true,
'no_null_property_initialization' => true,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_space_around_double_colon' => true,
'no_spaces_after_function_name' => true,
'no_spaces_around_offset' => ['positions' => ['inside', 'outside']],
'no_spaces_inside_parenthesis' => true,
'no_superfluous_elseif' => true,
'no_superfluous_phpdoc_tags' => [
'allow_mixed' => true,
'allow_unused_params' => true,
'remove_inheritdoc' => false,
],
'no_trailing_comma_in_list_call' => true,
'no_trailing_comma_in_singleline_array' => true,
'no_trailing_whitespace' => true,
'no_trailing_whitespace_in_comment' => true,
'no_trailing_whitespace_in_string' => true,
'no_unneeded_control_parentheses' => [
'statements' => [
'break',
'clone',
'continue',
'echo_print',
'return',
'switch_case',
'yield',
],
],
'no_unneeded_curly_braces' => ['namespaces' => true],
'no_unneeded_final_method' => ['private_methods' => true],
'no_unneeded_import_alias' => true,
'no_unreachable_default_argument_value' => true,
'no_unset_cast' => true,
'no_unset_on_property' => false,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'no_useless_sprintf' => true,
'no_whitespace_before_comma_in_array' => ['after_heredoc' => true],
'no_whitespace_in_blank_line' => true,
'non_printable_character' => ['use_escape_sequences_in_strings' => true],
'normalize_index_brace' => true,
'not_operator_with_space' => true,
'not_operator_with_successor_space' => true,
'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => true],
'object_operator_without_whitespace' => true,
'operator_linebreak' => ['only_booleans' => true, 'position' => 'beginning'],
'ordered_class_elements' => [
'order' => [
'use_trait',
'constant',
'property',
'method',
],
'sort_algorithm' => 'none',
],
'ordered_imports' => [
'sort_algorithm' => 'alpha',
'imports_order' => ['class', 'function', 'const'],
],
'ordered_interfaces' => false,
'ordered_traits' => false,
'php_unit_construct' => [
'assertions' => [
'assertSame',
'assertEquals',
'assertNotEquals',
'assertNotSame',
],
],
'php_unit_dedicate_assert' => ['target' => 'newest'],
'php_unit_dedicate_assert_internal_type' => ['target' => 'newest'],
'php_unit_expectation' => ['target' => 'newest'],
'php_unit_fqcn_annotation' => true,
'php_unit_internal_class' => ['types' => ['final']],
'php_unit_method_casing' => ['case' => 'camel_case'],
'php_unit_mock' => ['target' => 'newest'],
'php_unit_mock_short_will_return' => true,
'php_unit_namespaced' => ['target' => 'newest'],
'php_unit_no_expectation_annotation' => [
'target' => 'newest',
'use_class_const' => true,
],
'php_unit_set_up_tear_down_visibility' => true,
'php_unit_size_class' => false,
// 'php_unit_strict' => [
// 'assertions' => [
// 'assertAttributeEquals',
// 'assertAttributeNotEquals',
// 'assertEquals',
// 'assertNotEquals',
// ],
// ],
'php_unit_test_annotation' => ['style' => 'prefix'],
'php_unit_test_case_static_method_calls' => [
'call_type' => 'this',
'methods' => [],
],
'php_unit_test_class_requires_covers' => false,
'phpdoc_add_missing_param_annotation' => ['only_untyped' => true],
'phpdoc_align' => [
'align' => 'left'
],
'phpdoc_annotation_without_dot' => false,
'phpdoc_indent' => true,
'phpdoc_inline_tag_normalizer' => [
'tags' => [
'example',
'id',
'internal',
'inheritdoc',
'inheritdocs',
'link',
'source',
'toc',
'tutorial',
],
],
'phpdoc_line_span' => [
'const' => 'multi',
'method' => 'multi',
'property' => 'multi',
],
'phpdoc_no_access' => true,
'phpdoc_no_empty_return' => false,
'phpdoc_no_package' => false,
'phpdoc_no_useless_inheritdoc' => true,
'phpdoc_order' => true,
'phpdoc_order_by_value' => [
'annotations' => [
'author',
'covers',
'coversNothing',
'dataProvider',
'depends',
'group',
'internal',
'method',
'property',
'property-read',
'property-write',
'requires',
'throws',
'uses',
],
],
'phpdoc_return_self_reference' => [
'replacements' => [
'this' => '$this',
'@this' => '$this',
'$self' => 'self',
'@self' => 'self',
'$static' => 'static',
'@static' => 'static',
],
],
'phpdoc_scalar' => [
'types' => [
'boolean',
'callback',
'double',
'integer',
'real',
'str',
],
],
'phpdoc_separation' => false,
'phpdoc_single_line_var_spacing' => true,
'phpdoc_summary' => false,
'phpdoc_tag_casing' => ['tags' => ['inheritDoc']],
'phpdoc_tag_type' => ['tags' => ['inheritDoc' => 'inline']],
'phpdoc_to_comment' => false,
'phpdoc_to_param_type' => false,
'phpdoc_to_property_type' => false,
'phpdoc_to_return_type' => false,
'phpdoc_trim' => true,
'phpdoc_trim_consecutive_blank_line_separation' => true,
'phpdoc_types' => ['groups' => ['simple', 'alias', 'meta']],
'phpdoc_types_order' => [
'null_adjustment' => 'always_last',
'sort_algorithm' => 'alpha',
],
'phpdoc_var_annotation_correct_order' => true,
'phpdoc_var_without_name' => true,
'pow_to_exponentiation' => true,
'protected_to_private' => true,
'psr_autoloading' => ['dir' => null],
'random_api_migration' => [
'replacements' => [
'getrandmax' => 'mt_getrandmax',
'rand' => 'mt_rand',
'srand' => 'mt_srand',
],
],
'regular_callable_call' => true,
'return_assignment' => true,
'return_type_declaration' => ['space_before' => 'none'],
'self_accessor' => false,
'self_static_accessor' => true,
'semicolon_after_instruction' => false,
'set_type_to_cast' => true,
'short_scalar_cast' => true,
'simple_to_complex_string_variable' => true,
'simplified_if_return' => true,
'simplified_null_return' => false,
'single_blank_line_at_eof' => true,
'single_blank_line_before_namespace' => true,
'single_class_element_per_statement' => ['elements' => ['const', 'property']],
'single_import_per_statement' => false,
'single_line_after_imports' => true,
'single_line_comment_style' => ['comment_types' => ['asterisk', 'hash']],
'single_line_throw' => false,
'single_quote' => ['strings_containing_single_quote_chars' => false],
'single_space_after_construct' => [
'constructs' => [
'abstract',
'as',
'attribute',
'break',
'case',
'catch',
'class',
'clone',
'comment',
'const',
'const_import',
'continue',
'do',
'echo',
'else',
'elseif',
'extends',
'final',
'finally',
'for',
'foreach',
'function',
'function_import',
'global',
'goto',
'if',
'implements',
'include',
'include_once',
'instanceof',
'insteadof',
'interface',
'match',
'named_argument',
'new',
'open_tag_with_echo',
'php_doc',
'php_open',
'print',
'private',
'protected',
'public',
'require',
'require_once',
'return',
'static',
'throw',
'trait',
'try',
'use',
'use_lambda',
'use_trait',
'var',
'while',
'yield',
'yield_from',
],
],
'single_trait_insert_per_statement' => true,
'space_after_semicolon' => ['remove_in_empty_for_expressions' => true],
'standardize_increment' => true,
'standardize_not_equals' => true,
'static_lambda' => true,
'strict_comparison' => true,
'strict_param' => true,
'string_length_to_empty' => true,
'string_line_ending' => true,
'switch_case_semicolon_to_colon' => true,
'switch_case_space' => true,
'switch_continue_to_break' => true,
'ternary_operator_spaces' => true,
'ternary_to_elvis_operator' => true,
'ternary_to_null_coalescing' => true,
'trailing_comma_in_multiline' => [
'after_heredoc' => true,
'elements' => ['arrays'],
],
'trim_array_spaces' => true,
'types_spaces' => ['space' => 'none'],
'unary_operator_spaces' => false,
'use_arrow_functions' => true,
'visibility_required' => ['elements' => ['const', 'method', 'property']],
'void_return' => false, // changes method signature
'whitespace_after_comma_in_array' => true,
'yoda_style' => [
'equal' => false,
'identical' => null,
'less_and_greater' => false,
'always_move_variable' => false,
],
]);

View File

@ -57,4 +57,4 @@ return array_merge($tomlConfig, [
// Included config files
'routes' => require 'routes.php',
]);
]);

View File

@ -16,10 +16,10 @@
use const Aviat\AnimeClient\{
ALPHA_SLUG_PATTERN,
NUM_PATTERN,
SLUG_PATTERN,
DEFAULT_CONTROLLER,
DEFAULT_CONTROLLER_METHOD,
DEFAULT_CONTROLLER
NUM_PATTERN,
SLUG_PATTERN
};
// -------------------------------------------------------------------------
@ -190,14 +190,14 @@ $routes = [
'character' => [
'path' => '/character/{slug}',
'tokens' => [
'slug' => SLUG_PATTERN
]
'slug' => SLUG_PATTERN,
],
],
'person' => [
'path' => '/people/{slug}',
'tokens' => [
'slug' => SLUG_PATTERN,
]
],
],
'default_user_info' => [
'path' => '/me',
@ -209,8 +209,8 @@ $routes = [
'controller' => 'user',
'action' => 'about',
'tokens' => [
'username' => '.*?'
]
'username' => '.*?',
],
],
// ---------------------------------------------------------------------
// Default / Shared routes
@ -231,8 +231,8 @@ $routes = [
'controller' => 'images',
'tokens' => [
'type' => SLUG_PATTERN,
'file' => '[a-z0-9\-]+\.[a-z]{3,4}'
]
'file' => '[a-z0-9\-]+\.[a-z]{3,4}',
],
],
'settings' => [
'path' => '/settings',
@ -259,8 +259,8 @@ $routes = [
'controller' => 'history',
'path' => '/history/{type}',
'tokens' => [
'type' => SLUG_PATTERN
]
'type' => SLUG_PATTERN,
],
],
'increment' => [
'path' => '/{controller}/increment',
@ -316,7 +316,7 @@ $defaultMap = [
foreach ($routes as &$route)
{
foreach($defaultMap as $key => $val)
foreach ($defaultMap as $key => $val)
{
if ( ! array_key_exists($key, $route))
{

View File

@ -6,12 +6,10 @@
*
* PHP version 8
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2021 Timothy J. Warren
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 5.2
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient;
@ -20,12 +18,10 @@ use Aura\Html\HelperLocatorFactory;
use Aura\Router\RouterContainer;
use Aura\Session\SessionFactory;
use Aviat\AnimeClient\API\{Anilist, Kitsu};
use Aviat\AnimeClient\Component;
use Aviat\AnimeClient\Model;
use Aviat\AnimeClient\{Component, Model};
use Aviat\Banker\Teller;
use Aviat\Ion\Config;
use Aviat\Ion\Di\Container;
use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Di\{Container, ContainerInterface};
use Laminas\Diactoros\ServerRequestFactory;
use Monolog\Formatter\JsonFormatter;
use Monolog\Handler\RotatingFileHandler;
@ -38,7 +34,7 @@ if ( ! defined('HB_APP_DIR'))
{
define('HB_APP_DIR', __DIR__);
define('ROOT_DIR', dirname(HB_APP_DIR));
define('TEMPLATE_DIR', _dir(HB_APP_DIR, 'templates'));
define('TEMPLATE_DIR', _dir(HB_APP_DIR, 'templates'));
}
// -----------------------------------------------------------------------------
@ -74,18 +70,19 @@ return static function (array $configArray = []): Container {
$container->set('config', static fn () => new Config($configArray));
// Create Cache Object
$container->set('cache', static function(ContainerInterface $container): CacheInterface {
$container->set('cache', static function (ContainerInterface $container): CacheInterface {
$logger = $container->getLogger();
$config = $container->get('config')->get('cache');
return new Teller($config, $logger);
});
// Create Aura Router Object
$container->set('aura-router', static fn() => new RouterContainer);
$container->set('aura-router', static fn () => new RouterContainer());
// Create Html helpers
$container->set('html-helper', static function(ContainerInterface $container) {
$htmlHelper = (new HelperLocatorFactory)->newInstance();
$container->set('html-helper', static function (ContainerInterface $container) {
$htmlHelper = (new HelperLocatorFactory())->newInstance();
$helpers = [
'menu' => Helper\Menu::class,
'field' => Helper\Form::class,
@ -94,9 +91,10 @@ return static function (array $configArray = []): Container {
foreach ($helpers as $name => $class)
{
$htmlHelper->set($name, static function() use ($class, $container) {
$helper = new $class;
$htmlHelper->set($name, static function () use ($class, $container) {
$helper = new $class();
$helper->setContainer($container);
return $helper;
});
}
@ -106,7 +104,7 @@ return static function (array $configArray = []): Container {
// Create Component helpers
$container->set('component-helper', static function (ContainerInterface $container) {
$helper = (new HelperLocatorFactory)->newInstance();
$helper = (new HelperLocatorFactory())->newInstance();
$components = [
'animeCover' => Component\AnimeCover::class,
'mangaCover' => Component\MangaCover::class,
@ -119,8 +117,9 @@ return static function (array $configArray = []): Container {
foreach ($components as $name => $componentClass)
{
$helper->set($name, static function () use ($container, $componentClass) {
$helper = new $componentClass;
$helper = new $componentClass();
$helper->setContainer($container);
return $helper;
});
}
@ -144,7 +143,7 @@ return static function (array $configArray = []): Container {
$container->set('util', static fn ($container) => new Util($container));
// Models
$container->set('kitsu-model', static function(ContainerInterface $container): Kitsu\Model {
$container->set('kitsu-model', static function (ContainerInterface $container): Kitsu\Model {
$requestBuilder = new Kitsu\RequestBuilder($container);
$requestBuilder->setLogger($container->getLogger('kitsu-request'));
@ -158,9 +157,10 @@ return static function (array $configArray = []): Container {
$cache = $container->get('cache');
$model->setCache($cache);
return $model;
});
$container->set('anilist-model', static function(ContainerInterface $container): Anilist\Model {
$container->set('anilist-model', static function (ContainerInterface $container): Anilist\Model {
$requestBuilder = new Anilist\RequestBuilder($container);
$requestBuilder->setLogger($container->getLogger('anilist-request'));
@ -178,9 +178,10 @@ return static function (array $configArray = []): Container {
$container->set('manga-model', static fn ($container) => new Model\Manga($container));
$container->set('anime-collection-model', static fn ($container) => new Model\AnimeCollection($container));
$container->set('manga-collection-model', static fn ($container) => new Model\MangaCollection($container));
$container->set('settings-model', static function($container) {
$container->set('settings-model', static function ($container) {
$model = new Model\Settings($container->get('config'));
$model->setContainer($container);
return $model;
});
@ -196,4 +197,4 @@ return static function (array $configArray = []): Container {
return $container;
};
// End of bootstrap.php
// End of bootstrap.php

View File

@ -1,6 +1,7 @@
<article
class="media"
data-kitsu-id="<?= $item['id'] ?>"
data-anilist-id="<?= $item['anilist_id'] ?>"
data-mal-id="<?= $item['mal_id'] ?>"
>
<?php if ($auth->isAuthenticated()): ?>

View File

@ -1,4 +1,16 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime List Client
*
* An API client for Kitsu to manage anime and manga watch lists
*
* PHP version 8
*
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 5.2
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient;

View File

@ -1,99 +0,0 @@
<?php
declare(strict_types=1);
$file_patterns = [
'app/appConf/*.php',
'app/bootstrap.php',
'migrations/*.php',
'src/**/*.php',
'src/*.php',
'tests/**/*.php',
'tests/*.php',
'index.php',
'Robofile.php'
];
if ( ! function_exists('glob_recursive'))
{
// Does not support flag GLOB_BRACE
function glob_recursive(string $pattern, int $flags = 0): array
{
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir)
{
$files = array_merge($files, glob_recursive($dir . '/' . basename($pattern), $flags));
}
return $files;
}
}
function get_text_to_replace(array $tokens): string
{
$output = '';
// Tokens have the follow structure if arrays:
// [0] => token type constant
// [1] => raw syntax parsed to that token
// [2] => line number
foreach($tokens as $token)
{
// Since we only care about opening docblocks,
// bail out when we get to the namespace token
if (is_array($token) && $token[0] === T_NAMESPACE)
{
break;
}
if (is_array($token))
{
$token = $token[1];
}
$output .= $token;
}
return $output;
}
function get_tokens(string $source): array
{
return token_get_all($source);
}
function replace_files(array $files, string $template): void
{
print_r($files);
foreach ($files as $file)
{
$source = file_get_contents($file);
if ($source === FALSE)
{
continue;
}
if (stripos($source, 'namespace') === FALSE)
{
continue;
}
$tokens = get_tokens($source);
$text_to_replace = get_text_to_replace($tokens);
$header = file_get_contents(__DIR__ . $template);
$new_text = "<?php declare(strict_types=1);\n{$header}";
$new_source = str_replace($text_to_replace, $new_text, $source);
file_put_contents($file, $new_source);
}
}
foreach ($file_patterns as $glob)
{
$files = glob_recursive($glob);
replace_files($files, '/header_comment.txt');
}
echo "Successfully updated headers \n";

View File

@ -27,10 +27,7 @@
}
},
"config": {
"lock": false,
"platform": {
"php": "8"
}
"lock": false
},
"require": {
"amphp/amp": "^2.5.0",
@ -38,22 +35,20 @@
"aura/html": "^2.5.0",
"aura/router": "^3.1.0",
"aura/session": "^2.1.0",
"aviat/banker": "^3.0.0 || ^4.0.0",
"aviat/query": "^3.0.0",
"danielstjules/stringy": "^3.1.0",
"aviat/banker": "^4.1.2",
"aviat/query": "^4.0.0",
"ext-dom": "*",
"ext-gd": "*",
"ext-intl": "*",
"ext-json": "*",
"ext-gd": "*",
"ext-mbstring": "*",
"ext-pdo": "*",
"laminas/laminas-diactoros": "^2.5.0",
"laminas/laminas-httphandlerrunner": "^2.1.0",
"maximebf/consolekit": "^1.0.3",
"monolog/monolog": "^2.0.2",
"php": ">= 8.0.0",
"monolog/monolog": "^3.0.0",
"php": ">= 8.1.0",
"psr/http-message": "^1.0.1",
"psr/log": "*",
"robmorgan/phinx": "^0.12.4",
"symfony/polyfill-mbstring": "^1.0.0",
"symfony/polyfill-util": "^1.0.0",
"tracy/tracy": "^2.8.0",
@ -68,7 +63,7 @@
"scripts": {
"build:css": "cd public && npm run build:css && cd ..",
"build:js": "cd public && npm run build:js && cd ..",
"coverage": "phpdbg -qrr -- vendor/bin/phpunit -c build",
"coverage": "php -dpcov.enabled=1 -dpcov.directory=. -dpcov.exclude=\"~vendor~\" ./vendor/bin/phpunit -c build",
"phpstan": "phpstan analyse -c phpstan.neon",
"watch:css": "cd public && npm run watch:css",
"watch:js": "cd public && npm run watch:js",

View File

@ -63,6 +63,7 @@ _.on('body.anime.list', 'click', '.plus-one', (e) => {
// Setup the update data
let data = {
id: parentSel.dataset.kitsuId,
anilist_id: parentSel.dataset.anilistId,
mal_id: parentSel.dataset.malId,
data: {
progress: watchedCount + 1
@ -94,11 +95,18 @@ _.on('body.anime.list', 'click', '.plus-one', (e) => {
_.hide('#loading-shadow');
_.showMessage('error', `Failed to update ${title}. `);
_.scrollToTop();
return;
}
// We've completed the series
if (resData.data.libraryEntry.update.libraryEntry.status === 'COMPLETED') {
_.hide(parentSel);
_.hide('#loading-shadow');
_.showMessage('success', `Successfully completed ${title}`);
_.scrollToTop();
return;
}
_.hide('#loading-shadow');

View File

@ -83,6 +83,11 @@ _.on('.manga.list', 'click', '.edit-buttons button', (e) => {
if (String(data.data.status).toUpperCase() === 'COMPLETED') {
_.hide(parentSel);
_.hide('#loading-shadow');
_.showMessage('success', `Successfully completed ${mangaName}`);
_.scrollToTop();
return;
}
_.hide('#loading-shadow');

View File

@ -5,6 +5,7 @@ import _ from './anime-client.js';
_.on('main', 'change', '.big-check', (e) => {
const id = e.target.id;
document.getElementById(`mal_${id}`).checked = true;
document.getElementById(`anilist_${id}`).checked = true;
});
/**
@ -55,6 +56,7 @@ export function renderSearchResults (type, data, isCollection = false) {
return `
<article class="media search ${disabled}">
<div class="name">
<input type="radio" class="mal-check" id="anilist_${item.slug}" name="anilist_id" value="${item.anilist_id}" ${disabled} />
<input type="radio" class="mal-check" id="mal_${item.slug}" name="mal_id" value="${item.mal_id}" ${disabled} />
<input type="radio" class="big-check" id="${item.slug}" name="id" value="${item.id}" ${disabled} />
<label for="${item.slug}">

View File

@ -11,11 +11,11 @@
"devDependencies": {
"@swc/cli": "^0.1.39",
"@swc/core": "^1.2.54",
"concurrently": "^6.0.2",
"concurrently": "^7.4.0",
"cssnano": "^5.0.1",
"postcss": "^8.2.6",
"postcss-import": "^14.0.0",
"postcss-preset-env": "^6.7.0",
"postcss-import": "^15.0.0",
"postcss-preset-env": "^7.8.2",
"watch": "^1.0.2"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -6,12 +6,10 @@
*
* PHP version 8
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2021 Timothy J. Warren
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 5.2
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient;
@ -25,8 +23,8 @@ setlocale(LC_CTYPE, 'en_US');
// Load composer autoloader
require_once __DIR__ . '/vendor/autoload.php';
Debugger::$strictMode = E_ALL & ~E_DEPRECATED; // all errors except deprecated notices
Debugger::$showBar = false;
Debugger::$strictMode = E_ALL;
Debugger::$showBar = FALSE;
Debugger::enable(Debugger::DEVELOPMENT, __DIR__ . '/app/logs');
// Define base directories
@ -37,7 +35,7 @@ $CONF_DIR = _dir($APP_DIR, 'config');
// -----------------------------------------------------------------------------
// Dependency Injection setup
// -----------------------------------------------------------------------------
$baseConfig = require "{$APPCONF_DIR}/base_config.php";
$baseConfig = require _dir($APPCONF_DIR, 'base_config.php');
$di = require "{$APP_DIR}/bootstrap.php";
$config = loadConfig($CONF_DIR);
@ -59,7 +57,7 @@ if (is_array($checkedConfig) && array_key_exists('timezone', $checkedConfig) &&
{
date_default_timezone_set($checkedConfig['timezone']);
}
else if (is_string($timezone) && $timezone !== '')
elseif (is_string($timezone) && $timezone !== '')
{
date_default_timezone_set($timezone);
}
@ -76,4 +74,4 @@ unset($APP_DIR, $CONF_DIR, $APPCONF_DIR);
// -----------------------------------------------------------------------------
// Dispatch to the current route
// -----------------------------------------------------------------------------
$container->get('dispatcher')();
$container->get('dispatcher')();

35
justfile Normal file
View File

@ -0,0 +1,35 @@
# Lists the available actions
default:
@just --list
# Runs rector, showing what changes will be make
rector-dry-run:
tools/vendor/bin/rector process --config=tools/rector.php --dry-run src
# Runs rector, and updates the files
rector:
tools/vendor/bin/rector process --config=tools/rector.php src
# Check code formatting
check-fmt:
tools/vendor/bin/php-cs-fixer fix --dry-run --verbose
# Fix code formatting
fmt:
tools/vendor/bin/php-cs-fixer fix --verbose
# Run tests
test:
composer run-script test
# Run tests, update snapshots
test-update:
composer run-script test-update
# Update the per-file header comments
update-headers:
php tools/update_header_comments.php
# Run unit tests and generate test-coverage report
coverage:
composer run-script coverage

View File

@ -2,7 +2,8 @@
use Phinx\Migration\AbstractMigration;
class FirstMigration extends AbstractMigration {
class FirstMigration extends AbstractMigration
{
/**
* Migrate up
*/
@ -16,7 +17,7 @@ class FirstMigration extends AbstractMigration {
// Add items to media table
if ($this->hasTable('media'))
{
foreach(['DVD & Blu-ray', 'Blu-ray', 'DVD', 'Bootleg DVD'] as $type)
foreach (['DVD & Blu-ray', 'Blu-ray', 'DVD', 'Bootleg DVD'] as $type)
{
$this->execute('INSERT INTO "media" ("type") VALUES (\'' . $type . '\')');
}
@ -25,11 +26,11 @@ class FirstMigration extends AbstractMigration {
// Create anime_set table
$anime_set = $this->table('anime_set', ['id' => FALSE, 'primary_key' => ['hummingbird_id']]);
$anime_set->addColumn('hummingbird_id', 'biginteger')
->addColumn('slug', 'string', ['comment' => "URL slug used for image caching and generating links"])
->addColumn('slug', 'string', ['comment' => 'URL slug used for image caching and generating links'])
->addColumn('title', 'string')
->addColumn('alternate_title', 'string', ['null' => TRUE])
->addColumn('media_id', 'integer', ['default' => 3, 'null' => TRUE])
->addColumn('show_type', 'string', ['default' => 'TV', 'null' => TRUE, 'comment' => "TV Series/OVA/etc"])
->addColumn('show_type', 'string', ['default' => 'TV', 'null' => TRUE, 'comment' => 'TV Series/OVA/etc'])
->addColumn('age_rating', 'string', ['default' => 'PG13', 'null' => TRUE])
->addColumn('cover_image', 'string', ['null' => TRUE])
->addColumn('episode_count', 'integer', ['null' => TRUE])

View File

@ -1,35 +1,35 @@
<?php
<?php declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
class CacheMigration extends AbstractMigration
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
$cacheTable = $this->table('cache', ['id' => FALSE, 'primary_key' => ['key']]);
$cacheTable->addColumn('key', 'text')
->addColumn('value', 'text')
->create();
}
}
}

View File

@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
@ -11,7 +11,7 @@ class ReorganizeAnimeCollectionMedia extends AbstractMigration
{
$newLinkTable = $this->table('anime_set_media_link', [
'id' => FALSE,
'primary_key' => ['hummingbird_id', 'media_id']
'primary_key' => ['hummingbird_id', 'media_id'],
]);
$newLinkTable->addColumn('hummingbird_id', 'biginteger')
@ -31,6 +31,7 @@ class ReorganizeAnimeCollectionMedia extends AbstractMigration
foreach ($rows as $row)
{
$keys = array_keys($row);
foreach ($keys as $k)
{
if (is_numeric($k))
@ -49,6 +50,7 @@ class ReorganizeAnimeCollectionMedia extends AbstractMigration
// and replace those rows with the individual entries
$linkRows = $this->fetchAll('SELECT hummingbird_id FROM anime_set_media_link WHERE media_id=1');
$insertRows = [];
foreach ($linkRows as $row)
{
$insertRows[] = [

View File

@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
@ -18,6 +18,7 @@ class AnimeCollectionRefactorCleanup extends AbstractMigration
{
// Add some new media types
$moreMediaTypes = [];
foreach ($this->newMediaTypes as $id => $medium)
{
$moreMediaTypes[] = [
@ -47,7 +48,7 @@ class AnimeCollectionRefactorCleanup extends AbstractMigration
$this->execute("UPDATE media SET type='Bootleg DVD' WHERE id=4");
// Remove the new media types
$values = array_map(fn ($medium) => "'{$medium}'", $this->newMediaTypes);
$values = array_map(static fn ($medium) => "'{$medium}'", $this->newMediaTypes);
$valueList = implode(',', $values);
$this->execute("DELETE FROM media WHERE type IN ({$valueList})");
}

View File

@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
use Phinx\Migration\AbstractMigration;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
var LightTableSorter=function(){var th=null;var cellIndex=null;var order='';var text=function(row){return row.cells.item(cellIndex).textContent.toLowerCase()};var sort=function(a,b){var textA=text(a);var textB=text(b);console.log("Comparing "+textA+" and "+textB);if(th.classList.contains("numeric")){var arrayA=textA.replace('episodes: ','').replace('-',0).split("/");var arrayB=textB.replace('episodes: ','').replace('-',0).split("/");if(arrayA.length>1){textA=parseInt(arrayA[0],10)/parseInt(arrayA[1],10);textB=parseInt(arrayB[0],10)/parseInt(arrayB[1],10)}else{textA=parseInt(arrayA[0],10);textB=parseInt(arrayB[0],10)}}else if(parseInt(textA,10)){textA=parseInt(textA,10);textB=parseInt(textB,10)}if(textA>textB)return 1;if(textA<textB)return -1;return 0};var toggle=function(){var c=order!=='sorting-asc'?'sorting-asc':'sorting-desc';th.className=(th.className.replace(order,'')+' '+c).trim();return order=c};var reset=function(){th.classList.remove('sorting-asc','sorting-desc');th.classList.add('sorting');return order=''};var onClickEvent=function(e){if(th&&cellIndex!==e.target.cellIndex)reset();th=e.target;if(th.nodeName.toLowerCase()==='th'){cellIndex=th.cellIndex;var tbody=th.offsetParent.getElementsByTagName('tbody')[0];var rows=Array.from(tbody.rows);if(rows){rows.sort(sort);if(order==='sorting-asc')rows.reverse();toggle();tbody.innerHtml='';rows.forEach(function(row){tbody.appendChild(row)})}}};return{init:function(){var ths=document.getElementsByTagName('th');var results=[];for(var i=0,len=ths.length;i<len;i++){var th=ths[i];th.classList.add('sorting');th.classList.add('testing');results.push(th.onclick=onClickEvent)}return results}}}();LightTableSorter.init()
var LightTableSorter=function(){var th=null;var cellIndex=null;var order="";var text=function(row){return row.cells.item(cellIndex).textContent.toLowerCase()};var sort=function(a,b){var textA=text(a);var textB=text(b);console.log("Comparing "+textA+" and "+textB);if(th.classList.contains("numeric")){var arrayA=textA.replace("episodes: ","").replace("-",0).split("/");var arrayB=textB.replace("episodes: ","").replace("-",0).split("/");if(arrayA.length>1){textA=parseInt(arrayA[0],10)/parseInt(arrayA[1],10);textB=parseInt(arrayB[0],10)/parseInt(arrayB[1],10)}else{textA=parseInt(arrayA[0],10);textB=parseInt(arrayB[0],10)}}else if(parseInt(textA,10)){textA=parseInt(textA,10);textB=parseInt(textB,10)}if(textA>textB)return 1;if(textA<textB)return -1;return 0};var toggle=function(){var c=order!=="sorting-asc"?"sorting-asc":"sorting-desc";th.className=(th.className.replace(order,"")+" "+c).trim();return order=c};var reset=function(){th.classList.remove("sorting-asc","sorting-desc");th.classList.add("sorting");return order=""};var onClickEvent=function(e){if(th&&cellIndex!==e.target.cellIndex)reset();th=e.target;if(th.nodeName.toLowerCase()==="th"){cellIndex=th.cellIndex;var tbody=th.offsetParent.getElementsByTagName("tbody")[0];var rows=Array.from(tbody.rows);if(rows){rows.sort(sort);if(order==="sorting-asc")rows.reverse();toggle();tbody.innerHtml="";rows.forEach(function(row){tbody.appendChild(row)})}}};return{init:function(){var ths=document.getElementsByTagName("th");var results=[];for(var i=0,len=ths.length;i<len;i++){var th=ths[i];th.classList.add("sorting");th.classList.add("testing");results.push(th.onclick=onClickEvent)}return results}}}();LightTableSorter.init();

File diff suppressed because one or more lines are too long

View File

@ -6,31 +6,33 @@
*
* PHP version 8
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2021 Timothy J. Warren
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 5.2
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\API;
use const Aviat\AnimeClient\USER_AGENT;
use function Amp\Promise\wait;