Merge remote-tracking branch 'origin/develop'
This commit is contained in:
commit
5076657b38
6
.gitignore
vendored
6
.gitignore
vendored
@ -150,4 +150,8 @@ public/mal_mappings.json
|
|||||||
|
|
||||||
.is-dev
|
.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
528
.php-cs-fixer.dist.php
Normal 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,
|
||||||
|
],
|
||||||
|
]);
|
@ -57,4 +57,4 @@ return array_merge($tomlConfig, [
|
|||||||
|
|
||||||
// Included config files
|
// Included config files
|
||||||
'routes' => require 'routes.php',
|
'routes' => require 'routes.php',
|
||||||
]);
|
]);
|
||||||
|
@ -16,10 +16,10 @@
|
|||||||
|
|
||||||
use const Aviat\AnimeClient\{
|
use const Aviat\AnimeClient\{
|
||||||
ALPHA_SLUG_PATTERN,
|
ALPHA_SLUG_PATTERN,
|
||||||
NUM_PATTERN,
|
DEFAULT_CONTROLLER,
|
||||||
SLUG_PATTERN,
|
|
||||||
DEFAULT_CONTROLLER_METHOD,
|
DEFAULT_CONTROLLER_METHOD,
|
||||||
DEFAULT_CONTROLLER
|
NUM_PATTERN,
|
||||||
|
SLUG_PATTERN
|
||||||
};
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
@ -190,14 +190,14 @@ $routes = [
|
|||||||
'character' => [
|
'character' => [
|
||||||
'path' => '/character/{slug}',
|
'path' => '/character/{slug}',
|
||||||
'tokens' => [
|
'tokens' => [
|
||||||
'slug' => SLUG_PATTERN
|
'slug' => SLUG_PATTERN,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'person' => [
|
'person' => [
|
||||||
'path' => '/people/{slug}',
|
'path' => '/people/{slug}',
|
||||||
'tokens' => [
|
'tokens' => [
|
||||||
'slug' => SLUG_PATTERN,
|
'slug' => SLUG_PATTERN,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'default_user_info' => [
|
'default_user_info' => [
|
||||||
'path' => '/me',
|
'path' => '/me',
|
||||||
@ -209,8 +209,8 @@ $routes = [
|
|||||||
'controller' => 'user',
|
'controller' => 'user',
|
||||||
'action' => 'about',
|
'action' => 'about',
|
||||||
'tokens' => [
|
'tokens' => [
|
||||||
'username' => '.*?'
|
'username' => '.*?',
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Default / Shared routes
|
// Default / Shared routes
|
||||||
@ -231,8 +231,8 @@ $routes = [
|
|||||||
'controller' => 'images',
|
'controller' => 'images',
|
||||||
'tokens' => [
|
'tokens' => [
|
||||||
'type' => SLUG_PATTERN,
|
'type' => SLUG_PATTERN,
|
||||||
'file' => '[a-z0-9\-]+\.[a-z]{3,4}'
|
'file' => '[a-z0-9\-]+\.[a-z]{3,4}',
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'settings' => [
|
'settings' => [
|
||||||
'path' => '/settings',
|
'path' => '/settings',
|
||||||
@ -259,8 +259,8 @@ $routes = [
|
|||||||
'controller' => 'history',
|
'controller' => 'history',
|
||||||
'path' => '/history/{type}',
|
'path' => '/history/{type}',
|
||||||
'tokens' => [
|
'tokens' => [
|
||||||
'type' => SLUG_PATTERN
|
'type' => SLUG_PATTERN,
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'increment' => [
|
'increment' => [
|
||||||
'path' => '/{controller}/increment',
|
'path' => '/{controller}/increment',
|
||||||
@ -316,7 +316,7 @@ $defaultMap = [
|
|||||||
|
|
||||||
foreach ($routes as &$route)
|
foreach ($routes as &$route)
|
||||||
{
|
{
|
||||||
foreach($defaultMap as $key => $val)
|
foreach ($defaultMap as $key => $val)
|
||||||
{
|
{
|
||||||
if ( ! array_key_exists($key, $route))
|
if ( ! array_key_exists($key, $route))
|
||||||
{
|
{
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient;
|
namespace Aviat\AnimeClient;
|
||||||
@ -20,12 +18,10 @@ use Aura\Html\HelperLocatorFactory;
|
|||||||
use Aura\Router\RouterContainer;
|
use Aura\Router\RouterContainer;
|
||||||
use Aura\Session\SessionFactory;
|
use Aura\Session\SessionFactory;
|
||||||
use Aviat\AnimeClient\API\{Anilist, Kitsu};
|
use Aviat\AnimeClient\API\{Anilist, Kitsu};
|
||||||
use Aviat\AnimeClient\Component;
|
use Aviat\AnimeClient\{Component, Model};
|
||||||
use Aviat\AnimeClient\Model;
|
|
||||||
use Aviat\Banker\Teller;
|
use Aviat\Banker\Teller;
|
||||||
use Aviat\Ion\Config;
|
use Aviat\Ion\Config;
|
||||||
use Aviat\Ion\Di\Container;
|
use Aviat\Ion\Di\{Container, ContainerInterface};
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
|
||||||
use Laminas\Diactoros\ServerRequestFactory;
|
use Laminas\Diactoros\ServerRequestFactory;
|
||||||
use Monolog\Formatter\JsonFormatter;
|
use Monolog\Formatter\JsonFormatter;
|
||||||
use Monolog\Handler\RotatingFileHandler;
|
use Monolog\Handler\RotatingFileHandler;
|
||||||
@ -38,7 +34,7 @@ if ( ! defined('HB_APP_DIR'))
|
|||||||
{
|
{
|
||||||
define('HB_APP_DIR', __DIR__);
|
define('HB_APP_DIR', __DIR__);
|
||||||
define('ROOT_DIR', dirname(HB_APP_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));
|
$container->set('config', static fn () => new Config($configArray));
|
||||||
|
|
||||||
// Create Cache Object
|
// Create Cache Object
|
||||||
$container->set('cache', static function(ContainerInterface $container): CacheInterface {
|
$container->set('cache', static function (ContainerInterface $container): CacheInterface {
|
||||||
$logger = $container->getLogger();
|
$logger = $container->getLogger();
|
||||||
$config = $container->get('config')->get('cache');
|
$config = $container->get('config')->get('cache');
|
||||||
|
|
||||||
return new Teller($config, $logger);
|
return new Teller($config, $logger);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create Aura Router Object
|
// Create Aura Router Object
|
||||||
$container->set('aura-router', static fn() => new RouterContainer);
|
$container->set('aura-router', static fn () => new RouterContainer());
|
||||||
|
|
||||||
// Create Html helpers
|
// Create Html helpers
|
||||||
$container->set('html-helper', static function(ContainerInterface $container) {
|
$container->set('html-helper', static function (ContainerInterface $container) {
|
||||||
$htmlHelper = (new HelperLocatorFactory)->newInstance();
|
$htmlHelper = (new HelperLocatorFactory())->newInstance();
|
||||||
$helpers = [
|
$helpers = [
|
||||||
'menu' => Helper\Menu::class,
|
'menu' => Helper\Menu::class,
|
||||||
'field' => Helper\Form::class,
|
'field' => Helper\Form::class,
|
||||||
@ -94,9 +91,10 @@ return static function (array $configArray = []): Container {
|
|||||||
|
|
||||||
foreach ($helpers as $name => $class)
|
foreach ($helpers as $name => $class)
|
||||||
{
|
{
|
||||||
$htmlHelper->set($name, static function() use ($class, $container) {
|
$htmlHelper->set($name, static function () use ($class, $container) {
|
||||||
$helper = new $class;
|
$helper = new $class();
|
||||||
$helper->setContainer($container);
|
$helper->setContainer($container);
|
||||||
|
|
||||||
return $helper;
|
return $helper;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -106,7 +104,7 @@ return static function (array $configArray = []): Container {
|
|||||||
|
|
||||||
// Create Component helpers
|
// Create Component helpers
|
||||||
$container->set('component-helper', static function (ContainerInterface $container) {
|
$container->set('component-helper', static function (ContainerInterface $container) {
|
||||||
$helper = (new HelperLocatorFactory)->newInstance();
|
$helper = (new HelperLocatorFactory())->newInstance();
|
||||||
$components = [
|
$components = [
|
||||||
'animeCover' => Component\AnimeCover::class,
|
'animeCover' => Component\AnimeCover::class,
|
||||||
'mangaCover' => Component\MangaCover::class,
|
'mangaCover' => Component\MangaCover::class,
|
||||||
@ -119,8 +117,9 @@ return static function (array $configArray = []): Container {
|
|||||||
foreach ($components as $name => $componentClass)
|
foreach ($components as $name => $componentClass)
|
||||||
{
|
{
|
||||||
$helper->set($name, static function () use ($container, $componentClass) {
|
$helper->set($name, static function () use ($container, $componentClass) {
|
||||||
$helper = new $componentClass;
|
$helper = new $componentClass();
|
||||||
$helper->setContainer($container);
|
$helper->setContainer($container);
|
||||||
|
|
||||||
return $helper;
|
return $helper;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -144,7 +143,7 @@ return static function (array $configArray = []): Container {
|
|||||||
$container->set('util', static fn ($container) => new Util($container));
|
$container->set('util', static fn ($container) => new Util($container));
|
||||||
|
|
||||||
// Models
|
// 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 = new Kitsu\RequestBuilder($container);
|
||||||
$requestBuilder->setLogger($container->getLogger('kitsu-request'));
|
$requestBuilder->setLogger($container->getLogger('kitsu-request'));
|
||||||
|
|
||||||
@ -158,9 +157,10 @@ return static function (array $configArray = []): Container {
|
|||||||
|
|
||||||
$cache = $container->get('cache');
|
$cache = $container->get('cache');
|
||||||
$model->setCache($cache);
|
$model->setCache($cache);
|
||||||
|
|
||||||
return $model;
|
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 = new Anilist\RequestBuilder($container);
|
||||||
$requestBuilder->setLogger($container->getLogger('anilist-request'));
|
$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('manga-model', static fn ($container) => new Model\Manga($container));
|
||||||
$container->set('anime-collection-model', static fn ($container) => new Model\AnimeCollection($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('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 = new Model\Settings($container->get('config'));
|
||||||
$model->setContainer($container);
|
$model->setContainer($container);
|
||||||
|
|
||||||
return $model;
|
return $model;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -196,4 +197,4 @@ return static function (array $configArray = []): Container {
|
|||||||
return $container;
|
return $container;
|
||||||
};
|
};
|
||||||
|
|
||||||
// End of bootstrap.php
|
// End of bootstrap.php
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<article
|
<article
|
||||||
class="media"
|
class="media"
|
||||||
data-kitsu-id="<?= $item['id'] ?>"
|
data-kitsu-id="<?= $item['id'] ?>"
|
||||||
|
data-anilist-id="<?= $item['anilist_id'] ?>"
|
||||||
data-mal-id="<?= $item['mal_id'] ?>"
|
data-mal-id="<?= $item['mal_id'] ?>"
|
||||||
>
|
>
|
||||||
<?php if ($auth->isAuthenticated()): ?>
|
<?php if ($auth->isAuthenticated()): ?>
|
||||||
|
@ -1,4 +1,16 @@
|
|||||||
<?php declare(strict_types=1);
|
<?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;
|
namespace Aviat\AnimeClient;
|
||||||
|
|
||||||
|
@ -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";
|
|
@ -27,10 +27,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"lock": false,
|
"lock": false
|
||||||
"platform": {
|
|
||||||
"php": "8"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"amphp/amp": "^2.5.0",
|
"amphp/amp": "^2.5.0",
|
||||||
@ -38,22 +35,20 @@
|
|||||||
"aura/html": "^2.5.0",
|
"aura/html": "^2.5.0",
|
||||||
"aura/router": "^3.1.0",
|
"aura/router": "^3.1.0",
|
||||||
"aura/session": "^2.1.0",
|
"aura/session": "^2.1.0",
|
||||||
"aviat/banker": "^3.0.0 || ^4.0.0",
|
"aviat/banker": "^4.1.2",
|
||||||
"aviat/query": "^3.0.0",
|
"aviat/query": "^4.0.0",
|
||||||
"danielstjules/stringy": "^3.1.0",
|
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
|
"ext-gd": "*",
|
||||||
"ext-intl": "*",
|
"ext-intl": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-gd": "*",
|
"ext-mbstring": "*",
|
||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
"laminas/laminas-diactoros": "^2.5.0",
|
"laminas/laminas-diactoros": "^2.5.0",
|
||||||
"laminas/laminas-httphandlerrunner": "^2.1.0",
|
"laminas/laminas-httphandlerrunner": "^2.1.0",
|
||||||
"maximebf/consolekit": "^1.0.3",
|
"maximebf/consolekit": "^1.0.3",
|
||||||
"monolog/monolog": "^2.0.2",
|
"monolog/monolog": "^3.0.0",
|
||||||
"php": ">= 8.0.0",
|
"php": ">= 8.1.0",
|
||||||
"psr/http-message": "^1.0.1",
|
"psr/http-message": "^1.0.1",
|
||||||
"psr/log": "*",
|
|
||||||
"robmorgan/phinx": "^0.12.4",
|
|
||||||
"symfony/polyfill-mbstring": "^1.0.0",
|
"symfony/polyfill-mbstring": "^1.0.0",
|
||||||
"symfony/polyfill-util": "^1.0.0",
|
"symfony/polyfill-util": "^1.0.0",
|
||||||
"tracy/tracy": "^2.8.0",
|
"tracy/tracy": "^2.8.0",
|
||||||
@ -68,7 +63,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build:css": "cd public && npm run build:css && cd ..",
|
"build:css": "cd public && npm run build:css && cd ..",
|
||||||
"build:js": "cd public && npm run build:js && 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",
|
"phpstan": "phpstan analyse -c phpstan.neon",
|
||||||
"watch:css": "cd public && npm run watch:css",
|
"watch:css": "cd public && npm run watch:css",
|
||||||
"watch:js": "cd public && npm run watch:js",
|
"watch:js": "cd public && npm run watch:js",
|
||||||
|
@ -63,6 +63,7 @@ _.on('body.anime.list', 'click', '.plus-one', (e) => {
|
|||||||
// Setup the update data
|
// Setup the update data
|
||||||
let data = {
|
let data = {
|
||||||
id: parentSel.dataset.kitsuId,
|
id: parentSel.dataset.kitsuId,
|
||||||
|
anilist_id: parentSel.dataset.anilistId,
|
||||||
mal_id: parentSel.dataset.malId,
|
mal_id: parentSel.dataset.malId,
|
||||||
data: {
|
data: {
|
||||||
progress: watchedCount + 1
|
progress: watchedCount + 1
|
||||||
@ -94,11 +95,18 @@ _.on('body.anime.list', 'click', '.plus-one', (e) => {
|
|||||||
_.hide('#loading-shadow');
|
_.hide('#loading-shadow');
|
||||||
_.showMessage('error', `Failed to update ${title}. `);
|
_.showMessage('error', `Failed to update ${title}. `);
|
||||||
_.scrollToTop();
|
_.scrollToTop();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We've completed the series
|
||||||
if (resData.data.libraryEntry.update.libraryEntry.status === 'COMPLETED') {
|
if (resData.data.libraryEntry.update.libraryEntry.status === 'COMPLETED') {
|
||||||
_.hide(parentSel);
|
_.hide(parentSel);
|
||||||
|
_.hide('#loading-shadow');
|
||||||
|
_.showMessage('success', `Successfully completed ${title}`);
|
||||||
|
_.scrollToTop();
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_.hide('#loading-shadow');
|
_.hide('#loading-shadow');
|
||||||
|
@ -83,6 +83,11 @@ _.on('.manga.list', 'click', '.edit-buttons button', (e) => {
|
|||||||
|
|
||||||
if (String(data.data.status).toUpperCase() === 'COMPLETED') {
|
if (String(data.data.status).toUpperCase() === 'COMPLETED') {
|
||||||
_.hide(parentSel);
|
_.hide(parentSel);
|
||||||
|
_.hide('#loading-shadow');
|
||||||
|
_.showMessage('success', `Successfully completed ${mangaName}`);
|
||||||
|
_.scrollToTop();
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_.hide('#loading-shadow');
|
_.hide('#loading-shadow');
|
||||||
|
@ -5,6 +5,7 @@ import _ from './anime-client.js';
|
|||||||
_.on('main', 'change', '.big-check', (e) => {
|
_.on('main', 'change', '.big-check', (e) => {
|
||||||
const id = e.target.id;
|
const id = e.target.id;
|
||||||
document.getElementById(`mal_${id}`).checked = true;
|
document.getElementById(`mal_${id}`).checked = true;
|
||||||
|
document.getElementById(`anilist_${id}`).checked = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,6 +56,7 @@ export function renderSearchResults (type, data, isCollection = false) {
|
|||||||
return `
|
return `
|
||||||
<article class="media search ${disabled}">
|
<article class="media search ${disabled}">
|
||||||
<div class="name">
|
<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="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} />
|
<input type="radio" class="big-check" id="${item.slug}" name="id" value="${item.id}" ${disabled} />
|
||||||
<label for="${item.slug}">
|
<label for="${item.slug}">
|
||||||
|
@ -11,11 +11,11 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@swc/cli": "^0.1.39",
|
"@swc/cli": "^0.1.39",
|
||||||
"@swc/core": "^1.2.54",
|
"@swc/core": "^1.2.54",
|
||||||
"concurrently": "^6.0.2",
|
"concurrently": "^7.4.0",
|
||||||
"cssnano": "^5.0.1",
|
"cssnano": "^5.0.1",
|
||||||
"postcss": "^8.2.6",
|
"postcss": "^8.2.6",
|
||||||
"postcss-import": "^14.0.0",
|
"postcss-import": "^15.0.0",
|
||||||
"postcss-preset-env": "^6.7.0",
|
"postcss-preset-env": "^7.8.2",
|
||||||
"watch": "^1.0.2"
|
"watch": "^1.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
16
index.php
16
index.php
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient;
|
namespace Aviat\AnimeClient;
|
||||||
@ -25,8 +23,8 @@ setlocale(LC_CTYPE, 'en_US');
|
|||||||
// Load composer autoloader
|
// Load composer autoloader
|
||||||
require_once __DIR__ . '/vendor/autoload.php';
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
Debugger::$strictMode = E_ALL & ~E_DEPRECATED; // all errors except deprecated notices
|
Debugger::$strictMode = E_ALL;
|
||||||
Debugger::$showBar = false;
|
Debugger::$showBar = FALSE;
|
||||||
Debugger::enable(Debugger::DEVELOPMENT, __DIR__ . '/app/logs');
|
Debugger::enable(Debugger::DEVELOPMENT, __DIR__ . '/app/logs');
|
||||||
|
|
||||||
// Define base directories
|
// Define base directories
|
||||||
@ -37,7 +35,7 @@ $CONF_DIR = _dir($APP_DIR, 'config');
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Dependency Injection setup
|
// Dependency Injection setup
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
$baseConfig = require "{$APPCONF_DIR}/base_config.php";
|
$baseConfig = require _dir($APPCONF_DIR, 'base_config.php');
|
||||||
$di = require "{$APP_DIR}/bootstrap.php";
|
$di = require "{$APP_DIR}/bootstrap.php";
|
||||||
|
|
||||||
$config = loadConfig($CONF_DIR);
|
$config = loadConfig($CONF_DIR);
|
||||||
@ -59,7 +57,7 @@ if (is_array($checkedConfig) && array_key_exists('timezone', $checkedConfig) &&
|
|||||||
{
|
{
|
||||||
date_default_timezone_set($checkedConfig['timezone']);
|
date_default_timezone_set($checkedConfig['timezone']);
|
||||||
}
|
}
|
||||||
else if (is_string($timezone) && $timezone !== '')
|
elseif (is_string($timezone) && $timezone !== '')
|
||||||
{
|
{
|
||||||
date_default_timezone_set($timezone);
|
date_default_timezone_set($timezone);
|
||||||
}
|
}
|
||||||
@ -76,4 +74,4 @@ unset($APP_DIR, $CONF_DIR, $APPCONF_DIR);
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Dispatch to the current route
|
// Dispatch to the current route
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
$container->get('dispatcher')();
|
$container->get('dispatcher')();
|
||||||
|
35
justfile
Normal file
35
justfile
Normal 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
|
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
use Phinx\Migration\AbstractMigration;
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
class FirstMigration extends AbstractMigration {
|
class FirstMigration extends AbstractMigration
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Migrate up
|
* Migrate up
|
||||||
*/
|
*/
|
||||||
@ -16,7 +17,7 @@ class FirstMigration extends AbstractMigration {
|
|||||||
// Add items to media table
|
// Add items to media table
|
||||||
if ($this->hasTable('media'))
|
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 . '\')');
|
$this->execute('INSERT INTO "media" ("type") VALUES (\'' . $type . '\')');
|
||||||
}
|
}
|
||||||
@ -25,11 +26,11 @@ class FirstMigration extends AbstractMigration {
|
|||||||
// Create anime_set table
|
// Create anime_set table
|
||||||
$anime_set = $this->table('anime_set', ['id' => FALSE, 'primary_key' => ['hummingbird_id']]);
|
$anime_set = $this->table('anime_set', ['id' => FALSE, 'primary_key' => ['hummingbird_id']]);
|
||||||
$anime_set->addColumn('hummingbird_id', 'biginteger')
|
$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('title', 'string')
|
||||||
->addColumn('alternate_title', 'string', ['null' => TRUE])
|
->addColumn('alternate_title', 'string', ['null' => TRUE])
|
||||||
->addColumn('media_id', 'integer', ['default' => 3, '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('age_rating', 'string', ['default' => 'PG13', 'null' => TRUE])
|
||||||
->addColumn('cover_image', 'string', ['null' => TRUE])
|
->addColumn('cover_image', 'string', ['null' => TRUE])
|
||||||
->addColumn('episode_count', 'integer', ['null' => TRUE])
|
->addColumn('episode_count', 'integer', ['null' => TRUE])
|
||||||
|
@ -1,35 +1,35 @@
|
|||||||
<?php
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
use Phinx\Migration\AbstractMigration;
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
class CacheMigration extends AbstractMigration
|
class CacheMigration extends AbstractMigration
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Change Method.
|
* Change Method.
|
||||||
*
|
*
|
||||||
* Write your reversible migrations using this method.
|
* Write your reversible migrations using this method.
|
||||||
*
|
*
|
||||||
* More information on writing migrations is available here:
|
* More information on writing migrations is available here:
|
||||||
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
||||||
*
|
*
|
||||||
* The following commands can be used in this method and Phinx will
|
* The following commands can be used in this method and Phinx will
|
||||||
* automatically reverse them when rolling back:
|
* automatically reverse them when rolling back:
|
||||||
*
|
*
|
||||||
* createTable
|
* createTable
|
||||||
* renameTable
|
* renameTable
|
||||||
* addColumn
|
* addColumn
|
||||||
* renameColumn
|
* renameColumn
|
||||||
* addIndex
|
* addIndex
|
||||||
* addForeignKey
|
* addForeignKey
|
||||||
*
|
*
|
||||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||||
* with the Table class.
|
* with the Table class.
|
||||||
*/
|
*/
|
||||||
public function change()
|
public function change()
|
||||||
{
|
{
|
||||||
$cacheTable = $this->table('cache', ['id' => FALSE, 'primary_key' => ['key']]);
|
$cacheTable = $this->table('cache', ['id' => FALSE, 'primary_key' => ['key']]);
|
||||||
$cacheTable->addColumn('key', 'text')
|
$cacheTable->addColumn('key', 'text')
|
||||||
->addColumn('value', 'text')
|
->addColumn('value', 'text')
|
||||||
->create();
|
->create();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?php
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
use Phinx\Migration\AbstractMigration;
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ class ReorganizeAnimeCollectionMedia extends AbstractMigration
|
|||||||
{
|
{
|
||||||
$newLinkTable = $this->table('anime_set_media_link', [
|
$newLinkTable = $this->table('anime_set_media_link', [
|
||||||
'id' => FALSE,
|
'id' => FALSE,
|
||||||
'primary_key' => ['hummingbird_id', 'media_id']
|
'primary_key' => ['hummingbird_id', 'media_id'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$newLinkTable->addColumn('hummingbird_id', 'biginteger')
|
$newLinkTable->addColumn('hummingbird_id', 'biginteger')
|
||||||
@ -31,6 +31,7 @@ class ReorganizeAnimeCollectionMedia extends AbstractMigration
|
|||||||
foreach ($rows as $row)
|
foreach ($rows as $row)
|
||||||
{
|
{
|
||||||
$keys = array_keys($row);
|
$keys = array_keys($row);
|
||||||
|
|
||||||
foreach ($keys as $k)
|
foreach ($keys as $k)
|
||||||
{
|
{
|
||||||
if (is_numeric($k))
|
if (is_numeric($k))
|
||||||
@ -49,6 +50,7 @@ class ReorganizeAnimeCollectionMedia extends AbstractMigration
|
|||||||
// and replace those rows with the individual entries
|
// and replace those rows with the individual entries
|
||||||
$linkRows = $this->fetchAll('SELECT hummingbird_id FROM anime_set_media_link WHERE media_id=1');
|
$linkRows = $this->fetchAll('SELECT hummingbird_id FROM anime_set_media_link WHERE media_id=1');
|
||||||
$insertRows = [];
|
$insertRows = [];
|
||||||
|
|
||||||
foreach ($linkRows as $row)
|
foreach ($linkRows as $row)
|
||||||
{
|
{
|
||||||
$insertRows[] = [
|
$insertRows[] = [
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?php
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
use Phinx\Migration\AbstractMigration;
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
@ -18,6 +18,7 @@ class AnimeCollectionRefactorCleanup extends AbstractMigration
|
|||||||
{
|
{
|
||||||
// Add some new media types
|
// Add some new media types
|
||||||
$moreMediaTypes = [];
|
$moreMediaTypes = [];
|
||||||
|
|
||||||
foreach ($this->newMediaTypes as $id => $medium)
|
foreach ($this->newMediaTypes as $id => $medium)
|
||||||
{
|
{
|
||||||
$moreMediaTypes[] = [
|
$moreMediaTypes[] = [
|
||||||
@ -47,7 +48,7 @@ class AnimeCollectionRefactorCleanup extends AbstractMigration
|
|||||||
$this->execute("UPDATE media SET type='Bootleg DVD' WHERE id=4");
|
$this->execute("UPDATE media SET type='Bootleg DVD' WHERE id=4");
|
||||||
|
|
||||||
// Remove the new media types
|
// 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);
|
$valueList = implode(',', $values);
|
||||||
$this->execute("DELETE FROM media WHERE type IN ({$valueList})");
|
$this->execute("DELETE FROM media WHERE type IN ({$valueList})");
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?php
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
use Phinx\Migration\AbstractMigration;
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
2
public/css/auto.min.css
vendored
2
public/css/auto.min.css
vendored
File diff suppressed because one or more lines are too long
2
public/css/dark.min.css
vendored
2
public/css/dark.min.css
vendored
File diff suppressed because one or more lines are too long
2
public/css/light.min.css
vendored
2
public/css/light.min.css
vendored
File diff suppressed because one or more lines are too long
2
public/js/scripts.min.js
vendored
2
public/js/scripts.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
public/js/tables.min.js
vendored
2
public/js/tables.min.js
vendored
@ -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
@ -6,31 +6,33 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API;
|
namespace Aviat\AnimeClient\API;
|
||||||
|
|
||||||
use const Aviat\AnimeClient\USER_AGENT;
|
use Amp\Http\Client\Body\FormBody;
|
||||||
|
|
||||||
use function Amp\Promise\wait;
|
|
||||||
use function Aviat\AnimeClient\getResponse;
|
|
||||||
|
|
||||||
use Amp\Http\Client\Request;
|
use Amp\Http\Client\Request;
|
||||||
use Amp\Http\Client\Body\FormBody;
|
|
||||||
use Aviat\Ion\Json;
|
use Aviat\Ion\Json;
|
||||||
|
|
||||||
|
use Error;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use Psr\Log\LoggerAwareTrait;
|
use Psr\Log\LoggerAwareTrait;
|
||||||
|
use Throwable;
|
||||||
|
use TypeError;
|
||||||
|
use function Amp\Promise\wait;
|
||||||
|
use function Aviat\AnimeClient\getResponse;
|
||||||
|
use const Aviat\AnimeClient\USER_AGENT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper around Http\Client to make it easier to build API requests
|
* Wrapper around Http\Client to make it easier to build API requests
|
||||||
*/
|
*/
|
||||||
abstract class APIRequestBuilder {
|
abstract class APIRequestBuilder
|
||||||
|
{
|
||||||
use LoggerAwareTrait;
|
use LoggerAwareTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,9 +72,6 @@ abstract class APIRequestBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Do a basic minimal GET request
|
* Do a basic minimal GET request
|
||||||
*
|
|
||||||
* @param string $uri
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public static function simpleRequest(string $uri): Request
|
public static function simpleRequest(string $uri): Request
|
||||||
{
|
{
|
||||||
@ -89,7 +88,6 @@ abstract class APIRequestBuilder {
|
|||||||
*
|
*
|
||||||
* @param string $type The type of authorization, eg, basic, bearer, etc.
|
* @param string $type The type of authorization, eg, basic, bearer, etc.
|
||||||
* @param string $value The authorization value
|
* @param string $value The authorization value
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function setAuth(string $type, string $value): self
|
public function setAuth(string $type, string $value): self
|
||||||
{
|
{
|
||||||
@ -101,26 +99,21 @@ abstract class APIRequestBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a basic authentication header
|
* Set a basic authentication header
|
||||||
*
|
|
||||||
* @param string $username
|
|
||||||
* @param string $password
|
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function setBasicAuth(string $username, string $password): self
|
public function setBasicAuth(string $username, string $password): self
|
||||||
{
|
{
|
||||||
$this->setAuth('basic', base64_encode($username . ':' . $password));
|
$this->setAuth('basic', base64_encode($username . ':' . $password));
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the request body
|
* Set the request body
|
||||||
*
|
|
||||||
* @param FormBody|string $body
|
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function setBody(FormBody|string $body): self
|
public function setBody(FormBody|string $body): self
|
||||||
{
|
{
|
||||||
$this->request->setBody($body);
|
$this->request->setBody($body);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +121,6 @@ abstract class APIRequestBuilder {
|
|||||||
* Set body as form fields
|
* Set body as form fields
|
||||||
*
|
*
|
||||||
* @param array $fields Mapping of field names to values
|
* @param array $fields Mapping of field names to values
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function setFormFields(array $fields): self
|
public function setFormFields(array $fields): self
|
||||||
{
|
{
|
||||||
@ -140,24 +132,18 @@ abstract class APIRequestBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Unset a request header
|
* Unset a request header
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function unsetHeader(string $name): self
|
public function unsetHeader(string $name): self
|
||||||
{
|
{
|
||||||
$this->request->removeHeader($name);
|
$this->request->removeHeader($name);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a request header
|
* Set a request header
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
* @param string|null $value
|
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function setHeader(string $name, string $value = NULL): self
|
public function setHeader(string $name, ?string $value = NULL): self
|
||||||
{
|
{
|
||||||
if (NULL === $value)
|
if (NULL === $value)
|
||||||
{
|
{
|
||||||
@ -175,9 +161,6 @@ abstract class APIRequestBuilder {
|
|||||||
* Set multiple request headers
|
* Set multiple request headers
|
||||||
*
|
*
|
||||||
* name => value
|
* name => value
|
||||||
*
|
|
||||||
* @param array $headers
|
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function setHeaders(array $headers): self
|
public function setHeaders(array $headers): self
|
||||||
{
|
{
|
||||||
@ -191,36 +174,30 @@ abstract class APIRequestBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the request body
|
* Set the request body
|
||||||
*
|
|
||||||
* @param mixed $body
|
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function setJsonBody(mixed $body): self
|
public function setJsonBody(mixed $body): self
|
||||||
{
|
{
|
||||||
$requestBody = ( ! is_string($body))
|
$requestBody = (is_string($body))
|
||||||
? Json::encode($body)
|
? $body
|
||||||
: $body;
|
: Json::encode($body);
|
||||||
|
|
||||||
return $this->setBody($requestBody);
|
return $this->setBody($requestBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append a query string in array format
|
* Append a query string in array format
|
||||||
*
|
|
||||||
* @param array $params
|
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function setQuery(array $params): self
|
public function setQuery(array $params): self
|
||||||
{
|
{
|
||||||
$this->query = http_build_query($params);
|
$this->query = http_build_query($params);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the promise for the current request
|
* Return the promise for the current request
|
||||||
*
|
*
|
||||||
* @return Request
|
* @throws Throwable
|
||||||
* @throws \Throwable
|
|
||||||
*/
|
*/
|
||||||
public function getFullRequest(): Request
|
public function getFullRequest(): Request
|
||||||
{
|
{
|
||||||
@ -235,7 +212,7 @@ abstract class APIRequestBuilder {
|
|||||||
$this->request->getBody()
|
$this->request->getBody()
|
||||||
->createBodyStream()
|
->createBodyStream()
|
||||||
->read()
|
->read()
|
||||||
)
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,25 +222,22 @@ abstract class APIRequestBuilder {
|
|||||||
/**
|
/**
|
||||||
* Get the data from the response of the passed request
|
* Get the data from the response of the passed request
|
||||||
*
|
*
|
||||||
* @param Request $request
|
* @throws Error
|
||||||
|
* @throws Throwable
|
||||||
|
* @throws TypeError
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws \Error
|
|
||||||
* @throws \Throwable
|
|
||||||
* @throws \TypeError
|
|
||||||
*/
|
*/
|
||||||
public function getResponseData(Request $request)
|
public function getResponseData(Request $request)
|
||||||
{
|
{
|
||||||
$response = getResponse($request);
|
$response = getResponse($request);
|
||||||
|
|
||||||
return wait($response->getBody()->buffer());
|
return wait($response->getBody()->buffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new http request
|
* Create a new http request
|
||||||
*
|
*
|
||||||
* @param string $type
|
|
||||||
* @param string $uri
|
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function newRequest(string $type, string $uri): self
|
public function newRequest(string $type, string $uri): self
|
||||||
{
|
{
|
||||||
@ -292,8 +266,6 @@ abstract class APIRequestBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the full request url
|
* Create the full request url
|
||||||
*
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
private function buildUri(): Request
|
private function buildUri(): Request
|
||||||
{
|
{
|
||||||
@ -313,10 +285,6 @@ abstract class APIRequestBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the class state for a new request
|
* Reset the class state for a new request
|
||||||
*
|
|
||||||
* @param string|null $url
|
|
||||||
* @param string $type
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
private function resetState(?string $url, string $type = 'GET'): void
|
private function resetState(?string $url, string $type = 'GET'): void
|
||||||
{
|
{
|
||||||
@ -330,4 +298,4 @@ abstract class APIRequestBuilder {
|
|||||||
$this->request->setTcpConnectTimeout(300000);
|
$this->request->setTcpConnectTimeout(300000);
|
||||||
$this->request->setTransferTimeout(300000);
|
$this->request->setTransferTimeout(300000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API;
|
namespace Aviat\AnimeClient\API;
|
||||||
@ -22,21 +20,17 @@ use Aviat\AnimeClient\Types\FormItemData;
|
|||||||
/**
|
/**
|
||||||
* Common interface for anime and manga list item CRUD
|
* Common interface for anime and manga list item CRUD
|
||||||
*/
|
*/
|
||||||
abstract class AbstractListItem {
|
abstract class AbstractListItem
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Create a list item
|
* Create a list item
|
||||||
*
|
*
|
||||||
* @param array $data -
|
* @param array $data -
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
abstract public function create(array $data): Request;
|
abstract public function create(array $data): Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a full list item for syncing
|
* Create a full list item for syncing
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
abstract public function createFull(array $data): Request;
|
abstract public function createFull(array $data): Request;
|
||||||
|
|
||||||
@ -44,16 +38,12 @@ abstract class AbstractListItem {
|
|||||||
* Retrieve a list item
|
* Retrieve a list item
|
||||||
*
|
*
|
||||||
* @param string $id - The id of the list item
|
* @param string $id - The id of the list item
|
||||||
* @return array
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
abstract public function get(string $id): array;
|
abstract public function get(string $id): array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increase progress on a list item
|
* Increase progress on a list item
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
* @param FormItemData $data
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
abstract public function increment(string $id, FormItemData $data): Request;
|
abstract public function increment(string $id, FormItemData $data): Request;
|
||||||
|
|
||||||
@ -62,7 +52,6 @@ abstract class AbstractListItem {
|
|||||||
*
|
*
|
||||||
* @param string $id - The id of the list item to update
|
* @param string $id - The id of the list item to update
|
||||||
* @param FormItemData $data - The data with which to update the list item
|
* @param FormItemData $data - The data with which to update the list item
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
abstract public function update(string $id, FormItemData $data): Request;
|
abstract public function update(string $id, FormItemData $data): Request;
|
||||||
|
|
||||||
@ -70,7 +59,6 @@ abstract class AbstractListItem {
|
|||||||
* Delete a list item
|
* Delete a list item
|
||||||
*
|
*
|
||||||
* @param string $id - The id of the list item to delete
|
* @param string $id - The id of the list item to delete
|
||||||
* @return Request|null
|
|
||||||
*/
|
*/
|
||||||
abstract public function delete(string $id):?Request;
|
abstract public function delete(string $id): ?Request;
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Anilist;
|
namespace Aviat\AnimeClient\API\Anilist;
|
||||||
@ -26,39 +24,32 @@ use Aviat\AnimeClient\Types\FormItemData;
|
|||||||
/**
|
/**
|
||||||
* CRUD operations for MAL list items
|
* CRUD operations for MAL list items
|
||||||
*/
|
*/
|
||||||
final class ListItem extends AbstractListItem {
|
final class ListItem extends AbstractListItem
|
||||||
|
{
|
||||||
use RequestBuilderTrait;
|
use RequestBuilderTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a minimal list item
|
* Create a minimal list item
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function create(array $data): Request
|
public function create(array $data): Request
|
||||||
{
|
{
|
||||||
$checkedData = Types\MediaListEntry::check($data);
|
$checkedData = Types\MediaListEntry::check($data);
|
||||||
|
|
||||||
return $this->requestBuilder->mutateRequest('CreateMediaListEntry', $checkedData ?? []);
|
return $this->requestBuilder->mutateRequest('CreateMediaListEntry', $checkedData ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a fleshed-out list item
|
* Create a fleshed-out list item
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function createFull(array $data): Request
|
public function createFull(array $data): Request
|
||||||
{
|
{
|
||||||
$checkedData = Types\MediaListEntry::check($data);
|
$checkedData = Types\MediaListEntry::check($data);
|
||||||
|
|
||||||
return $this->requestBuilder->mutateRequest('CreateFullMediaListEntry', $checkedData ?? []);
|
return $this->requestBuilder->mutateRequest('CreateFullMediaListEntry', $checkedData ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a list item
|
* Delete a list item
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
* @param string $type
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function delete(string $id, string $type = 'anime'): Request
|
public function delete(string $id, string $type = 'anime'): Request
|
||||||
{
|
{
|
||||||
@ -67,9 +58,6 @@ final class ListItem extends AbstractListItem {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the data for a list item
|
* Get the data for a list item
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function get(string $id): array
|
public function get(string $id): array
|
||||||
{
|
{
|
||||||
@ -78,10 +66,6 @@ final class ListItem extends AbstractListItem {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Increase the progress on the medium by 1
|
* Increase the progress on the medium by 1
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
* @param FormItemData $data
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function increment(string $id, FormItemData $data): Request
|
public function increment(string $id, FormItemData $data): Request
|
||||||
{
|
{
|
||||||
@ -95,31 +79,27 @@ final class ListItem extends AbstractListItem {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a list item
|
* Update a list item
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
* @param FormItemData $data
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function update(string $id, FormItemData $data): Request
|
public function update(string $id, FormItemData $data): Request
|
||||||
{
|
{
|
||||||
$notes = $data->notes ?? '';
|
$notes = $data->notes ?? '';
|
||||||
$progress = (int)$data->progress;
|
$progress = (int) $data->progress;
|
||||||
$private = (bool)$data->private;
|
$private = (bool) $data->private;
|
||||||
$rating = $data->ratingTwenty;
|
$rating = $data->ratingTwenty;
|
||||||
$status = ($data->reconsuming === TRUE)
|
$status = ($data->reconsuming === TRUE)
|
||||||
? AnilistStatus::REPEATING
|
? AnilistStatus::REPEATING
|
||||||
: AnimeWatchingStatus::KITSU_TO_ANILIST[$data->status];
|
: AnimeWatchingStatus::KITSU_TO_ANILIST[$data->status];
|
||||||
|
|
||||||
$updateData = Types\MediaListEntry::check([
|
$updateData = Types\MediaListEntry::check([
|
||||||
'id' => (int)$id,
|
'id' => (int) $id,
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
'score' => $rating * 5,
|
'score' => $rating * 5,
|
||||||
'progress' => $progress,
|
'progress' => $progress,
|
||||||
'repeat' => (int)$data['reconsumeCount'],
|
'repeat' => (int) $data['reconsumeCount'],
|
||||||
'private' => $private,
|
'private' => $private,
|
||||||
'notes' => $notes,
|
'notes' => $notes,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $this->requestBuilder->mutateRequest('UpdateMediaListEntry', $updateData ?? []);
|
return $this->requestBuilder->mutateRequest('UpdateMediaListEntry', $updateData ?? []);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,16 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Anilist;
|
namespace Aviat\AnimeClient\API\Anilist;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
|
||||||
class MissingIdException extends InvalidArgumentException {}
|
class MissingIdException extends InvalidArgumentException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@ -6,29 +6,25 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Anilist;
|
namespace Aviat\AnimeClient\API\Anilist;
|
||||||
|
|
||||||
use function Amp\Promise\wait;
|
|
||||||
|
|
||||||
use InvalidArgumentException;
|
|
||||||
|
|
||||||
use Amp\Http\Client\Request;
|
use Amp\Http\Client\Request;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Anilist;
|
use Aviat\AnimeClient\Anilist;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
|
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
|
||||||
use Aviat\AnimeClient\Types\FormItem;
|
use Aviat\AnimeClient\Types\FormItem;
|
||||||
|
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
||||||
use Aviat\Ion\Json;
|
use Aviat\Ion\Json;
|
||||||
use Aviat\Ion\Di\Exception\ContainerException;
|
use InvalidArgumentException;
|
||||||
use Aviat\Ion\Di\Exception\NotFoundException;
|
|
||||||
|
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
use function Amp\Promise\wait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Anilist API Model
|
* Anilist API Model
|
||||||
@ -36,32 +32,24 @@ use Throwable;
|
|||||||
final class Model
|
final class Model
|
||||||
{
|
{
|
||||||
use RequestBuilderTrait;
|
use RequestBuilderTrait;
|
||||||
/**
|
|
||||||
* @var ListItem
|
|
||||||
*/
|
|
||||||
private ListItem $listItem;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
|
||||||
* @param ListItem $listItem
|
|
||||||
*/
|
*/
|
||||||
public function __construct(ListItem $listItem)
|
public function __construct(private ListItem $listItem)
|
||||||
{
|
{
|
||||||
$this->listItem = $listItem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// ! Generic API calls
|
// ! Generic API calls
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to get an auth token
|
* Attempt to get an auth token
|
||||||
*
|
*
|
||||||
* @param string $code - The request token
|
* @param string $code - The request token
|
||||||
* @param string $redirectUri - The oauth callback url
|
* @param string $redirectUri - The oauth callback url
|
||||||
* @return array
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
public function authenticate(string $code, string $redirectUri): array
|
public function authenticate(string $code, string $redirectUri): array
|
||||||
{
|
{
|
||||||
@ -84,8 +72,6 @@ final class Model
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check auth status with simple API call
|
* Check auth status with simple API call
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function checkAuth(): array
|
public function checkAuth(): array
|
||||||
{
|
{
|
||||||
@ -95,8 +81,6 @@ final class Model
|
|||||||
/**
|
/**
|
||||||
* Get user list data for syncing with Kitsu
|
* Get user list data for syncing with Kitsu
|
||||||
*
|
*
|
||||||
* @param string $type
|
|
||||||
* @return array
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
@ -118,20 +102,10 @@ final class Model
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a list item
|
* Create a list item
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @param string $type
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function createListItem(array $data, string $type = 'anime'): ?Request
|
public function createListItem(array $data, string $type = 'anime'): ?Request
|
||||||
{
|
{
|
||||||
if ($data['mal_id'] === NULL)
|
$mediaId = $this->getMediaId($data, $type);
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
$mediaId = $this->getMediaIdFromMalId($data['mal_id'], mb_strtoupper($type));
|
|
||||||
|
|
||||||
if ($mediaId === NULL)
|
if ($mediaId === NULL)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -159,15 +133,11 @@ final class Model
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a list item with all the relevant data
|
* Create a list item with all the relevant data
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @param string $type
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function createFullListItem(array $data, string $type): Request
|
public function createFullListItem(array $data, string $type): Request
|
||||||
{
|
{
|
||||||
$createData = $data['data'];
|
$createData = $data['data'];
|
||||||
$mediaId = $this->getMediaIdFromMalId($data['mal_id'], strtoupper($type));
|
$mediaId = $this->getMediaId($data, $type);
|
||||||
|
|
||||||
if (empty($mediaId))
|
if (empty($mediaId))
|
||||||
{
|
{
|
||||||
@ -179,39 +149,14 @@ final class Model
|
|||||||
return $this->listItem->createFull($createData);
|
return $this->listItem->createFull($createData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the data for a specific list item, generally for editing
|
|
||||||
*
|
|
||||||
* @param string $malId - The unique identifier of that list item
|
|
||||||
* @param string $type - Them media type (anime/manga)
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getListItem(string $malId, string $type): array
|
|
||||||
{
|
|
||||||
$id = $this->getListIdFromMalId($malId, $type);
|
|
||||||
if ($id === NULL)
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = $this->listItem->get($id)['data'];
|
|
||||||
|
|
||||||
return ($data !== null)
|
|
||||||
? $data['MediaList']
|
|
||||||
: [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increase the watch count for the current list item
|
* Increase the watch count for the current list item
|
||||||
*
|
*
|
||||||
* @param FormItem $data
|
|
||||||
* @param string $type - Them media type (anime/manga)
|
* @param string $type - Them media type (anime/manga)
|
||||||
* @return Request|null
|
|
||||||
*/
|
*/
|
||||||
public function incrementListItem(FormItem $data, string $type): ?Request
|
public function incrementListItem(FormItem $data, string $type): ?Request
|
||||||
{
|
{
|
||||||
$id = $this->getListIdFromMalId($data['mal_id'], $type);
|
$id = $this->getListIdFromData($data, $type);
|
||||||
if ($id === NULL)
|
if ($id === NULL)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -223,14 +168,11 @@ final class Model
|
|||||||
/**
|
/**
|
||||||
* Modify a list item
|
* Modify a list item
|
||||||
*
|
*
|
||||||
* @param FormItem $data
|
|
||||||
* @param string $type - Them media type (anime/manga)
|
* @param string $type - Them media type (anime/manga)
|
||||||
* @return Request|null
|
|
||||||
*/
|
*/
|
||||||
public function updateListItem(FormItem $data, string $type): ?Request
|
public function updateListItem(FormItem $data, string $type): ?Request
|
||||||
{
|
{
|
||||||
$id = $this->getListIdFromMalId($data['mal_id'], mb_strtoupper($type));
|
$id = $this->getListIdFromData($data, $type);
|
||||||
|
|
||||||
if ($id === NULL)
|
if ($id === NULL)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -242,31 +184,32 @@ final class Model
|
|||||||
/**
|
/**
|
||||||
* Remove a list item
|
* Remove a list item
|
||||||
*
|
*
|
||||||
* @param string $malId - The id of the list item to remove
|
* @param FormItem $data - The entry to remove
|
||||||
* @param string $type - Them media type (anime/manga)
|
* @param string $type - The media type (anime/manga)
|
||||||
* @return Request|null
|
|
||||||
*/
|
*/
|
||||||
public function deleteListItem(string $malId, string $type): ?Request
|
public function deleteItem(FormItem $data, string $type): ?Request
|
||||||
{
|
{
|
||||||
$id = $this->getListIdFromMalId($malId, $type);
|
$mediaId = $this->getMediaId((array)$data, $type);
|
||||||
if ($id === NULL)
|
if ($mediaId === NULL)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->listItem->delete($id);
|
$id = $this->getListIdFromMediaId($mediaId);
|
||||||
|
if (is_string($id))
|
||||||
|
{
|
||||||
|
return $this->listItem->delete($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the id of the specific list entry from the malId
|
* Get the id of the specific list entry from the data
|
||||||
*
|
|
||||||
* @param string $malId
|
|
||||||
* @param string $type - The media type (anime/manga)
|
|
||||||
* @return string|null
|
|
||||||
*/
|
*/
|
||||||
public function getListIdFromMalId(string $malId, string $type): ?string
|
public function getListIdFromData(FormItem $data, string $type = 'ANIME'): ?string
|
||||||
{
|
{
|
||||||
$mediaId = $this->getMediaIdFromMalId($malId, $type);
|
$mediaId = $this->getMediaId((array)$data, $type);
|
||||||
if ($mediaId === NULL)
|
if ($mediaId === NULL)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -279,9 +222,6 @@ final class Model
|
|||||||
* Get the Anilist list item id from the media id from its MAL id
|
* Get the Anilist list item id from the media id from its MAL id
|
||||||
* this way is more accurate than getting the list item id
|
* this way is more accurate than getting the list item id
|
||||||
* directly from the MAL id
|
* directly from the MAL id
|
||||||
*
|
|
||||||
* @param string $mediaId
|
|
||||||
* @return string|null
|
|
||||||
*/
|
*/
|
||||||
private function getListIdFromMediaId(string $mediaId): ?string
|
private function getListIdFromMediaId(string $mediaId): ?string
|
||||||
{
|
{
|
||||||
@ -298,15 +238,26 @@ final class Model
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (string)$info['data']['MediaList']['id'];
|
return (string) $info['data']['MediaList']['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the id to update by
|
||||||
|
*/
|
||||||
|
private function getMediaId (array $data, string $type = 'ANIME'): ?string
|
||||||
|
{
|
||||||
|
if (isset($data['anilist_id']))
|
||||||
|
{
|
||||||
|
return $data['anilist_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (isset($data['mal_id']))
|
||||||
|
? $this->getMediaIdFromMalId($data['mal_id'], mb_strtoupper($type))
|
||||||
|
: NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Anilist media id from the malId
|
* Get the Anilist media id from the malId
|
||||||
*
|
|
||||||
* @param string $malId
|
|
||||||
* @param string $type
|
|
||||||
* @return string|null
|
|
||||||
*/
|
*/
|
||||||
private function getMediaIdFromMalId(string $malId, string $type = 'ANIME'): ?string
|
private function getMediaIdFromMalId(string $malId, string $type = 'ANIME'): ?string
|
||||||
{
|
{
|
||||||
@ -325,6 +276,6 @@ final class Model
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (string)$info['data']['Media']['id'];
|
return (string) $info['data']['Media']['id'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,52 +6,44 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Anilist;
|
namespace Aviat\AnimeClient\API\Anilist;
|
||||||
|
|
||||||
use Amp\Http\Client\Request;
|
use Amp\Http\Client\{Request, Response};
|
||||||
use Amp\Http\Client\Response;
|
|
||||||
use Aviat\AnimeClient\Anilist;
|
use Aviat\AnimeClient\Anilist;
|
||||||
use Aviat\Ion\Di\ContainerAware;
|
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
|
||||||
use Aviat\Ion\Json;
|
|
||||||
|
|
||||||
use Aviat\Ion\JsonException;
|
|
||||||
use function Amp\Promise\wait;
|
|
||||||
use function Aviat\AnimeClient\getResponse;
|
|
||||||
use const Aviat\AnimeClient\USER_AGENT;
|
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\APIRequestBuilder;
|
use Aviat\AnimeClient\API\APIRequestBuilder;
|
||||||
|
use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
|
||||||
|
use Aviat\Ion\{Json, JsonException};
|
||||||
use LogicException;
|
use LogicException;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
final class RequestBuilder extends APIRequestBuilder {
|
use function Amp\Promise\wait;
|
||||||
|
|
||||||
|
use function Aviat\AnimeClient\getResponse;
|
||||||
|
use function in_array;
|
||||||
|
use const Aviat\AnimeClient\USER_AGENT;
|
||||||
|
|
||||||
|
final class RequestBuilder extends APIRequestBuilder
|
||||||
|
{
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base url for api requests
|
* The base url for api requests
|
||||||
* @var string $base_url
|
|
||||||
*/
|
*/
|
||||||
protected string $baseUrl = Anilist::BASE_URL;
|
protected string $baseUrl = Anilist::BASE_URL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Valid HTTP request methods
|
* Valid HTTP request methods
|
||||||
* @var array
|
|
||||||
*/
|
*/
|
||||||
protected array $validMethods = ['POST'];
|
protected array $validMethods = ['POST'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP headers to send with every request
|
* HTTP headers to send with every request
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
*/
|
||||||
protected array $defaultHeaders = [
|
protected array $defaultHeaders = [
|
||||||
'Accept' => 'application/json',
|
'Accept' => 'application/json',
|
||||||
@ -67,9 +59,6 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a request object
|
* Create a request object
|
||||||
* @param string $url
|
|
||||||
* @param array $options
|
|
||||||
* @return Request
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function setUpRequest(string $url, array $options = []): Request
|
public function setUpRequest(string $url, array $options = []): Request
|
||||||
@ -111,10 +100,6 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Run a GraphQL API query
|
* Run a GraphQL API query
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
* @param array $variables
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function runQuery(string $name, array $variables = []): array
|
public function runQuery(string $name, array $variables = []): array
|
||||||
{
|
{
|
||||||
@ -126,30 +111,28 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
|
|
||||||
$query = file_get_contents($file);
|
$query = file_get_contents($file);
|
||||||
$body = [
|
$body = [
|
||||||
'query' => $query
|
'query' => $query,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ( ! empty($variables))
|
if ( ! empty($variables))
|
||||||
{
|
{
|
||||||
$body['variables'] = [];
|
$body['variables'] = [];
|
||||||
foreach($variables as $key => $val)
|
|
||||||
|
foreach ($variables as $key => $val)
|
||||||
{
|
{
|
||||||
$body['variables'][$key] = $val;
|
$body['variables'][$key] = $val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->postRequest([
|
return $this->postRequest([
|
||||||
'body' => $body
|
'body' => $body,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
|
||||||
* @param array $variables
|
|
||||||
* @return Request
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function mutateRequest (string $name, array $variables = []): Request
|
public function mutateRequest(string $name, array $variables = []): Request
|
||||||
{
|
{
|
||||||
$file = __DIR__ . "/Mutations/{$name}.graphql";
|
$file = __DIR__ . "/Mutations/{$name}.graphql";
|
||||||
if ( ! file_exists($file))
|
if ( ! file_exists($file))
|
||||||
@ -160,11 +143,13 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
$query = file_get_contents($file);
|
$query = file_get_contents($file);
|
||||||
|
|
||||||
$body = [
|
$body = [
|
||||||
'query' => $query
|
'query' => $query,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!empty($variables)) {
|
if ( ! empty($variables))
|
||||||
|
{
|
||||||
$body['variables'] = [];
|
$body['variables'] = [];
|
||||||
|
|
||||||
foreach ($variables as $key => $val)
|
foreach ($variables as $key => $val)
|
||||||
{
|
{
|
||||||
$body['variables'][$key] = $val;
|
$body['variables'][$key] = $val;
|
||||||
@ -177,12 +162,10 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
|
||||||
* @param array $variables
|
|
||||||
* @return array
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
public function mutate (string $name, array $variables = []): array
|
public function mutate(string $name, array $variables = []): array
|
||||||
{
|
{
|
||||||
$request = $this->mutateRequest($name, $variables);
|
$request = $this->mutateRequest($name, $variables);
|
||||||
$response = $this->getResponseFromRequest($request);
|
$response = $this->getResponseFromRequest($request);
|
||||||
@ -193,9 +176,6 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
/**
|
/**
|
||||||
* Make a request
|
* Make a request
|
||||||
*
|
*
|
||||||
* @param string $url
|
|
||||||
* @param array $options
|
|
||||||
* @return Response
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
private function getResponse(string $url, array $options = []): Response
|
private function getResponse(string $url, array $options = []): Response
|
||||||
@ -220,8 +200,6 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Request $request
|
|
||||||
* @return Response
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function getResponseFromRequest(Request $request): Response
|
public function getResponseFromRequest(Request $request): Response
|
||||||
@ -247,8 +225,6 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
/**
|
/**
|
||||||
* Remove some boilerplate for post requests
|
* Remove some boilerplate for post requests
|
||||||
*
|
*
|
||||||
* @param array $options
|
|
||||||
* @return array
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
protected function postRequest(array $options = []): array
|
protected function postRequest(array $options = []): array
|
||||||
@ -265,13 +241,13 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
//'requestHeaders' => $request->getHeaders(),
|
//'requestHeaders' => $request->getHeaders(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if ( ! in_array($response->getStatus(), $validResponseCodes, TRUE))
|
||||||
if ( ! \in_array($response->getStatus(), $validResponseCodes, TRUE))
|
|
||||||
{
|
{
|
||||||
$logger?->warning('Non 200 response for POST api call', (array)$response->getBody());
|
$logger?->warning('Non 200 response for POST api call', (array) $response->getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
$rawBody = wait($response->getBody()->buffer());
|
$rawBody = wait($response->getBody()->buffer());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Json::decode($rawBody);
|
return Json::decode($rawBody);
|
||||||
@ -280,7 +256,8 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
{
|
{
|
||||||
dump($e);
|
dump($e);
|
||||||
dump($rawBody);
|
dump($rawBody);
|
||||||
die();
|
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,18 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Anilist;
|
namespace Aviat\AnimeClient\API\Anilist;
|
||||||
|
|
||||||
use Aviat\Ion\Di\ContainerAware;
|
use Aviat\Ion\Di\ContainerAware;
|
||||||
|
|
||||||
trait RequestBuilderTrait {
|
trait RequestBuilderTrait
|
||||||
|
{
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,13 +27,11 @@ trait RequestBuilderTrait {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the request builder object
|
* Set the request builder object
|
||||||
*
|
|
||||||
* @param RequestBuilder $requestBuilder
|
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function setRequestBuilder(RequestBuilder $requestBuilder): self
|
public function setRequestBuilder(RequestBuilder $requestBuilder): self
|
||||||
{
|
{
|
||||||
$this->requestBuilder = $requestBuilder;
|
$this->requestBuilder = $requestBuilder;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,15 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Anilist\Transformer;
|
namespace Aviat\AnimeClient\API\Anilist\Transformer;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\Anilist as AnilistStatus;
|
use Aviat\AnimeClient\API\{Enum, Mapping};
|
||||||
use Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\Kitsu as KitsuStatus;
|
|
||||||
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
|
|
||||||
use Aviat\AnimeClient\Types\{AnimeListItem, FormItem};
|
use Aviat\AnimeClient\Types\{AnimeListItem, FormItem};
|
||||||
|
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
@ -26,8 +22,8 @@ use Aviat\Ion\Transformer\AbstractTransformer;
|
|||||||
use DateTime;
|
use DateTime;
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
|
|
||||||
class AnimeListTransformer extends AbstractTransformer {
|
class AnimeListTransformer extends AbstractTransformer
|
||||||
|
{
|
||||||
public function transform(array|object $item): AnimeListItem
|
public function transform(array|object $item): AnimeListItem
|
||||||
{
|
{
|
||||||
return AnimeListItem::from([]);
|
return AnimeListItem::from([]);
|
||||||
@ -35,13 +31,10 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform Anilist list item to Kitsu form update format
|
* Transform Anilist list item to Kitsu form update format
|
||||||
*
|
|
||||||
* @param array $item
|
|
||||||
* @return FormItem
|
|
||||||
*/
|
*/
|
||||||
public function untransform(array $item): FormItem
|
public function untransform(array $item): FormItem
|
||||||
{
|
{
|
||||||
$reconsuming = $item['status'] === AnilistStatus::REPEATING;
|
$reconsuming = $item['status'] === Enum\AnimeWatchingStatus\Anilist::REPEATING;
|
||||||
|
|
||||||
return FormItem::from([
|
return FormItem::from([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
@ -54,12 +47,12 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
'reconsumeCount' => $item['repeat'],
|
'reconsumeCount' => $item['repeat'],
|
||||||
'reconsuming' => $reconsuming,
|
'reconsuming' => $reconsuming,
|
||||||
'status' => $reconsuming
|
'status' => $reconsuming
|
||||||
? KitsuStatus::WATCHING
|
? Enum\AnimeWatchingStatus\Kitsu::WATCHING
|
||||||
: AnimeWatchingStatus::ANILIST_TO_KITSU[$item['status']],
|
: Mapping\AnimeWatchingStatus::ANILIST_TO_KITSU[$item['status']],
|
||||||
'updatedAt' => (new DateTime())
|
'updatedAt' => (new DateTime())
|
||||||
->setTimestamp($item['updatedAt'])
|
->setTimestamp($item['updatedAt'])
|
||||||
->format(DateTimeInterface::W3C)
|
->format(DateTimeInterface::W3C),
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,29 +6,23 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Anilist\Transformer;
|
namespace Aviat\AnimeClient\API\Anilist\Transformer;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Enum\MangaReadingStatus\Anilist as AnilistStatus;
|
use Aviat\AnimeClient\API\{Enum, Mapping};
|
||||||
use Aviat\AnimeClient\API\Enum\MangaReadingStatus\Kitsu as KitsuStatus;
|
use Aviat\AnimeClient\Types\{FormItem, MangaListItem};
|
||||||
use Aviat\AnimeClient\API\Mapping\MangaReadingStatus;
|
|
||||||
use Aviat\AnimeClient\Types\MangaListItem;
|
|
||||||
use Aviat\AnimeClient\Types\FormItem;
|
|
||||||
|
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
|
|
||||||
class MangaListTransformer extends AbstractTransformer {
|
class MangaListTransformer extends AbstractTransformer
|
||||||
|
{
|
||||||
public function transform(array|object $item): MangaListItem
|
public function transform(array|object $item): MangaListItem
|
||||||
{
|
{
|
||||||
return MangaListItem::from([]);
|
return MangaListItem::from([]);
|
||||||
@ -36,13 +30,10 @@ class MangaListTransformer extends AbstractTransformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform Anilist list item to Kitsu form update format
|
* Transform Anilist list item to Kitsu form update format
|
||||||
*
|
|
||||||
* @param array $item
|
|
||||||
* @return FormItem
|
|
||||||
*/
|
*/
|
||||||
public function untransform(array $item): FormItem
|
public function untransform(array $item): FormItem
|
||||||
{
|
{
|
||||||
$reconsuming = $item['status'] === AnilistStatus::REPEATING;
|
$reconsuming = $item['status'] === Enum\MangaReadingStatus\Anilist::REPEATING;
|
||||||
|
|
||||||
return FormItem::from([
|
return FormItem::from([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
@ -55,12 +46,12 @@ class MangaListTransformer extends AbstractTransformer {
|
|||||||
'reconsumeCount' => $item['repeat'],
|
'reconsumeCount' => $item['repeat'],
|
||||||
'reconsuming' => $reconsuming,
|
'reconsuming' => $reconsuming,
|
||||||
'status' => $reconsuming
|
'status' => $reconsuming
|
||||||
? KitsuStatus::READING
|
? Enum\MangaReadingStatus\Kitsu::READING
|
||||||
: MangaReadingStatus::ANILIST_TO_KITSU[$item['status']],
|
: Mapping\MangaReadingStatus::ANILIST_TO_KITSU[$item['status']],
|
||||||
'updatedAt' => (new DateTime())
|
'updatedAt' => (new DateTime())
|
||||||
->setTimestamp($item['updatedAt'])
|
->setTimestamp($item['updatedAt'])
|
||||||
->format(DateTimeInterface::W3C),
|
->format(DateTimeInterface::W3C),
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,31 +6,23 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Anilist\Types;
|
namespace Aviat\AnimeClient\API\Anilist\Types;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Types\AbstractType;
|
use Aviat\AnimeClient\Types\AbstractType;
|
||||||
|
|
||||||
class MediaListEntry extends AbstractType {
|
class MediaListEntry extends AbstractType
|
||||||
|
{
|
||||||
public int|string $id;
|
public int|string $id;
|
||||||
|
|
||||||
public ?string $notes;
|
public ?string $notes;
|
||||||
|
|
||||||
public ?bool $private;
|
public ?bool $private;
|
||||||
|
|
||||||
public int $progress;
|
public int $progress;
|
||||||
|
|
||||||
public ?int $repeat;
|
public ?int $repeat;
|
||||||
|
|
||||||
public string $status;
|
public string $status;
|
||||||
|
|
||||||
public ?int $score;
|
public ?int $score;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API;
|
namespace Aviat\AnimeClient\API;
|
||||||
@ -21,29 +19,22 @@ use Psr\SimpleCache\CacheInterface;
|
|||||||
/**
|
/**
|
||||||
* Helper methods for dealing with the Cache
|
* Helper methods for dealing with the Cache
|
||||||
*/
|
*/
|
||||||
trait CacheTrait {
|
trait CacheTrait
|
||||||
|
{
|
||||||
/**
|
|
||||||
* @var CacheInterface
|
|
||||||
*/
|
|
||||||
protected CacheInterface $cache;
|
protected CacheInterface $cache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inject the cache object
|
* Inject the cache object
|
||||||
*
|
|
||||||
* @param CacheInterface $cache
|
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function setCache(CacheInterface $cache): self
|
public function setCache(CacheInterface $cache): self
|
||||||
{
|
{
|
||||||
$this->cache = $cache;
|
$this->cache = $cache;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the cache object if it exists
|
* Get the cache object if it exists
|
||||||
*
|
|
||||||
* @return CacheInterface
|
|
||||||
*/
|
*/
|
||||||
public function getCache(): CacheInterface
|
public function getCache(): CacheInterface
|
||||||
{
|
{
|
||||||
@ -53,11 +44,6 @@ trait CacheTrait {
|
|||||||
/**
|
/**
|
||||||
* Get the cached value if it exists, otherwise set the cache value
|
* Get the cached value if it exists, otherwise set the cache value
|
||||||
* and return it.
|
* and return it.
|
||||||
*
|
|
||||||
* @param string $key
|
|
||||||
* @param callable $primer
|
|
||||||
* @param array|null $primeArgs
|
|
||||||
* @return mixed
|
|
||||||
*/
|
*/
|
||||||
public function getCached(string $key, callable $primer, ?array $primeArgs = []): mixed
|
public function getCached(string $key, callable $primer, ?array $primeArgs = []): mixed
|
||||||
{
|
{
|
||||||
@ -77,4 +63,4 @@ trait CacheTrait {
|
|||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Enum\AnimeWatchingStatus;
|
namespace Aviat\AnimeClient\API\Enum\AnimeWatchingStatus;
|
||||||
@ -21,11 +19,12 @@ use Aviat\Ion\Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for watching status for the current anime
|
* Possible values for watching status for the current anime
|
||||||
*/
|
*/
|
||||||
final class Anilist extends Enum {
|
final class Anilist extends Enum
|
||||||
|
{
|
||||||
public const WATCHING = 'CURRENT';
|
public const WATCHING = 'CURRENT';
|
||||||
public const COMPLETED = 'COMPLETED';
|
public const COMPLETED = 'COMPLETED';
|
||||||
public const ON_HOLD = 'PAUSED';
|
public const ON_HOLD = 'PAUSED';
|
||||||
public const DROPPED = 'DROPPED';
|
public const DROPPED = 'DROPPED';
|
||||||
public const PLAN_TO_WATCH = 'PLANNING';
|
public const PLAN_TO_WATCH = 'PLANNING';
|
||||||
public const REPEATING = 'REPEATING';
|
public const REPEATING = 'REPEATING';
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Enum\AnimeWatchingStatus;
|
namespace Aviat\AnimeClient\API\Enum\AnimeWatchingStatus;
|
||||||
@ -21,10 +19,11 @@ use Aviat\Ion\Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for watching status for the current anime
|
* Possible values for watching status for the current anime
|
||||||
*/
|
*/
|
||||||
final class Kitsu extends Enum {
|
final class Kitsu extends Enum
|
||||||
|
{
|
||||||
public const WATCHING = 'current';
|
public const WATCHING = 'current';
|
||||||
public const PLAN_TO_WATCH = 'planned';
|
public const PLAN_TO_WATCH = 'planned';
|
||||||
public const ON_HOLD = 'on_hold';
|
public const ON_HOLD = 'on_hold';
|
||||||
public const DROPPED = 'dropped';
|
public const DROPPED = 'dropped';
|
||||||
public const COMPLETED = 'completed';
|
public const COMPLETED = 'completed';
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Enum\AnimeWatchingStatus;
|
namespace Aviat\AnimeClient\API\Enum\AnimeWatchingStatus;
|
||||||
@ -21,7 +19,8 @@ use Aviat\Ion\Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for current watching status of anime
|
* Possible values for current watching status of anime
|
||||||
*/
|
*/
|
||||||
final class Route extends Enum {
|
final class Route extends Enum
|
||||||
|
{
|
||||||
public const ALL = 'all';
|
public const ALL = 'all';
|
||||||
public const WATCHING = 'watching';
|
public const WATCHING = 'watching';
|
||||||
public const PLAN_TO_WATCH = 'plan_to_watch';
|
public const PLAN_TO_WATCH = 'plan_to_watch';
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Enum\AnimeWatchingStatus;
|
namespace Aviat\AnimeClient\API\Enum\AnimeWatchingStatus;
|
||||||
@ -21,7 +19,8 @@ use Aviat\Ion\Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for current watching status of anime
|
* Possible values for current watching status of anime
|
||||||
*/
|
*/
|
||||||
final class Title extends Enum {
|
final class Title extends Enum
|
||||||
|
{
|
||||||
public const ALL = 'All';
|
public const ALL = 'All';
|
||||||
public const WATCHING = 'Currently Watching';
|
public const WATCHING = 'Currently Watching';
|
||||||
public const PLAN_TO_WATCH = 'Plan to Watch';
|
public const PLAN_TO_WATCH = 'Plan to Watch';
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
|
namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
|
||||||
@ -21,11 +19,12 @@ use Aviat\Ion\Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for watching status for the current anime
|
* Possible values for watching status for the current anime
|
||||||
*/
|
*/
|
||||||
final class Anilist extends Enum {
|
final class Anilist extends Enum
|
||||||
|
{
|
||||||
public const READING = 'CURRENT';
|
public const READING = 'CURRENT';
|
||||||
public const COMPLETED = 'COMPLETED';
|
public const COMPLETED = 'COMPLETED';
|
||||||
public const ON_HOLD = 'PAUSED';
|
public const ON_HOLD = 'PAUSED';
|
||||||
public const DROPPED = 'DROPPED';
|
public const DROPPED = 'DROPPED';
|
||||||
public const PLAN_TO_READ = 'PLANNING';
|
public const PLAN_TO_READ = 'PLANNING';
|
||||||
public const REPEATING = 'REPEATING';
|
public const REPEATING = 'REPEATING';
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
|
namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
|
||||||
@ -21,10 +19,11 @@ use Aviat\Ion\Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for current reading status of manga
|
* Possible values for current reading status of manga
|
||||||
*/
|
*/
|
||||||
final class Kitsu extends Enum {
|
final class Kitsu extends Enum
|
||||||
|
{
|
||||||
public const READING = 'current';
|
public const READING = 'current';
|
||||||
public const PLAN_TO_READ = 'planned';
|
public const PLAN_TO_READ = 'planned';
|
||||||
public const DROPPED = 'dropped';
|
public const DROPPED = 'dropped';
|
||||||
public const ON_HOLD = 'on_hold';
|
public const ON_HOLD = 'on_hold';
|
||||||
public const COMPLETED = 'completed';
|
public const COMPLETED = 'completed';
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
|
namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
|
||||||
@ -21,7 +19,8 @@ use Aviat\Ion\Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for current reading status of manga
|
* Possible values for current reading status of manga
|
||||||
*/
|
*/
|
||||||
final class Route extends Enum {
|
final class Route extends Enum
|
||||||
|
{
|
||||||
public const ALL = 'all';
|
public const ALL = 'all';
|
||||||
public const READING = 'reading';
|
public const READING = 'reading';
|
||||||
public const PLAN_TO_READ = 'plan_to_read';
|
public const PLAN_TO_READ = 'plan_to_read';
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
|
namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
|
||||||
@ -21,7 +19,8 @@ use Aviat\Ion\Enum;
|
|||||||
/**
|
/**
|
||||||
* Possible values for current reading status of manga
|
* Possible values for current reading status of manga
|
||||||
*/
|
*/
|
||||||
final class Title extends Enum {
|
final class Title extends Enum
|
||||||
|
{
|
||||||
public const ALL = 'All';
|
public const ALL = 'All';
|
||||||
public const READING = 'Currently Reading';
|
public const READING = 'Currently Reading';
|
||||||
public const PLAN_TO_READ = 'Plan to Read';
|
public const PLAN_TO_READ = 'Plan to Read';
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API;
|
namespace Aviat\AnimeClient\API;
|
||||||
@ -21,6 +19,6 @@ use UnexpectedValueException;
|
|||||||
/**
|
/**
|
||||||
* Exception for an API Request that fails validation
|
* Exception for an API Request that fails validation
|
||||||
*/
|
*/
|
||||||
class FailedResponseException extends UnexpectedValueException {
|
class FailedResponseException extends UnexpectedValueException
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
@ -6,50 +6,43 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu;
|
namespace Aviat\AnimeClient\API\Kitsu;
|
||||||
|
|
||||||
use Aura\Session\Segment;
|
use Aura\Session\Segment;
|
||||||
|
|
||||||
use const Aviat\AnimeClient\SESSION_SEGMENT;
|
use Aviat\AnimeClient\API\CacheTrait;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Kitsu as K;
|
use Aviat\AnimeClient\Kitsu as K;
|
||||||
use Aviat\AnimeClient\API\CacheTrait;
|
|
||||||
use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
|
use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
|
||||||
use Aviat\Ion\Event;
|
use Aviat\Ion\Event;
|
||||||
|
use const Aviat\AnimeClient\SESSION_SEGMENT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kitsu API Authentication
|
* Kitsu API Authentication
|
||||||
*/
|
*/
|
||||||
final class Auth {
|
final class Auth
|
||||||
|
{
|
||||||
use CacheTrait;
|
use CacheTrait;
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Anime API Model
|
* Anime API Model
|
||||||
*
|
|
||||||
* @var Model
|
|
||||||
*/
|
*/
|
||||||
private Model $model;
|
private Model $model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Session object
|
* Session object
|
||||||
*
|
|
||||||
* @var Segment
|
|
||||||
*/
|
*/
|
||||||
private Segment $segment;
|
private Segment $segment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
|
||||||
* @param ContainerInterface $container
|
|
||||||
*/
|
*/
|
||||||
public function __construct(ContainerInterface $container)
|
public function __construct(ContainerInterface $container)
|
||||||
{
|
{
|
||||||
@ -65,9 +58,6 @@ final class Auth {
|
|||||||
/**
|
/**
|
||||||
* Make the appropriate authentication call,
|
* Make the appropriate authentication call,
|
||||||
* and save the resulting auth token if successful
|
* and save the resulting auth token if successful
|
||||||
*
|
|
||||||
* @param string $password
|
|
||||||
* @return boolean
|
|
||||||
*/
|
*/
|
||||||
public function authenticate(string $password): bool
|
public function authenticate(string $password): bool
|
||||||
{
|
{
|
||||||
@ -81,9 +71,6 @@ final class Auth {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Make the call to re-authenticate with the existing refresh token
|
* Make the call to re-authenticate with the existing refresh token
|
||||||
*
|
|
||||||
* @param string|null $refreshToken
|
|
||||||
* @return boolean
|
|
||||||
*/
|
*/
|
||||||
public function reAuthenticate(?string $refreshToken = NULL): bool
|
public function reAuthenticate(?string $refreshToken = NULL): bool
|
||||||
{
|
{
|
||||||
@ -101,18 +88,14 @@ final class Auth {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the current user is authenticated
|
* Check whether the current user is authenticated
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
*/
|
||||||
public function isAuthenticated(): bool
|
public function isAuthenticated(): bool
|
||||||
{
|
{
|
||||||
return ($this->getAuthToken() !== NULL);
|
return $this->getAuthToken() !== NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear authentication values
|
* Clear authentication values
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
public function logout(): void
|
public function logout(): void
|
||||||
{
|
{
|
||||||
@ -121,8 +104,6 @@ final class Auth {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the authentication token from the session
|
* Retrieve the authentication token from the session
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
*/
|
||||||
public function getAuthToken(): ?string
|
public function getAuthToken(): ?string
|
||||||
{
|
{
|
||||||
@ -137,8 +118,6 @@ final class Auth {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the refresh token
|
* Retrieve the refresh token
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
*/
|
||||||
private function getRefreshToken(): ?string
|
private function getRefreshToken(): ?string
|
||||||
{
|
{
|
||||||
@ -153,11 +132,8 @@ final class Auth {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the new authentication information
|
* Save the new authentication information
|
||||||
*
|
|
||||||
* @param array|false $auth
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
private function storeAuth(array|false $auth): bool
|
private function storeAuth(array|FALSE $auth): bool
|
||||||
{
|
{
|
||||||
if (FALSE !== $auth)
|
if (FALSE !== $auth)
|
||||||
{
|
{
|
||||||
@ -178,6 +154,7 @@ final class Auth {
|
|||||||
$this->segment->set('auth_token', $auth['access_token']);
|
$this->segment->set('auth_token', $auth['access_token']);
|
||||||
$this->segment->set('auth_token_expires', $expire_time);
|
$this->segment->set('auth_token_expires', $expire_time);
|
||||||
$this->segment->set('refresh_token', $auth['refresh_token']);
|
$this->segment->set('refresh_token', $auth['refresh_token']);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,4 +162,5 @@ final class Auth {
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// End of KitsuAuth.php
|
|
||||||
|
// End of KitsuAuth.php
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Enum;
|
namespace Aviat\AnimeClient\API\Kitsu\Enum;
|
||||||
@ -21,7 +19,8 @@ use Aviat\Ion\Enum as BaseEnum;
|
|||||||
/**
|
/**
|
||||||
* Status of when anime is being/was/will be aired
|
* Status of when anime is being/was/will be aired
|
||||||
*/
|
*/
|
||||||
final class AnimeAiringStatus extends BaseEnum {
|
final class AnimeAiringStatus extends BaseEnum
|
||||||
|
{
|
||||||
public const NOT_YET_AIRED = 'Not Yet Aired';
|
public const NOT_YET_AIRED = 'Not Yet Aired';
|
||||||
public const AIRING = 'Currently Airing';
|
public const AIRING = 'Currently Airing';
|
||||||
public const FINISHED_AIRING = 'Finished Airing';
|
public const FINISHED_AIRING = 'Finished Airing';
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Enum;
|
namespace Aviat\AnimeClient\API\Kitsu\Enum;
|
||||||
@ -21,7 +19,8 @@ use Aviat\Ion\Enum as BaseEnum;
|
|||||||
/**
|
/**
|
||||||
* Status of when anime is being/was/will be aired
|
* Status of when anime is being/was/will be aired
|
||||||
*/
|
*/
|
||||||
final class MangaPublishingStatus extends BaseEnum {
|
final class MangaPublishingStatus extends BaseEnum
|
||||||
|
{
|
||||||
public const NOT_YET_PUBLISHED = 'Not Yet Published';
|
public const NOT_YET_PUBLISHED = 'Not Yet Published';
|
||||||
public const FINISHED = 'Completed';
|
public const FINISHED = 'Completed';
|
||||||
public const CURRENT = 'Current';
|
public const CURRENT = 'Current';
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu;
|
namespace Aviat\AnimeClient\API\Kitsu;
|
||||||
@ -26,13 +24,12 @@ use Throwable;
|
|||||||
/**
|
/**
|
||||||
* CRUD operations for Kitsu list items
|
* CRUD operations for Kitsu list items
|
||||||
*/
|
*/
|
||||||
final class ListItem extends AbstractListItem {
|
final class ListItem extends AbstractListItem
|
||||||
|
{
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
use RequestBuilderTrait;
|
use RequestBuilderTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $data
|
|
||||||
* @return Request
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function create(array $data): Request
|
public function create(array $data): Request
|
||||||
@ -52,23 +49,23 @@ final class ListItem extends AbstractListItem {
|
|||||||
'type' => 'libraryEntries',
|
'type' => 'libraryEntries',
|
||||||
'attributes' => [
|
'attributes' => [
|
||||||
'status' => $data['status'],
|
'status' => $data['status'],
|
||||||
'progress' => $data['progress'] ?? 0
|
'progress' => $data['progress'] ?? 0,
|
||||||
],
|
],
|
||||||
'relationships' => [
|
'relationships' => [
|
||||||
'user' => [
|
'user' => [
|
||||||
'data' => [
|
'data' => [
|
||||||
'id' => $data['user_id'],
|
'id' => $data['user_id'],
|
||||||
'type' => 'users'
|
'type' => 'users',
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'media' => [
|
'media' => [
|
||||||
'data' => [
|
'data' => [
|
||||||
'id' => $data['id'],
|
'id' => $data['id'],
|
||||||
'type' => $data['type']
|
'type' => $data['type'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
if (array_key_exists('notes', $data))
|
if (array_key_exists('notes', $data))
|
||||||
@ -90,21 +87,18 @@ final class ListItem extends AbstractListItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $id
|
|
||||||
* @return Request
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function delete(string $id): Request
|
public function delete(string $id): Request
|
||||||
{
|
{
|
||||||
return $this->requestBuilder->mutateRequest('DeleteLibraryItem', [
|
return $this->requestBuilder->mutateRequest('DeleteLibraryItem', [
|
||||||
'id' => $id
|
'id' => $id,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $id
|
|
||||||
* @return array
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
public function get(string $id): array
|
public function get(string $id): array
|
||||||
{
|
{
|
||||||
@ -115,23 +109,16 @@ final class ListItem extends AbstractListItem {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Increase the progress on the medium by 1
|
* Increase the progress on the medium by 1
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
* @param FormItemData $data
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function increment(string $id, FormItemData $data): Request
|
public function increment(string $id, FormItemData $data): Request
|
||||||
{
|
{
|
||||||
return $this->requestBuilder->mutateRequest('IncrementLibraryItem', [
|
return $this->requestBuilder->mutateRequest('IncrementLibraryItem', [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'progress' => $data->progress
|
'progress' => $data->progress,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $id
|
|
||||||
* @param FormItemData $data
|
|
||||||
* @return Request
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function update(string $id, FormItemData $data): Request
|
public function update(string $id, FormItemData $data): Request
|
||||||
@ -140,20 +127,21 @@ final class ListItem extends AbstractListItem {
|
|||||||
$updateData = [
|
$updateData = [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'notes' => $data['notes'],
|
'notes' => $data['notes'],
|
||||||
'private' => (bool)$data['private'],
|
'private' => (bool) $data['private'],
|
||||||
'reconsumeCount' => (int)$data['reconsumeCount'],
|
'reconsumeCount' => (int) $data['reconsumeCount'],
|
||||||
'reconsuming' => (bool)$data['reconsuming'],
|
'reconsuming' => (bool) $data['reconsuming'],
|
||||||
'status' => strtoupper($data['status']),
|
'status' => strtoupper($data['status']),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Only send these variables if they have a value
|
// Only send these variables if they have a value
|
||||||
if ($data['progress'] !== NULL)
|
if ($data['progress'] !== NULL)
|
||||||
{
|
{
|
||||||
$updateData['progress'] = (int)$data['progress'];
|
$updateData['progress'] = (int) $data['progress'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($data['ratingTwenty'] !== NULL)
|
if ($data['ratingTwenty'] !== NULL)
|
||||||
{
|
{
|
||||||
$updateData['ratingTwenty'] = (int)$data['ratingTwenty'];
|
$updateData['ratingTwenty'] = (int) $data['ratingTwenty'];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->requestBuilder->mutateRequest('UpdateLibraryItem', $updateData);
|
return $this->requestBuilder->mutateRequest('UpdateLibraryItem', $updateData);
|
||||||
@ -164,10 +152,11 @@ final class ListItem extends AbstractListItem {
|
|||||||
$auth = $this->getContainer()->get('auth');
|
$auth = $this->getContainer()->get('auth');
|
||||||
$token = $auth->getAuthToken();
|
$token = $auth->getAuthToken();
|
||||||
|
|
||||||
if ( ! empty($token)) {
|
if ( ! empty($token))
|
||||||
|
{
|
||||||
return "bearer {$token}";
|
return "bearer {$token}";
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,24 +6,15 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu;
|
namespace Aviat\AnimeClient\API\Kitsu;
|
||||||
|
|
||||||
use Amp;
|
use Amp;
|
||||||
use Aviat\AnimeClient\API\{
|
|
||||||
CacheTrait,
|
|
||||||
Enum\AnimeWatchingStatus\Kitsu as KitsuWatchingStatus,
|
|
||||||
Enum\MangaReadingStatus\Kitsu as KitsuReadingStatus,
|
|
||||||
Mapping\AnimeWatchingStatus,
|
|
||||||
Mapping\MangaReadingStatus
|
|
||||||
};
|
|
||||||
use Aviat\AnimeClient\API\Kitsu\Transformer\{
|
use Aviat\AnimeClient\API\Kitsu\Transformer\{
|
||||||
AnimeHistoryTransformer,
|
AnimeHistoryTransformer,
|
||||||
AnimeListTransformer,
|
AnimeListTransformer,
|
||||||
@ -33,10 +24,16 @@ use Aviat\AnimeClient\API\Kitsu\Transformer\{
|
|||||||
MangaListTransformer,
|
MangaListTransformer,
|
||||||
MangaTransformer
|
MangaTransformer
|
||||||
};
|
};
|
||||||
|
use Aviat\AnimeClient\API\{
|
||||||
|
CacheTrait,
|
||||||
|
Enum\AnimeWatchingStatus\Kitsu as KitsuWatchingStatus,
|
||||||
|
Enum\MangaReadingStatus\Kitsu as KitsuReadingStatus,
|
||||||
|
Mapping\AnimeWatchingStatus,
|
||||||
|
Mapping\MangaReadingStatus
|
||||||
|
};
|
||||||
use Aviat\AnimeClient\Enum\MediaType;
|
use Aviat\AnimeClient\Enum\MediaType;
|
||||||
use Aviat\AnimeClient\Kitsu as K;
|
use Aviat\AnimeClient\Kitsu as K;
|
||||||
use Aviat\AnimeClient\Types\Anime;
|
use Aviat\AnimeClient\Types\{Anime, MangaPage};
|
||||||
use Aviat\AnimeClient\Types\MangaPage;
|
|
||||||
use Aviat\Ion\{
|
use Aviat\Ion\{
|
||||||
Di\ContainerAware,
|
Di\ContainerAware,
|
||||||
Json
|
Json
|
||||||
@ -49,7 +46,8 @@ use const Aviat\AnimeClient\SESSION_SEGMENT;
|
|||||||
/**
|
/**
|
||||||
* Kitsu API Model
|
* Kitsu API Model
|
||||||
*/
|
*/
|
||||||
final class Model {
|
final class Model
|
||||||
|
{
|
||||||
use CacheTrait;
|
use CacheTrait;
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
use RequestBuilderTrait;
|
use RequestBuilderTrait;
|
||||||
@ -57,40 +55,20 @@ final class Model {
|
|||||||
|
|
||||||
protected const LIST_PAGE_SIZE = 100;
|
protected const LIST_PAGE_SIZE = 100;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var AnimeTransformer
|
|
||||||
*/
|
|
||||||
protected AnimeTransformer $animeTransformer;
|
protected AnimeTransformer $animeTransformer;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var MangaTransformer
|
|
||||||
*/
|
|
||||||
protected MangaTransformer $mangaTransformer;
|
protected MangaTransformer $mangaTransformer;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ListItem
|
|
||||||
*/
|
|
||||||
protected ListItem $listItem;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
|
||||||
* @param ListItem $listItem
|
|
||||||
*/
|
*/
|
||||||
public function __construct(ListItem $listItem)
|
public function __construct(protected ListItem $listItem)
|
||||||
{
|
{
|
||||||
$this->animeTransformer = new AnimeTransformer();
|
$this->animeTransformer = new AnimeTransformer();
|
||||||
$this->mangaTransformer = new MangaTransformer();
|
$this->mangaTransformer = new MangaTransformer();
|
||||||
|
|
||||||
$this->listItem = $listItem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the access token from the Kitsu API
|
* Get the access token from the Kitsu API
|
||||||
*
|
|
||||||
* @param string $username
|
|
||||||
* @param string $password
|
|
||||||
* @return array|false
|
|
||||||
*/
|
*/
|
||||||
public function authenticate(string $username, string $password): array|false
|
public function authenticate(string $username, string $password): array|false
|
||||||
{
|
{
|
||||||
@ -100,24 +78,25 @@ final class Model {
|
|||||||
'accept' => NULL,
|
'accept' => NULL,
|
||||||
'Content-type' => 'application/x-www-form-urlencoded',
|
'Content-type' => 'application/x-www-form-urlencoded',
|
||||||
'client_id' => NULL,
|
'client_id' => NULL,
|
||||||
'client_secret' => NULL
|
'client_secret' => NULL,
|
||||||
],
|
],
|
||||||
'form_params' => [
|
'form_params' => [
|
||||||
'grant_type' => 'password',
|
'grant_type' => 'password',
|
||||||
'username' => $username,
|
'username' => $username,
|
||||||
'password' => $password
|
'password' => $password,
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
$data = Json::decode(wait($response->getBody()->buffer()));
|
$data = Json::decode(wait($response->getBody()->buffer()));
|
||||||
|
|
||||||
if (array_key_exists('error', $data))
|
if (array_key_exists('error', $data))
|
||||||
{
|
{
|
||||||
dump([
|
dump([
|
||||||
'method' => __CLASS__ . '\\' . __METHOD__,
|
'method' => self::class . '\\' . __METHOD__,
|
||||||
'error' => $data['error'],
|
'error' => $data['error'],
|
||||||
'response' => $response,
|
'response' => $response,
|
||||||
]);
|
]);
|
||||||
die();
|
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array_key_exists('access_token', $data))
|
if (array_key_exists('access_token', $data))
|
||||||
@ -130,9 +109,6 @@ final class Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend the current session with a refresh token
|
* Extend the current session with a refresh token
|
||||||
*
|
|
||||||
* @param string $token
|
|
||||||
* @return array|false
|
|
||||||
*/
|
*/
|
||||||
public function reAuthenticate(string $token): array|false
|
public function reAuthenticate(string $token): array|false
|
||||||
{
|
{
|
||||||
@ -140,23 +116,24 @@ final class Model {
|
|||||||
'headers' => [
|
'headers' => [
|
||||||
'accept' => NULL,
|
'accept' => NULL,
|
||||||
'Content-type' => 'application/x-www-form-urlencoded',
|
'Content-type' => 'application/x-www-form-urlencoded',
|
||||||
'Accept-encoding' => '*'
|
'Accept-encoding' => '*',
|
||||||
],
|
],
|
||||||
'form_params' => [
|
'form_params' => [
|
||||||
'grant_type' => 'refresh_token',
|
'grant_type' => 'refresh_token',
|
||||||
'refresh_token' => $token
|
'refresh_token' => $token,
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
$data = Json::decode(wait($response->getBody()->buffer()));
|
$data = Json::decode(wait($response->getBody()->buffer()));
|
||||||
|
|
||||||
if (array_key_exists('error', $data))
|
if (array_key_exists('error', $data))
|
||||||
{
|
{
|
||||||
dump([
|
dump([
|
||||||
'method' => __CLASS__ . '\\' . __METHOD__,
|
'method' => self::class . '\\' . __METHOD__,
|
||||||
'error' => $data['error'],
|
'error' => $data['error'],
|
||||||
'response' => $response,
|
'response' => $response,
|
||||||
]);
|
]);
|
||||||
die();
|
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array_key_exists('access_token', $data))
|
if (array_key_exists('access_token', $data))
|
||||||
@ -169,20 +146,17 @@ final class Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the userid for a username from Kitsu
|
* Get the userid for a username from Kitsu
|
||||||
*
|
|
||||||
* @param string|null $username
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function getUserIdByUsername(string $username = NULL): string
|
public function getUserIdByUsername(?string $username = NULL): string
|
||||||
{
|
{
|
||||||
if ($username === NULL)
|
if ($username === NULL)
|
||||||
{
|
{
|
||||||
$username = $this->getUsername();
|
$username = $this->getUsername();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->getCached(K::AUTH_USER_ID_KEY, function(string $username) {
|
return $this->getCached(K::AUTH_USER_ID_KEY, function (string $username) {
|
||||||
$data = $this->requestBuilder->runQuery('GetUserId', [
|
$data = $this->requestBuilder->runQuery('GetUserId', [
|
||||||
'slug' => $username
|
'slug' => $username,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $data['data']['findProfileBySlug']['id'] ?? NULL;
|
return $data['data']['findProfileBySlug']['id'] ?? NULL;
|
||||||
@ -192,34 +166,31 @@ final class Model {
|
|||||||
/**
|
/**
|
||||||
* Get information about a character
|
* Get information about a character
|
||||||
*
|
*
|
||||||
* @param string $slug
|
* @return mixed[]
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function getCharacter(string $slug): array
|
public function getCharacter(string $slug): array
|
||||||
{
|
{
|
||||||
return $this->requestBuilder->runQuery('CharacterDetails', [
|
return $this->requestBuilder->runQuery('CharacterDetails', [
|
||||||
'slug' => $slug
|
'slug' => $slug,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about a person
|
* Get information about a person
|
||||||
*
|
*
|
||||||
* @param string $slug
|
* @return mixed[]
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function getPerson(string $slug): array
|
public function getPerson(string $slug): array
|
||||||
{
|
{
|
||||||
return $this->getCached("kitsu-person-{$slug}", fn () => $this->requestBuilder->runQuery('PersonDetails', [
|
return $this->getCached("kitsu-person-{$slug}", fn () => $this->requestBuilder->runQuery('PersonDetails', [
|
||||||
'slug' => $slug
|
'slug' => $slug,
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get profile information for the configured user
|
* Get profile information for the configured user
|
||||||
*
|
*
|
||||||
* @param string $username
|
* @return mixed[]
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function getUserData(string $username): array
|
public function getUserData(string $username): array
|
||||||
{
|
{
|
||||||
@ -231,17 +202,13 @@ final class Model {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// ! Anime-specific methods
|
// ! Anime-specific methods
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about a particular anime
|
* Get information about a particular anime
|
||||||
*
|
|
||||||
* @param string $slug
|
|
||||||
* @return Anime
|
|
||||||
*/
|
*/
|
||||||
public function getAnime(string $slug): Anime
|
public function getAnime(string $slug): Anime
|
||||||
{
|
{
|
||||||
$baseData = $this->requestBuilder->runQuery('AnimeDetails', [
|
$baseData = $this->requestBuilder->runQuery('AnimeDetails', [
|
||||||
'slug' => $slug
|
'slug' => $slug,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (empty($baseData))
|
if (empty($baseData))
|
||||||
@ -255,7 +222,7 @@ final class Model {
|
|||||||
public function getRandomAnime(): Anime
|
public function getRandomAnime(): Anime
|
||||||
{
|
{
|
||||||
$baseData = $this->requestBuilder->runQuery('RandomMedia', [
|
$baseData = $this->requestBuilder->runQuery('RandomMedia', [
|
||||||
'type' => 'ANIME'
|
'type' => 'ANIME',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $this->animeTransformer->transform($baseData);
|
return $this->animeTransformer->transform($baseData);
|
||||||
@ -269,22 +236,20 @@ final class Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about a particular anime
|
* Get information about a particular anime
|
||||||
*
|
|
||||||
* @param string $animeId
|
|
||||||
* @return Anime
|
|
||||||
*/
|
*/
|
||||||
public function getAnimeById(string $animeId): Anime
|
public function getAnimeById(string $animeId): Anime
|
||||||
{
|
{
|
||||||
$baseData = $this->requestBuilder->runQuery('AnimeDetailsById', [
|
$baseData = $this->requestBuilder->runQuery('AnimeDetailsById', [
|
||||||
'id' => $animeId,
|
'id' => $animeId,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $this->animeTransformer->transform($baseData);
|
return $this->animeTransformer->transform($baseData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the data for the anime watch history page
|
* Retrieve the data for the anime watch history page
|
||||||
*
|
*
|
||||||
* @return array
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
public function getAnimeHistory(): array
|
public function getAnimeHistory(): array
|
||||||
{
|
{
|
||||||
@ -298,7 +263,6 @@ final class Model {
|
|||||||
$list = (new AnimeHistoryTransformer())->transform($raw);
|
$list = (new AnimeHistoryTransformer())->transform($raw);
|
||||||
|
|
||||||
$this->cache->set($key, $list);
|
$this->cache->set($key, $list);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $list;
|
return $list;
|
||||||
@ -308,7 +272,7 @@ final class Model {
|
|||||||
* Get the anime list for the configured user
|
* Get the anime list for the configured user
|
||||||
*
|
*
|
||||||
* @param string $status - The watching status to filter the list with
|
* @param string $status - The watching status to filter the list with
|
||||||
* @return array
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
public function getAnimeList(string $status): array
|
public function getAnimeList(string $status): array
|
||||||
{
|
{
|
||||||
@ -330,7 +294,7 @@ final class Model {
|
|||||||
$transformed = $transformer->transformCollection($data);
|
$transformed = $transformer->transformCollection($data);
|
||||||
$keyed = [];
|
$keyed = [];
|
||||||
|
|
||||||
foreach($transformed as $item)
|
foreach ($transformed as $item)
|
||||||
{
|
{
|
||||||
$keyed[$item['id']] = $item;
|
$keyed[$item['id']] = $item;
|
||||||
}
|
}
|
||||||
@ -346,9 +310,8 @@ final class Model {
|
|||||||
* Get the number of anime list items
|
* Get the number of anime list items
|
||||||
*
|
*
|
||||||
* @param string $status - Optional status to filter by
|
* @param string $status - Optional status to filter by
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function getAnimeListCount(string $status = '') : int
|
public function getAnimeListCount(string $status = ''): int
|
||||||
{
|
{
|
||||||
return $this->getListCount(MediaType::ANIME, $status);
|
return $this->getListCount(MediaType::ANIME, $status);
|
||||||
}
|
}
|
||||||
@ -356,7 +319,7 @@ final class Model {
|
|||||||
/**
|
/**
|
||||||
* Get all the anime entries, that are organized for output to html
|
* Get all the anime entries, that are organized for output to html
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array<string, mixed[]>
|
||||||
*/
|
*/
|
||||||
public function getFullOrganizedAnimeList(): array
|
public function getFullOrganizedAnimeList(): array
|
||||||
{
|
{
|
||||||
@ -364,7 +327,7 @@ final class Model {
|
|||||||
|
|
||||||
$statuses = KitsuWatchingStatus::getConstList();
|
$statuses = KitsuWatchingStatus::getConstList();
|
||||||
|
|
||||||
foreach ($statuses as $key => $status)
|
foreach ($statuses as $status)
|
||||||
{
|
{
|
||||||
$mappedStatus = AnimeWatchingStatus::KITSU_TO_TITLE[$status];
|
$mappedStatus = AnimeWatchingStatus::KITSU_TO_TITLE[$status];
|
||||||
$output[$mappedStatus] = $this->getAnimeList($status) ?? [];
|
$output[$mappedStatus] = $this->getAnimeList($status) ?? [];
|
||||||
@ -376,17 +339,13 @@ final class Model {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// ! Manga-specific methods
|
// ! Manga-specific methods
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about a particular manga
|
* Get information about a particular manga
|
||||||
*
|
|
||||||
* @param string $slug
|
|
||||||
* @return MangaPage
|
|
||||||
*/
|
*/
|
||||||
public function getManga(string $slug): MangaPage
|
public function getManga(string $slug): MangaPage
|
||||||
{
|
{
|
||||||
$baseData = $this->requestBuilder->runQuery('MangaDetails', [
|
$baseData = $this->requestBuilder->runQuery('MangaDetails', [
|
||||||
'slug' => $slug
|
'slug' => $slug,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (empty($baseData))
|
if (empty($baseData))
|
||||||
@ -400,7 +359,7 @@ final class Model {
|
|||||||
public function getRandomManga(): MangaPage
|
public function getRandomManga(): MangaPage
|
||||||
{
|
{
|
||||||
$baseData = $this->requestBuilder->runQuery('RandomMedia', [
|
$baseData = $this->requestBuilder->runQuery('RandomMedia', [
|
||||||
'type' => 'MANGA'
|
'type' => 'MANGA',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $this->mangaTransformer->transform($baseData);
|
return $this->mangaTransformer->transform($baseData);
|
||||||
@ -408,22 +367,20 @@ final class Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about a particular manga
|
* Get information about a particular manga
|
||||||
*
|
|
||||||
* @param string $mangaId
|
|
||||||
* @return MangaPage
|
|
||||||
*/
|
*/
|
||||||
public function getMangaById(string $mangaId): MangaPage
|
public function getMangaById(string $mangaId): MangaPage
|
||||||
{
|
{
|
||||||
$baseData = $this->requestBuilder->runQuery('MangaDetailsById', [
|
$baseData = $this->requestBuilder->runQuery('MangaDetailsById', [
|
||||||
'id' => $mangaId,
|
'id' => $mangaId,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $this->mangaTransformer->transform($baseData);
|
return $this->mangaTransformer->transform($baseData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the data for the manga read history page
|
* Retrieve the data for the manga read history page
|
||||||
*
|
*
|
||||||
* @return array
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
public function getMangaHistory(): array
|
public function getMangaHistory(): array
|
||||||
{
|
{
|
||||||
@ -445,7 +402,7 @@ final class Model {
|
|||||||
* Get the manga list for the configured user
|
* Get the manga list for the configured user
|
||||||
*
|
*
|
||||||
* @param string $status - The reading status by which to filter the list
|
* @param string $status - The reading status by which to filter the list
|
||||||
* @return array
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
public function getMangaList(string $status): array
|
public function getMangaList(string $status): array
|
||||||
{
|
{
|
||||||
@ -467,7 +424,7 @@ final class Model {
|
|||||||
$transformed = $transformer->transformCollection($data);
|
$transformed = $transformer->transformCollection($data);
|
||||||
$keyed = [];
|
$keyed = [];
|
||||||
|
|
||||||
foreach($transformed as $item)
|
foreach ($transformed as $item)
|
||||||
{
|
{
|
||||||
$keyed[$item['id']] = $item;
|
$keyed[$item['id']] = $item;
|
||||||
}
|
}
|
||||||
@ -483,9 +440,8 @@ final class Model {
|
|||||||
* Get the number of manga list items
|
* Get the number of manga list items
|
||||||
*
|
*
|
||||||
* @param string $status - Optional status to filter by
|
* @param string $status - Optional status to filter by
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function getMangaListCount(string $status = '') : int
|
public function getMangaListCount(string $status = ''): int
|
||||||
{
|
{
|
||||||
return $this->getListCount(MediaType::MANGA, $status);
|
return $this->getListCount(MediaType::MANGA, $status);
|
||||||
}
|
}
|
||||||
@ -493,12 +449,13 @@ final class Model {
|
|||||||
/**
|
/**
|
||||||
* Get all Manga lists
|
* Get all Manga lists
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array<string, mixed[]>
|
||||||
*/
|
*/
|
||||||
public function getFullOrganizedMangaList(): array
|
public function getFullOrganizedMangaList(): array
|
||||||
{
|
{
|
||||||
$statuses = KitsuReadingStatus::getConstList();
|
$statuses = KitsuReadingStatus::getConstList();
|
||||||
$output = [];
|
$output = [];
|
||||||
|
|
||||||
foreach ($statuses as $status)
|
foreach ($statuses as $status)
|
||||||
{
|
{
|
||||||
$mappedStatus = MangaReadingStatus::KITSU_TO_TITLE[$status];
|
$mappedStatus = MangaReadingStatus::KITSU_TO_TITLE[$status];
|
||||||
@ -511,13 +468,12 @@ final class Model {
|
|||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Base methods
|
// Base methods
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search for an anime or manga
|
* Search for an anime or manga
|
||||||
*
|
*
|
||||||
* @param string $type - 'anime' or 'manga'
|
* @param string $type - 'anime' or 'manga'
|
||||||
* @param string $query - name of the item to search for
|
* @param string $query - name of the item to search for
|
||||||
* @return array
|
* @return array<int, array<string, mixed>>
|
||||||
*/
|
*/
|
||||||
public function search(string $type, string $query): array
|
public function search(string $type, string $query): array
|
||||||
{
|
{
|
||||||
@ -543,9 +499,9 @@ final class Model {
|
|||||||
// Search for MAL mapping
|
// Search for MAL mapping
|
||||||
if (is_array($item['mappings']['nodes']))
|
if (is_array($item['mappings']['nodes']))
|
||||||
{
|
{
|
||||||
foreach($item['mappings']['nodes'] as $mapping)
|
foreach ($item['mappings']['nodes'] as $mapping)
|
||||||
{
|
{
|
||||||
if ($mapping['externalSite'] === "MYANIMELIST_" . strtoupper($type))
|
if ($mapping['externalSite'] === 'MYANIMELIST_' . strtoupper($type))
|
||||||
{
|
{
|
||||||
$searchItem['mal_id'] = $mapping['externalId'];
|
$searchItem['mal_id'] = $mapping['externalId'];
|
||||||
break;
|
break;
|
||||||
@ -554,7 +510,6 @@ final class Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$data[] = $searchItem;
|
$data[] = $searchItem;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
@ -563,11 +518,9 @@ final class Model {
|
|||||||
/**
|
/**
|
||||||
* Find a media item on Kitsu by its associated MAL id
|
* Find a media item on Kitsu by its associated MAL id
|
||||||
*
|
*
|
||||||
* @param string $malId
|
|
||||||
* @param string $type "anime" or "manga"
|
* @param string $type "anime" or "manga"
|
||||||
* @return string|NULL
|
|
||||||
*/
|
*/
|
||||||
public function getKitsuIdFromMALId(string $malId, string $type='anime'): ?string
|
public function getKitsuIdFromMALId(string $malId, string $type = 'anime'): ?string
|
||||||
{
|
{
|
||||||
$raw = $this->requestBuilder->runQuery('GetIdByMapping', [
|
$raw = $this->requestBuilder->runQuery('GetIdByMapping', [
|
||||||
'id' => $malId,
|
'id' => $malId,
|
||||||
@ -594,6 +547,9 @@ final class Model {
|
|||||||
return (new LibraryEntryTransformer())->transform($baseData['data']['findLibraryEntryById']);
|
return (new LibraryEntryTransformer())->transform($baseData['data']['findLibraryEntryById']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
public function getThumbList(string $type): array
|
public function getThumbList(string $type): array
|
||||||
{
|
{
|
||||||
$statuses = [
|
$statuses = [
|
||||||
@ -620,11 +576,9 @@ final class Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Get the data to sync Kitsu anime/manga list with another API
|
* Get the data to sync Kitsu anime/manga list with another API
|
||||||
*
|
*
|
||||||
* @param string $type
|
* @return mixed[]
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function getSyncList(string $type): array
|
public function getSyncList(string $type): array
|
||||||
{
|
{
|
||||||
@ -654,7 +608,7 @@ final class Model {
|
|||||||
/**
|
/**
|
||||||
* Get the aggregated pages of anime or manga history
|
* Get the aggregated pages of anime or manga history
|
||||||
*
|
*
|
||||||
* @return array
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
protected function getHistoryList(): array
|
protected function getHistoryList(): array
|
||||||
{
|
{
|
||||||
@ -666,9 +620,7 @@ final class Model {
|
|||||||
/**
|
/**
|
||||||
* Get the raw anime/manga list from GraphQL
|
* Get the raw anime/manga list from GraphQL
|
||||||
*
|
*
|
||||||
* @param string $type
|
* @return mixed[]
|
||||||
* @param string $status
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
protected function getList(string $type, string $status = ''): array
|
protected function getList(string $type, string $status = ''): array
|
||||||
{
|
{
|
||||||
@ -687,7 +639,7 @@ final class Model {
|
|||||||
$cursor = '';
|
$cursor = '';
|
||||||
$username = $this->getUsername();
|
$username = $this->getUsername();
|
||||||
|
|
||||||
return new Amp\Producer(function (callable $emit) use ($type, $status, $cursor, $username) {
|
return new Amp\Producer(function (callable $emit) use ($type, $status, $cursor, $username): Generator {
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
$vars = [
|
$vars = [
|
||||||
@ -698,6 +650,7 @@ final class Model {
|
|||||||
{
|
{
|
||||||
$vars['status'] = $status;
|
$vars['status'] = $status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cursor !== '')
|
if ($cursor !== '')
|
||||||
{
|
{
|
||||||
$vars['after'] = $cursor;
|
$vars['after'] = $cursor;
|
||||||
@ -719,7 +672,8 @@ final class Model {
|
|||||||
|
|
||||||
// @TODO Proper Error logging
|
// @TODO Proper Error logging
|
||||||
dump($rawData);
|
dump($rawData);
|
||||||
die();
|
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$cursor = $page['endCursor'];
|
$cursor = $page['endCursor'];
|
||||||
@ -734,11 +688,12 @@ final class Model {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getSyncPages(string $type, string $status): Amp\Iterator {
|
private function getSyncPages(string $type, string $status): Amp\Iterator
|
||||||
|
{
|
||||||
$cursor = '';
|
$cursor = '';
|
||||||
$username = $this->getUsername();
|
$username = $this->getUsername();
|
||||||
|
|
||||||
return new Amp\Producer(function (callable $emit) use ($type, $status, $cursor, $username) {
|
return new Amp\Producer(function (callable $emit) use ($type, $status, $cursor, $username): Generator {
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
$vars = [
|
$vars = [
|
||||||
@ -761,7 +716,8 @@ final class Model {
|
|||||||
if (empty($data))
|
if (empty($data))
|
||||||
{
|
{
|
||||||
dump($rawData);
|
dump($rawData);
|
||||||
die();
|
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$cursor = $page['endCursor'];
|
$cursor = $page['endCursor'];
|
||||||
@ -781,7 +737,7 @@ final class Model {
|
|||||||
$cursor = '';
|
$cursor = '';
|
||||||
$username = $this->getUsername();
|
$username = $this->getUsername();
|
||||||
|
|
||||||
return new Amp\Producer(function (callable $emit) use ($type, $status, $cursor, $username) {
|
return new Amp\Producer(function (callable $emit) use ($type, $status, $cursor, $username): Generator {
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
$vars = [
|
$vars = [
|
||||||
@ -804,7 +760,8 @@ final class Model {
|
|||||||
if (empty($data))
|
if (empty($data))
|
||||||
{
|
{
|
||||||
dump($rawData);
|
dump($rawData);
|
||||||
die();
|
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$cursor = $page['endCursor'];
|
$cursor = $page['endCursor'];
|
||||||
@ -843,8 +800,6 @@ final class Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the kitsu username from config
|
* Get the kitsu username from config
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
private function getUsername(): string
|
private function getUsername(): string
|
||||||
{
|
{
|
||||||
@ -857,7 +812,7 @@ final class Model {
|
|||||||
{
|
{
|
||||||
$args = [
|
$args = [
|
||||||
'type' => strtoupper($type),
|
'type' => strtoupper($type),
|
||||||
'slug' => $this->getUsername()
|
'slug' => $this->getUsername(),
|
||||||
];
|
];
|
||||||
if ($status !== '')
|
if ($status !== '')
|
||||||
{
|
{
|
||||||
@ -868,4 +823,4 @@ final class Model {
|
|||||||
|
|
||||||
return $res['data']['findProfileBySlug']['library']['all']['totalCount'];
|
return $res['data']['findProfileBySlug']['library']['all']['totalCount'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu;
|
namespace Aviat\AnimeClient\API\Kitsu;
|
||||||
@ -22,16 +20,13 @@ use Aviat\AnimeClient\Types\FormItem;
|
|||||||
/**
|
/**
|
||||||
* Kitsu API calls that mutate data, C/U/D parts of CRUD
|
* Kitsu API calls that mutate data, C/U/D parts of CRUD
|
||||||
*/
|
*/
|
||||||
trait MutationTrait {
|
trait MutationTrait
|
||||||
|
{
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// ! Generic API calls
|
// ! Generic API calls
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a list item
|
* Create a list item
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @return Request|null
|
|
||||||
*/
|
*/
|
||||||
public function createListItem(array $data): ?Request
|
public function createListItem(array $data): ?Request
|
||||||
{
|
{
|
||||||
@ -46,9 +41,6 @@ trait MutationTrait {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Increase the progress count for a list item
|
* Increase the progress count for a list item
|
||||||
*
|
|
||||||
* @param FormItem $data
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function incrementListItem(FormItem $data): Request
|
public function incrementListItem(FormItem $data): Request
|
||||||
{
|
{
|
||||||
@ -57,9 +49,6 @@ trait MutationTrait {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Modify a list item
|
* Modify a list item
|
||||||
*
|
|
||||||
* @param FormItem $data
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function updateListItem(FormItem $data): Request
|
public function updateListItem(FormItem $data): Request
|
||||||
{
|
{
|
||||||
@ -70,10 +59,20 @@ trait MutationTrait {
|
|||||||
* Remove a list item
|
* Remove a list item
|
||||||
*
|
*
|
||||||
* @param string $id - The id of the list item to remove
|
* @param string $id - The id of the list item to remove
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function deleteListItem(string $id): Request
|
public function deleteListItem(string $id): Request
|
||||||
{
|
{
|
||||||
return $this->listItem->delete($id);
|
return $this->listItem->delete($id);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Remove a list item
|
||||||
|
*
|
||||||
|
* @param FormItem $data
|
||||||
|
* @return Request
|
||||||
|
*/
|
||||||
|
public function deleteItem(FormItem $data): Request
|
||||||
|
{
|
||||||
|
return $this->listItem->delete($data['id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,57 +6,46 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu;
|
namespace Aviat\AnimeClient\API\Kitsu;
|
||||||
|
|
||||||
use const Aviat\AnimeClient\SESSION_SEGMENT;
|
use Amp\Http\Client\{Request, Response};
|
||||||
use const Aviat\AnimeClient\USER_AGENT;
|
|
||||||
|
|
||||||
use function Amp\Promise\wait;
|
|
||||||
use function Aviat\AnimeClient\getResponse;
|
|
||||||
|
|
||||||
use Amp\Http\Client\Request;
|
|
||||||
use Amp\Http\Client\Response;
|
|
||||||
use Aviat\AnimeClient\Kitsu as K;
|
|
||||||
use Aviat\AnimeClient\API\APIRequestBuilder;
|
use Aviat\AnimeClient\API\APIRequestBuilder;
|
||||||
use Aviat\AnimeClient\Enum\EventType;
|
use Aviat\AnimeClient\Enum\EventType;
|
||||||
use Aviat\Ion\Di\ContainerAware;
|
use Aviat\AnimeClient\Kitsu as K;
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
|
||||||
use Aviat\Ion\Event;
|
use Aviat\Ion\{Event, Json, JsonException};
|
||||||
use Aviat\Ion\Json;
|
|
||||||
use Aviat\Ion\JsonException;
|
|
||||||
|
|
||||||
use LogicException;
|
use LogicException;
|
||||||
|
use function Amp\Promise\wait;
|
||||||
|
use function Aviat\AnimeClient\getResponse;
|
||||||
|
use function in_array;
|
||||||
|
use const Aviat\AnimeClient\{SESSION_SEGMENT, USER_AGENT};
|
||||||
|
|
||||||
final class RequestBuilder extends APIRequestBuilder {
|
final class RequestBuilder extends APIRequestBuilder
|
||||||
|
{
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base url for api requests
|
* The base url for api requests
|
||||||
* @var string $base_url
|
|
||||||
*/
|
*/
|
||||||
protected string $baseUrl = K::GRAPHQL_ENDPOINT;
|
protected string $baseUrl = K::GRAPHQL_ENDPOINT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Where to look for GraphQL request files
|
* Where to look for GraphQL request files
|
||||||
* @var string
|
|
||||||
*/
|
*/
|
||||||
protected string $filePath = __DIR__;
|
protected string $filePath = __DIR__;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP headers to send with every request
|
* HTTP headers to send with every request
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
*/
|
||||||
protected array $defaultHeaders = [
|
protected array $defaultHeaders = [
|
||||||
'User-Agent' => USER_AGENT,
|
'User-Agent' => USER_AGENT,
|
||||||
'Accept' => 'application/vnd.api+json',
|
'Accept' => 'application/vnd.api+json',
|
||||||
'Content-Type' => 'application/vnd.api+json',
|
'Content-Type' => 'application/vnd.api+json',
|
||||||
'CLIENT_ID' => 'dd031b32d2f56c990b1425efe6c42ad847e7fe3ab46bf1299f05ecd856bdb7dd',
|
'CLIENT_ID' => 'dd031b32d2f56c990b1425efe6c42ad847e7fe3ab46bf1299f05ecd856bdb7dd',
|
||||||
@ -70,11 +59,6 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a request object
|
* Create a request object
|
||||||
*
|
|
||||||
* @param string $type
|
|
||||||
* @param string $url
|
|
||||||
* @param array $options
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function setUpRequest(string $type, string $url, array $options = []): Request
|
public function setUpRequest(string $type, string $url, array $options = []): Request
|
||||||
{
|
{
|
||||||
@ -85,13 +69,13 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
->getSegment(SESSION_SEGMENT);
|
->getSegment(SESSION_SEGMENT);
|
||||||
|
|
||||||
$cache = $this->getContainer()->get('cache');
|
$cache = $this->getContainer()->get('cache');
|
||||||
$token = null;
|
$token = NULL;
|
||||||
|
|
||||||
if ($cache->has(K::AUTH_TOKEN_CACHE_KEY))
|
if ($cache->has(K::AUTH_TOKEN_CACHE_KEY))
|
||||||
{
|
{
|
||||||
$token = $cache->get(K::AUTH_TOKEN_CACHE_KEY);
|
$token = $cache->get(K::AUTH_TOKEN_CACHE_KEY);
|
||||||
}
|
}
|
||||||
else if ($url !== K::AUTH_URL && $sessionSegment->get('auth_token') !== NULL)
|
elseif ($url !== K::AUTH_URL && $sessionSegment->get('auth_token') !== NULL)
|
||||||
{
|
{
|
||||||
$token = $sessionSegment->get('auth_token');
|
$token = $sessionSegment->get('auth_token');
|
||||||
if ( ! (empty($token) || $cache->has(K::AUTH_TOKEN_CACHE_KEY)))
|
if ( ! (empty($token) || $cache->has(K::AUTH_TOKEN_CACHE_KEY)))
|
||||||
@ -131,9 +115,7 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
/**
|
/**
|
||||||
* Run a GraphQL API query
|
* Run a GraphQL API query
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @return mixed[]
|
||||||
* @param array $variables
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function runQuery(string $name, array $variables = []): array
|
public function runQuery(string $name, array $variables = []): array
|
||||||
{
|
{
|
||||||
@ -141,12 +123,12 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
$response = getResponse($request);
|
$response = getResponse($request);
|
||||||
$validResponseCodes = [200, 201];
|
$validResponseCodes = [200, 201];
|
||||||
|
|
||||||
if ( ! \in_array($response->getStatus(), $validResponseCodes, TRUE))
|
if ( ! in_array($response->getStatus(), $validResponseCodes, TRUE))
|
||||||
{
|
{
|
||||||
$logger = $this->container->getLogger('kitsu-graphql');
|
$logger = $this->container->getLogger('kitsu-graphql');
|
||||||
if ($logger !== NULL)
|
if ($logger !== NULL)
|
||||||
{
|
{
|
||||||
$logger->warning('Non 200 response for GraphQL call', (array)$response->getBody());
|
$logger->warning('Non 200 response for GraphQL call', (array) $response->getBody());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,9 +138,7 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
/**
|
/**
|
||||||
* Run a GraphQL mutation
|
* Run a GraphQL mutation
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @return mixed[]
|
||||||
* @param array $variables
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function mutate(string $name, array $variables = []): array
|
public function mutate(string $name, array $variables = []): array
|
||||||
{
|
{
|
||||||
@ -166,12 +146,12 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
$response = getResponse($request);
|
$response = getResponse($request);
|
||||||
$validResponseCodes = [200, 201];
|
$validResponseCodes = [200, 201];
|
||||||
|
|
||||||
if ( ! \in_array($response->getStatus(), $validResponseCodes, TRUE))
|
if ( ! in_array($response->getStatus(), $validResponseCodes, TRUE))
|
||||||
{
|
{
|
||||||
$logger = $this->container->getLogger('kitsu-graphql');
|
$logger = $this->container->getLogger('kitsu-graphql');
|
||||||
if ($logger !== NULL)
|
if ($logger !== NULL)
|
||||||
{
|
{
|
||||||
$logger->warning('Non 200 response for GraphQL call', (array)$response->getBody());
|
$logger->warning('Non 200 response for GraphQL call', (array) $response->getBody());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,11 +160,6 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a request
|
* Make a request
|
||||||
*
|
|
||||||
* @param string $type
|
|
||||||
* @param string $url
|
|
||||||
* @param array $options
|
|
||||||
* @return Response
|
|
||||||
*/
|
*/
|
||||||
public function getResponse(string $type, string $url, array $options = []): Response
|
public function getResponse(string $type, string $url, array $options = []): Response
|
||||||
{
|
{
|
||||||
@ -205,10 +180,6 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a GraphQL query and return the Request object
|
* Create a GraphQL query and return the Request object
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
* @param array $variables
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function queryRequest(string $name, array $variables = []): Request
|
public function queryRequest(string $name, array $variables = []): Request
|
||||||
{
|
{
|
||||||
@ -220,13 +191,14 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
|
|
||||||
$query = file_get_contents($file);
|
$query = file_get_contents($file);
|
||||||
$body = [
|
$body = [
|
||||||
'query' => $query
|
'query' => $query,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ( ! empty($variables))
|
if ( ! empty($variables))
|
||||||
{
|
{
|
||||||
$body['variables'] = [];
|
$body['variables'] = [];
|
||||||
foreach($variables as $key => $val)
|
|
||||||
|
foreach ($variables as $key => $val)
|
||||||
{
|
{
|
||||||
$body['variables'][$key] = $val;
|
$body['variables'][$key] = $val;
|
||||||
}
|
}
|
||||||
@ -239,12 +211,8 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a GraphQL mutation request, and return the Request object
|
* Create a GraphQL mutation request, and return the Request object
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
* @param array $variables
|
|
||||||
* @return Request
|
|
||||||
*/
|
*/
|
||||||
public function mutateRequest (string $name, array $variables = []): Request
|
public function mutateRequest(string $name, array $variables = []): Request
|
||||||
{
|
{
|
||||||
$file = realpath("{$this->filePath}/Mutations/{$name}.graphql");
|
$file = realpath("{$this->filePath}/Mutations/{$name}.graphql");
|
||||||
if ($file === FALSE || ! file_exists($file))
|
if ($file === FALSE || ! file_exists($file))
|
||||||
@ -254,11 +222,13 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
|
|
||||||
$query = file_get_contents($file);
|
$query = file_get_contents($file);
|
||||||
$body = [
|
$body = [
|
||||||
'query' => $query
|
'query' => $query,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!empty($variables)) {
|
if ( ! empty($variables))
|
||||||
|
{
|
||||||
$body['variables'] = [];
|
$body['variables'] = [];
|
||||||
|
|
||||||
foreach ($variables as $key => $val)
|
foreach ($variables as $key => $val)
|
||||||
{
|
{
|
||||||
$body['variables'][$key] = $val;
|
$body['variables'][$key] = $val;
|
||||||
@ -272,11 +242,6 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a request
|
* Make a request
|
||||||
*
|
|
||||||
* @param string $type
|
|
||||||
* @param string $url
|
|
||||||
* @param array $options
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
private function request(string $type, string $url, array $options = []): array
|
private function request(string $type, string $url, array $options = []): array
|
||||||
{
|
{
|
||||||
@ -297,7 +262,7 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
{
|
{
|
||||||
if ($logger !== NULL)
|
if ($logger !== NULL)
|
||||||
{
|
{
|
||||||
$logger->warning('Non 2xx response for api call', (array)$response);
|
$logger->warning('Non 2xx response for api call', (array) $response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,11 +270,12 @@ final class RequestBuilder extends APIRequestBuilder {
|
|||||||
{
|
{
|
||||||
return Json::decode($rawBody);
|
return Json::decode($rawBody);
|
||||||
}
|
}
|
||||||
catch (JsonException $e)
|
catch (JsonException)
|
||||||
{
|
{
|
||||||
// dump($e);
|
// dump($e);
|
||||||
dump($rawBody);
|
dump($rawBody);
|
||||||
die();
|
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,32 +6,30 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu;
|
namespace Aviat\AnimeClient\API\Kitsu;
|
||||||
|
|
||||||
trait RequestBuilderTrait {
|
trait RequestBuilderTrait
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* The request builder for the Kitsu API
|
* The request builder for the Kitsu API
|
||||||
* @var RequestBuilder
|
|
||||||
*/
|
*/
|
||||||
protected RequestBuilder $requestBuilder;
|
protected RequestBuilder $requestBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the request builder object
|
* Set the request builder object
|
||||||
*
|
*
|
||||||
* @param RequestBuilder $requestBuilder
|
* @return ListItem|Model|RequestBuilderTrait
|
||||||
* @return RequestBuilderTrait|ListItem|Model
|
|
||||||
*/
|
*/
|
||||||
public function setRequestBuilder(RequestBuilder $requestBuilder): self
|
public function setRequestBuilder(RequestBuilder $requestBuilder): self
|
||||||
{
|
{
|
||||||
$this->requestBuilder = $requestBuilder;
|
$this->requestBuilder = $requestBuilder;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,28 +6,22 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
|
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
|
||||||
|
|
||||||
class AnimeHistoryTransformer extends HistoryTransformer {
|
class AnimeHistoryTransformer extends HistoryTransformer
|
||||||
|
{
|
||||||
protected string $type = 'anime';
|
protected string $type = 'anime';
|
||||||
|
|
||||||
protected string $progressAction = 'Watched episode';
|
protected string $progressAction = 'Watched episode';
|
||||||
|
|
||||||
protected string $reconsumeAction = 'Rewatched episode';
|
protected string $reconsumeAction = 'Rewatched episode';
|
||||||
|
|
||||||
protected string $largeAggregateAction = 'Marathoned episodes';
|
protected string $largeAggregateAction = 'Marathoned episodes';
|
||||||
|
|
||||||
protected string $reconsumingStatus = 'Rewatching';
|
protected string $reconsumingStatus = 'Rewatching';
|
||||||
|
|
||||||
protected array $statusMap = AnimeWatchingStatus::KITSU_TO_TITLE;
|
protected array $statusMap = AnimeWatchingStatus::KITSU_TO_TITLE;
|
||||||
}
|
}
|
||||||
|
@ -6,20 +6,18 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Kitsu;
|
use Aviat\AnimeClient\Kitsu;
|
||||||
use Aviat\AnimeClient\Types\{
|
use Aviat\AnimeClient\Types\{
|
||||||
FormItem,
|
AnimeListItem,
|
||||||
AnimeListItem
|
FormItem
|
||||||
};
|
};
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
use Aviat\Ion\Type\StringType;
|
use Aviat\Ion\Type\StringType;
|
||||||
@ -27,31 +25,31 @@ use Aviat\Ion\Type\StringType;
|
|||||||
/**
|
/**
|
||||||
* Transformer for anime list
|
* Transformer for anime list
|
||||||
*/
|
*/
|
||||||
final class AnimeListTransformer extends AbstractTransformer {
|
final class AnimeListTransformer extends AbstractTransformer
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Convert raw api response to a more
|
* Convert raw api response to a more
|
||||||
* logical and workable structure
|
* logical and workable structure
|
||||||
*
|
*
|
||||||
* @param array|object $item API library item
|
* @param array|object $item API library item
|
||||||
* @return AnimeListItem
|
|
||||||
*/
|
*/
|
||||||
public function transform(array|object $item): AnimeListItem
|
public function transform(array|object $item): AnimeListItem
|
||||||
{
|
{
|
||||||
$item = (array)$item;
|
$item = (array) $item;
|
||||||
$animeId = $item['media']['id'];
|
$animeId = $item['media']['id'];
|
||||||
$anime = $item['media'];
|
$anime = $item['media'];
|
||||||
|
|
||||||
$genres = [];
|
$genres = [];
|
||||||
|
|
||||||
$rating = (int) $item['rating'] !== 0
|
$rating = (int) $item['rating'] !== 0
|
||||||
? (int)$item['rating'] / 2
|
? (int) $item['rating'] / 2
|
||||||
: '-';
|
: '-';
|
||||||
|
|
||||||
$total_episodes = (int) $anime['episodeCount'] !== 0
|
$total_episodes = (int) $anime['episodeCount'] !== 0
|
||||||
? (int) $anime['episodeCount']
|
? (int) $anime['episodeCount']
|
||||||
: '-';
|
: '-';
|
||||||
|
|
||||||
|
$AnilistId = NULL;
|
||||||
$MALid = NULL;
|
$MALid = NULL;
|
||||||
|
|
||||||
$mappings = $anime['mappings']['nodes'] ?? [];
|
$mappings = $anime['mappings']['nodes'] ?? [];
|
||||||
@ -62,7 +60,11 @@ final class AnimeListTransformer extends AbstractTransformer {
|
|||||||
if ($mapping['externalSite'] === 'MYANIMELIST_ANIME')
|
if ($mapping['externalSite'] === 'MYANIMELIST_ANIME')
|
||||||
{
|
{
|
||||||
$MALid = $mapping['externalId'];
|
$MALid = $mapping['externalId'];
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
if ($mapping['externalSite'] === 'ANILIST_ANIME')
|
||||||
|
{
|
||||||
|
$AnilistId = $mapping['externalId'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,6 +78,7 @@ final class AnimeListTransformer extends AbstractTransformer {
|
|||||||
|
|
||||||
return AnimeListItem::from([
|
return AnimeListItem::from([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
|
'anilist_id' => $AnilistId,
|
||||||
'mal_id' => $MALid,
|
'mal_id' => $MALid,
|
||||||
'episodes' => [
|
'episodes' => [
|
||||||
'watched' => (int) $item['progress'] !== 0
|
'watched' => (int) $item['progress'] !== 0
|
||||||
@ -87,7 +90,7 @@ final class AnimeListTransformer extends AbstractTransformer {
|
|||||||
'airing' => [
|
'airing' => [
|
||||||
'status' => Kitsu::getAiringStatus($anime['startDate'], $anime['endDate']),
|
'status' => Kitsu::getAiringStatus($anime['startDate'], $anime['endDate']),
|
||||||
'started' => $anime['startDate'],
|
'started' => $anime['startDate'],
|
||||||
'ended' => $anime['endDate']
|
'ended' => $anime['endDate'],
|
||||||
],
|
],
|
||||||
'anime' => [
|
'anime' => [
|
||||||
'id' => $animeId,
|
'id' => $animeId,
|
||||||
@ -95,7 +98,7 @@ final class AnimeListTransformer extends AbstractTransformer {
|
|||||||
'title' => $title,
|
'title' => $title,
|
||||||
'titles' => $titles,
|
'titles' => $titles,
|
||||||
'slug' => $anime['slug'],
|
'slug' => $anime['slug'],
|
||||||
'show_type' => (string)StringType::from($anime['subtype'])->upperCaseFirst(),
|
'show_type' => (string) StringType::from($anime['subtype'])->upperCaseFirst(),
|
||||||
'cover_image' => Kitsu::getPosterImage($anime),
|
'cover_image' => Kitsu::getPosterImage($anime),
|
||||||
'genres' => $genres,
|
'genres' => $genres,
|
||||||
'streaming_links' => $streamingLinks,
|
'streaming_links' => $streamingLinks,
|
||||||
@ -123,14 +126,15 @@ final class AnimeListTransformer extends AbstractTransformer {
|
|||||||
|
|
||||||
$untransformed = FormItem::from([
|
$untransformed = FormItem::from([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
|
'anilist_id' => $item['anilist_id'] ?? NULL,
|
||||||
'mal_id' => $item['mal_id'] ?? NULL,
|
'mal_id' => $item['mal_id'] ?? NULL,
|
||||||
'data' => [
|
'data' => [
|
||||||
'status' => $item['watching_status'],
|
'status' => $item['watching_status'],
|
||||||
'reconsuming' => $rewatching,
|
'reconsuming' => $rewatching,
|
||||||
'reconsumeCount' => $item['rewatched'],
|
'reconsumeCount' => $item['rewatched'],
|
||||||
'notes' => $item['notes'],
|
'notes' => $item['notes'],
|
||||||
'private' => $privacy
|
'private' => $privacy,
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (is_numeric($item['episodes_watched']) && $item['episodes_watched'] > 0)
|
if (is_numeric($item['episodes_watched']) && $item['episodes_watched'] > 0)
|
||||||
@ -146,4 +150,5 @@ final class AnimeListTransformer extends AbstractTransformer {
|
|||||||
return $untransformed;
|
return $untransformed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// End of AnimeListTransformer.php
|
|
||||||
|
// End of AnimeListTransformer.php
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
@ -23,23 +21,22 @@ use Aviat\Ion\Transformer\AbstractTransformer;
|
|||||||
/**
|
/**
|
||||||
* Transformer for anime description page
|
* Transformer for anime description page
|
||||||
*/
|
*/
|
||||||
final class AnimeTransformer extends AbstractTransformer {
|
final class AnimeTransformer extends AbstractTransformer
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Convert raw api response to a more
|
* Convert raw api response to a more
|
||||||
* logical and workable structure
|
* logical and workable structure
|
||||||
*
|
*
|
||||||
* @param array|object $item API library item
|
* @param array|object $item API library item
|
||||||
* @return AnimePage
|
|
||||||
*/
|
*/
|
||||||
public function transform(array|object $item): AnimePage
|
public function transform(array|object $item): AnimePage
|
||||||
{
|
{
|
||||||
$item = (array)$item;
|
$item = (array) $item;
|
||||||
$base = $item['data']['findAnimeBySlug'] ?? $item['data']['findAnimeById'] ?? $item['data']['randomMedia'];
|
$base = $item['data']['findAnimeBySlug'] ?? $item['data']['findAnimeById'] ?? $item['data']['randomMedia'];
|
||||||
$characters = [];
|
$characters = [];
|
||||||
$links = [];
|
$links = [];
|
||||||
$staff = [];
|
$staff = [];
|
||||||
$genres = array_map(fn ($genre) => $genre['title']['en'], $base['categories']['nodes']);
|
$genres = array_map(static fn ($genre) => $genre['title']['en'], $base['categories']['nodes']);
|
||||||
|
|
||||||
sort($genres);
|
sort($genres);
|
||||||
|
|
||||||
@ -47,7 +44,7 @@ final class AnimeTransformer extends AbstractTransformer {
|
|||||||
$titles = Kitsu::getTitles($base['titles']);
|
$titles = Kitsu::getTitles($base['titles']);
|
||||||
$titles_more = Kitsu::filterLocalizedTitles($base['titles']);
|
$titles_more = Kitsu::filterLocalizedTitles($base['titles']);
|
||||||
|
|
||||||
if (count($base['characters']['nodes']) > 0)
|
if ((is_countable($base['characters']['nodes']) ? count($base['characters']['nodes']) : 0) > 0)
|
||||||
{
|
{
|
||||||
foreach ($base['characters']['nodes'] as $rawCharacter)
|
foreach ($base['characters']['nodes'] as $rawCharacter)
|
||||||
{
|
{
|
||||||
@ -73,14 +70,14 @@ final class AnimeTransformer extends AbstractTransformer {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uasort($characters[$type], fn($a, $b) => $a['name'] <=> $b['name']);
|
uasort($characters[$type], static fn ($a, $b) => $a['name'] <=> $b['name']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
krsort($characters);
|
krsort($characters);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($base['staff']['nodes']) > 0)
|
if ((is_countable($base['staff']['nodes']) ? count($base['staff']['nodes']) : 0) > 0)
|
||||||
{
|
{
|
||||||
foreach ($base['staff']['nodes'] as $staffing)
|
foreach ($base['staff']['nodes'] as $staffing)
|
||||||
{
|
{
|
||||||
@ -90,7 +87,7 @@ final class AnimeTransformer extends AbstractTransformer {
|
|||||||
|
|
||||||
// If this person object is so broken as to not have a proper image object,
|
// If this person object is so broken as to not have a proper image object,
|
||||||
// just skip it. No point in showing a role with nothing in it.
|
// just skip it. No point in showing a role with nothing in it.
|
||||||
if ($person === null || $person['id'] === null || $person['image'] === null)
|
if ($person === NULL || $person['id'] === NULL || $person['image'] === NULL)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -103,17 +100,17 @@ final class AnimeTransformer extends AbstractTransformer {
|
|||||||
$staff[$role][$person['id']] = [
|
$staff[$role][$person['id']] = [
|
||||||
'id' => $person['id'],
|
'id' => $person['id'],
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
'image' => $person['image']['original']['url'],
|
'image' => $person['image']['original']['url'],
|
||||||
'slug' => $person['slug'],
|
'slug' => $person['slug'],
|
||||||
];
|
];
|
||||||
|
|
||||||
usort($staff[$role], fn ($a, $b) => $a['name'] <=> $b['name']);
|
usort($staff[$role], static fn ($a, $b) => $a['name'] <=> $b['name']);
|
||||||
}
|
}
|
||||||
|
|
||||||
ksort($staff);
|
ksort($staff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($base['mappings']['nodes']) > 0)
|
if ((is_countable($base['mappings']['nodes']) ? count($base['mappings']['nodes']) : 0) > 0)
|
||||||
{
|
{
|
||||||
$links = Kitsu::mappingsToUrls($base['mappings']['nodes'], "https://kitsu.io/anime/{$base['slug']}");
|
$links = Kitsu::mappingsToUrls($base['mappings']['nodes'], "https://kitsu.io/anime/{$base['slug']}");
|
||||||
}
|
}
|
||||||
@ -143,4 +140,4 @@ final class AnimeTransformer extends AbstractTransformer {
|
|||||||
'url' => "https://kitsu.io/anime/{$base['slug']}",
|
'url' => "https://kitsu.io/anime/{$base['slug']}",
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
@ -25,15 +23,11 @@ use Locale;
|
|||||||
/**
|
/**
|
||||||
* Data transformation class for character pages
|
* Data transformation class for character pages
|
||||||
*/
|
*/
|
||||||
final class CharacterTransformer extends AbstractTransformer {
|
final class CharacterTransformer extends AbstractTransformer
|
||||||
|
{
|
||||||
/**
|
|
||||||
* @param array|object $item
|
|
||||||
* @return Character
|
|
||||||
*/
|
|
||||||
public function transform(array|object $item): Character
|
public function transform(array|object $item): Character
|
||||||
{
|
{
|
||||||
$item = (array)$item;
|
$item = (array) $item;
|
||||||
$data = $item['data']['findCharacterBySlug'] ?? [];
|
$data = $item['data']['findCharacterBySlug'] ?? [];
|
||||||
$castings = [];
|
$castings = [];
|
||||||
$media = [
|
$media = [
|
||||||
@ -42,10 +36,7 @@ final class CharacterTransformer extends AbstractTransformer {
|
|||||||
];
|
];
|
||||||
|
|
||||||
$names = array_unique(
|
$names = array_unique(
|
||||||
array_merge(
|
[...[$data['names']['canonical']], ...array_values($data['names']['localized'])]
|
||||||
[$data['names']['canonical']],
|
|
||||||
array_values($data['names']['localized'])
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
$name = array_shift($names);
|
$name = array_shift($names);
|
||||||
|
|
||||||
@ -66,19 +57,22 @@ final class CharacterTransformer extends AbstractTransformer {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function organizeMediaAndVoices (array $data): array
|
/**
|
||||||
|
* @return array<int, mixed[]>
|
||||||
|
*/
|
||||||
|
protected function organizeMediaAndVoices(array $data): array
|
||||||
{
|
{
|
||||||
if (empty($data))
|
if (empty($data))
|
||||||
{
|
{
|
||||||
return [[], []];
|
return [[], []];
|
||||||
}
|
}
|
||||||
|
|
||||||
$titleSort = fn ($a, $b) => $a['title'] <=> $b['title'];
|
$titleSort = static fn ($a, $b) => $a['title'] <=> $b['title'];
|
||||||
|
|
||||||
// First, let's deal with related media
|
// First, let's deal with related media
|
||||||
$rawMedia = array_column($data, 'media');
|
$rawMedia = array_column($data, 'media');
|
||||||
$rawAnime = array_filter($rawMedia, fn ($item) => $item['type'] === 'Anime');
|
$rawAnime = array_filter($rawMedia, static fn ($item) => $item['type'] === 'Anime');
|
||||||
$rawManga = array_filter($rawMedia, fn ($item) => $item['type'] === 'Manga');
|
$rawManga = array_filter($rawMedia, static fn ($item) => $item['type'] === 'Manga');
|
||||||
|
|
||||||
$anime = array_map(static function ($item) {
|
$anime = array_map(static function ($item) {
|
||||||
$output = $item;
|
$output = $item;
|
||||||
@ -106,7 +100,7 @@ final class CharacterTransformer extends AbstractTransformer {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// And now, reorganize voice actor relationships
|
// And now, reorganize voice actor relationships
|
||||||
$rawVoices = array_filter($data, fn($item) => (! empty($item['voices'])) && count((array)$item['voices']['nodes']) > 0);
|
$rawVoices = array_filter($data, static fn ($item) => ( ! empty($item['voices'])) && (array) $item['voices']['nodes'] !== []);
|
||||||
|
|
||||||
if (empty($rawVoices))
|
if (empty($rawVoices))
|
||||||
{
|
{
|
||||||
@ -139,7 +133,7 @@ final class CharacterTransformer extends AbstractTransformer {
|
|||||||
'image' => $voice['person']['image']['original']['url'],
|
'image' => $voice['person']['image']['original']['url'],
|
||||||
'name' => $voice['person']['name'],
|
'name' => $voice['person']['name'],
|
||||||
],
|
],
|
||||||
'series' => []
|
'series' => [],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,4 +152,4 @@ final class CharacterTransformer extends AbstractTransformer {
|
|||||||
|
|
||||||
return [$media, $castings];
|
return [$media, $castings];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,23 +6,22 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Types\HistoryItem;
|
|
||||||
use Aviat\AnimeClient\Kitsu;
|
use Aviat\AnimeClient\Kitsu;
|
||||||
|
use Aviat\AnimeClient\Types\HistoryItem;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
|
|
||||||
abstract class HistoryTransformer {
|
abstract class HistoryTransformer
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* @var string The media type
|
* @var string The media type
|
||||||
*/
|
*/
|
||||||
@ -51,13 +50,10 @@ abstract class HistoryTransformer {
|
|||||||
/**
|
/**
|
||||||
* @var array The mapping of api status to display status
|
* @var array The mapping of api status to display status
|
||||||
*/
|
*/
|
||||||
protected array $statusMap;
|
protected array $statusMap = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert raw history
|
* Convert raw history
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function transform(array $data): array
|
public function transform(array $data): array
|
||||||
{
|
{
|
||||||
@ -73,7 +69,7 @@ abstract class HistoryTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Hide private library entries
|
// Hide private library entries
|
||||||
if ($entry['libraryEntry']['private'] === true)
|
if ($entry['libraryEntry']['private'] === TRUE)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -88,7 +84,7 @@ abstract class HistoryTransformer {
|
|||||||
$output[] = $transformed;
|
$output[] = $transformed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ($kind === 'updated')
|
elseif ($kind === 'updated')
|
||||||
{
|
{
|
||||||
$output[] = $this->transformUpdated($entry);
|
$output[] = $this->transformUpdated($entry);
|
||||||
}
|
}
|
||||||
@ -99,15 +95,13 @@ abstract class HistoryTransformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Combine consecutive 'progressed' events
|
* Combine consecutive 'progressed' events
|
||||||
*
|
|
||||||
* @param array $singles
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
protected function aggregate (array $singles): array
|
protected function aggregate(array $singles): array
|
||||||
{
|
{
|
||||||
$output = [];
|
$output = [];
|
||||||
|
|
||||||
$count = count($singles);
|
$count = count($singles);
|
||||||
|
|
||||||
for ($i = 0; $i < $count; $i++)
|
for ($i = 0; $i < $count; $i++)
|
||||||
{
|
{
|
||||||
$entries = [];
|
$entries = [];
|
||||||
@ -115,9 +109,10 @@ abstract class HistoryTransformer {
|
|||||||
$prevTitle = $entry['title'];
|
$prevTitle = $entry['title'];
|
||||||
$nextId = $i;
|
$nextId = $i;
|
||||||
$next = $singles[$nextId];
|
$next = $singles[$nextId];
|
||||||
|
|
||||||
while (
|
while (
|
||||||
$next['kind'] === 'progressed' &&
|
$next['kind'] === 'progressed'
|
||||||
$next['title'] === $prevTitle
|
&& $next['title'] === $prevTitle
|
||||||
) {
|
) {
|
||||||
$entries[] = $next;
|
$entries[] = $next;
|
||||||
$prevTitle = $next['title'];
|
$prevTitle = $next['title'];
|
||||||
@ -126,6 +121,7 @@ abstract class HistoryTransformer {
|
|||||||
{
|
{
|
||||||
$nextId++;
|
$nextId++;
|
||||||
$next = $singles[$nextId];
|
$next = $singles[$nextId];
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +139,7 @@ abstract class HistoryTransformer {
|
|||||||
$items[] = array_pop($progressItem);
|
$items[] = array_pop($progressItem);
|
||||||
$updated[] = $e['updated'];
|
$updated[] = $e['updated'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$firstItem = min($items);
|
$firstItem = min($items);
|
||||||
$lastItem = max($items);
|
$lastItem = max($items);
|
||||||
$firstUpdate = min($updated);
|
$firstUpdate = min($updated);
|
||||||
@ -165,7 +162,7 @@ abstract class HistoryTransformer {
|
|||||||
'action' => $action,
|
'action' => $action,
|
||||||
'coverImg' => $entries[0]['coverImg'],
|
'coverImg' => $entries[0]['coverImg'],
|
||||||
'dateRange' => [$firstUpdate, $lastUpdate],
|
'dateRange' => [$firstUpdate, $lastUpdate],
|
||||||
'isAggregate' => true,
|
'isAggregate' => TRUE,
|
||||||
'original' => $entries,
|
'original' => $entries,
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'updated' => $entries[0]['updated'],
|
'updated' => $entries[0]['updated'],
|
||||||
@ -174,6 +171,7 @@ abstract class HistoryTransformer {
|
|||||||
|
|
||||||
// Skip the rest of the aggregate in the main loop
|
// Skip the rest of the aggregate in the main loop
|
||||||
$i += count($entries) - 1;
|
$i += count($entries) - 1;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,14 +181,14 @@ abstract class HistoryTransformer {
|
|||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function transformProgress (array $entry): ?HistoryItem
|
protected function transformProgress(array $entry): ?HistoryItem
|
||||||
{
|
{
|
||||||
$data = $entry['media'];
|
$data = $entry['media'];
|
||||||
$title = $this->linkTitle($data);
|
$title = $this->linkTitle($data);
|
||||||
$item = end($entry['changedData']['progress']);
|
$item = end($entry['changedData']['progress']);
|
||||||
|
|
||||||
// No showing episode 0 nonsense
|
// No showing episode 0 nonsense
|
||||||
if (((int)$item) === 0)
|
if (((int) $item) === 0)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -256,12 +254,12 @@ abstract class HistoryTransformer {
|
|||||||
return HistoryItem::from($entry);
|
return HistoryItem::from($entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function linkTitle (array $data): string
|
protected function linkTitle(array $data): string
|
||||||
{
|
{
|
||||||
return $data['titles']['canonical'];
|
return $data['titles']['canonical'];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function parseDate (string $date): DateTimeImmutable
|
protected function parseDate(string $date): DateTimeImmutable
|
||||||
{
|
{
|
||||||
$dateTime = DateTimeImmutable::createFromFormat(
|
$dateTime = DateTimeImmutable::createFromFormat(
|
||||||
DateTimeInterface::RFC3339,
|
DateTimeInterface::RFC3339,
|
||||||
@ -276,13 +274,13 @@ abstract class HistoryTransformer {
|
|||||||
return $dateTime->setTimezone(new DateTimeZone(date_default_timezone_get()));
|
return $dateTime->setTimezone(new DateTimeZone(date_default_timezone_get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getUrl (array $data): string
|
protected function getUrl(array $data): string
|
||||||
{
|
{
|
||||||
return "/{$this->type}/details/{$data['slug']}";
|
return "/{$this->type}/details/{$data['slug']}";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function isReconsuming (array $entry): bool
|
protected function isReconsuming(array $entry): bool
|
||||||
{
|
{
|
||||||
return $entry['libraryEntry']['reconsuming'];
|
return $entry['libraryEntry']['reconsuming'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,18 +6,16 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Kitsu;
|
use Aviat\AnimeClient\Kitsu;
|
||||||
use Aviat\AnimeClient\Types\{FormItem, AnimeListItem, MangaListItem, MangaListItemDetail};
|
use Aviat\AnimeClient\Types\{AnimeListItem, FormItem, MangaListItem, MangaListItemDetail};
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
use Aviat\Ion\Type\StringType;
|
use Aviat\Ion\Type\StringType;
|
||||||
|
|
||||||
@ -28,7 +26,7 @@ final class LibraryEntryTransformer extends AbstractTransformer
|
|||||||
{
|
{
|
||||||
public function transform(array|object $item): AnimeListItem|MangaListItem
|
public function transform(array|object $item): AnimeListItem|MangaListItem
|
||||||
{
|
{
|
||||||
$item = (array)$item;
|
$item = (array) $item;
|
||||||
$type = $item['media']['type'] ?? '';
|
$type = $item['media']['type'] ?? '';
|
||||||
|
|
||||||
$genres = [];
|
$genres = [];
|
||||||
@ -60,6 +58,7 @@ final class LibraryEntryTransformer extends AbstractTransformer
|
|||||||
: '-';
|
: '-';
|
||||||
|
|
||||||
$MALid = NULL;
|
$MALid = NULL;
|
||||||
|
$AnilistId = NULL;
|
||||||
|
|
||||||
if (isset($anime['mappings']['nodes']))
|
if (isset($anime['mappings']['nodes']))
|
||||||
{
|
{
|
||||||
@ -68,7 +67,11 @@ final class LibraryEntryTransformer extends AbstractTransformer
|
|||||||
if ($mapping['externalSite'] === 'MYANIMELIST_ANIME')
|
if ($mapping['externalSite'] === 'MYANIMELIST_ANIME')
|
||||||
{
|
{
|
||||||
$MALid = $mapping['externalId'];
|
$MALid = $mapping['externalId'];
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
if ($mapping['externalSite'] === 'ANILIST_ANIME')
|
||||||
|
{
|
||||||
|
$AnilistId = $mapping['externalId'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,6 +85,7 @@ final class LibraryEntryTransformer extends AbstractTransformer
|
|||||||
|
|
||||||
return AnimeListItem::from([
|
return AnimeListItem::from([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
|
'anilist_id' => $AnilistId,
|
||||||
'mal_id' => $MALid,
|
'mal_id' => $MALid,
|
||||||
'episodes' => [
|
'episodes' => [
|
||||||
'watched' => (int) $item['progress'] !== 0
|
'watched' => (int) $item['progress'] !== 0
|
||||||
@ -93,7 +97,7 @@ final class LibraryEntryTransformer extends AbstractTransformer
|
|||||||
'airing' => [
|
'airing' => [
|
||||||
'status' => Kitsu::getAiringStatus($anime['startDate'], $anime['endDate']),
|
'status' => Kitsu::getAiringStatus($anime['startDate'], $anime['endDate']),
|
||||||
'started' => $anime['startDate'],
|
'started' => $anime['startDate'],
|
||||||
'ended' => $anime['endDate']
|
'ended' => $anime['endDate'],
|
||||||
],
|
],
|
||||||
'anime' => [
|
'anime' => [
|
||||||
'id' => $animeId,
|
'id' => $animeId,
|
||||||
@ -101,7 +105,7 @@ final class LibraryEntryTransformer extends AbstractTransformer
|
|||||||
'title' => $title,
|
'title' => $title,
|
||||||
'titles' => $titles,
|
'titles' => $titles,
|
||||||
'slug' => $anime['slug'],
|
'slug' => $anime['slug'],
|
||||||
'show_type' => (string)StringType::from($anime['subtype'])->upperCaseFirst(),
|
'show_type' => (string) StringType::from($anime['subtype'])->upperCaseFirst(),
|
||||||
'cover_image' => Kitsu::getPosterImage($anime),
|
'cover_image' => Kitsu::getPosterImage($anime),
|
||||||
'genres' => $genres,
|
'genres' => $genres,
|
||||||
'streaming_links' => $streamingLinks,
|
'streaming_links' => $streamingLinks,
|
||||||
@ -137,6 +141,7 @@ final class LibraryEntryTransformer extends AbstractTransformer
|
|||||||
: '-';
|
: '-';
|
||||||
|
|
||||||
$MALid = NULL;
|
$MALid = NULL;
|
||||||
|
$AnilistId = NULL;
|
||||||
|
|
||||||
if (isset($manga['mappings']['nodes']))
|
if (isset($manga['mappings']['nodes']))
|
||||||
{
|
{
|
||||||
@ -145,7 +150,11 @@ final class LibraryEntryTransformer extends AbstractTransformer
|
|||||||
if ($mapping['externalSite'] === 'MYANIMELIST_MANGA')
|
if ($mapping['externalSite'] === 'MYANIMELIST_MANGA')
|
||||||
{
|
{
|
||||||
$MALid = $mapping['externalId'];
|
$MALid = $mapping['externalId'];
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
if ($mapping['externalSite'] === 'ANILIST_MANGA')
|
||||||
|
{
|
||||||
|
$AnilistId = $mapping['externalId'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,14 +164,15 @@ final class LibraryEntryTransformer extends AbstractTransformer
|
|||||||
|
|
||||||
return MangaListItem::from([
|
return MangaListItem::from([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
|
'anilist_id' => $AnilistId,
|
||||||
'mal_id' => $MALid,
|
'mal_id' => $MALid,
|
||||||
'chapters' => [
|
'chapters' => [
|
||||||
'read' => $readChapters,
|
'read' => $readChapters,
|
||||||
'total' => $totalChapters
|
'total' => $totalChapters,
|
||||||
],
|
],
|
||||||
'volumes' => [
|
'volumes' => [
|
||||||
'read' => '-', //$item['attributes']['volumes_read'],
|
'read' => '-', //$item['attributes']['volumes_read'],
|
||||||
'total' => $totalVolumes
|
'total' => $totalVolumes,
|
||||||
],
|
],
|
||||||
'manga' => MangaListItemDetail::from([
|
'manga' => MangaListItemDetail::from([
|
||||||
'genres' => $genres,
|
'genres' => $genres,
|
||||||
@ -171,14 +181,14 @@ final class LibraryEntryTransformer extends AbstractTransformer
|
|||||||
'slug' => $manga['slug'],
|
'slug' => $manga['slug'],
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'titles' => $titles,
|
'titles' => $titles,
|
||||||
'type' => (string)StringType::from($manga['subtype'])->upperCaseFirst(),
|
'type' => (string) StringType::from($manga['subtype'])->upperCaseFirst(),
|
||||||
'url' => 'https://kitsu.io/manga/' . $manga['slug'],
|
'url' => 'https://kitsu.io/manga/' . $manga['slug'],
|
||||||
]),
|
]),
|
||||||
'reading_status' => strtolower($item['status']),
|
'reading_status' => strtolower($item['status']),
|
||||||
'notes' => $item['notes'],
|
'notes' => $item['notes'],
|
||||||
'rereading' => (bool)$item['reconsuming'],
|
'rereading' => (bool) $item['reconsuming'],
|
||||||
'reread' => $item['reconsumeCount'],
|
'reread' => $item['reconsumeCount'],
|
||||||
'user_rating' => $rating,
|
'user_rating' => $rating,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,28 +6,22 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Mapping\MangaReadingStatus;
|
use Aviat\AnimeClient\API\Mapping\MangaReadingStatus;
|
||||||
|
|
||||||
class MangaHistoryTransformer extends HistoryTransformer {
|
class MangaHistoryTransformer extends HistoryTransformer
|
||||||
|
{
|
||||||
protected string $type = 'manga';
|
protected string $type = 'manga';
|
||||||
|
|
||||||
protected string $progressAction = 'Read chapter';
|
protected string $progressAction = 'Read chapter';
|
||||||
|
|
||||||
protected string $reconsumeAction = 'Reread chapter';
|
protected string $reconsumeAction = 'Reread chapter';
|
||||||
|
|
||||||
protected string $largeAggregateAction = 'Blew through chapters';
|
protected string $largeAggregateAction = 'Blew through chapters';
|
||||||
|
|
||||||
protected string $reconsumingStatus = 'Rereading';
|
protected string $reconsumingStatus = 'Rereading';
|
||||||
|
|
||||||
protected array $statusMap = MangaReadingStatus::KITSU_TO_TITLE;
|
protected array $statusMap = MangaReadingStatus::KITSU_TO_TITLE;
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
@ -27,16 +25,16 @@ use Aviat\Ion\Type\StringType;
|
|||||||
/**
|
/**
|
||||||
* Data transformation class for zippered Hummingbird manga
|
* Data transformation class for zippered Hummingbird manga
|
||||||
*/
|
*/
|
||||||
final class MangaListTransformer extends AbstractTransformer {
|
final class MangaListTransformer extends AbstractTransformer
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Remap zipped anime data to a more logical form
|
* Remap zipped anime data to a more logical form
|
||||||
*
|
*
|
||||||
* @param array|object $item manga entry item
|
* @param array|object $item manga entry item
|
||||||
* @return MangaListItem
|
|
||||||
*/
|
*/
|
||||||
public function transform(array|object $item): MangaListItem
|
public function transform(array|object $item): MangaListItem
|
||||||
{
|
{
|
||||||
$item = (array)$item;
|
$item = (array) $item;
|
||||||
$mangaId = $item['media']['id'];
|
$mangaId = $item['media']['id'];
|
||||||
$manga = $item['media'];
|
$manga = $item['media'];
|
||||||
|
|
||||||
@ -82,11 +80,11 @@ final class MangaListTransformer extends AbstractTransformer {
|
|||||||
'mal_id' => $MALid,
|
'mal_id' => $MALid,
|
||||||
'chapters' => [
|
'chapters' => [
|
||||||
'read' => $readChapters,
|
'read' => $readChapters,
|
||||||
'total' => $totalChapters
|
'total' => $totalChapters,
|
||||||
],
|
],
|
||||||
'volumes' => [
|
'volumes' => [
|
||||||
'read' => '-', //$item['attributes']['volumes_read'],
|
'read' => '-', //$item['attributes']['volumes_read'],
|
||||||
'total' => $totalVolumes
|
'total' => $totalVolumes,
|
||||||
],
|
],
|
||||||
'manga' => MangaListItemDetail::from([
|
'manga' => MangaListItemDetail::from([
|
||||||
'genres' => $genres,
|
'genres' => $genres,
|
||||||
@ -95,12 +93,12 @@ final class MangaListTransformer extends AbstractTransformer {
|
|||||||
'slug' => $manga['slug'],
|
'slug' => $manga['slug'],
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'titles' => $titles,
|
'titles' => $titles,
|
||||||
'type' => (string)StringType::from($manga['subtype'])->toLowerCase()->upperCaseFirst(),
|
'type' => (string) StringType::from($manga['subtype'])->toLowerCase()->upperCaseFirst(),
|
||||||
'url' => 'https://kitsu.io/manga/' . $manga['slug'],
|
'url' => 'https://kitsu.io/manga/' . $manga['slug'],
|
||||||
]),
|
]),
|
||||||
'reading_status' => strtolower($item['status']),
|
'reading_status' => strtolower($item['status']),
|
||||||
'notes' => $item['notes'],
|
'notes' => $item['notes'],
|
||||||
'rereading' => (bool)$item['reconsuming'],
|
'rereading' => (bool) $item['reconsuming'],
|
||||||
'reread' => $item['reconsumeCount'],
|
'reread' => $item['reconsumeCount'],
|
||||||
'user_rating' => $rating,
|
'user_rating' => $rating,
|
||||||
]);
|
]);
|
||||||
@ -109,12 +107,11 @@ final class MangaListTransformer extends AbstractTransformer {
|
|||||||
/**
|
/**
|
||||||
* Untransform data to update the api
|
* Untransform data to update the api
|
||||||
*
|
*
|
||||||
* @param array $item
|
* @param array $item
|
||||||
* @return FormItem
|
|
||||||
*/
|
*/
|
||||||
public function untransform($item): FormItem
|
public function untransform($item): FormItem
|
||||||
{
|
{
|
||||||
$rereading = array_key_exists('rereading', $item) && (bool)$item['rereading'];
|
$rereading = array_key_exists('rereading', $item) && (bool) $item['rereading'];
|
||||||
|
|
||||||
$map = FormItem::from([
|
$map = FormItem::from([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
@ -122,14 +119,14 @@ final class MangaListTransformer extends AbstractTransformer {
|
|||||||
'data' => FormItemData::from([
|
'data' => FormItemData::from([
|
||||||
'status' => $item['status'],
|
'status' => $item['status'],
|
||||||
'reconsuming' => $rereading,
|
'reconsuming' => $rereading,
|
||||||
'reconsumeCount' => (int)$item['reread_count'],
|
'reconsumeCount' => (int) $item['reread_count'],
|
||||||
'notes' => $item['notes'],
|
'notes' => $item['notes'],
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (is_numeric($item['chapters_read']) && $item['chapters_read'] > 0)
|
if (is_numeric($item['chapters_read']) && $item['chapters_read'] > 0)
|
||||||
{
|
{
|
||||||
$map['data']['progress'] = (int)$item['chapters_read'];
|
$map['data']['progress'] = (int) $item['chapters_read'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_numeric($item['new_rating']) && $item['new_rating'] > 0)
|
if (is_numeric($item['new_rating']) && $item['new_rating'] > 0)
|
||||||
@ -140,4 +137,5 @@ final class MangaListTransformer extends AbstractTransformer {
|
|||||||
return $map;
|
return $map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// End of MangaListTransformer.php
|
|
||||||
|
// End of MangaListTransformer.php
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
@ -23,30 +21,29 @@ use Aviat\Ion\Transformer\AbstractTransformer;
|
|||||||
/**
|
/**
|
||||||
* Transformer for manga description page
|
* Transformer for manga description page
|
||||||
*/
|
*/
|
||||||
final class MangaTransformer extends AbstractTransformer {
|
final class MangaTransformer extends AbstractTransformer
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Convert raw api response to a more
|
* Convert raw api response to a more
|
||||||
* logical and workable structure
|
* logical and workable structure
|
||||||
*
|
*
|
||||||
* @param array|object $item API library item
|
* @param array|object $item API library item
|
||||||
* @return MangaPage
|
|
||||||
*/
|
*/
|
||||||
public function transform(array|object $item): MangaPage
|
public function transform(array|object $item): MangaPage
|
||||||
{
|
{
|
||||||
$item = (array)$item;
|
$item = (array) $item;
|
||||||
$base = $item['data']['findMangaBySlug'] ?? $item['data']['findMangaById'] ?? $item['data']['randomMedia'];
|
$base = $item['data']['findMangaBySlug'] ?? $item['data']['findMangaById'] ?? $item['data']['randomMedia'];
|
||||||
$characters = [];
|
$characters = [];
|
||||||
$links = [];
|
$links = [];
|
||||||
$staff = [];
|
$staff = [];
|
||||||
$genres = array_map(fn ($genre) => $genre['title']['en'], $base['categories']['nodes']);
|
$genres = array_map(static fn ($genre) => $genre['title']['en'], $base['categories']['nodes']);
|
||||||
sort($genres);
|
sort($genres);
|
||||||
|
|
||||||
$title = $base['titles']['canonical'];
|
$title = $base['titles']['canonical'];
|
||||||
$titles = Kitsu::getTitles($base['titles']);
|
$titles = Kitsu::getTitles($base['titles']);
|
||||||
$titles_more = Kitsu::filterLocalizedTitles($base['titles']);
|
$titles_more = Kitsu::filterLocalizedTitles($base['titles']);
|
||||||
|
|
||||||
if (count($base['characters']['nodes']) > 0)
|
if ((is_countable($base['characters']['nodes']) ? count($base['characters']['nodes']) : 0) > 0)
|
||||||
{
|
{
|
||||||
foreach ($base['characters']['nodes'] as $rawCharacter)
|
foreach ($base['characters']['nodes'] as $rawCharacter)
|
||||||
{
|
{
|
||||||
@ -57,11 +54,14 @@ final class MangaTransformer extends AbstractTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$details = $rawCharacter['character'];
|
$details = $rawCharacter['character'];
|
||||||
$characters[$type][$details['id']] = [
|
if (array_key_exists($details['id'], $characters[$type]))
|
||||||
'image' => $details['image']['original']['url'],
|
{
|
||||||
'name' => $details['names']['canonical'],
|
$characters[$type][$details['id']] = [
|
||||||
'slug' => $details['slug'],
|
'image' => $details['image']['original']['url'],
|
||||||
];
|
'name' => $details['names']['canonical'],
|
||||||
|
'slug' => $details['slug'],
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (array_keys($characters) as $type)
|
foreach (array_keys($characters) as $type)
|
||||||
@ -72,14 +72,14 @@ final class MangaTransformer extends AbstractTransformer {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uasort($characters[$type], fn($a, $b) => $a['name'] <=> $b['name']);
|
uasort($characters[$type], static fn ($a, $b) => $a['name'] <=> $b['name']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
krsort($characters);
|
krsort($characters);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($base['staff']['nodes']) > 0)
|
if ((is_countable($base['staff']['nodes']) ? count($base['staff']['nodes']) : 0) > 0)
|
||||||
{
|
{
|
||||||
foreach ($base['staff']['nodes'] as $staffing)
|
foreach ($base['staff']['nodes'] as $staffing)
|
||||||
{
|
{
|
||||||
@ -89,7 +89,7 @@ final class MangaTransformer extends AbstractTransformer {
|
|||||||
|
|
||||||
// If this person object is so broken as to not have a proper image object,
|
// If this person object is so broken as to not have a proper image object,
|
||||||
// just skip it. No point in showing a role with nothing in it.
|
// just skip it. No point in showing a role with nothing in it.
|
||||||
if ($person === null || $person['id'] === null || $person['image'] === null)
|
if ($person === NULL || $person['id'] === NULL || $person['image'] === NULL)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -106,13 +106,13 @@ final class MangaTransformer extends AbstractTransformer {
|
|||||||
'image' => $person['image']['original']['url'],
|
'image' => $person['image']['original']['url'],
|
||||||
];
|
];
|
||||||
|
|
||||||
usort($staff[$role], fn ($a, $b) => $a['name'] <=> $b['name']);
|
usort($staff[$role], static fn ($a, $b) => $a['name'] <=> $b['name']);
|
||||||
}
|
}
|
||||||
|
|
||||||
ksort($staff);
|
ksort($staff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($base['mappings']['nodes']) > 0)
|
if ((is_countable($base['mappings']['nodes']) ? count($base['mappings']['nodes']) : 0) > 0)
|
||||||
{
|
{
|
||||||
$links = Kitsu::mappingsToUrls($base['mappings']['nodes'], "https://kitsu.io/manga/{$base['slug']}");
|
$links = Kitsu::mappingsToUrls($base['mappings']['nodes'], "https://kitsu.io/manga/{$base['slug']}");
|
||||||
}
|
}
|
||||||
@ -139,4 +139,4 @@ final class MangaTransformer extends AbstractTransformer {
|
|||||||
|
|
||||||
return MangaPage::from($data);
|
return MangaPage::from($data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
@ -23,15 +21,11 @@ use Aviat\Ion\Transformer\AbstractTransformer;
|
|||||||
/**
|
/**
|
||||||
* Data transformation class for people pages
|
* Data transformation class for people pages
|
||||||
*/
|
*/
|
||||||
final class PersonTransformer extends AbstractTransformer {
|
final class PersonTransformer extends AbstractTransformer
|
||||||
|
{
|
||||||
/**
|
|
||||||
* @param array|object $item
|
|
||||||
* @return Person
|
|
||||||
*/
|
|
||||||
public function transform(array|object $item): Person
|
public function transform(array|object $item): Person
|
||||||
{
|
{
|
||||||
$item = (array)$item;
|
$item = (array) $item;
|
||||||
$data = $item['data']['findPersonBySlug'] ?? [];
|
$data = $item['data']['findPersonBySlug'] ?? [];
|
||||||
$canonicalName = $data['names']['localized'][$data['names']['canonical']]
|
$canonicalName = $data['names']['localized'][$data['names']['canonical']]
|
||||||
?? array_shift($data['names']['localized']);
|
?? array_shift($data['names']['localized']);
|
||||||
@ -49,6 +43,9 @@ final class PersonTransformer extends AbstractTransformer {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, array<int|string, array<int|string, array<int|string, array<int|string, mixed>>>>>
|
||||||
|
*/
|
||||||
protected function organizeData(array $data): array
|
protected function organizeData(array $data): array
|
||||||
{
|
{
|
||||||
$output = [
|
$output = [
|
||||||
@ -59,13 +56,15 @@ final class PersonTransformer extends AbstractTransformer {
|
|||||||
$characters = [];
|
$characters = [];
|
||||||
$staff = [];
|
$staff = [];
|
||||||
|
|
||||||
if (count($data['mediaStaff']['nodes']) > 0)
|
if ((is_countable($data['mediaStaff']['nodes']) ? count($data['mediaStaff']['nodes']) : 0) > 0)
|
||||||
{
|
{
|
||||||
$roles = array_unique(array_column($data['mediaStaff']['nodes'], 'role'));
|
$roles = array_unique(array_column($data['mediaStaff']['nodes'], 'role'));
|
||||||
|
|
||||||
foreach ($roles as $role)
|
foreach ($roles as $role)
|
||||||
{
|
{
|
||||||
$staff[$role] = [];
|
$staff[$role] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
ksort($staff);
|
ksort($staff);
|
||||||
|
|
||||||
foreach ($data['mediaStaff']['nodes'] as $staffing)
|
foreach ($data['mediaStaff']['nodes'] as $staffing)
|
||||||
@ -88,13 +87,13 @@ final class PersonTransformer extends AbstractTransformer {
|
|||||||
'slug' => $media['slug'],
|
'slug' => $media['slug'],
|
||||||
];
|
];
|
||||||
|
|
||||||
uasort($staff[$role][$type], fn ($a, $b) => $a['title'] <=> $b['title']);
|
uasort($staff[$role][$type], static fn ($a, $b) => $a['title'] <=> $b['title']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$output['staff'] = $staff;
|
$output['staff'] = $staff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($data['voices']['nodes']) > 0)
|
if ((is_countable($data['voices']['nodes']) ? count($data['voices']['nodes']) : 0) > 0)
|
||||||
{
|
{
|
||||||
foreach ($data['voices']['nodes'] as $voicing)
|
foreach ($data['voices']['nodes'] as $voicing)
|
||||||
{
|
{
|
||||||
@ -128,7 +127,7 @@ final class PersonTransformer extends AbstractTransformer {
|
|||||||
'canonicalName' => $character['names']['canonical'],
|
'canonicalName' => $character['names']['canonical'],
|
||||||
],
|
],
|
||||||
'media' => [
|
'media' => [
|
||||||
$media['id'] => $media
|
$media['id'] => $media,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -143,7 +142,7 @@ final class PersonTransformer extends AbstractTransformer {
|
|||||||
// Sort the characters by name
|
// Sort the characters by name
|
||||||
uasort(
|
uasort(
|
||||||
$characters[$role],
|
$characters[$role],
|
||||||
fn($a, $b) => $a['character']['canonicalName'] <=> $b['character']['canonicalName']
|
static fn ($a, $b) => $a['character']['canonicalName'] <=> $b['character']['canonicalName']
|
||||||
);
|
);
|
||||||
|
|
||||||
// Sort the media for the character
|
// Sort the media for the character
|
||||||
@ -151,7 +150,7 @@ final class PersonTransformer extends AbstractTransformer {
|
|||||||
{
|
{
|
||||||
uasort(
|
uasort(
|
||||||
$characters[$role][$charId]['media'],
|
$characters[$role][$charId]['media'],
|
||||||
fn ($a, $b) => $a['titles'][0] <=> $b['titles'][0]
|
static fn ($a, $b) => $a['titles'][0] <=> $b['titles'][0]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,4 +162,4 @@ final class PersonTransformer extends AbstractTransformer {
|
|||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,18 +6,15 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
namespace Aviat\AnimeClient\API\Kitsu\Transformer;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Kitsu;
|
use Aviat\AnimeClient\Kitsu;
|
||||||
use function Aviat\AnimeClient\getLocalImg;
|
|
||||||
|
|
||||||
use Aviat\AnimeClient\Types\User;
|
use Aviat\AnimeClient\Types\User;
|
||||||
use Aviat\Ion\Transformer\AbstractTransformer;
|
use Aviat\Ion\Transformer\AbstractTransformer;
|
||||||
@ -28,10 +25,11 @@ use Aviat\Ion\Transformer\AbstractTransformer;
|
|||||||
* @param array|object $profileData
|
* @param array|object $profileData
|
||||||
* @return User
|
* @return User
|
||||||
*/
|
*/
|
||||||
final class UserTransformer extends AbstractTransformer {
|
final class UserTransformer extends AbstractTransformer
|
||||||
|
{
|
||||||
public function transform(array|object $item): User
|
public function transform(array|object $item): User
|
||||||
{
|
{
|
||||||
$item = (array)$item;
|
$item = (array) $item;
|
||||||
$base = $item['data']['findProfileBySlug'] ?? [];
|
$base = $item['data']['findProfileBySlug'] ?? [];
|
||||||
$favorites = $base['favorites']['nodes'] ?? [];
|
$favorites = $base['favorites']['nodes'] ?? [];
|
||||||
$stats = $base['stats'] ?? [];
|
$stats = $base['stats'] ?? [];
|
||||||
@ -56,8 +54,7 @@ final class UserTransformer extends AbstractTransformer {
|
|||||||
/**
|
/**
|
||||||
* Reorganize favorites data to be more useful
|
* Reorganize favorites data to be more useful
|
||||||
*
|
*
|
||||||
* @param array $rawFavorites
|
* @return array<string, array<int|string, mixed>>
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
private function organizeFavorites(array $rawFavorites): array
|
private function organizeFavorites(array $rawFavorites): array
|
||||||
{
|
{
|
||||||
@ -72,6 +69,9 @@ final class UserTransformer extends AbstractTransformer {
|
|||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, string>
|
||||||
|
*/
|
||||||
private function organizeStats(array $stats, array $data = []): array
|
private function organizeStats(array $stats, array $data = []): array
|
||||||
{
|
{
|
||||||
$animeStats = [];
|
$animeStats = [];
|
||||||
@ -106,4 +106,4 @@ final class UserTransformer extends AbstractTransformer {
|
|||||||
|
|
||||||
return array_merge($animeStats, $mangaStats, $otherStats);
|
return array_merge($animeStats, $mangaStats, $otherStats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,8 +73,10 @@ interface Media {
|
|||||||
ageRatingGuide: String
|
ageRatingGuide: String
|
||||||
"The average rating of this media amongst all Kitsu users"
|
"The average rating of this media amongst all Kitsu users"
|
||||||
averageRating: Float
|
averageRating: Float
|
||||||
|
"The rank of this media by rating"
|
||||||
|
averageRatingRank: Int
|
||||||
"A large banner image for this media"
|
"A large banner image for this media"
|
||||||
bannerImage: Image!
|
bannerImage: Image
|
||||||
"A list of categories for this media"
|
"A list of categories for this media"
|
||||||
categories(
|
categories(
|
||||||
"Returns the elements in the list that come after the specified cursor."
|
"Returns the elements in the list that come after the specified cursor."
|
||||||
@ -133,10 +135,26 @@ interface Media {
|
|||||||
): WikiSubmissionConnection!
|
): WikiSubmissionConnection!
|
||||||
"The time of the next release of this media"
|
"The time of the next release of this media"
|
||||||
nextRelease: ISO8601DateTime
|
nextRelease: ISO8601DateTime
|
||||||
|
"The countries in which the media was originally primarily produced"
|
||||||
|
originCountries: [String!]!
|
||||||
|
"The languages the media was originally produced in"
|
||||||
|
originLanguages: [String!]!
|
||||||
"The country in which the media was primarily produced"
|
"The country in which the media was primarily produced"
|
||||||
originalLocale: String
|
originalLocale: String @deprecated(reason: "Replaced with originCountries and originLanguages")
|
||||||
"The poster image of this media"
|
"The poster image of this media"
|
||||||
posterImage: Image!
|
posterImage: Image
|
||||||
|
"All posts that tag this media."
|
||||||
|
posts(
|
||||||
|
"Returns the elements in the list that come after the specified cursor."
|
||||||
|
after: String,
|
||||||
|
"Returns the elements in the list that come before the specified cursor."
|
||||||
|
before: String,
|
||||||
|
"Returns the first _n_ elements from the list."
|
||||||
|
first: Int,
|
||||||
|
"Returns the last _n_ elements from the list."
|
||||||
|
last: Int,
|
||||||
|
sort: [PostSortOption]
|
||||||
|
): PostConnection!
|
||||||
"The companies which helped to produce this media"
|
"The companies which helped to produce this media"
|
||||||
productions(
|
productions(
|
||||||
"Returns the elements in the list that come after the specified cursor."
|
"Returns the elements in the list that come after the specified cursor."
|
||||||
@ -198,6 +216,8 @@ interface Media {
|
|||||||
type: String!
|
type: String!
|
||||||
"The number of users with this in their library"
|
"The number of users with this in their library"
|
||||||
userCount: Int
|
userCount: Int
|
||||||
|
"The rank of this media by popularity"
|
||||||
|
userCountRank: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
"Media that is streamable."
|
"Media that is streamable."
|
||||||
@ -230,6 +250,8 @@ interface WithTimestamps {
|
|||||||
updatedAt: ISO8601DateTime!
|
updatedAt: ISO8601DateTime!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
union AccountCreateErrorsUnion = ValidationError
|
||||||
|
|
||||||
"Objects which are Favoritable"
|
"Objects which are Favoritable"
|
||||||
union FavoriteItemUnion = Anime | Character | Manga | Person
|
union FavoriteItemUnion = Anime | Character | Manga | Person
|
||||||
|
|
||||||
@ -274,6 +296,12 @@ type Account implements WithTimestamps {
|
|||||||
updatedAt: ISO8601DateTime!
|
updatedAt: ISO8601DateTime!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"Autogenerated return type of AccountCreate"
|
||||||
|
type AccountCreatePayload {
|
||||||
|
errors: [AccountCreateErrorsUnion!]
|
||||||
|
result: Account
|
||||||
|
}
|
||||||
|
|
||||||
type AccountMutations {
|
type AccountMutations {
|
||||||
"Send a password reset email"
|
"Send a password reset email"
|
||||||
sendPasswordReset(
|
sendPasswordReset(
|
||||||
@ -294,8 +322,10 @@ type Anime implements Episodic & Media & WithTimestamps {
|
|||||||
ageRatingGuide: String
|
ageRatingGuide: String
|
||||||
"The average rating of this media amongst all Kitsu users"
|
"The average rating of this media amongst all Kitsu users"
|
||||||
averageRating: Float
|
averageRating: Float
|
||||||
|
"The rank of this media by rating"
|
||||||
|
averageRatingRank: Int
|
||||||
"A large banner image for this media"
|
"A large banner image for this media"
|
||||||
bannerImage: Image!
|
bannerImage: Image
|
||||||
"A list of categories for this media"
|
"A list of categories for this media"
|
||||||
categories(
|
categories(
|
||||||
"Returns the elements in the list that come after the specified cursor."
|
"Returns the elements in the list that come after the specified cursor."
|
||||||
@ -371,10 +401,26 @@ type Anime implements Episodic & Media & WithTimestamps {
|
|||||||
): WikiSubmissionConnection!
|
): WikiSubmissionConnection!
|
||||||
"The time of the next release of this media"
|
"The time of the next release of this media"
|
||||||
nextRelease: ISO8601DateTime
|
nextRelease: ISO8601DateTime
|
||||||
|
"The countries in which the media was originally primarily produced"
|
||||||
|
originCountries: [String!]!
|
||||||
|
"The languages the media was originally produced in"
|
||||||
|
originLanguages: [String!]!
|
||||||
"The country in which the media was primarily produced"
|
"The country in which the media was primarily produced"
|
||||||
originalLocale: String
|
originalLocale: String @deprecated(reason: "Replaced with originCountries and originLanguages")
|
||||||
"The poster image of this media"
|
"The poster image of this media"
|
||||||
posterImage: Image!
|
posterImage: Image
|
||||||
|
"All posts that tag this media."
|
||||||
|
posts(
|
||||||
|
"Returns the elements in the list that come after the specified cursor."
|
||||||
|
after: String,
|
||||||
|
"Returns the elements in the list that come before the specified cursor."
|
||||||
|
before: String,
|
||||||
|
"Returns the first _n_ elements from the list."
|
||||||
|
first: Int,
|
||||||
|
"Returns the last _n_ elements from the list."
|
||||||
|
last: Int,
|
||||||
|
sort: [PostSortOption]
|
||||||
|
): PostConnection!
|
||||||
"The companies which helped to produce this media"
|
"The companies which helped to produce this media"
|
||||||
productions(
|
productions(
|
||||||
"Returns the elements in the list that come after the specified cursor."
|
"Returns the elements in the list that come after the specified cursor."
|
||||||
@ -454,6 +500,8 @@ type Anime implements Episodic & Media & WithTimestamps {
|
|||||||
updatedAt: ISO8601DateTime!
|
updatedAt: ISO8601DateTime!
|
||||||
"The number of users with this in their library"
|
"The number of users with this in their library"
|
||||||
userCount: Int
|
userCount: Int
|
||||||
|
"The rank of this media by popularity"
|
||||||
|
userCountRank: Int
|
||||||
"Video id for a trailer on YouTube"
|
"Video id for a trailer on YouTube"
|
||||||
youtubeTrailerVideoId: String
|
youtubeTrailerVideoId: String
|
||||||
}
|
}
|
||||||
@ -598,6 +646,8 @@ type Chapter implements Unit & WithTimestamps {
|
|||||||
"A brief summary or description of the unit"
|
"A brief summary or description of the unit"
|
||||||
description(locales: [String!]): Map!
|
description(locales: [String!]): Map!
|
||||||
id: ID!
|
id: ID!
|
||||||
|
"Number of pages in chapter."
|
||||||
|
length: Int
|
||||||
"The manga this chapter is in."
|
"The manga this chapter is in."
|
||||||
manga: Manga!
|
manga: Manga!
|
||||||
"The sequence number of this unit"
|
"The sequence number of this unit"
|
||||||
@ -906,7 +956,11 @@ type FranchiseEdge {
|
|||||||
node: Franchise
|
node: Franchise
|
||||||
}
|
}
|
||||||
|
|
||||||
type Generic implements Error {
|
type GenericDelete {
|
||||||
|
id: ID!
|
||||||
|
}
|
||||||
|
|
||||||
|
type GenericError implements Error {
|
||||||
"The error code."
|
"The error code."
|
||||||
code: String
|
code: String
|
||||||
"A description of the error"
|
"A description of the error"
|
||||||
@ -915,10 +969,6 @@ type Generic implements Error {
|
|||||||
path: [String!]
|
path: [String!]
|
||||||
}
|
}
|
||||||
|
|
||||||
type GenericDelete {
|
|
||||||
id: ID!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Image {
|
type Image {
|
||||||
"A blurhash-encoded version of this image"
|
"A blurhash-encoded version of this image"
|
||||||
blurhash: String
|
blurhash: String
|
||||||
@ -1273,8 +1323,10 @@ type Manga implements Media & WithTimestamps {
|
|||||||
ageRatingGuide: String
|
ageRatingGuide: String
|
||||||
"The average rating of this media amongst all Kitsu users"
|
"The average rating of this media amongst all Kitsu users"
|
||||||
averageRating: Float
|
averageRating: Float
|
||||||
|
"The rank of this media by rating"
|
||||||
|
averageRatingRank: Int
|
||||||
"A large banner image for this media"
|
"A large banner image for this media"
|
||||||
bannerImage: Image!
|
bannerImage: Image
|
||||||
"A list of categories for this media"
|
"A list of categories for this media"
|
||||||
categories(
|
categories(
|
||||||
"Returns the elements in the list that come after the specified cursor."
|
"Returns the elements in the list that come after the specified cursor."
|
||||||
@ -1350,10 +1402,26 @@ type Manga implements Media & WithTimestamps {
|
|||||||
): WikiSubmissionConnection!
|
): WikiSubmissionConnection!
|
||||||
"The time of the next release of this media"
|
"The time of the next release of this media"
|
||||||
nextRelease: ISO8601DateTime
|
nextRelease: ISO8601DateTime
|
||||||
|
"The countries in which the media was originally primarily produced"
|
||||||
|
originCountries: [String!]!
|
||||||
|
"The languages the media was originally produced in"
|
||||||
|
originLanguages: [String!]!
|
||||||
"The country in which the media was primarily produced"
|
"The country in which the media was primarily produced"
|
||||||
originalLocale: String
|
originalLocale: String @deprecated(reason: "Replaced with originCountries and originLanguages")
|
||||||
"The poster image of this media"
|
"The poster image of this media"
|
||||||
posterImage: Image!
|
posterImage: Image
|
||||||
|
"All posts that tag this media."
|
||||||
|
posts(
|
||||||
|
"Returns the elements in the list that come after the specified cursor."
|
||||||
|
after: String,
|
||||||
|
"Returns the elements in the list that come before the specified cursor."
|
||||||
|
before: String,
|
||||||
|
"Returns the first _n_ elements from the list."
|
||||||
|
first: Int,
|
||||||
|
"Returns the last _n_ elements from the list."
|
||||||
|
last: Int,
|
||||||
|
sort: [PostSortOption]
|
||||||
|
): PostConnection!
|
||||||
"The companies which helped to produce this media"
|
"The companies which helped to produce this media"
|
||||||
productions(
|
productions(
|
||||||
"Returns the elements in the list that come after the specified cursor."
|
"Returns the elements in the list that come after the specified cursor."
|
||||||
@ -1418,6 +1486,8 @@ type Manga implements Media & WithTimestamps {
|
|||||||
updatedAt: ISO8601DateTime!
|
updatedAt: ISO8601DateTime!
|
||||||
"The number of users with this in their library"
|
"The number of users with this in their library"
|
||||||
userCount: Int
|
userCount: Int
|
||||||
|
"The rank of this media by popularity"
|
||||||
|
userCountRank: Int
|
||||||
"The number of volumes in this manga."
|
"The number of volumes in this manga."
|
||||||
volumeCount: Int
|
volumeCount: Int
|
||||||
}
|
}
|
||||||
@ -1639,6 +1709,8 @@ type MediaReaction implements WithTimestamps {
|
|||||||
"The author who wrote this reaction."
|
"The author who wrote this reaction."
|
||||||
author: Profile!
|
author: Profile!
|
||||||
createdAt: ISO8601DateTime!
|
createdAt: ISO8601DateTime!
|
||||||
|
"Whether you have liked this media reaction"
|
||||||
|
hasLiked: Boolean!
|
||||||
id: ID!
|
id: ID!
|
||||||
"The library entry related to this reaction."
|
"The library entry related to this reaction."
|
||||||
libraryEntry: LibraryEntry!
|
libraryEntry: LibraryEntry!
|
||||||
@ -1718,6 +1790,8 @@ type MediaStaffEdge {
|
|||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
account: AccountMutations!
|
account: AccountMutations!
|
||||||
|
"Create a new Kitsu account"
|
||||||
|
accountCreate(input: AccountCreateInput!): AccountCreatePayload
|
||||||
anime: AnimeMutations!
|
anime: AnimeMutations!
|
||||||
episode: EpisodeMutations!
|
episode: EpisodeMutations!
|
||||||
libraryEntry: LibraryEntryMutations!
|
libraryEntry: LibraryEntryMutations!
|
||||||
@ -1852,6 +1926,12 @@ type PostConnection {
|
|||||||
totalCount: Int!
|
totalCount: Int!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"Autogenerated return type of PostCreate"
|
||||||
|
type PostCreatePayload {
|
||||||
|
errors: [Error!]
|
||||||
|
post: Post
|
||||||
|
}
|
||||||
|
|
||||||
"An edge in a connection."
|
"An edge in a connection."
|
||||||
type PostEdge {
|
type PostEdge {
|
||||||
"A cursor for use in pagination."
|
"A cursor for use in pagination."
|
||||||
@ -1867,6 +1947,11 @@ type PostLockPayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PostMutations {
|
type PostMutations {
|
||||||
|
"Create a Post."
|
||||||
|
create(
|
||||||
|
"Create a Post"
|
||||||
|
input: PostCreateInput!
|
||||||
|
): PostCreatePayload
|
||||||
"Lock a Post."
|
"Lock a Post."
|
||||||
lock(
|
lock(
|
||||||
"Lock a Post."
|
"Lock a Post."
|
||||||
@ -2116,6 +2201,19 @@ type ProfileEdge {
|
|||||||
node: Profile
|
node: Profile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"An external site that can be linked to a user."
|
||||||
|
type ProfileLinkSite implements WithTimestamps {
|
||||||
|
createdAt: ISO8601DateTime!
|
||||||
|
id: ID!
|
||||||
|
"Name of the external profile website."
|
||||||
|
name: String!
|
||||||
|
updatedAt: ISO8601DateTime!
|
||||||
|
"Regex pattern used to validate the profile link."
|
||||||
|
validateFind: String!
|
||||||
|
"Pattern to be replaced after validation."
|
||||||
|
validateReplace: String!
|
||||||
|
}
|
||||||
|
|
||||||
"The different types of user stats that we calculate."
|
"The different types of user stats that we calculate."
|
||||||
type ProfileStats {
|
type ProfileStats {
|
||||||
"The total amount of anime you have watched over your whole life."
|
"The total amount of anime you have watched over your whole life."
|
||||||
@ -2185,6 +2283,8 @@ type Query {
|
|||||||
findMangaById(id: ID!): Manga
|
findMangaById(id: ID!): Manga
|
||||||
"Find a single Manga by Slug"
|
"Find a single Manga by Slug"
|
||||||
findMangaBySlug(slug: String!): Manga
|
findMangaBySlug(slug: String!): Manga
|
||||||
|
"Find a single Media by ID and Type"
|
||||||
|
findMediaByIdAndType(id: ID!, mediaType: MediaTypeEnum!): Media
|
||||||
"Find a single Person by ID"
|
"Find a single Person by ID"
|
||||||
findPersonById(id: ID!): Person
|
findPersonById(id: ID!): Person
|
||||||
"Find a single Person by Slug"
|
"Find a single Person by Slug"
|
||||||
@ -2471,7 +2571,7 @@ type Report implements WithTimestamps {
|
|||||||
"The moderator who responded to this report"
|
"The moderator who responded to this report"
|
||||||
moderator: Profile
|
moderator: Profile
|
||||||
"The entity that the report is related to"
|
"The entity that the report is related to"
|
||||||
naughty: ReportItemUnion!
|
naughty: ReportItemUnion
|
||||||
"The reason for why the report was made"
|
"The reason for why the report was made"
|
||||||
reason: ReportReasonEnum!
|
reason: ReportReasonEnum!
|
||||||
"The user who made this report"
|
"The user who made this report"
|
||||||
@ -2573,6 +2673,8 @@ type SiteLink implements WithTimestamps {
|
|||||||
author: Profile!
|
author: Profile!
|
||||||
createdAt: ISO8601DateTime!
|
createdAt: ISO8601DateTime!
|
||||||
id: ID!
|
id: ID!
|
||||||
|
"The actual linked website."
|
||||||
|
site: ProfileLinkSite!
|
||||||
updatedAt: ISO8601DateTime!
|
updatedAt: ISO8601DateTime!
|
||||||
"A fully qualified URL of the user profile on an external site."
|
"A fully qualified URL of the user profile on an external site."
|
||||||
url: String!
|
url: String!
|
||||||
@ -2672,11 +2774,34 @@ type TitlesList {
|
|||||||
"A list of additional, alternative, abbreviated, or unofficial titles"
|
"A list of additional, alternative, abbreviated, or unofficial titles"
|
||||||
alternatives: [String!]
|
alternatives: [String!]
|
||||||
"The official or de facto international title"
|
"The official or de facto international title"
|
||||||
canonical: String
|
canonical: String!
|
||||||
"The locale code that identifies which title is used as the canonical title"
|
"The locale code that identifies which title is used as the canonical title"
|
||||||
canonicalLocale: String
|
canonicalLocale: String
|
||||||
"The list of localized titles keyed by locale"
|
"The list of localized titles keyed by locale"
|
||||||
localized(locales: [String!]): Map!
|
localized(locales: [String!]): Map!
|
||||||
|
"The original title of the media in the original language"
|
||||||
|
original: String
|
||||||
|
"The locale code that identifies which title is used as the original title"
|
||||||
|
originalLocale: String
|
||||||
|
"The title that best matches the user's preferred settings"
|
||||||
|
preferred: String!
|
||||||
|
"The original title, romanized into latin script"
|
||||||
|
romanized: String
|
||||||
|
"The locale code that identifies which title is used as the romanized title"
|
||||||
|
romanizedLocale: String
|
||||||
|
"The title translated into the user's locale"
|
||||||
|
translated: String
|
||||||
|
"The locale code that identifies which title is used as the translated title"
|
||||||
|
translatedLocale: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type ValidationError implements Error {
|
||||||
|
"The error code."
|
||||||
|
code: String
|
||||||
|
"A description of the error"
|
||||||
|
message: String!
|
||||||
|
"Which input value this error came from"
|
||||||
|
path: [String!]
|
||||||
}
|
}
|
||||||
|
|
||||||
"The media video."
|
"The media video."
|
||||||
@ -2875,6 +3000,11 @@ enum EpisodeSortEnum {
|
|||||||
UPDATED_AT
|
UPDATED_AT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ExternalIdentityProviderEnum {
|
||||||
|
"Facebook identity"
|
||||||
|
FACEBOOK
|
||||||
|
}
|
||||||
|
|
||||||
enum FollowSortEnum {
|
enum FollowSortEnum {
|
||||||
CREATED_AT
|
CREATED_AT
|
||||||
FOLLOWING_FOLLOWED
|
FOLLOWING_FOLLOWED
|
||||||
@ -3029,9 +3159,9 @@ enum PostSortEnum {
|
|||||||
|
|
||||||
enum ProTierEnum {
|
enum ProTierEnum {
|
||||||
"Aozora Pro (only hides ads)"
|
"Aozora Pro (only hides ads)"
|
||||||
AO_PRO @deprecated(reason : "No longer for sale")
|
AO_PRO @deprecated(reason: "No longer for sale")
|
||||||
"Aozora Pro+ (only hides ads)"
|
"Aozora Pro+ (only hides ads)"
|
||||||
AO_PRO_PLUS @deprecated(reason : "No longer for sale")
|
AO_PRO_PLUS @deprecated(reason: "No longer for sale")
|
||||||
"Top tier of Kitsu Pro"
|
"Top tier of Kitsu Pro"
|
||||||
PATRON
|
PATRON
|
||||||
"Basic tier of Kitsu Pro"
|
"Basic tier of Kitsu Pro"
|
||||||
@ -3134,6 +3264,39 @@ enum WikiSubmissionStatusEnum {
|
|||||||
REJECTED
|
REJECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"A date, expressed as an ISO8601 string"
|
||||||
|
scalar Date
|
||||||
|
|
||||||
|
"An ISO 8601-encoded date"
|
||||||
|
scalar ISO8601Date
|
||||||
|
|
||||||
|
"An ISO 8601-encoded datetime"
|
||||||
|
scalar ISO8601DateTime
|
||||||
|
|
||||||
|
"Represents untyped JSON"
|
||||||
|
scalar JSON
|
||||||
|
|
||||||
|
"A loose key-value map in GraphQL"
|
||||||
|
scalar Map
|
||||||
|
|
||||||
|
scalar Upload
|
||||||
|
|
||||||
|
input AccountCreateInput {
|
||||||
|
"The email address to reset the password for"
|
||||||
|
email: String!
|
||||||
|
"An external identity to associate with the account on creation"
|
||||||
|
externalIdentity: AccountExternalIdentityInput
|
||||||
|
"The name of the user"
|
||||||
|
name: String!
|
||||||
|
"The password for the user"
|
||||||
|
password: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
input AccountExternalIdentityInput {
|
||||||
|
id: String!
|
||||||
|
provider: ExternalIdentityProviderEnum!
|
||||||
|
}
|
||||||
|
|
||||||
input AnimeCreateInput {
|
input AnimeCreateInput {
|
||||||
ageRating: AgeRatingEnum
|
ageRating: AgeRatingEnum
|
||||||
ageRatingGuide: String
|
ageRatingGuide: String
|
||||||
@ -3324,6 +3487,16 @@ input MediaReactionVoteSortOption {
|
|||||||
on: MediaReactionVoteSortEnum!
|
on: MediaReactionVoteSortEnum!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input PostCreateInput {
|
||||||
|
content: String!
|
||||||
|
isNsfw: Boolean = false
|
||||||
|
isSpoiler: Boolean = false
|
||||||
|
mediaId: ID
|
||||||
|
mediaType: MediaTypeEnum
|
||||||
|
spoiledUnitId: ID
|
||||||
|
spoiledUnitType: String
|
||||||
|
}
|
||||||
|
|
||||||
input PostLikeSortOption {
|
input PostLikeSortOption {
|
||||||
direction: SortDirection!
|
direction: SortDirection!
|
||||||
on: PostLikeSortEnum!
|
on: PostLikeSortEnum!
|
||||||
@ -3373,21 +3546,3 @@ input WikiSubmissionUpdateDraftInput {
|
|||||||
id: ID!
|
id: ID!
|
||||||
notes: String
|
notes: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
"A date, expressed as an ISO8601 string"
|
|
||||||
scalar Date
|
|
||||||
|
|
||||||
"An ISO 8601-encoded date"
|
|
||||||
scalar ISO8601Date
|
|
||||||
|
|
||||||
"An ISO 8601-encoded datetime"
|
|
||||||
scalar ISO8601DateTime
|
|
||||||
|
|
||||||
"Represents untyped JSON"
|
|
||||||
scalar JSON
|
|
||||||
|
|
||||||
"A loose key-value map in GraphQL"
|
|
||||||
scalar Map
|
|
||||||
|
|
||||||
scalar Upload
|
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Mapping;
|
namespace Aviat\AnimeClient\API\Mapping;
|
||||||
@ -23,54 +21,50 @@ use Aviat\Ion\Enum;
|
|||||||
* Anime watching status mappings, among Kitsu, MAL, Page titles
|
* Anime watching status mappings, among Kitsu, MAL, Page titles
|
||||||
* and url route segments
|
* and url route segments
|
||||||
*/
|
*/
|
||||||
final class AnimeWatchingStatus extends Enum {
|
final class AnimeWatchingStatus extends Enum
|
||||||
|
{
|
||||||
public const ANILIST_TO_KITSU = [
|
public const ANILIST_TO_KITSU = [
|
||||||
Anilist::WATCHING => Kitsu::WATCHING,
|
Anilist::WATCHING => Kitsu::WATCHING,
|
||||||
Anilist::PLAN_TO_WATCH => Kitsu::PLAN_TO_WATCH,
|
Anilist::PLAN_TO_WATCH => Kitsu::PLAN_TO_WATCH,
|
||||||
Anilist::COMPLETED => Kitsu::COMPLETED,
|
Anilist::COMPLETED => Kitsu::COMPLETED,
|
||||||
Anilist::ON_HOLD => Kitsu::ON_HOLD,
|
Anilist::ON_HOLD => Kitsu::ON_HOLD,
|
||||||
Anilist::DROPPED => Kitsu::DROPPED
|
Anilist::DROPPED => Kitsu::DROPPED,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const KITSU_TO_ANILIST = [
|
public const KITSU_TO_ANILIST = [
|
||||||
Kitsu::WATCHING => Anilist::WATCHING,
|
Kitsu::WATCHING => Anilist::WATCHING,
|
||||||
Kitsu::PLAN_TO_WATCH => Anilist::PLAN_TO_WATCH,
|
Kitsu::PLAN_TO_WATCH => Anilist::PLAN_TO_WATCH,
|
||||||
Kitsu::COMPLETED => Anilist::COMPLETED,
|
Kitsu::COMPLETED => Anilist::COMPLETED,
|
||||||
Kitsu::ON_HOLD => Anilist::ON_HOLD,
|
Kitsu::ON_HOLD => Anilist::ON_HOLD,
|
||||||
Kitsu::DROPPED => Anilist::DROPPED
|
Kitsu::DROPPED => Anilist::DROPPED,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const KITSU_TO_TITLE = [
|
public const KITSU_TO_TITLE = [
|
||||||
Kitsu::WATCHING => Title::WATCHING,
|
Kitsu::WATCHING => Title::WATCHING,
|
||||||
Kitsu::PLAN_TO_WATCH => Title::PLAN_TO_WATCH,
|
Kitsu::PLAN_TO_WATCH => Title::PLAN_TO_WATCH,
|
||||||
Kitsu::ON_HOLD => Title::ON_HOLD,
|
Kitsu::ON_HOLD => Title::ON_HOLD,
|
||||||
Kitsu::DROPPED => Title::DROPPED,
|
Kitsu::DROPPED => Title::DROPPED,
|
||||||
Kitsu::COMPLETED => Title::COMPLETED
|
Kitsu::COMPLETED => Title::COMPLETED,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const ROUTE_TO_KITSU = [
|
public const ROUTE_TO_KITSU = [
|
||||||
Route::WATCHING => Kitsu::WATCHING,
|
Route::WATCHING => Kitsu::WATCHING,
|
||||||
Route::PLAN_TO_WATCH => Kitsu::PLAN_TO_WATCH,
|
Route::PLAN_TO_WATCH => Kitsu::PLAN_TO_WATCH,
|
||||||
Route::ON_HOLD => Kitsu::ON_HOLD,
|
Route::ON_HOLD => Kitsu::ON_HOLD,
|
||||||
Route::DROPPED => Kitsu::DROPPED,
|
Route::DROPPED => Kitsu::DROPPED,
|
||||||
Route::COMPLETED => Kitsu::COMPLETED
|
Route::COMPLETED => Kitsu::COMPLETED,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const ROUTE_TO_TITLE = [
|
public const ROUTE_TO_TITLE = [
|
||||||
Route::ALL => Title::ALL,
|
Route::ALL => Title::ALL,
|
||||||
Route::WATCHING => Title::WATCHING,
|
Route::WATCHING => Title::WATCHING,
|
||||||
Route::PLAN_TO_WATCH => Title::PLAN_TO_WATCH,
|
Route::PLAN_TO_WATCH => Title::PLAN_TO_WATCH,
|
||||||
Route::ON_HOLD => Title::ON_HOLD,
|
Route::ON_HOLD => Title::ON_HOLD,
|
||||||
Route::DROPPED => Title::DROPPED,
|
Route::DROPPED => Title::DROPPED,
|
||||||
Route::COMPLETED => Title::COMPLETED
|
Route::COMPLETED => Title::COMPLETED,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const TITLE_TO_ROUTE = [
|
public const TITLE_TO_ROUTE = [
|
||||||
Title::ALL => Route::ALL,
|
Title::ALL => Route::ALL,
|
||||||
Title::WATCHING => Route::WATCHING,
|
Title::WATCHING => Route::WATCHING,
|
||||||
Title::PLAN_TO_WATCH => Route::PLAN_TO_WATCH,
|
Title::PLAN_TO_WATCH => Route::PLAN_TO_WATCH,
|
||||||
Title::ON_HOLD => Route::ON_HOLD,
|
Title::ON_HOLD => Route::ON_HOLD,
|
||||||
Title::DROPPED => Route::DROPPED,
|
Title::DROPPED => Route::DROPPED,
|
||||||
Title::COMPLETED => Route::COMPLETED
|
Title::COMPLETED => Route::COMPLETED,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -6,40 +6,37 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Mapping;
|
namespace Aviat\AnimeClient\API\Mapping;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Enum\MangaReadingStatus\{Anilist, Kitsu, Title, Route};
|
use Aviat\AnimeClient\API\Enum\MangaReadingStatus\{Anilist, Kitsu, Route, Title};
|
||||||
use Aviat\Ion\Enum;
|
use Aviat\Ion\Enum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manga reading status mappings, among Kitsu, MAL, Page titles
|
* Manga reading status mappings, among Kitsu, MAL, Page titles
|
||||||
* and url route segments
|
* and url route segments
|
||||||
*/
|
*/
|
||||||
final class MangaReadingStatus extends Enum {
|
final class MangaReadingStatus extends Enum
|
||||||
|
{
|
||||||
public const ANILIST_TO_KITSU = [
|
public const ANILIST_TO_KITSU = [
|
||||||
Anilist::READING => Kitsu::READING,
|
Anilist::READING => Kitsu::READING,
|
||||||
Anilist::PLAN_TO_READ => Kitsu::PLAN_TO_READ,
|
Anilist::PLAN_TO_READ => Kitsu::PLAN_TO_READ,
|
||||||
Anilist::COMPLETED => Kitsu::COMPLETED,
|
Anilist::COMPLETED => Kitsu::COMPLETED,
|
||||||
Anilist::ON_HOLD => Kitsu::ON_HOLD,
|
Anilist::ON_HOLD => Kitsu::ON_HOLD,
|
||||||
Anilist::DROPPED => Kitsu::DROPPED
|
Anilist::DROPPED => Kitsu::DROPPED,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const KITSU_TO_ANILIST = [
|
public const KITSU_TO_ANILIST = [
|
||||||
Kitsu::READING => Anilist::READING,
|
Kitsu::READING => Anilist::READING,
|
||||||
Kitsu::PLAN_TO_READ => Anilist::PLAN_TO_READ,
|
Kitsu::PLAN_TO_READ => Anilist::PLAN_TO_READ,
|
||||||
Kitsu::COMPLETED => Anilist::COMPLETED,
|
Kitsu::COMPLETED => Anilist::COMPLETED,
|
||||||
Kitsu::ON_HOLD => Anilist::ON_HOLD,
|
Kitsu::ON_HOLD => Anilist::ON_HOLD,
|
||||||
Kitsu::DROPPED => Anilist::DROPPED
|
Kitsu::DROPPED => Anilist::DROPPED,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const KITSU_TO_TITLE = [
|
public const KITSU_TO_TITLE = [
|
||||||
Kitsu::READING => Title::READING,
|
Kitsu::READING => Title::READING,
|
||||||
Kitsu::PLAN_TO_READ => Title::PLAN_TO_READ,
|
Kitsu::PLAN_TO_READ => Title::PLAN_TO_READ,
|
||||||
@ -47,15 +44,13 @@ final class MangaReadingStatus extends Enum {
|
|||||||
Kitsu::ON_HOLD => Title::ON_HOLD,
|
Kitsu::ON_HOLD => Title::ON_HOLD,
|
||||||
Kitsu::DROPPED => Title::DROPPED,
|
Kitsu::DROPPED => Title::DROPPED,
|
||||||
];
|
];
|
||||||
|
public const ROUTE_TO_KITSU = [
|
||||||
public const ROUTE_TO_KITSU = [
|
|
||||||
Route::PLAN_TO_READ => Kitsu::PLAN_TO_READ,
|
Route::PLAN_TO_READ => Kitsu::PLAN_TO_READ,
|
||||||
Route::READING => Kitsu::READING,
|
Route::READING => Kitsu::READING,
|
||||||
Route::COMPLETED => Kitsu::COMPLETED,
|
Route::COMPLETED => Kitsu::COMPLETED,
|
||||||
Route::DROPPED => Kitsu::DROPPED,
|
Route::DROPPED => Kitsu::DROPPED,
|
||||||
Route::ON_HOLD => Kitsu::ON_HOLD,
|
Route::ON_HOLD => Kitsu::ON_HOLD,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const ROUTE_TO_TITLE = [
|
public const ROUTE_TO_TITLE = [
|
||||||
Route::ALL => Title::ALL,
|
Route::ALL => Title::ALL,
|
||||||
Route::PLAN_TO_READ => Title::PLAN_TO_READ,
|
Route::PLAN_TO_READ => Title::PLAN_TO_READ,
|
||||||
@ -64,7 +59,6 @@ final class MangaReadingStatus extends Enum {
|
|||||||
Route::DROPPED => Title::DROPPED,
|
Route::DROPPED => Title::DROPPED,
|
||||||
Route::ON_HOLD => Title::ON_HOLD,
|
Route::ON_HOLD => Title::ON_HOLD,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const TITLE_TO_KITSU = [
|
public const TITLE_TO_KITSU = [
|
||||||
Title::PLAN_TO_READ => Kitsu::PLAN_TO_READ,
|
Title::PLAN_TO_READ => Kitsu::PLAN_TO_READ,
|
||||||
Title::READING => Kitsu::READING,
|
Title::READING => Kitsu::READING,
|
||||||
@ -72,4 +66,4 @@ final class MangaReadingStatus extends Enum {
|
|||||||
Title::DROPPED => Kitsu::DROPPED,
|
Title::DROPPED => Kitsu::DROPPED,
|
||||||
Title::ON_HOLD => Kitsu::ON_HOLD,
|
Title::ON_HOLD => Kitsu::ON_HOLD,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -6,71 +6,66 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API;
|
namespace Aviat\AnimeClient\API;
|
||||||
|
|
||||||
use Amp\Http\Client\Request;
|
use Amp\Http\Client\Request;
|
||||||
|
use Generator;
|
||||||
|
use Throwable;
|
||||||
use function Amp\call;
|
use function Amp\call;
|
||||||
|
|
||||||
use function Amp\Promise\{all, wait};
|
use function Amp\Promise\{all, wait};
|
||||||
use function Aviat\AnimeClient\getApiClient;
|
use function Aviat\AnimeClient\getApiClient;
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to simplify making and validating simultaneous requests
|
* Class to simplify making and validating simultaneous requests
|
||||||
*/
|
*/
|
||||||
final class ParallelAPIRequest {
|
final class ParallelAPIRequest
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Set of requests to make in parallel
|
* Set of requests to make in parallel
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
*/
|
||||||
private array $requests = [];
|
private array $requests = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a request
|
* Add a request
|
||||||
*
|
|
||||||
* @param string|Request $request
|
|
||||||
* @param string|int|null $key
|
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function addRequest(string|Request $request, string|int|null $key = NULL): self
|
public function addRequest(string|Request $request, string|int|NULL $key = NULL): self
|
||||||
{
|
{
|
||||||
if ($key !== NULL)
|
if ($key !== NULL)
|
||||||
{
|
{
|
||||||
$this->requests[$key] = $request;
|
$this->requests[$key] = $request;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->requests[] = $request;
|
$this->requests[] = $request;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add multiple requests
|
* Add multiple requests
|
||||||
*
|
*
|
||||||
* @param string[]|Request[] $requests
|
* @param Request[]|string[] $requests
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function addRequests(array $requests): self
|
public function addRequests(array $requests): self
|
||||||
{
|
{
|
||||||
array_walk($requests, [$this, 'addRequest']);
|
array_walk($requests, [$this, 'addRequest']);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make the requests, and return the body for each
|
* Make the requests, and return the body for each
|
||||||
*
|
*
|
||||||
* @return array
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
public function makeRequests(): array
|
public function makeRequests(): array
|
||||||
{
|
{
|
||||||
@ -80,7 +75,7 @@ final class ParallelAPIRequest {
|
|||||||
|
|
||||||
foreach ($this->requests as $key => $url)
|
foreach ($this->requests as $key => $url)
|
||||||
{
|
{
|
||||||
$promises[$key] = call(static function () use ($client, $url) {
|
$promises[$key] = call(static function () use ($client, $url): Generator {
|
||||||
$response = yield $client->request($url);
|
$response = yield $client->request($url);
|
||||||
return yield $response->getBody()->buffer();
|
return yield $response->getBody()->buffer();
|
||||||
});
|
});
|
||||||
@ -92,8 +87,8 @@ final class ParallelAPIRequest {
|
|||||||
/**
|
/**
|
||||||
* Make the requests and return the response objects
|
* Make the requests and return the response objects
|
||||||
*
|
*
|
||||||
* @return array
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
public function getResponses(): array
|
public function getResponses(): array
|
||||||
{
|
{
|
||||||
@ -103,9 +98,9 @@ final class ParallelAPIRequest {
|
|||||||
|
|
||||||
foreach ($this->requests as $key => $url)
|
foreach ($this->requests as $key => $url)
|
||||||
{
|
{
|
||||||
$promises[$key] = call(fn () => yield $client->request($url));
|
$promises[$key] = call(static fn () => yield $client->request($url));
|
||||||
}
|
}
|
||||||
|
|
||||||
return wait(all($promises));
|
return wait(all($promises));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,33 +6,31 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient;
|
namespace Aviat\AnimeClient;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Enum\{
|
|
||||||
AnimeWatchingStatus\Kitsu as KAWS,
|
|
||||||
MangaReadingStatus\Kitsu as KMRS
|
|
||||||
};
|
|
||||||
use Aviat\AnimeClient\API\Enum\{
|
use Aviat\AnimeClient\API\Enum\{
|
||||||
AnimeWatchingStatus\Anilist as AnimeWatchingStatus,
|
AnimeWatchingStatus\Anilist as AnimeWatchingStatus,
|
||||||
MangaReadingStatus\Anilist as MangaReadingStatus
|
MangaReadingStatus\Anilist as MangaReadingStatus
|
||||||
};
|
};
|
||||||
|
use Aviat\AnimeClient\API\Enum\{
|
||||||
|
AnimeWatchingStatus\Kitsu as KAWS,
|
||||||
|
MangaReadingStatus\Kitsu as KMRS
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constants and mappings for the Anilist API
|
* Constants and mappings for the Anilist API
|
||||||
*/
|
*/
|
||||||
final class Anilist {
|
final class Anilist
|
||||||
|
{
|
||||||
public const AUTH_URL = 'https://anilist.co/api/v2/oauth/authorize';
|
public const AUTH_URL = 'https://anilist.co/api/v2/oauth/authorize';
|
||||||
public const TOKEN_URL = 'https://anilist.co/api/v2/oauth/token';
|
public const TOKEN_URL = 'https://anilist.co/api/v2/oauth/token';
|
||||||
public const BASE_URL = 'https://graphql.anilist.co';
|
public const BASE_URL = 'https://graphql.anilist.co';
|
||||||
|
|
||||||
public const KITSU_ANILIST_WATCHING_STATUS_MAP = [
|
public const KITSU_ANILIST_WATCHING_STATUS_MAP = [
|
||||||
KAWS::WATCHING => AnimeWatchingStatus::WATCHING,
|
KAWS::WATCHING => AnimeWatchingStatus::WATCHING,
|
||||||
KAWS::COMPLETED => AnimeWatchingStatus::COMPLETED,
|
KAWS::COMPLETED => AnimeWatchingStatus::COMPLETED,
|
||||||
@ -40,7 +38,6 @@ final class Anilist {
|
|||||||
KAWS::DROPPED => AnimeWatchingStatus::DROPPED,
|
KAWS::DROPPED => AnimeWatchingStatus::DROPPED,
|
||||||
KAWS::PLAN_TO_WATCH => AnimeWatchingStatus::PLAN_TO_WATCH,
|
KAWS::PLAN_TO_WATCH => AnimeWatchingStatus::PLAN_TO_WATCH,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const ANILIST_KITSU_WATCHING_STATUS_MAP = [
|
public const ANILIST_KITSU_WATCHING_STATUS_MAP = [
|
||||||
AnimeWatchingStatus::WATCHING => KAWS::WATCHING,
|
AnimeWatchingStatus::WATCHING => KAWS::WATCHING,
|
||||||
AnimeWatchingStatus::COMPLETED => KAWS::COMPLETED,
|
AnimeWatchingStatus::COMPLETED => KAWS::COMPLETED,
|
||||||
@ -48,7 +45,6 @@ final class Anilist {
|
|||||||
AnimeWatchingStatus::DROPPED => KAWS::DROPPED,
|
AnimeWatchingStatus::DROPPED => KAWS::DROPPED,
|
||||||
AnimeWatchingStatus::PLAN_TO_WATCH => KAWS::PLAN_TO_WATCH,
|
AnimeWatchingStatus::PLAN_TO_WATCH => KAWS::PLAN_TO_WATCH,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const KITSU_ANILIST_READING_STATUS_MAP = [
|
public const KITSU_ANILIST_READING_STATUS_MAP = [
|
||||||
KMRS::READING => MangaReadingStatus::READING,
|
KMRS::READING => MangaReadingStatus::READING,
|
||||||
KMRS::COMPLETED => MangaReadingStatus::COMPLETED,
|
KMRS::COMPLETED => MangaReadingStatus::COMPLETED,
|
||||||
@ -56,7 +52,6 @@ final class Anilist {
|
|||||||
KMRS::DROPPED => MangaReadingStatus::DROPPED,
|
KMRS::DROPPED => MangaReadingStatus::DROPPED,
|
||||||
KMRS::PLAN_TO_READ => MangaReadingStatus::PLAN_TO_READ,
|
KMRS::PLAN_TO_READ => MangaReadingStatus::PLAN_TO_READ,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const ANILIST_KITSU_READING_STATUS_MAP = [
|
public const ANILIST_KITSU_READING_STATUS_MAP = [
|
||||||
MangaReadingStatus::READING => KMRS::READING,
|
MangaReadingStatus::READING => KMRS::READING,
|
||||||
MangaReadingStatus::COMPLETED => KMRS::COMPLETED,
|
MangaReadingStatus::COMPLETED => KMRS::COMPLETED,
|
||||||
@ -64,4 +59,4 @@ final class Anilist {
|
|||||||
MangaReadingStatus::DROPPED => KMRS::DROPPED,
|
MangaReadingStatus::DROPPED => KMRS::DROPPED,
|
||||||
MangaReadingStatus::PLAN_TO_READ => KMRS::PLAN_TO_READ,
|
MangaReadingStatus::PLAN_TO_READ => KMRS::PLAN_TO_READ,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -6,41 +6,33 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient;
|
namespace Aviat\AnimeClient;
|
||||||
|
|
||||||
use Aviat\Ion\ImageBuilder;
|
use Amp\Http\Client\{HttpClient, HttpClientBuilder, Request, Response};
|
||||||
|
|
||||||
|
use Aviat\Ion\{ConfigInterface, ImageBuilder};
|
||||||
use Psr\SimpleCache\CacheInterface;
|
use Psr\SimpleCache\CacheInterface;
|
||||||
|
|
||||||
use Amp\Http\Client\Request;
|
|
||||||
use Amp\Http\Client\Response;
|
|
||||||
use Amp\Http\Client\HttpClient;
|
|
||||||
use Amp\Http\Client\HttpClientBuilder;
|
|
||||||
|
|
||||||
use Aviat\Ion\ConfigInterface;
|
|
||||||
use Yosymfony\Toml\{Toml, TomlBuilder};
|
|
||||||
|
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
|
use Yosymfony\Toml\{Toml, TomlBuilder};
|
||||||
|
|
||||||
use function Amp\Promise\wait;
|
use function Amp\Promise\wait;
|
||||||
use function Aviat\Ion\_dir;
|
use function Aviat\Ion\_dir;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
//! TOML Functions
|
//! TOML Functions
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load configuration options from .toml files
|
* Load configuration options from .toml files
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param string $path - Path to load config
|
* @param string $path - Path to load config
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
function loadConfig(string $path): array
|
function loadConfig(string $path): array
|
||||||
{
|
{
|
||||||
@ -64,7 +56,7 @@ function loadConfig(string $path): array
|
|||||||
|
|
||||||
if ($key === 'config')
|
if ($key === 'config')
|
||||||
{
|
{
|
||||||
foreach($config as $name => $value)
|
foreach ($config as $name => $value)
|
||||||
{
|
{
|
||||||
$output[$name] = $value;
|
$output[$name] = $value;
|
||||||
}
|
}
|
||||||
@ -82,8 +74,6 @@ function loadConfig(string $path): array
|
|||||||
* Load config from one specific TOML file
|
* Load config from one specific TOML file
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param string $filename
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
function loadTomlFile(string $filename): array
|
function loadTomlFile(string $filename): array
|
||||||
{
|
{
|
||||||
@ -100,10 +90,10 @@ function _iterateToml(TomlBuilder $builder, iterable $data, mixed $parentKey = N
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (is_scalar($value) || isSequentialArray($value))
|
if (is_scalar($value) || isSequentialArray($value))
|
||||||
{
|
{
|
||||||
$builder->addValue($key, $value);
|
$builder->addValue($key, $value);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,10 +101,7 @@ function _iterateToml(TomlBuilder $builder, iterable $data, mixed $parentKey = N
|
|||||||
? "{$parentKey}.{$key}"
|
? "{$parentKey}.{$key}"
|
||||||
: $key;
|
: $key;
|
||||||
|
|
||||||
if ( ! isSequentialArray($value))
|
$builder->addTable($newKey);
|
||||||
{
|
|
||||||
$builder->addTable($newKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
_iterateToml($builder, $value, $newKey);
|
_iterateToml($builder, $value, $newKey);
|
||||||
}
|
}
|
||||||
@ -122,9 +109,6 @@ function _iterateToml(TomlBuilder $builder, iterable $data, mixed $parentKey = N
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize config data into a Toml file
|
* Serialize config data into a Toml file
|
||||||
*
|
|
||||||
* @param iterable $data
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
function arrayToToml(iterable $data): string
|
function arrayToToml(iterable $data): string
|
||||||
{
|
{
|
||||||
@ -137,9 +121,6 @@ function arrayToToml(iterable $data): string
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize toml back to an array
|
* Serialize toml back to an array
|
||||||
*
|
|
||||||
* @param string $toml
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
function tomlToArray(string $toml): array
|
function tomlToArray(string $toml): array
|
||||||
{
|
{
|
||||||
@ -156,8 +137,6 @@ if ( ! function_exists('array_is_list'))
|
|||||||
* Polyfill for PHP 8
|
* Polyfill for PHP 8
|
||||||
*
|
*
|
||||||
* @see https://www.php.net/manual/en/function.array-is-list
|
* @see https://www.php.net/manual/en/function.array-is-list
|
||||||
* @param array $a
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
function array_is_list(array $a): bool
|
function array_is_list(array $a): bool
|
||||||
{
|
{
|
||||||
@ -167,25 +146,14 @@ if ( ! function_exists('array_is_list'))
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the array sequential, not associative?
|
* Is the array sequential, not associative?
|
||||||
*
|
|
||||||
* @param mixed $array
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
function isSequentialArray(mixed $array): bool
|
function isSequentialArray(mixed $array): bool
|
||||||
{
|
{
|
||||||
if ( ! is_array($array))
|
return is_array($array) && array_is_list($array);
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_is_list($array);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check that folder permissions are correct for proper operation
|
* Check that folder permissions are correct for proper operation
|
||||||
*
|
|
||||||
* @param ConfigInterface $config
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
function checkFolderPermissions(ConfigInterface $config): array
|
function checkFolderPermissions(ConfigInterface $config): array
|
||||||
{
|
{
|
||||||
@ -206,6 +174,7 @@ function checkFolderPermissions(ConfigInterface $config): array
|
|||||||
if ( ! is_dir($actual))
|
if ( ! is_dir($actual))
|
||||||
{
|
{
|
||||||
$errors['missing'][] = $pretty;
|
$errors['missing'][] = $pretty;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,10 +193,8 @@ function checkFolderPermissions(ConfigInterface $config): array
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an API Client, with better defaults
|
* Get an API Client, with better defaults
|
||||||
*
|
|
||||||
* @return HttpClient
|
|
||||||
*/
|
*/
|
||||||
function getApiClient (): HttpClient
|
function getApiClient(): HttpClient
|
||||||
{
|
{
|
||||||
static $client;
|
static $client;
|
||||||
|
|
||||||
@ -242,11 +209,9 @@ function getApiClient (): HttpClient
|
|||||||
/**
|
/**
|
||||||
* Simplify making a request with Http\Client
|
* Simplify making a request with Http\Client
|
||||||
*
|
*
|
||||||
* @param string|Request $request
|
|
||||||
* @return Response
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
function getResponse (Request|string $request): Response
|
function getResponse(Request|string $request): Response
|
||||||
{
|
{
|
||||||
$client = getApiClient();
|
$client = getApiClient();
|
||||||
|
|
||||||
@ -260,12 +225,8 @@ function getResponse (Request|string $request): Response
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the path for the cached image from the original image
|
* Generate the path for the cached image from the original image
|
||||||
*
|
|
||||||
* @param string $kitsuUrl
|
|
||||||
* @param bool $webp
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
function getLocalImg (string $kitsuUrl, bool $webp = TRUE): string
|
function getLocalImg(string $kitsuUrl, bool $webp = TRUE): string
|
||||||
{
|
{
|
||||||
if (empty($kitsuUrl) || ( ! is_string($kitsuUrl)))
|
if (empty($kitsuUrl) || ( ! is_string($kitsuUrl)))
|
||||||
{
|
{
|
||||||
@ -297,13 +258,8 @@ function getLocalImg (string $kitsuUrl, bool $webp = TRUE): string
|
|||||||
* Create a transparent placeholder image
|
* Create a transparent placeholder image
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param string $path
|
|
||||||
* @param int $width
|
|
||||||
* @param int $height
|
|
||||||
* @param string $text
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
function createPlaceholderImage (string $path, int $width = 200, int $height = 200, string $text = 'Image Unavailable'): bool
|
function createPlaceholderImage(string $path, int $width = 200, int $height = 200, string $text = 'Image Unavailable'): bool
|
||||||
{
|
{
|
||||||
$img = ImageBuilder::new($width, $height)
|
$img = ImageBuilder::new($width, $height)
|
||||||
->enableAlphaBlending(TRUE)
|
->enableAlphaBlending(TRUE)
|
||||||
@ -322,22 +278,16 @@ function createPlaceholderImage (string $path, int $width = 200, int $height = 2
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check that there is a value for at least one item in a collection with the specified key
|
* Check that there is a value for at least one item in a collection with the specified key
|
||||||
*
|
|
||||||
* @param array $search
|
|
||||||
* @param string $key
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
function colNotEmpty(array $search, string $key): bool
|
function colNotEmpty(array $search, string $key): bool
|
||||||
{
|
{
|
||||||
$items = array_filter(array_column($search, $key), static fn ($x) => ( ! empty($x)));
|
$items = array_filter(array_column($search, $key), static fn ($x) => ( ! empty($x)));
|
||||||
return count($items) > 0;
|
|
||||||
|
return $items !== [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the cache, but save user auth data
|
* Clear the cache, but save user auth data
|
||||||
*
|
|
||||||
* @param CacheInterface $cache
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
function clearCache(CacheInterface $cache): bool
|
function clearCache(CacheInterface $cache): bool
|
||||||
{
|
{
|
||||||
@ -349,10 +299,11 @@ function clearCache(CacheInterface $cache): bool
|
|||||||
Kitsu::AUTH_TOKEN_REFRESH_CACHE_KEY,
|
Kitsu::AUTH_TOKEN_REFRESH_CACHE_KEY,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$userData = array_filter((array)$userData, static fn ($value) => $value !== NULL);
|
$userData = array_filter((array) $userData, static fn ($value) => $value !== NULL);
|
||||||
|
|
||||||
$cleared = $cache->clear();
|
$cleared = $cache->clear();
|
||||||
|
|
||||||
$saved = ( ! empty($userData)) ? $cache->setMultiple($userData) : TRUE;
|
$saved = (empty($userData)) ? TRUE : $cache->setMultiple($userData);
|
||||||
|
|
||||||
return $cleared && $saved;
|
return $cleared && $saved;
|
||||||
}
|
}
|
||||||
@ -361,9 +312,6 @@ function clearCache(CacheInterface $cache): bool
|
|||||||
* Render a PHP code template as a string
|
* Render a PHP code template as a string
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param string $path
|
|
||||||
* @param array $data
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
function renderTemplate(string $path, array $data): string
|
function renderTemplate(string $path, array $data): string
|
||||||
{
|
{
|
||||||
@ -371,5 +319,6 @@ function renderTemplate(string $path, array $data): string
|
|||||||
extract($data, EXTR_OVERWRITE);
|
extract($data, EXTR_OVERWRITE);
|
||||||
include $path;
|
include $path;
|
||||||
$rawOutput = ob_get_clean();
|
$rawOutput = ob_get_clean();
|
||||||
|
|
||||||
return (is_string($rawOutput)) ? $rawOutput : '';
|
return (is_string($rawOutput)) ? $rawOutput : '';
|
||||||
}
|
}
|
||||||
|
@ -6,53 +6,45 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Command;
|
namespace Aviat\AnimeClient\Command;
|
||||||
|
|
||||||
use Monolog\Formatter\JsonFormatter;
|
|
||||||
|
|
||||||
use function Aviat\Ion\_dir;
|
|
||||||
use const Aviat\AnimeClient\SRC_DIR;
|
|
||||||
|
|
||||||
use function Aviat\AnimeClient\loadConfig;
|
|
||||||
use function Aviat\AnimeClient\loadTomlFile;
|
|
||||||
|
|
||||||
use Aura\Router\RouterContainer;
|
use Aura\Router\RouterContainer;
|
||||||
|
|
||||||
use Aura\Session\SessionFactory;
|
use Aura\Session\SessionFactory;
|
||||||
use Aviat\AnimeClient\{Model, UrlGenerator, Util};
|
|
||||||
use Aviat\AnimeClient\API\{Anilist, CacheTrait, Kitsu};
|
use Aviat\AnimeClient\API\{Anilist, CacheTrait, Kitsu};
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\{Model, UrlGenerator, Util};
|
||||||
use Aviat\Banker\Teller;
|
use Aviat\Banker\Teller;
|
||||||
use Aviat\Ion\Config;
|
use Aviat\Ion\Config;
|
||||||
use Aviat\Ion\Di\{Container, ContainerInterface, ContainerAware};
|
use Aviat\Ion\Di\{Container, ContainerAware, ContainerInterface};
|
||||||
use ConsoleKit\{Colors, Command, ConsoleException};
|
|
||||||
use ConsoleKit\Widgets\Box;
|
use ConsoleKit\Widgets\Box;
|
||||||
|
use ConsoleKit\{Colors, Command, ConsoleException};
|
||||||
use Laminas\Diactoros\{Response, ServerRequestFactory};
|
use Laminas\Diactoros\{Response, ServerRequestFactory};
|
||||||
|
use Monolog\Formatter\JsonFormatter;
|
||||||
use Monolog\Handler\RotatingFileHandler;
|
use Monolog\Handler\RotatingFileHandler;
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
|
use function Aviat\AnimeClient\{loadConfig, loadTomlFile};
|
||||||
|
use function Aviat\Ion\_dir;
|
||||||
|
use const Aviat\AnimeClient\SRC_DIR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for console command setup
|
* Base class for console command setup
|
||||||
*/
|
*/
|
||||||
abstract class BaseCommand extends Command {
|
abstract class BaseCommand extends Command
|
||||||
|
{
|
||||||
use CacheTrait;
|
use CacheTrait;
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Echo text in a box
|
* Echo text in a box
|
||||||
*
|
|
||||||
* @param string|array $message
|
|
||||||
* @param string|int|null $fgColor
|
|
||||||
* @param string|int|null $bgColor
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
public function echoBox(string|array $message, string|int|null $fgColor = NULL, string|int|null $bgColor = NULL): void
|
public function echoBox(string|array $message, string|int|NULL $fgColor = NULL, string|int|NULL $bgColor = NULL): void
|
||||||
{
|
{
|
||||||
if (is_array($message))
|
if (is_array($message))
|
||||||
{
|
{
|
||||||
@ -61,11 +53,12 @@ abstract class BaseCommand extends Command {
|
|||||||
|
|
||||||
if ($fgColor !== NULL)
|
if ($fgColor !== NULL)
|
||||||
{
|
{
|
||||||
$fgColor = (int)$fgColor;
|
$fgColor = (int) $fgColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($bgColor !== NULL)
|
if ($bgColor !== NULL)
|
||||||
{
|
{
|
||||||
$bgColor = (int)$bgColor;
|
$bgColor = (int) $bgColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Colorize the CLI output
|
// Colorize the CLI output
|
||||||
@ -118,15 +111,13 @@ abstract class BaseCommand extends Command {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup the Di container
|
* Setup the Di container
|
||||||
*
|
|
||||||
* @return Containerinterface
|
|
||||||
*/
|
*/
|
||||||
public function setupContainer(): ContainerInterface
|
public function setupContainer(): ContainerInterface
|
||||||
{
|
{
|
||||||
$APP_DIR = _dir(dirname(dirname(SRC_DIR)), 'app');
|
$APP_DIR = _dir(dirname(SRC_DIR, 2), 'app');
|
||||||
$APPCONF_DIR = _dir($APP_DIR, 'appConf');
|
$APPCONF_DIR = _dir($APP_DIR, 'appConf');
|
||||||
$CONF_DIR = _dir($APP_DIR, 'config');
|
$CONF_DIR = _dir($APP_DIR, 'config');
|
||||||
$baseConfig = require _dir($APPCONF_DIR, 'base_config.php');
|
$baseConfig = require _dir($APPCONF_DIR, 'base_config.php');
|
||||||
|
|
||||||
$config = loadConfig($CONF_DIR);
|
$config = loadConfig($CONF_DIR);
|
||||||
|
|
||||||
@ -140,15 +131,16 @@ abstract class BaseCommand extends Command {
|
|||||||
return $this->_di($configArray, $APP_DIR);
|
return $this->_di($configArray, $APP_DIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function _line(string $message, int|string|null $fgColor = NULL, int|string|null $bgColor = NULL): void
|
private function _line(string $message, int|string|NULL $fgColor = NULL, int|string|NULL $bgColor = NULL): void
|
||||||
{
|
{
|
||||||
if ($fgColor !== NULL)
|
if ($fgColor !== NULL)
|
||||||
{
|
{
|
||||||
$fgColor = (int)$fgColor;
|
$fgColor = (int) $fgColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($bgColor !== NULL)
|
if ($bgColor !== NULL)
|
||||||
{
|
{
|
||||||
$bgColor = (int)$bgColor;
|
$bgColor = (int) $bgColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Colorize the CLI output
|
// Colorize the CLI output
|
||||||
@ -168,12 +160,13 @@ abstract class BaseCommand extends Command {
|
|||||||
|
|
||||||
$appLogger = new Logger('animeclient');
|
$appLogger = new Logger('animeclient');
|
||||||
$appLogger->pushHandler(new RotatingFileHandler($APP_DIR . '/logs/app-cli.log', 2, Logger::WARNING));
|
$appLogger->pushHandler(new RotatingFileHandler($APP_DIR . '/logs/app-cli.log', 2, Logger::WARNING));
|
||||||
|
|
||||||
$container->setLogger($appLogger);
|
$container->setLogger($appLogger);
|
||||||
|
|
||||||
foreach (['kitsu-request', 'anilist-request', 'anilist-request-cli', 'kitsu-request-cli'] as $channel)
|
foreach (['kitsu-request', 'anilist-request', 'anilist-request-cli', 'kitsu-request-cli'] as $channel)
|
||||||
{
|
{
|
||||||
$logger = new Logger($channel);
|
$logger = new Logger($channel);
|
||||||
$handler = new RotatingFileHandler( "{$APP_DIR}/logs/{$channel}.log", 2, Logger::WARNING);
|
$handler = new RotatingFileHandler("{$APP_DIR}/logs/{$channel}.log", 2, Logger::WARNING);
|
||||||
$handler->setFormatter(new JsonFormatter());
|
$handler->setFormatter(new JsonFormatter());
|
||||||
$logger->pushHandler($handler);
|
$logger->pushHandler($handler);
|
||||||
|
|
||||||
@ -181,33 +174,34 @@ abstract class BaseCommand extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create Config Object
|
// Create Config Object
|
||||||
$container->set('config', fn () => new Config($configArray));
|
$container->set('config', static fn () => new Config($configArray));
|
||||||
|
|
||||||
// Create Cache Object
|
// Create Cache Object
|
||||||
$container->set('cache', static function($container) {
|
$container->set('cache', static function ($container): Teller {
|
||||||
$logger = $container->getLogger();
|
$logger = $container->getLogger();
|
||||||
$config = $container->get('config')->get('cache');
|
$config = $container->get('config')->get('cache');
|
||||||
|
|
||||||
return new Teller($config, $logger);
|
return new Teller($config, $logger);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create Aura Router Object
|
// Create Aura Router Object
|
||||||
$container->set('aura-router', fn () => new RouterContainer);
|
$container->set('aura-router', static fn () => new RouterContainer());
|
||||||
|
|
||||||
// Create Request/Response Objects
|
// Create Request/Response Objects
|
||||||
$container->set('request', fn () => ServerRequestFactory::fromGlobals(
|
$container->set('request', static fn () => ServerRequestFactory::fromGlobals(
|
||||||
$GLOBALS['_SERVER'],
|
$GLOBALS['_SERVER'],
|
||||||
$_GET,
|
$_GET,
|
||||||
$_POST,
|
$_POST,
|
||||||
$_COOKIE,
|
$_COOKIE,
|
||||||
$_FILES
|
$_FILES
|
||||||
));
|
));
|
||||||
$container->set('response', fn () => new Response);
|
$container->set('response', static fn () => new Response());
|
||||||
|
|
||||||
// Create session Object
|
// Create session Object
|
||||||
$container->set('session', fn () => (new SessionFactory())->newInstance($_COOKIE));
|
$container->set('session', static fn () => (new SessionFactory())->newInstance($_COOKIE));
|
||||||
|
|
||||||
// Models
|
// Models
|
||||||
$container->set('kitsu-model', static function($container): Kitsu\Model {
|
$container->set('kitsu-model', static function ($container): Kitsu\Model {
|
||||||
$requestBuilder = new Kitsu\RequestBuilder($container);
|
$requestBuilder = new Kitsu\RequestBuilder($container);
|
||||||
$requestBuilder->setLogger($container->getLogger('kitsu-request'));
|
$requestBuilder->setLogger($container->getLogger('kitsu-request'));
|
||||||
|
|
||||||
@ -221,6 +215,7 @@ abstract class BaseCommand extends Command {
|
|||||||
|
|
||||||
$cache = $container->get('cache');
|
$cache = $container->get('cache');
|
||||||
$model->setCache($cache);
|
$model->setCache($cache);
|
||||||
|
|
||||||
return $model;
|
return $model;
|
||||||
});
|
});
|
||||||
$container->set('anilist-model', static function ($container): Anilist\Model {
|
$container->set('anilist-model', static function ($container): Anilist\Model {
|
||||||
@ -237,18 +232,19 @@ abstract class BaseCommand extends Command {
|
|||||||
|
|
||||||
return $model;
|
return $model;
|
||||||
});
|
});
|
||||||
$container->set('settings-model', static function($container): Model\Settings {
|
$container->set('settings-model', static function ($container): Model\Settings {
|
||||||
$model = new Model\Settings($container->get('config'));
|
$model = new Model\Settings($container->get('config'));
|
||||||
$model->setContainer($container);
|
$model->setContainer($container);
|
||||||
|
|
||||||
return $model;
|
return $model;
|
||||||
});
|
});
|
||||||
|
|
||||||
$container->set('auth', fn ($container) => new Kitsu\Auth($container));
|
$container->set('auth', static fn ($container) => new Kitsu\Auth($container));
|
||||||
|
|
||||||
$container->set('url-generator', fn ($container) => new UrlGenerator($container));
|
$container->set('url-generator', static fn ($container) => new UrlGenerator($container));
|
||||||
|
|
||||||
$container->set('util', fn ($container) => new Util($container));
|
$container->set('util', static fn ($container) => new Util($container));
|
||||||
|
|
||||||
return $container;
|
return $container;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,32 +6,27 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Command;
|
namespace Aviat\AnimeClient\Command;
|
||||||
|
|
||||||
use Aviat\Ion\Di\Exception\ContainerException;
|
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
||||||
use Aviat\Ion\Di\Exception\NotFoundException;
|
|
||||||
use function Aviat\AnimeClient\clearCache;
|
use function Aviat\AnimeClient\clearCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the API Cache
|
* Clears the API Cache
|
||||||
*/
|
*/
|
||||||
final class CacheClear extends BaseCommand {
|
final class CacheClear extends BaseCommand
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Clear the API cache
|
* Clear the API cache
|
||||||
*
|
*
|
||||||
* @param array $args
|
|
||||||
* @param array $options
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
public function execute(array $args, array $options = []): void
|
public function execute(array $args, array $options = []): void
|
||||||
{
|
{
|
||||||
|
@ -6,32 +6,27 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Command;
|
namespace Aviat\AnimeClient\Command;
|
||||||
|
|
||||||
use Aviat\Ion\Di\Exception\ContainerException;
|
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
||||||
use Aviat\Ion\Di\Exception\NotFoundException;
|
|
||||||
use function Aviat\AnimeClient\clearCache;
|
use function Aviat\AnimeClient\clearCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the API Cache
|
* Clears the API Cache
|
||||||
*/
|
*/
|
||||||
final class CachePrime extends BaseCommand {
|
final class CachePrime extends BaseCommand
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Clear, then prime the API cache
|
* Clear, then prime the API cache
|
||||||
*
|
*
|
||||||
* @param array $args
|
|
||||||
* @param array $options
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
public function execute(array $args, array $options = []): void
|
public function execute(array $args, array $options = []): void
|
||||||
{
|
{
|
||||||
@ -42,6 +37,7 @@ final class CachePrime extends BaseCommand {
|
|||||||
if ( ! $cleared)
|
if ( ! $cleared)
|
||||||
{
|
{
|
||||||
$this->echoErrorBox('Failed to clear cache.');
|
$this->echoErrorBox('Failed to clear cache.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Command;
|
namespace Aviat\AnimeClient\Command;
|
||||||
@ -19,8 +17,8 @@ namespace Aviat\AnimeClient\Command;
|
|||||||
/**
|
/**
|
||||||
* Clears out image cache directories
|
* Clears out image cache directories
|
||||||
*/
|
*/
|
||||||
class ClearThumbnails extends BaseCommand {
|
class ClearThumbnails extends BaseCommand
|
||||||
|
{
|
||||||
public function execute(array $args, array $options = []): void
|
public function execute(array $args, array $options = []): void
|
||||||
{
|
{
|
||||||
$this->clearThumbs();
|
$this->clearThumbs();
|
||||||
@ -50,10 +48,10 @@ class ClearThumbnails extends BaseCommand {
|
|||||||
'people/*.webp',
|
'people/*.webp',
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach($paths as $path)
|
foreach ($paths as $path)
|
||||||
{
|
{
|
||||||
$cmd = "find {$imgDir} -path \"*/{$path}\" | xargs rm -f";
|
$cmd = "find {$imgDir} -path \"*/{$path}\" | xargs rm -f";
|
||||||
exec($cmd);
|
exec($cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,74 +6,64 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Command;
|
namespace Aviat\AnimeClient\Command;
|
||||||
|
|
||||||
use Aviat\Ion\JsonException;
|
use Aviat\AnimeClient\API\Anilist;
|
||||||
use ConsoleKit\Widgets;
|
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
|
||||||
use Aviat\AnimeClient\API\{
|
use Aviat\AnimeClient\API\{
|
||||||
Anilist\MissingIdException,
|
Anilist\MissingIdException,
|
||||||
ParallelAPIRequest
|
ParallelAPIRequest
|
||||||
};
|
};
|
||||||
use Aviat\AnimeClient\API;
|
|
||||||
use Aviat\AnimeClient\API\Anilist;
|
|
||||||
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
|
|
||||||
use Aviat\AnimeClient\Enum;
|
|
||||||
use Aviat\AnimeClient\Enum\{MediaType, SyncAction};
|
use Aviat\AnimeClient\Enum\{MediaType, SyncAction};
|
||||||
use Aviat\AnimeClient\Types\FormItem;
|
use Aviat\AnimeClient\Types\FormItem;
|
||||||
use Aviat\Ion\Di\Exception\ContainerException;
|
use Aviat\AnimeClient\{API, Enum};
|
||||||
use Aviat\Ion\Di\Exception\NotFoundException;
|
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
||||||
use Aviat\Ion\Json;
|
use Aviat\Ion\{Json, JsonException};
|
||||||
|
use ConsoleKit\Widgets;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use function in_array;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Syncs list data between Anilist and Kitsu
|
* Syncs list data between Anilist and Kitsu
|
||||||
*/
|
*/
|
||||||
final class SyncLists extends BaseCommand {
|
final class SyncLists extends BaseCommand
|
||||||
|
{
|
||||||
protected const KITSU_GREATER = 1;
|
protected const KITSU_GREATER = 1;
|
||||||
protected const ANILIST_GREATER = -1;
|
protected const ANILIST_GREATER = -1;
|
||||||
protected const SAME = 0;
|
protected const SAME = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for making requests to Anilist API
|
* Model for making requests to Anilist API
|
||||||
* @var Anilist\Model
|
|
||||||
*/
|
*/
|
||||||
private Anilist\Model $anilistModel;
|
private Anilist\Model $anilistModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for making requests to Kitsu API
|
* Model for making requests to Kitsu API
|
||||||
* @var API\Kitsu\Model
|
|
||||||
*/
|
*/
|
||||||
private API\Kitsu\Model $kitsuModel;
|
private API\Kitsu\Model $kitsuModel;
|
||||||
|
|
||||||
/**
|
|
||||||
* Does the Kitsu API have valid authentication?
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private bool $isKitsuAuthenticated = FALSE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sync Kitsu <=> Anilist
|
* Sync Kitsu <=> Anilist
|
||||||
*
|
*
|
||||||
* @param array $args
|
|
||||||
* @param array $options
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function execute(array $args, array $options = []): void
|
public function execute(array $args, array $options = []): void
|
||||||
{
|
{
|
||||||
$this->init();
|
$canRun = $this->init();
|
||||||
|
|
||||||
|
if ( ! $canRun)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ([MediaType::MANGA, MediaType::ANIME] as $type)
|
foreach ([MediaType::MANGA, MediaType::ANIME] as $type)
|
||||||
{
|
{
|
||||||
@ -96,7 +86,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
protected function init(): void
|
protected function init(): bool
|
||||||
{
|
{
|
||||||
$this->setContainer($this->setupContainer());
|
$this->setContainer($this->setupContainer());
|
||||||
$this->setCache($this->container->get('cache'));
|
$this->setCache($this->container->get('cache'));
|
||||||
@ -108,28 +98,32 @@ final class SyncLists extends BaseCommand {
|
|||||||
if ( ! $anilistEnabled)
|
if ( ! $anilistEnabled)
|
||||||
{
|
{
|
||||||
$this->echoErrorBox('Anlist API is not enabled. Can not sync.');
|
$this->echoErrorBox('Anlist API is not enabled. Can not sync.');
|
||||||
exit();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authentication is required to update Kitsu
|
// Authentication is required to update Kitsu
|
||||||
$this->isKitsuAuthenticated = $this->container->get('auth')->isAuthenticated();
|
$isKitsuAuthenticated = $this->container->get('auth')->isAuthenticated();
|
||||||
if ( ! $this->isKitsuAuthenticated)
|
if ( !$isKitsuAuthenticated)
|
||||||
{
|
{
|
||||||
$this->echoWarningBox('Kitsu is not authenticated. Kitsu list can not be updated.');
|
$this->echoErrorBox('Kitsu is not authenticated. Kitsu list can not be updated.');
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->anilistModel = $this->container->get('anilist-model');
|
$this->anilistModel = $this->container->get('anilist-model');
|
||||||
$this->kitsuModel = $this->container->get('kitsu-model');
|
$this->kitsuModel = $this->container->get('kitsu-model');
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get and display the count of items for each API
|
* Get and display the count of items for each API
|
||||||
*
|
|
||||||
* @param string $type
|
|
||||||
*/
|
*/
|
||||||
protected function fetchCount(string $type): void
|
protected function fetchCount(string $type): void
|
||||||
{
|
{
|
||||||
$this->echo('Fetching List Counts');
|
// This pulls too much data from Anilist, so skipping this step should result
|
||||||
|
// in fewer instances of API throttling
|
||||||
|
|
||||||
|
/* $this->echo('Fetching List Counts');
|
||||||
$progress = new Widgets\ProgressBar($this->getConsole(), 2, 50, FALSE);
|
$progress = new Widgets\ProgressBar($this->getConsole(), 2, 50, FALSE);
|
||||||
|
|
||||||
$displayLines = [];
|
$displayLines = [];
|
||||||
@ -144,18 +138,17 @@ final class SyncLists extends BaseCommand {
|
|||||||
|
|
||||||
$this->clearLine();
|
$this->clearLine();
|
||||||
|
|
||||||
$this->echoBox($displayLines);
|
$this->echoBox($displayLines); */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list data
|
* Get the list data
|
||||||
*
|
*
|
||||||
* @param string $type
|
* @return array<string, mixed[]>
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
protected function fetch(string $type): array
|
protected function fetch(string $type): array
|
||||||
{
|
{
|
||||||
$this->echo('Fetching List Data');
|
$this->echo("Fetching $type List Data");
|
||||||
$progress = new Widgets\ProgressBar($this->getConsole(), 2, 50, FALSE);
|
$progress = new Widgets\ProgressBar($this->getConsole(), 2, 50, FALSE);
|
||||||
|
|
||||||
$anilist = $this->fetchAnilist($type);
|
$anilist = $this->fetchAnilist($type);
|
||||||
@ -175,9 +168,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
/**
|
/**
|
||||||
* Normalize the list data for comparison
|
* Normalize the list data for comparison
|
||||||
*
|
*
|
||||||
* @param string $type
|
* @return array<string, mixed[]>
|
||||||
* @param array $data
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
protected function transform(string $type, array $data): array
|
protected function transform(string $type, array $data): array
|
||||||
{
|
{
|
||||||
@ -201,9 +192,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
/**
|
/**
|
||||||
* Compare the lists data
|
* Compare the lists data
|
||||||
*
|
*
|
||||||
* @param string $type
|
* @return array<string, mixed[]>
|
||||||
* @param array $data
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
protected function compare(string $type, array $data): array
|
protected function compare(string $type, array $data): array
|
||||||
{
|
{
|
||||||
@ -215,45 +204,36 @@ final class SyncLists extends BaseCommand {
|
|||||||
/**
|
/**
|
||||||
* Updated outdated list items
|
* Updated outdated list items
|
||||||
*
|
*
|
||||||
* @param string $type
|
|
||||||
* @param array $data
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
protected function update(string $type, array $data): void
|
protected function update(string $type, array $data): void
|
||||||
{
|
{
|
||||||
if ( ! empty($data['addToAnilist']))
|
if ( ! empty($data['addToAnilist']))
|
||||||
{
|
{
|
||||||
$count = count($data['addToAnilist']);
|
$count = is_countable($data['addToAnilist']) ? count($data['addToAnilist']) : 0;
|
||||||
$this->echoBox("Adding {$count} missing {$type} list items to Anilist");
|
$this->echoBox("Adding {$count} missing {$type} list items to Anilist");
|
||||||
$this->updateAnilistListItems($data['addToAnilist'], SyncAction::CREATE, $type);
|
$this->updateAnilistListItems($data['addToAnilist'], SyncAction::CREATE, $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! empty($data['updateAnilist']))
|
if ( ! empty($data['updateAnilist']))
|
||||||
{
|
{
|
||||||
$count = count($data['updateAnilist']);
|
$count = is_countable($data['updateAnilist']) ? count($data['updateAnilist']) : 0;
|
||||||
$this->echoBox("Updating {$count} outdated Anilist {$type} list items");
|
$this->echoBox("Updating {$count} outdated Anilist {$type} list items");
|
||||||
$this->updateAnilistListItems($data['updateAnilist'], SyncAction::UPDATE, $type);
|
$this->updateAnilistListItems($data['updateAnilist'], SyncAction::UPDATE, $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isKitsuAuthenticated)
|
if ( ! empty($data['addToKitsu']))
|
||||||
{
|
{
|
||||||
if ( ! empty($data['addToKitsu']))
|
$count = is_countable($data['addToKitsu']) ? count($data['addToKitsu']) : 0;
|
||||||
{
|
$this->echoBox("Adding {$count} missing {$type} list items to Kitsu");
|
||||||
$count = count($data['addToKitsu']);
|
$this->updateKitsuListItems($data['addToKitsu'], SyncAction::CREATE, $type);
|
||||||
$this->echoBox("Adding {$count} missing {$type} list items to Kitsu");
|
|
||||||
$this->updateKitsuListItems($data['addToKitsu'], SyncAction::CREATE, $type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! empty($data['updateKitsu']))
|
|
||||||
{
|
|
||||||
$count = count($data['updateKitsu']);
|
|
||||||
$this->echoBox("Updating {$count} outdated Kitsu {$type} list items");
|
|
||||||
$this->updateKitsuListItems($data['updateKitsu'], SyncAction::UPDATE, $type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if ( ! empty($data['updateKitsu']))
|
||||||
{
|
{
|
||||||
$this->echoErrorBox('Kitsu is not authenticated, so lists can not be updated');
|
$count = is_countable($data['updateKitsu']) ? count($data['updateKitsu']) : 0;
|
||||||
|
$this->echoBox("Updating {$count} outdated Kitsu {$type} list items");
|
||||||
|
$this->updateKitsuListItems($data['updateKitsu'], SyncAction::UPDATE, $type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,12 +253,15 @@ final class SyncLists extends BaseCommand {
|
|||||||
|
|
||||||
foreach ($list['data']['MediaListCollection']['lists'] as $subList)
|
foreach ($list['data']['MediaListCollection']['lists'] as $subList)
|
||||||
{
|
{
|
||||||
$count += array_reduce($subList, fn ($carry, $item) => $carry + count(array_values($item)), 0);
|
$count += array_reduce($subList, static fn ($carry, $item) => $carry + count(array_values($item)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $count;
|
return $count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
private function fetchAnilist(string $type): array
|
private function fetchAnilist(string $type): array
|
||||||
{
|
{
|
||||||
static $list = [
|
static $list = [
|
||||||
@ -296,7 +279,8 @@ final class SyncLists extends BaseCommand {
|
|||||||
catch (JsonException)
|
catch (JsonException)
|
||||||
{
|
{
|
||||||
$this->echoErrorBox('Anlist API exception. Can not sync.');
|
$this->echoErrorBox('Anlist API exception. Can not sync.');
|
||||||
die();
|
|
||||||
|
exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,6 +294,9 @@ final class SyncLists extends BaseCommand {
|
|||||||
return $this->kitsuModel->{"get{$uType}ListCount"}() ?? 0;
|
return $this->kitsuModel->{"get{$uType}ListCount"}() ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
private function fetchKitsu(string $type): array
|
private function fetchKitsu(string $type): array
|
||||||
{
|
{
|
||||||
return $this->kitsuModel->getSyncList($type);
|
return $this->kitsuModel->getSyncList($type);
|
||||||
@ -318,7 +305,9 @@ final class SyncLists extends BaseCommand {
|
|||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Transform Helpers
|
// Transform Helpers
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
private function transformKitsu(string $type, array $data): array
|
private function transformKitsu(string $type, array $data): array
|
||||||
{
|
{
|
||||||
if (empty($data))
|
if (empty($data))
|
||||||
@ -328,13 +317,14 @@ final class SyncLists extends BaseCommand {
|
|||||||
|
|
||||||
$output = [];
|
$output = [];
|
||||||
|
|
||||||
foreach($data as $listItem)
|
foreach ($data as $listItem)
|
||||||
{
|
{
|
||||||
// If there's no mapping, we can't sync, so continue
|
// If there's no mapping, we can't sync, so continue
|
||||||
if ( ! is_array($listItem['media']['mappings']['nodes']))
|
if ( ! is_array($listItem['media']['mappings']['nodes']))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$malId = NULL;
|
$malId = NULL;
|
||||||
|
|
||||||
foreach ($listItem['media']['mappings']['nodes'] as $mapping)
|
foreach ($listItem['media']['mappings']['nodes'] as $mapping)
|
||||||
@ -368,18 +358,21 @@ final class SyncLists extends BaseCommand {
|
|||||||
'reconsuming' => $listItem['reconsuming'],
|
'reconsuming' => $listItem['reconsuming'],
|
||||||
'status' => strtolower($listItem['status']),
|
'status' => strtolower($listItem['status']),
|
||||||
'updatedAt' => $listItem['progressedAt'],
|
'updatedAt' => $listItem['progressedAt'],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int|string, mixed>
|
||||||
|
*/
|
||||||
private function transformAnilist(string $type, array $data): array
|
private function transformAnilist(string $type, array $data): array
|
||||||
{
|
{
|
||||||
$uType = ucfirst($type);
|
$uType = ucfirst($type);
|
||||||
$className = "\\Aviat\\AnimeClient\\API\\Anilist\\Transformer\\{$uType}ListTransformer";
|
$className = "\\Aviat\\AnimeClient\\API\\Anilist\\Transformer\\{$uType}ListTransformer";
|
||||||
$transformer = new $className;
|
$transformer = new $className();
|
||||||
|
|
||||||
$firstTransformed = [];
|
$firstTransformed = [];
|
||||||
|
|
||||||
@ -392,6 +385,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
|
|
||||||
// Key the array by mal_id
|
// Key the array by mal_id
|
||||||
$output = [];
|
$output = [];
|
||||||
|
|
||||||
foreach ($transformed as $item)
|
foreach ($transformed as $item)
|
||||||
{
|
{
|
||||||
$output[$item['mal_id']] = $item->toArray();
|
$output[$item['mal_id']] = $item->toArray();
|
||||||
@ -403,7 +397,9 @@ final class SyncLists extends BaseCommand {
|
|||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Compare Helpers
|
// Compare Helpers
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed[]>
|
||||||
|
*/
|
||||||
private function compareLists(string $type, array $anilistList, array $kitsuList): array
|
private function compareLists(string $type, array $anilistList, array $kitsuList): array
|
||||||
{
|
{
|
||||||
$itemsToAddToAnilist = [];
|
$itemsToAddToAnilist = [];
|
||||||
@ -413,10 +409,10 @@ final class SyncLists extends BaseCommand {
|
|||||||
|
|
||||||
$malIds = array_keys($anilistList);
|
$malIds = array_keys($anilistList);
|
||||||
$kitsuMalIds = array_map('intval', array_column($kitsuList, 'malId'));
|
$kitsuMalIds = array_map('intval', array_column($kitsuList, 'malId'));
|
||||||
$missingMalIds = array_filter($malIds, fn ($id) => ! in_array($id, $kitsuMalIds));
|
$missingMalIds = array_filter($malIds, static fn ($id) => ! in_array($id, $kitsuMalIds, TRUE));
|
||||||
|
|
||||||
// Add items on Anilist, but not Kitsu to Kitsu
|
// Add items on Anilist, but not Kitsu to Kitsu
|
||||||
foreach($missingMalIds as $mid)
|
foreach ($missingMalIds as $mid)
|
||||||
{
|
{
|
||||||
if ( ! array_key_exists($mid, $anilistList))
|
if ( ! array_key_exists($mid, $anilistList))
|
||||||
{
|
{
|
||||||
@ -424,13 +420,13 @@ final class SyncLists extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$data = $anilistList[$mid]['data'];
|
$data = $anilistList[$mid]['data'];
|
||||||
$data['id'] = $this->kitsuModel->getKitsuIdFromMALId((string)$mid, $type);
|
$data['id'] = $this->kitsuModel->getKitsuIdFromMALId((string) $mid, $type);
|
||||||
$data['type'] = $type;
|
$data['type'] = $type;
|
||||||
|
|
||||||
$itemsToAddToKitsu[] = $data;
|
$itemsToAddToKitsu[] = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($kitsuList as $kitsuItem)
|
foreach ($kitsuList as $kitsuItem)
|
||||||
{
|
{
|
||||||
$malId = $kitsuItem['malId'];
|
$malId = $kitsuItem['malId'];
|
||||||
|
|
||||||
@ -462,7 +458,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
|
|
||||||
// Looks like this item only exists on Kitsu
|
// Looks like this item only exists on Kitsu
|
||||||
$kItem = $kitsuItem['data'];
|
$kItem = $kitsuItem['data'];
|
||||||
$newItemStatus = ($kItem['reconsuming'] === true) ? 'REPEATING' : $statusMap::KITSU_TO_ANILIST[$kItem['status']];
|
$newItemStatus = ($kItem['reconsuming'] === TRUE) ? 'REPEATING' : $statusMap::KITSU_TO_ANILIST[$kItem['status']];
|
||||||
$itemsToAddToAnilist[] = [
|
$itemsToAddToAnilist[] = [
|
||||||
'mal_id' => $malId,
|
'mal_id' => $malId,
|
||||||
'data' => [
|
'data' => [
|
||||||
@ -480,16 +476,12 @@ final class SyncLists extends BaseCommand {
|
|||||||
'addToAnilist' => $itemsToAddToAnilist,
|
'addToAnilist' => $itemsToAddToAnilist,
|
||||||
'updateAnilist' => $anilistUpdateItems,
|
'updateAnilist' => $anilistUpdateItems,
|
||||||
'addToKitsu' => $itemsToAddToKitsu,
|
'addToKitsu' => $itemsToAddToKitsu,
|
||||||
'updateKitsu' => $kitsuUpdateItems
|
'updateKitsu' => $kitsuUpdateItems,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare two list items, and return the out of date one, if one exists
|
* Compare two list items, and return the out of date one, if one exists
|
||||||
*
|
|
||||||
* @param array $kitsuItem
|
|
||||||
* @param array $anilistItem
|
|
||||||
* @return array|null
|
|
||||||
*/
|
*/
|
||||||
private function compareListItems(array $kitsuItem, array $anilistItem): ?array
|
private function compareListItems(array $kitsuItem, array $anilistItem): ?array
|
||||||
{
|
{
|
||||||
@ -503,10 +495,10 @@ final class SyncLists extends BaseCommand {
|
|||||||
];
|
];
|
||||||
$diff = [];
|
$diff = [];
|
||||||
$dateDiff = ($kitsuItem['data']['updatedAt'] !== NULL)
|
$dateDiff = ($kitsuItem['data']['updatedAt'] !== NULL)
|
||||||
? new DateTime($kitsuItem['data']['updatedAt']) <=> new DateTime((string)$anilistItem['data']['updatedAt'])
|
? new DateTime($kitsuItem['data']['updatedAt']) <=> new DateTime((string) $anilistItem['data']['updatedAt'])
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
foreach($compareKeys as $key)
|
foreach ($compareKeys as $key)
|
||||||
{
|
{
|
||||||
$diff[$key] = $kitsuItem['data'][$key] <=> $anilistItem['data'][$key];
|
$diff[$key] = $kitsuItem['data'][$key] <=> $anilistItem['data'][$key];
|
||||||
}
|
}
|
||||||
@ -522,10 +514,10 @@ final class SyncLists extends BaseCommand {
|
|||||||
$update = [
|
$update = [
|
||||||
'id' => $kitsuItem['id'],
|
'id' => $kitsuItem['id'],
|
||||||
'mal_id' => $kitsuItem['malId'],
|
'mal_id' => $kitsuItem['malId'],
|
||||||
'data' => []
|
'data' => [],
|
||||||
];
|
];
|
||||||
$return = [
|
$return = [
|
||||||
'updateType' => []
|
'updateType' => [],
|
||||||
];
|
];
|
||||||
|
|
||||||
$sameNotes = $diff['notes'] === 0;
|
$sameNotes = $diff['notes'] === 0;
|
||||||
@ -549,7 +541,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
$update['data']['progress'] = $kitsuItem['data']['progress'];
|
$update['data']['progress'] = $kitsuItem['data']['progress'];
|
||||||
$return['updateType'][] = Enum\API::ANILIST;
|
$return['updateType'][] = Enum\API::ANILIST;
|
||||||
}
|
}
|
||||||
else if($diff['progress'] === self::ANILIST_GREATER)
|
elseif ($diff['progress'] === self::ANILIST_GREATER)
|
||||||
{
|
{
|
||||||
$update['data']['progress'] = $anilistItem['data']['progress'];
|
$update['data']['progress'] = $anilistItem['data']['progress'];
|
||||||
$return['updateType'][] = Enum\API::KITSU;
|
$return['updateType'][] = Enum\API::KITSU;
|
||||||
@ -564,7 +556,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
$update['data']['status'] = $kitsuItem['data']['status'];
|
$update['data']['status'] = $kitsuItem['data']['status'];
|
||||||
$return['updateType'][] = Enum\API::ANILIST;
|
$return['updateType'][] = Enum\API::ANILIST;
|
||||||
}
|
}
|
||||||
else if ($dateDiff === self::ANILIST_GREATER)
|
elseif ($dateDiff === self::ANILIST_GREATER)
|
||||||
{
|
{
|
||||||
$update['data']['status'] = $anilistItem['data']['status'];
|
$update['data']['status'] = $anilistItem['data']['status'];
|
||||||
$return['updateType'][] = Enum\API::KITSU;
|
$return['updateType'][] = Enum\API::KITSU;
|
||||||
@ -579,18 +571,18 @@ final class SyncLists extends BaseCommand {
|
|||||||
{
|
{
|
||||||
$update['data']['status'] = $kitsuItem['data']['status'];
|
$update['data']['status'] = $kitsuItem['data']['status'];
|
||||||
|
|
||||||
if ((int)$kitsuItem['data']['progress'] !== 0)
|
if ((int) $kitsuItem['data']['progress'] !== 0)
|
||||||
{
|
{
|
||||||
$update['data']['progress'] = $kitsuItem['data']['progress'];
|
$update['data']['progress'] = $kitsuItem['data']['progress'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$return['updateType'][] = Enum\API::ANILIST;
|
$return['updateType'][] = Enum\API::ANILIST;
|
||||||
}
|
}
|
||||||
else if($dateDiff === self::ANILIST_GREATER)
|
elseif ($dateDiff === self::ANILIST_GREATER)
|
||||||
{
|
{
|
||||||
$update['data']['status'] = $anilistItem['data']['status'];
|
$update['data']['status'] = $anilistItem['data']['status'];
|
||||||
|
|
||||||
if ((int)$anilistItem['data']['progress'] !== 0)
|
if ((int) $anilistItem['data']['progress'] !== 0)
|
||||||
{
|
{
|
||||||
$update['data']['progress'] = $kitsuItem['data']['progress'];
|
$update['data']['progress'] = $kitsuItem['data']['progress'];
|
||||||
}
|
}
|
||||||
@ -603,15 +595,14 @@ final class SyncLists extends BaseCommand {
|
|||||||
if ( ! $sameRating)
|
if ( ! $sameRating)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
$dateDiff === self::KITSU_GREATER &&
|
$dateDiff === self::KITSU_GREATER
|
||||||
$kitsuItem['data']['rating'] !== 0 &&
|
&& $kitsuItem['data']['rating'] !== 0
|
||||||
$kitsuItem['data']['ratingTwenty'] !== 0
|
&& $kitsuItem['data']['ratingTwenty'] !== 0
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
$update['data']['ratingTwenty'] = $kitsuItem['data']['rating'];
|
$update['data']['ratingTwenty'] = $kitsuItem['data']['rating'];
|
||||||
$return['updateType'][] = Enum\API::ANILIST;
|
$return['updateType'][] = Enum\API::ANILIST;
|
||||||
}
|
}
|
||||||
else if($dateDiff === self::ANILIST_GREATER && $anilistItem['data']['rating'] !== 0)
|
elseif ($dateDiff === self::ANILIST_GREATER && $anilistItem['data']['rating'] !== 0)
|
||||||
{
|
{
|
||||||
$update['data']['ratingTwenty'] = $anilistItem['data']['rating'] * 2;
|
$update['data']['ratingTwenty'] = $anilistItem['data']['rating'] * 2;
|
||||||
$return['updateType'][] = Enum\API::KITSU;
|
$return['updateType'][] = Enum\API::KITSU;
|
||||||
@ -641,7 +632,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
$update['data']['reconsumeCount'] = $kitsuItem['data']['reconsumeCount'];
|
$update['data']['reconsumeCount'] = $kitsuItem['data']['reconsumeCount'];
|
||||||
$return['updateType'][] = Enum\API::ANILIST;
|
$return['updateType'][] = Enum\API::ANILIST;
|
||||||
}
|
}
|
||||||
else if ($diff['reconsumeCount'] === self::ANILIST_GREATER)
|
elseif ($diff['reconsumeCount'] === self::ANILIST_GREATER)
|
||||||
{
|
{
|
||||||
$update['data']['reconsumeCount'] = $anilistItem['data']['reconsumeCount'];
|
$update['data']['reconsumeCount'] = $anilistItem['data']['reconsumeCount'];
|
||||||
$return['updateType'][] = Enum\API::KITSU;
|
$return['updateType'][] = Enum\API::KITSU;
|
||||||
@ -683,7 +674,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
|
|
||||||
$return['data']['data'] = array_merge($prevData, $return['data']['data']);
|
$return['data']['data'] = array_merge($prevData, $return['data']['data']);
|
||||||
}
|
}
|
||||||
else if ($return['updateType'][0] === Enum\API::KITSU)
|
elseif ($return['updateType'][0] === Enum\API::KITSU)
|
||||||
{
|
{
|
||||||
$prevData = [
|
$prevData = [
|
||||||
'notes' => $anilistItem['data']['notes'],
|
'notes' => $anilistItem['data']['notes'],
|
||||||
@ -691,7 +682,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
'progress' => $anilistItem['data']['progress'] ?? 0,
|
'progress' => $anilistItem['data']['progress'] ?? 0,
|
||||||
// Anilist returns a rating between 1-100
|
// Anilist returns a rating between 1-100
|
||||||
// Kitsu expects a rating from 1-20
|
// Kitsu expects a rating from 1-20
|
||||||
'rating' => (((int)$anilistItem['data']['rating']) > 0)
|
'rating' => (((int) $anilistItem['data']['rating']) > 0)
|
||||||
? (int) $anilistItem['data']['rating'] / 5
|
? (int) $anilistItem['data']['rating'] / 5
|
||||||
: 0,
|
: 0,
|
||||||
'reconsumeCount' => $anilistItem['data']['reconsumeCount'],
|
'reconsumeCount' => $anilistItem['data']['reconsumeCount'],
|
||||||
@ -708,19 +699,16 @@ final class SyncLists extends BaseCommand {
|
|||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Update Helpers
|
// Update Helpers
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/Update list items on Kitsu
|
* Create/Update list items on Kitsu
|
||||||
*
|
*
|
||||||
* @param array $itemsToUpdate
|
|
||||||
* @param string $action
|
|
||||||
* @param string $type
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
private function updateKitsuListItems(array $itemsToUpdate, string $action = SyncAction::UPDATE, string $type = MediaType::ANIME): void
|
private function updateKitsuListItems(array $itemsToUpdate, string $action = SyncAction::UPDATE, string $type = MediaType::ANIME): void
|
||||||
{
|
{
|
||||||
$requester = new ParallelAPIRequest();
|
$requester = new ParallelAPIRequest();
|
||||||
foreach($itemsToUpdate as $item)
|
|
||||||
|
foreach ($itemsToUpdate as $item)
|
||||||
{
|
{
|
||||||
if ($action === SyncAction::UPDATE)
|
if ($action === SyncAction::UPDATE)
|
||||||
{
|
{
|
||||||
@ -728,21 +716,23 @@ final class SyncLists extends BaseCommand {
|
|||||||
$this->kitsuModel->updateListItem(FormItem::from($item))
|
$this->kitsuModel->updateListItem(FormItem::from($item))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if ($action === SyncAction::CREATE)
|
elseif ($action === SyncAction::CREATE)
|
||||||
{
|
{
|
||||||
$maybeRequest = $this->kitsuModel->createListItem($item);
|
$maybeRequest = $this->kitsuModel->createListItem($item);
|
||||||
if ($maybeRequest === NULL)
|
if ($maybeRequest === NULL)
|
||||||
{
|
{
|
||||||
$this->echoWarning("Skipped creating Kitsu {$type} due to missing id ¯\_(ツ)_/¯");
|
$this->echoWarning("Skipped creating Kitsu {$type} due to missing id ¯\\_(ツ)_/¯");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$requester->addRequest($maybeRequest);
|
$requester->addRequest($maybeRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$responses = $requester->makeRequests();
|
$responses = $requester->makeRequests();
|
||||||
|
|
||||||
foreach($responses as $key => $response)
|
foreach ($responses as $key => $response)
|
||||||
{
|
{
|
||||||
$responseData = Json::decode($response);
|
$responseData = Json::decode($response);
|
||||||
|
|
||||||
@ -752,6 +742,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
{
|
{
|
||||||
$verb = ($action === SyncAction::UPDATE) ? 'updated' : 'created';
|
$verb = ($action === SyncAction::UPDATE) ? 'updated' : 'created';
|
||||||
$this->echoSuccess("Successfully {$verb} Kitsu {$type} list item with id: {$id}");
|
$this->echoSuccess("Successfully {$verb} Kitsu {$type} list item with id: {$id}");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,6 +754,7 @@ final class SyncLists extends BaseCommand {
|
|||||||
if ($errorTitle === 'cannot exceed length of media')
|
if ($errorTitle === 'cannot exceed length of media')
|
||||||
{
|
{
|
||||||
$this->echoWarning("Skipped Kitsu {$type} {$id} due to episode count mismatch with other API");
|
$this->echoWarning("Skipped Kitsu {$type} {$id} due to episode count mismatch with other API");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -774,23 +766,19 @@ final class SyncLists extends BaseCommand {
|
|||||||
]);
|
]);
|
||||||
$verb = ($action === SyncAction::UPDATE) ? SyncAction::UPDATE : SyncAction::CREATE;
|
$verb = ($action === SyncAction::UPDATE) ? SyncAction::UPDATE : SyncAction::CREATE;
|
||||||
$this->echoError("Failed to {$verb} Kitsu {$type} list item with id: {$id}, and mal_id: {$mal_id}");
|
$this->echoError("Failed to {$verb} Kitsu {$type} list item with id: {$id}, and mal_id: {$mal_id}");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/Update list items on Anilist
|
* Create/Update list items on Anilist
|
||||||
*
|
*
|
||||||
* @param array $itemsToUpdate
|
|
||||||
* @param string $action
|
|
||||||
* @param string $type
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
private function updateAnilistListItems(array $itemsToUpdate, string $action = SyncAction::UPDATE, string $type = MediaType::ANIME): void
|
private function updateAnilistListItems(array $itemsToUpdate, string $action = SyncAction::UPDATE, string $type = MediaType::ANIME): void
|
||||||
{
|
{
|
||||||
$requester = new ParallelAPIRequest();
|
$requester = new ParallelAPIRequest();
|
||||||
|
|
||||||
foreach($itemsToUpdate as $item)
|
foreach ($itemsToUpdate as $item)
|
||||||
{
|
{
|
||||||
if ($action === SyncAction::UPDATE)
|
if ($action === SyncAction::UPDATE)
|
||||||
{
|
{
|
||||||
@ -800,24 +788,27 @@ final class SyncLists extends BaseCommand {
|
|||||||
$requester->addRequest($maybeRequest);
|
$requester->addRequest($maybeRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ($action === SyncAction::CREATE)
|
else
|
||||||
{
|
{
|
||||||
try
|
if ($action === SyncAction::CREATE)
|
||||||
{
|
{
|
||||||
$requester->addRequest($this->anilistModel->createFullListItem($item, $type));
|
try
|
||||||
}
|
{
|
||||||
catch (MissingIdException $e)
|
$requester->addRequest($this->anilistModel->createFullListItem($item, $type));
|
||||||
{
|
}
|
||||||
// Case where there's a MAL mapping from Kitsu, but no equivalent Anlist item
|
catch (MissingIdException)
|
||||||
$id = $item['mal_id'];
|
{
|
||||||
$this->echoWarning("Skipping Anilist ${type} with MAL id: {$id} due to missing mapping");
|
// Case where there's a MAL mapping from Kitsu, but no equivalent Anlist item
|
||||||
|
$id = $item['mal_id'];
|
||||||
|
$this->echoWarning("Skipping Anilist {$type} with MAL id: {$id} due to missing mapping");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$responses = $requester->makeRequests();
|
$responses = $requester->makeRequests();
|
||||||
|
|
||||||
foreach($responses as $key => $response)
|
foreach ($responses as $key => $response)
|
||||||
{
|
{
|
||||||
$id = $itemsToUpdate[$key]['mal_id'];
|
$id = $itemsToUpdate[$key]['mal_id'];
|
||||||
|
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Command;
|
namespace Aviat\AnimeClient\Command;
|
||||||
@ -23,10 +21,10 @@ use Aviat\AnimeClient\Controller\Images;
|
|||||||
* Clears out image cache directories, then re-creates the image cache
|
* Clears out image cache directories, then re-creates the image cache
|
||||||
* for manga and anime
|
* for manga and anime
|
||||||
*/
|
*/
|
||||||
final class UpdateThumbnails extends ClearThumbnails {
|
final class UpdateThumbnails extends ClearThumbnails
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Model for making requests to Kitsu API
|
* Model for making requests to Kitsu API
|
||||||
* @var KitsuModel
|
|
||||||
*/
|
*/
|
||||||
protected KitsuModel $kitsuModel;
|
protected KitsuModel $kitsuModel;
|
||||||
|
|
||||||
@ -49,7 +47,7 @@ final class UpdateThumbnails extends ClearThumbnails {
|
|||||||
$ids = $this->getImageList();
|
$ids = $this->getImageList();
|
||||||
|
|
||||||
// Resave the images
|
// Resave the images
|
||||||
foreach($ids as $type => $typeIds)
|
foreach ($ids as $type => $typeIds)
|
||||||
{
|
{
|
||||||
foreach ($typeIds as $id)
|
foreach ($typeIds as $id)
|
||||||
{
|
{
|
||||||
@ -82,4 +80,4 @@ final class UpdateThumbnails extends ClearThumbnails {
|
|||||||
'manga' => $mangaIds,
|
'manga' => $mangaIds,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,18 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Component;
|
namespace Aviat\AnimeClient\Component;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Types\AnimeListItem;
|
use Aviat\AnimeClient\Types\AnimeListItem;
|
||||||
|
|
||||||
final class AnimeCover {
|
final class AnimeCover
|
||||||
|
{
|
||||||
use ComponentTrait;
|
use ComponentTrait;
|
||||||
|
|
||||||
public function __invoke(AnimeListItem $item): string
|
public function __invoke(AnimeListItem $item): string
|
||||||
@ -27,4 +26,4 @@ final class AnimeCover {
|
|||||||
'item' => $item,
|
'item' => $item,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,17 +6,16 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Component;
|
namespace Aviat\AnimeClient\Component;
|
||||||
|
|
||||||
final class Character {
|
final class Character
|
||||||
|
{
|
||||||
use ComponentTrait;
|
use ComponentTrait;
|
||||||
|
|
||||||
public function __invoke(string $name, string $link, string $picture, string $className = 'character'): string
|
public function __invoke(string $name, string $link, string $picture, string $className = 'character'): string
|
||||||
@ -28,4 +27,4 @@ final class Character {
|
|||||||
'className' => $className,
|
'className' => $className,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,32 +6,26 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Component;
|
namespace Aviat\AnimeClient\Component;
|
||||||
|
|
||||||
use Aviat\Ion\Di\ContainerAware;
|
use Aviat\Ion\Di\ContainerAware;
|
||||||
use const TEMPLATE_DIR;
|
|
||||||
use function Aviat\AnimeClient\renderTemplate;
|
use function Aviat\AnimeClient\renderTemplate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared logic for component-based functionality, like Tabs
|
* Shared logic for component-based functionality, like Tabs
|
||||||
*/
|
*/
|
||||||
trait ComponentTrait {
|
trait ComponentTrait
|
||||||
|
{
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render a template with common container values
|
* Render a template with common container values
|
||||||
*
|
|
||||||
* @param string $path
|
|
||||||
* @param array $data
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function render(string $path, array $data): string
|
public function render(string $path, array $data): string
|
||||||
{
|
{
|
||||||
@ -47,4 +41,4 @@ trait ComponentTrait {
|
|||||||
|
|
||||||
return renderTemplate(TEMPLATE_DIR . '/' . $path, array_merge($baseData, $data));
|
return renderTemplate(TEMPLATE_DIR . '/' . $path, array_merge($baseData, $data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,18 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Component;
|
namespace Aviat\AnimeClient\Component;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Types\MangaListItem;
|
use Aviat\AnimeClient\Types\MangaListItem;
|
||||||
|
|
||||||
final class MangaCover {
|
final class MangaCover
|
||||||
|
{
|
||||||
use ComponentTrait;
|
use ComponentTrait;
|
||||||
|
|
||||||
public function __invoke(MangaListItem $item, string $name): string
|
public function __invoke(MangaListItem $item, string $name): string
|
||||||
@ -28,4 +27,4 @@ final class MangaCover {
|
|||||||
'name' => $name,
|
'name' => $name,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,17 +6,16 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Component;
|
namespace Aviat\AnimeClient\Component;
|
||||||
|
|
||||||
final class Media {
|
final class Media
|
||||||
|
{
|
||||||
use ComponentTrait;
|
use ComponentTrait;
|
||||||
|
|
||||||
public function __invoke(array $titles, string $link, string $picture, string $className = 'media'): string
|
public function __invoke(array $titles, string $link, string $picture, string $className = 'media'): string
|
||||||
@ -28,4 +27,4 @@ final class Media {
|
|||||||
'className' => $className,
|
'className' => $className,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,38 +6,33 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Component;
|
namespace Aviat\AnimeClient\Component;
|
||||||
|
|
||||||
final class Tabs {
|
final class Tabs
|
||||||
|
{
|
||||||
use ComponentTrait;
|
use ComponentTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a tabbed content view
|
* Creates a tabbed content view
|
||||||
*
|
*
|
||||||
* @param string $name the name attribute for the input[type-option] form elements
|
* @param string $name the name attribute for the input[type-option] form elements
|
||||||
* also used to generate id attributes
|
* also used to generate id attributes
|
||||||
* @param array $tabData The data used to create the tab content, indexed by the tab label
|
* @param array $tabData The data used to create the tab content, indexed by the tab label
|
||||||
* @param callable $cb The function to generate the tab content
|
* @param callable $cb The function to generate the tab content
|
||||||
* @param string $className
|
|
||||||
* @param bool $hasSectionWrapper
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
string $name,
|
string $name,
|
||||||
array $tabData,
|
array $tabData,
|
||||||
callable $cb,
|
callable $cb,
|
||||||
string $className = 'content media-wrap flex flex-wrap flex-justify-start',
|
string $className = 'content media-wrap flex flex-wrap flex-justify-start',
|
||||||
bool $hasSectionWrapper = false
|
bool $hasSectionWrapper = FALSE
|
||||||
): string
|
): string {
|
||||||
{
|
|
||||||
if (count($tabData) < 2)
|
if (count($tabData) < 2)
|
||||||
{
|
{
|
||||||
return $this->render('single-tab.php', [
|
return $this->render('single-tab.php', [
|
||||||
@ -57,4 +52,4 @@ final class Tabs {
|
|||||||
'hasSectionWrapper' => $hasSectionWrapper,
|
'hasSectionWrapper' => $hasSectionWrapper,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,36 +6,32 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Component;
|
namespace Aviat\AnimeClient\Component;
|
||||||
|
|
||||||
final class VerticalTabs {
|
final class VerticalTabs
|
||||||
|
{
|
||||||
use ComponentTrait;
|
use ComponentTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a vertical tab content view
|
* Creates a vertical tab content view
|
||||||
*
|
*
|
||||||
* @param string $name the name attribute for the input[type-option] form elements
|
* @param string $name the name attribute for the input[type-option] form elements
|
||||||
* also used to generate id attributes
|
* also used to generate id attributes
|
||||||
* @param array $tabData The data used to create the tab content, indexed by the tab label
|
* @param array $tabData The data used to create the tab content, indexed by the tab label
|
||||||
* @param callable $cb The function to generate the tab content
|
* @param callable $cb The function to generate the tab content
|
||||||
* @param string $className
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
string $name,
|
string $name,
|
||||||
array $tabData,
|
array $tabData,
|
||||||
callable $cb,
|
callable $cb,
|
||||||
string $className='content media-wrap flex flex-wrap flex-justify-start'
|
string $className = 'content media-wrap flex flex-wrap flex-justify-start'
|
||||||
): string
|
): string {
|
||||||
{
|
|
||||||
return $this->render('vertical-tabs.php', [
|
return $this->render('vertical-tabs.php', [
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
'data' => $tabData,
|
'data' => $tabData,
|
||||||
@ -43,4 +39,4 @@ final class VerticalTabs {
|
|||||||
'className' => $className,
|
'className' => $className,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,42 +6,40 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient;
|
namespace Aviat\AnimeClient;
|
||||||
|
|
||||||
use function Aviat\Ion\_dir;
|
|
||||||
|
|
||||||
use Aviat\AnimeClient\Enum\EventType;
|
|
||||||
use Aura\Router\Generator;
|
use Aura\Router\Generator;
|
||||||
|
|
||||||
use Aura\Session\Segment;
|
use Aura\Session\Segment;
|
||||||
use Aviat\AnimeClient\API\Kitsu\Auth;
|
use Aviat\AnimeClient\API\Kitsu\Auth;
|
||||||
use Aviat\Ion\ConfigInterface;
|
use Aviat\AnimeClient\Enum\EventType;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
|
||||||
use Psr\SimpleCache\CacheInterface;
|
|
||||||
|
|
||||||
use Aviat\Ion\Di\{
|
use Aviat\Ion\Di\{
|
||||||
ContainerAware,
|
ContainerAware,
|
||||||
ContainerInterface,
|
ContainerInterface,
|
||||||
Exception\ContainerException,
|
Exception\ContainerException,
|
||||||
Exception\NotFoundException
|
Exception\NotFoundException
|
||||||
};
|
};
|
||||||
use Aviat\Ion\Event;
|
|
||||||
use Aviat\Ion\Exception\DoubleRenderException;
|
use Aviat\Ion\Exception\DoubleRenderException;
|
||||||
use Aviat\Ion\View\{HtmlView, HttpView, JsonView};
|
use Aviat\Ion\View\{HtmlView, HttpView, JsonView};
|
||||||
|
|
||||||
|
use Aviat\Ion\{ConfigInterface, Event};
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\SimpleCache\CacheInterface;
|
||||||
|
use function Aviat\Ion\_dir;
|
||||||
|
use function is_array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller base, defines output methods
|
* Controller base, defines output methods
|
||||||
*/
|
*/
|
||||||
class Controller {
|
class Controller
|
||||||
|
{
|
||||||
use ContainerAware;
|
use ContainerAware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,7 +85,6 @@ class Controller {
|
|||||||
/**
|
/**
|
||||||
* Controller constructor.
|
* Controller constructor.
|
||||||
*
|
*
|
||||||
* @param ContainerInterface $container
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
@ -100,7 +97,7 @@ class Controller {
|
|||||||
$urlGenerator = $container->get('url-generator');
|
$urlGenerator = $container->get('url-generator');
|
||||||
|
|
||||||
$this->auth = $container->get('auth');
|
$this->auth = $container->get('auth');
|
||||||
$this->cache = $container->get('cache');
|
$this->cache = $container->get('cache');
|
||||||
$this->config = $container->get('config');
|
$this->config = $container->get('config');
|
||||||
$this->request = $container->get('request');
|
$this->request = $container->get('request');
|
||||||
$this->session = $session->getSegment(SESSION_SEGMENT);
|
$this->session = $session->getSegment(SESSION_SEGMENT);
|
||||||
@ -127,11 +124,10 @@ class Controller {
|
|||||||
* Set the current url in the session as the target of a future redirect
|
* Set the current url in the session as the target of a future redirect
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param string|NULL $url
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
public function setSessionRedirect(string $url = NULL): void
|
public function setSessionRedirect(?string $url = NULL): void
|
||||||
{
|
{
|
||||||
$serverParams = $this->request->getServerParams();
|
$serverParams = $this->request->getServerParams();
|
||||||
|
|
||||||
@ -169,7 +165,6 @@ class Controller {
|
|||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
public function sessionRedirect(): void
|
public function sessionRedirect(): void
|
||||||
{
|
{
|
||||||
@ -199,10 +194,6 @@ class Controller {
|
|||||||
* Get the string output of a partial template
|
* Get the string output of a partial template
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param HtmlView $view
|
|
||||||
* @param string $template
|
|
||||||
* @param array $data
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
protected function loadPartial(HtmlView $view, string $template, array $data = []): string
|
protected function loadPartial(HtmlView $view, string $template, array $data = []): string
|
||||||
{
|
{
|
||||||
@ -216,7 +207,6 @@ class Controller {
|
|||||||
$route = $router->getRoute();
|
$route = $router->getRoute();
|
||||||
$data['route_path'] = $route !== FALSE ? $route->path : '';
|
$data['route_path'] = $route !== FALSE ? $route->path : '';
|
||||||
|
|
||||||
|
|
||||||
$templatePath = _dir($this->config->get('view_path'), "{$template}.php");
|
$templatePath = _dir($this->config->get('view_path'), "{$template}.php");
|
||||||
|
|
||||||
if ( ! is_file($templatePath))
|
if ( ! is_file($templatePath))
|
||||||
@ -231,10 +221,6 @@ class Controller {
|
|||||||
* Render a template with header and footer
|
* Render a template with header and footer
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param HtmlView $view
|
|
||||||
* @param string $template
|
|
||||||
* @param array $data
|
|
||||||
* @return HtmlView
|
|
||||||
*/
|
*/
|
||||||
protected function renderFullPage(HtmlView $view, string $template, array $data): HtmlView
|
protected function renderFullPage(HtmlView $view, string $template, array $data): HtmlView
|
||||||
{
|
{
|
||||||
@ -247,7 +233,7 @@ class Controller {
|
|||||||
$view->addHeader('Content-Security-Policy', implode('; ', $csp));
|
$view->addHeader('Content-Security-Policy', implode('; ', $csp));
|
||||||
$view->appendOutput($this->loadPartial($view, 'header', $data));
|
$view->appendOutput($this->loadPartial($view, 'header', $data));
|
||||||
|
|
||||||
if (array_key_exists('message', $data) && \is_array($data['message']))
|
if (array_key_exists('message', $data) && is_array($data['message']))
|
||||||
{
|
{
|
||||||
$view->appendOutput($this->loadPartial($view, 'message', $data['message']));
|
$view->appendOutput($this->loadPartial($view, 'message', $data['message']));
|
||||||
}
|
}
|
||||||
@ -262,20 +248,17 @@ class Controller {
|
|||||||
* 404 action
|
* 404 action
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param string $title
|
|
||||||
* @param string $message
|
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
public function notFound(
|
public function notFound(
|
||||||
string $title = 'Sorry, page not found',
|
string $title = 'Sorry, page not found',
|
||||||
string $message = 'Page Not Found'
|
string $message = 'Page Not Found'
|
||||||
): void
|
): void {
|
||||||
{
|
|
||||||
$this->outputHTML('404', [
|
$this->outputHTML('404', [
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'message' => $message,
|
'message' => $message,
|
||||||
], NULL, 404);
|
], NULL, 404);
|
||||||
|
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,19 +266,14 @@ class Controller {
|
|||||||
* Display a generic error page
|
* Display a generic error page
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param int $httpCode
|
|
||||||
* @param string $title
|
|
||||||
* @param string $message
|
|
||||||
* @param string $longMessage
|
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
public function errorPage(int $httpCode, string $title, string $message, string $longMessage = ''): void
|
public function errorPage(int $httpCode, string $title, string $message, string $longMessage = ''): void
|
||||||
{
|
{
|
||||||
$this->outputHTML('error', [
|
$this->outputHTML('error', [
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'message' => $message,
|
'message' => $message,
|
||||||
'long_message' => $longMessage
|
'long_message' => $longMessage,
|
||||||
], NULL, $httpCode);
|
], NULL, $httpCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,7 +282,6 @@ class Controller {
|
|||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
public function redirectToDefaultRoute(): void
|
public function redirectToDefaultRoute(): void
|
||||||
{
|
{
|
||||||
@ -317,9 +294,6 @@ class Controller {
|
|||||||
* next page load
|
* next page load
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param string $message
|
|
||||||
* @param string $type
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
public function setFlashMessage(string $message, string $type = 'info'): void
|
public function setFlashMessage(string $message, string $type = 'info'): void
|
||||||
{
|
{
|
||||||
@ -332,7 +306,7 @@ class Controller {
|
|||||||
|
|
||||||
$messages[] = [
|
$messages[] = [
|
||||||
'message_type' => $type,
|
'message_type' => $type,
|
||||||
'message' => $message
|
'message' => $message,
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->session->setFlash('message', $messages);
|
$this->session->setFlash('message', $messages);
|
||||||
@ -342,9 +316,8 @@ class Controller {
|
|||||||
* Helper for consistent page titles
|
* Helper for consistent page titles
|
||||||
*
|
*
|
||||||
* @param string ...$parts Title segments
|
* @param string ...$parts Title segments
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function formatTitle(string ...$parts) : string
|
public function formatTitle(string ...$parts): string
|
||||||
{
|
{
|
||||||
return implode(' · ', $parts);
|
return implode(' · ', $parts);
|
||||||
}
|
}
|
||||||
@ -353,17 +326,13 @@ class Controller {
|
|||||||
* Add a message box to the page
|
* Add a message box to the page
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param HtmlView $view
|
|
||||||
* @param string $type
|
|
||||||
* @param string $message
|
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
protected function showMessage(HtmlView $view, string $type, string $message): string
|
protected function showMessage(HtmlView $view, string $type, string $message): string
|
||||||
{
|
{
|
||||||
return $this->loadPartial($view, 'message', [
|
return $this->loadPartial($view, 'message', [
|
||||||
'message_type' => $type,
|
'message_type' => $type,
|
||||||
'message' => $message
|
'message' => $message,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,14 +340,9 @@ class Controller {
|
|||||||
* Output a template to HTML, using the provided data
|
* Output a template to HTML, using the provided data
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param string $template
|
* @throws InvalidArgumentException
|
||||||
* @param array $data
|
|
||||||
* @param HtmlView|NULL $view
|
|
||||||
* @param int $code
|
|
||||||
* @return void
|
|
||||||
*@throws InvalidArgumentException
|
|
||||||
*/
|
*/
|
||||||
protected function outputHTML(string $template, array $data = [], HtmlView $view = NULL, int $code = 200): void
|
protected function outputHTML(string $template, array $data = [], ?HtmlView $view = NULL, int $code = 200): void
|
||||||
{
|
{
|
||||||
if (NULL === $view)
|
if (NULL === $view)
|
||||||
{
|
{
|
||||||
@ -393,14 +357,12 @@ class Controller {
|
|||||||
* Output a JSON Response
|
* Output a JSON Response
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param mixed $data
|
|
||||||
* @param int $code - the http status code
|
* @param int $code - the http status code
|
||||||
* @throws DoubleRenderException
|
* @throws DoubleRenderException
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
protected function outputJSON(mixed $data, int $code): void
|
protected function outputJSON(mixed $data, int $code): void
|
||||||
{
|
{
|
||||||
(new JsonView())
|
JsonView::new()
|
||||||
->setOutput($data)
|
->setOutput($data)
|
||||||
->setStatusCode($code)
|
->setStatusCode($code)
|
||||||
->send();
|
->send();
|
||||||
@ -410,17 +372,13 @@ class Controller {
|
|||||||
* Redirect to the selected page
|
* Redirect to the selected page
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @param string $url
|
|
||||||
* @param int $code
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
protected function redirect(string $url, int $code): void
|
protected function redirect(string $url, int $code): void
|
||||||
{
|
{
|
||||||
try
|
HttpView::new()
|
||||||
{
|
->redirect($url, $code)
|
||||||
(new HttpView())->redirect($url, $code)->send();
|
->send();
|
||||||
}
|
|
||||||
catch (\Throwable) {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// End of BaseController.php
|
|
||||||
|
// End of BaseController.php
|
||||||
|
@ -6,26 +6,25 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Controller;
|
namespace Aviat\AnimeClient\Controller;
|
||||||
|
|
||||||
use Aura\Router\Exception\RouteNotFound;
|
use Aura\Router\Exception\RouteNotFound;
|
||||||
use Aviat\AnimeClient\Controller as BaseController;
|
|
||||||
use Aviat\AnimeClient\API\Kitsu\Transformer\AnimeListTransformer;
|
|
||||||
use Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\Kitsu as KitsuWatchingStatus;
|
use Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\Kitsu as KitsuWatchingStatus;
|
||||||
|
use Aviat\AnimeClient\API\Kitsu\Transformer\AnimeListTransformer;
|
||||||
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
|
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
|
||||||
|
use Aviat\AnimeClient\Controller as BaseController;
|
||||||
use Aviat\AnimeClient\Model\Anime as AnimeModel;
|
use Aviat\AnimeClient\Model\Anime as AnimeModel;
|
||||||
use Aviat\AnimeClient\Types\FormItem;
|
use Aviat\AnimeClient\Types\FormItem;
|
||||||
|
use Aviat\Ion\Attribute\Controller;
|
||||||
|
use Aviat\Ion\Attribute\Route;
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\Di\Exception\ContainerException;
|
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
||||||
use Aviat\Ion\Di\Exception\NotFoundException;
|
|
||||||
use Aviat\Ion\Json;
|
use Aviat\Ion\Json;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
@ -35,18 +34,17 @@ use TypeError;
|
|||||||
/**
|
/**
|
||||||
* Controller for Anime-related pages
|
* Controller for Anime-related pages
|
||||||
*/
|
*/
|
||||||
final class Anime extends BaseController {
|
#[Controller('anime')]
|
||||||
|
final class Anime extends BaseController
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* The anime list model
|
* The anime list model
|
||||||
* @var AnimeModel $model
|
|
||||||
*/
|
*/
|
||||||
protected AnimeModel $model;
|
protected AnimeModel $model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param ContainerInterface $container
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
@ -68,10 +66,10 @@ final class Anime extends BaseController {
|
|||||||
*
|
*
|
||||||
* @param int|string $status - The section of the list
|
* @param int|string $status - The section of the list
|
||||||
* @param string|null $view - List or cover view
|
* @param string|null $view - List or cover view
|
||||||
* @return void
|
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.list', '/anime/{status}{/view}')]
|
||||||
public function index(int|string $status = KitsuWatchingStatus::WATCHING, ?string $view = NULL): void
|
public function index(int|string $status = KitsuWatchingStatus::WATCHING, ?string $view = NULL): void
|
||||||
{
|
{
|
||||||
if ( ! in_array($status, [
|
if ( ! in_array($status, [
|
||||||
@ -95,7 +93,7 @@ final class Anime extends BaseController {
|
|||||||
|
|
||||||
$viewMap = [
|
$viewMap = [
|
||||||
'' => 'cover',
|
'' => 'cover',
|
||||||
'list' => 'list'
|
'list' => 'list',
|
||||||
];
|
];
|
||||||
|
|
||||||
$data = ($status !== 'all')
|
$data = ($status !== 'all')
|
||||||
@ -104,7 +102,7 @@ final class Anime extends BaseController {
|
|||||||
|
|
||||||
$this->outputHTML('anime/' . $viewMap[$view], [
|
$this->outputHTML('anime/' . $viewMap[$view], [
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'sections' => $data
|
'sections' => $data,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,12 +110,12 @@ final class Anime extends BaseController {
|
|||||||
* Form to add an anime
|
* Form to add an anime
|
||||||
*
|
*
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
|
* @throws InvalidArgumentException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
* @throws RouteNotFound
|
* @throws RouteNotFound
|
||||||
* @throws InvalidArgumentException
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.add.get', '/anime/add')]
|
||||||
public function addForm(): void
|
public function addForm(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
@ -129,7 +127,7 @@ final class Anime extends BaseController {
|
|||||||
'Add'
|
'Add'
|
||||||
),
|
),
|
||||||
'action_url' => $this->url->generate('anime.add.post'),
|
'action_url' => $this->url->generate('anime.add.post'),
|
||||||
'status_list' => AnimeWatchingStatus::KITSU_TO_TITLE
|
'status_list' => AnimeWatchingStatus::KITSU_TO_TITLE,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,13 +135,13 @@ final class Anime extends BaseController {
|
|||||||
* Add an anime to the list
|
* Add an anime to the list
|
||||||
*
|
*
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.add.post', '/anime/add', Route::POST)]
|
||||||
public function add(): void
|
public function add(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
|
|
||||||
$data = (array)$this->request->getParsedBody();
|
$data = (array) $this->request->getParsedBody();
|
||||||
|
|
||||||
if (empty($data['mal_id']))
|
if (empty($data['mal_id']))
|
||||||
{
|
{
|
||||||
@ -155,7 +153,7 @@ final class Anime extends BaseController {
|
|||||||
$this->redirect('anime/add', 303);
|
$this->redirect('anime/add', 303);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $this->model->createLibraryItem($data);
|
$result = $this->model->createItem($data);
|
||||||
|
|
||||||
if ($result)
|
if ($result)
|
||||||
{
|
{
|
||||||
@ -172,15 +170,13 @@ final class Anime extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Form to edit details about a series
|
* Form to edit details about a series
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
* @param string $status
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.edit', '/anime/edit/{id}/{status}')]
|
||||||
public function edit(string $id, string $status = 'all'): void
|
public function edit(string $id, string $status = 'all'): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
|
|
||||||
$item = $this->model->getLibraryItem($id);
|
$item = $this->model->getItem($id);
|
||||||
$this->setSessionRedirect();
|
$this->setSessionRedirect();
|
||||||
|
|
||||||
$this->outputHTML('anime/edit', [
|
$this->outputHTML('anime/edit', [
|
||||||
@ -191,16 +187,15 @@ final class Anime extends BaseController {
|
|||||||
'item' => $item,
|
'item' => $item,
|
||||||
'statuses' => AnimeWatchingStatus::KITSU_TO_TITLE,
|
'statuses' => AnimeWatchingStatus::KITSU_TO_TITLE,
|
||||||
'action' => $this->url->generate('update.post', [
|
'action' => $this->url->generate('update.post', [
|
||||||
'controller' => 'anime'
|
'controller' => 'anime',
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search for anime
|
* Search for anime
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.search', '/anime/search')]
|
||||||
public function search(): void
|
public function search(): void
|
||||||
{
|
{
|
||||||
$queryParams = $this->request->getQueryParams();
|
$queryParams = $this->request->getQueryParams();
|
||||||
@ -212,19 +207,19 @@ final class Anime extends BaseController {
|
|||||||
* Update an anime item via a form submission
|
* Update an anime item via a form submission
|
||||||
*
|
*
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.update.post', '/anime/update_form', Route::POST)]
|
||||||
public function formUpdate(): void
|
public function formUpdate(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
|
|
||||||
$data = (array)$this->request->getParsedBody();
|
$data = (array) $this->request->getParsedBody();
|
||||||
|
|
||||||
// Do some minor data manipulation for
|
// Do some minor data manipulation for
|
||||||
// large form-based updates
|
// large form-based updates
|
||||||
$transformer = new AnimeListTransformer();
|
$transformer = new AnimeListTransformer();
|
||||||
$postData = $transformer->untransform($data);
|
$postData = $transformer->untransform($data);
|
||||||
$fullResult = $this->model->updateLibraryItem(FormItem::from($postData));
|
$fullResult = $this->model->updateItem(FormItem::from($postData));
|
||||||
|
|
||||||
if ($fullResult['statusCode'] === 200)
|
if ($fullResult['statusCode'] === 200)
|
||||||
{
|
{
|
||||||
@ -243,28 +238,24 @@ final class Anime extends BaseController {
|
|||||||
* Increase the watched count for an anime item
|
* Increase the watched count for an anime item
|
||||||
*
|
*
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.increment', '/anime/increment', Route::POST)]
|
||||||
public function increment(): void
|
public function increment(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
|
|
||||||
if (str_contains($this->request->getHeader('content-type')[0], 'application/json'))
|
$data = str_contains($this->request->getHeader('content-type')[0], 'application/json')
|
||||||
{
|
? Json::decode((string) $this->request->getBody())
|
||||||
$data = Json::decode((string)$this->request->getBody());
|
: (array) $this->request->getParsedBody();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$data = (array)$this->request->getParsedBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($data))
|
if (empty($data))
|
||||||
{
|
{
|
||||||
$this->errorPage(400, 'Bad Request', '');
|
$this->errorPage(400, 'Bad Request', '');
|
||||||
|
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = $this->model->incrementLibraryItem(FormItem::from($data));
|
$response = $this->model->incrementItem(FormItem::from($data));
|
||||||
|
|
||||||
$this->cache->clear();
|
$this->cache->clear();
|
||||||
$this->outputJSON($response['body'], $response['statusCode']);
|
$this->outputJSON($response['body'], $response['statusCode']);
|
||||||
@ -274,14 +265,14 @@ final class Anime extends BaseController {
|
|||||||
* Remove an anime from the list
|
* Remove an anime from the list
|
||||||
*
|
*
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.delete', '/anime/delete', Route::POST)]
|
||||||
public function delete(): void
|
public function delete(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
|
|
||||||
$body = (array)$this->request->getParsedBody();
|
$body = (array) $this->request->getParsedBody();
|
||||||
$response = $this->model->deleteLibraryItem($body['id'], $body['mal_id']);
|
$response = $this->model->deleteItem(FormItem::from($body));
|
||||||
|
|
||||||
if ($response === TRUE)
|
if ($response === TRUE)
|
||||||
{
|
{
|
||||||
@ -299,10 +290,9 @@ final class Anime extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* View details of an anime
|
* View details of an anime
|
||||||
*
|
*
|
||||||
* @param string $id
|
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.details', '/anime/details/{id}')]
|
||||||
public function details(string $id): void
|
public function details(string $id): void
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -341,6 +331,7 @@ final class Anime extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route('anime.random', '/anime/details/random')]
|
||||||
public function random(): void
|
public function random(): void
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -379,4 +370,5 @@ final class Anime extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// End of AnimeController.php
|
|
||||||
|
// End of AnimeController.php
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Controller;
|
namespace Aviat\AnimeClient\Controller;
|
||||||
@ -22,9 +20,11 @@ use Aviat\AnimeClient\Model\{
|
|||||||
Anime as AnimeModel,
|
Anime as AnimeModel,
|
||||||
AnimeCollection as AnimeCollectionModel
|
AnimeCollection as AnimeCollectionModel
|
||||||
};
|
};
|
||||||
|
use Aviat\Ion\Attribute\Controller;
|
||||||
|
use Aviat\Ion\Attribute\Route;
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\Di\Exception\ContainerException;
|
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
||||||
use Aviat\Ion\Di\Exception\NotFoundException;
|
use Aviat\Ion\Json;
|
||||||
use Aviat\Ion\Exception\DoubleRenderException;
|
use Aviat\Ion\Exception\DoubleRenderException;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
@ -32,24 +32,22 @@ use InvalidArgumentException;
|
|||||||
/**
|
/**
|
||||||
* Controller for Anime collection pages
|
* Controller for Anime collection pages
|
||||||
*/
|
*/
|
||||||
final class AnimeCollection extends BaseController {
|
#[Controller('anime.collection')]
|
||||||
|
final class AnimeCollection extends BaseController
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* The anime collection model
|
* The anime collection model
|
||||||
* @var AnimeCollectionModel $animeCollectionModel
|
|
||||||
*/
|
*/
|
||||||
private AnimeCollectionModel $animeCollectionModel;
|
private AnimeCollectionModel $animeCollectionModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The anime API model
|
* The anime API model
|
||||||
* @var AnimeModel $animeModel
|
|
||||||
*/
|
*/
|
||||||
private AnimeModel $animeModel;
|
private AnimeModel $animeModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param ContainerInterface $container
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
@ -67,6 +65,8 @@ final class AnimeCollection extends BaseController {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route('anime.collection.redirect', '/anime-collection')]
|
||||||
|
#[Route('anime.collection.redirect2', '/anime-collection/')]
|
||||||
public function index(): void
|
public function index(): void
|
||||||
{
|
{
|
||||||
$this->redirect('/anime-collection/view', 303);
|
$this->redirect('/anime-collection/view', 303);
|
||||||
@ -76,8 +76,8 @@ final class AnimeCollection extends BaseController {
|
|||||||
* Search for anime
|
* Search for anime
|
||||||
*
|
*
|
||||||
* @throws DoubleRenderException
|
* @throws DoubleRenderException
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.collection.search', '/anime-collection/search')]
|
||||||
public function search(): void
|
public function search(): void
|
||||||
{
|
{
|
||||||
$queryParams = $this->request->getQueryParams();
|
$queryParams = $this->request->getQueryParams();
|
||||||
@ -88,17 +88,16 @@ final class AnimeCollection extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* Show the anime collection page
|
* Show the anime collection page
|
||||||
*
|
*
|
||||||
* @param string|null $view
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @return void
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.collection.view', '/anime-collection/view{/view}')]
|
||||||
public function view(?string $view = ''): void
|
public function view(?string $view = ''): void
|
||||||
{
|
{
|
||||||
$viewMap = [
|
$viewMap = [
|
||||||
'' => 'cover',
|
'' => 'cover',
|
||||||
'list' => 'list'
|
'list' => 'list',
|
||||||
];
|
];
|
||||||
|
|
||||||
$sections = array_merge(
|
$sections = array_merge(
|
||||||
@ -115,14 +114,15 @@ final class AnimeCollection extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* Show the anime collection add/edit form
|
* Show the anime collection add/edit form
|
||||||
*
|
*
|
||||||
* @param integer|null $id
|
* @param int|null $id
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
|
* @throws InvalidArgumentException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
* @throws RouteNotFound
|
* @throws RouteNotFound
|
||||||
* @throws InvalidArgumentException
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
public function form($id = NULL): void
|
#[Route('anime.collection.add.get', '/anime-collection/add')]
|
||||||
|
#[Route('anime.collection.edit.get', '/anime-collection/edit/{id}')]
|
||||||
|
public function form(?int $id = NULL): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ final class AnimeCollection extends BaseController {
|
|||||||
$action
|
$action
|
||||||
),
|
),
|
||||||
'media_items' => $this->animeCollectionModel->getMediaTypeList(),
|
'media_items' => $this->animeCollectionModel->getMediaTypeList(),
|
||||||
'item' => ($action === 'Edit' && $id !== NULL) ? $this->animeCollectionModel->get($id) : []
|
'item' => ($action === 'Edit' && $id !== NULL) ? $this->animeCollectionModel->get($id) : [],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,29 +147,29 @@ final class AnimeCollection extends BaseController {
|
|||||||
* Update a collection item
|
* Update a collection item
|
||||||
*
|
*
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @return void
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.collection.edit.post', '/anime-collection/edit', Route::POST)]
|
||||||
public function edit(): void
|
public function edit(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
$this->update((array)$this->request->getParsedBody());
|
$this->update((array) $this->request->getParsedBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a collection item
|
* Add a collection item
|
||||||
*
|
*
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
* @return void
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.collection.add.post', '/anime-collection/add', Route::POST)]
|
||||||
public function add(): void
|
public function add(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
|
|
||||||
$data = (array)$this->request->getParsedBody();
|
$data = (array) $this->request->getParsedBody();
|
||||||
if (array_key_exists('id', $data))
|
if (array_key_exists('id', $data))
|
||||||
{
|
{
|
||||||
// Check for existing entry
|
// Check for existing entry
|
||||||
@ -191,6 +191,7 @@ final class AnimeCollection extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->update($data);
|
$this->update($data);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,6 +202,7 @@ final class AnimeCollection extends BaseController {
|
|||||||
{
|
{
|
||||||
$this->setFlashMessage('Successfully added collection item', 'success');
|
$this->setFlashMessage('Successfully added collection item', 'success');
|
||||||
$this->sessionRedirect();
|
$this->sessionRedirect();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,14 +213,13 @@ final class AnimeCollection extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a collection item
|
* Remove a collection item
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('anime.collection.delete', '/anime-collection/delete', Route::POST)]
|
||||||
public function delete(): void
|
public function delete(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
|
|
||||||
$data = (array)$this->request->getParsedBody();
|
$data = (array) $this->request->getParsedBody();
|
||||||
if ( ! array_key_exists('hummingbird_id', $data))
|
if ( ! array_key_exists('hummingbird_id', $data))
|
||||||
{
|
{
|
||||||
$this->setFlashMessage("Can't delete item that doesn't exist", 'error');
|
$this->setFlashMessage("Can't delete item that doesn't exist", 'error');
|
||||||
@ -237,8 +238,6 @@ final class AnimeCollection extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a collection item
|
* Update a collection item
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
*/
|
*/
|
||||||
protected function update(array $data): void
|
protected function update(array $data): void
|
||||||
{
|
{
|
||||||
@ -259,4 +258,5 @@ final class AnimeCollection extends BaseController {
|
|||||||
$this->sessionRedirect();
|
$this->sessionRedirect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// End of AnimeCollection.php
|
|
||||||
|
// End of AnimeCollection.php
|
||||||
|
@ -6,38 +6,34 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Controller;
|
namespace Aviat\AnimeClient\Controller;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Kitsu\Model;
|
use Aviat\AnimeClient\API\Kitsu\Model;
|
||||||
use Aviat\AnimeClient\Controller as BaseController;
|
|
||||||
use Aviat\AnimeClient\API\Kitsu\Transformer\CharacterTransformer;
|
use Aviat\AnimeClient\API\Kitsu\Transformer\CharacterTransformer;
|
||||||
|
use Aviat\AnimeClient\Controller as BaseController;
|
||||||
|
|
||||||
|
use Aviat\Ion\Attribute\Controller;
|
||||||
|
use Aviat\Ion\Attribute\Route;
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\Di\Exception\ContainerException;
|
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
||||||
use Aviat\Ion\Di\Exception\NotFoundException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for character description pages
|
* Controller for character description pages
|
||||||
*/
|
*/
|
||||||
final class Character extends BaseController {
|
#[Controller]
|
||||||
|
final class Character extends BaseController
|
||||||
/**
|
{
|
||||||
* @var Model
|
|
||||||
*/
|
|
||||||
private Model $model;
|
private Model $model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Character constructor.
|
* Character constructor.
|
||||||
*
|
*
|
||||||
* @param ContainerInterface $container
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
@ -49,10 +45,8 @@ final class Character extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Show information about a character
|
* Show information about a character
|
||||||
*
|
|
||||||
* @param string $slug
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('character', '/character/{slug}')]
|
||||||
public function index(string $slug): void
|
public function index(string $slug): void
|
||||||
{
|
{
|
||||||
$rawData = $this->model->getCharacter($slug);
|
$rawData = $this->model->getCharacter($slug);
|
||||||
@ -80,4 +74,4 @@ final class Character extends BaseController {
|
|||||||
'data' => $data,
|
'data' => $data,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,43 +6,39 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Controller;
|
namespace Aviat\AnimeClient\Controller;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Controller as BaseController;
|
use Aviat\Ion\Attribute\Controller;
|
||||||
use Aviat\AnimeClient\Model\Anime as AnimeModel;
|
use Aviat\Ion\Attribute\Route;
|
||||||
use Aviat\AnimeClient\Model\Manga as MangaModel;
|
use Aviat\AnimeClient\{Controller as BaseController, Model};
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\Di\Exception\ContainerException;
|
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
||||||
use Aviat\Ion\Di\Exception\NotFoundException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for Anime-related pages
|
* Controller for Anime-related pages
|
||||||
*/
|
*/
|
||||||
final class History extends BaseController {
|
#[Controller]
|
||||||
|
final class History extends BaseController
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* The anime list model
|
* The anime list model
|
||||||
* @var AnimeModel
|
|
||||||
*/
|
*/
|
||||||
protected AnimeModel $animeModel;
|
protected Model\Anime $animeModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The manga list model
|
* The manga list model
|
||||||
* @var MangaModel
|
|
||||||
*/
|
*/
|
||||||
protected MangaModel $mangaModel;
|
protected Model\Manga $mangaModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param ContainerInterface $container
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
@ -54,11 +50,13 @@ final class History extends BaseController {
|
|||||||
$this->mangaModel = $container->get('manga-model');
|
$this->mangaModel = $container->get('manga-model');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route('history', '/history/{type}')]
|
||||||
public function index(string $type = 'anime'): void
|
public function index(string $type = 'anime'): void
|
||||||
{
|
{
|
||||||
if (method_exists($this, $type))
|
if (method_exists($this, $type))
|
||||||
{
|
{
|
||||||
$this->$type();
|
$this->{$type}();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,40 +6,42 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Controller;
|
namespace Aviat\AnimeClient\Controller;
|
||||||
|
|
||||||
use function Amp\Promise\wait;
|
|
||||||
use function Aviat\AnimeClient\getResponse;
|
|
||||||
use function Aviat\AnimeClient\createPlaceholderImage;
|
|
||||||
|
|
||||||
use Aviat\AnimeClient\Controller as BaseController;
|
use Aviat\AnimeClient\Controller as BaseController;
|
||||||
|
use Aviat\Ion\Attribute\Controller;
|
||||||
|
use Aviat\Ion\Attribute\Route;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
use function Amp\Promise\wait;
|
||||||
|
use function Aviat\AnimeClient\{createPlaceholderImage, getResponse};
|
||||||
|
use function imagepalletetotruecolor;
|
||||||
|
|
||||||
|
use function in_array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for handling routes that don't fit elsewhere
|
* Controller for handling routes that don't fit elsewhere
|
||||||
*/
|
*/
|
||||||
final class Images extends BaseController {
|
#[Controller]
|
||||||
|
final class Images extends BaseController
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Get image covers from kitsu
|
* Get image covers from kitsu
|
||||||
*
|
*
|
||||||
* @param string $type The category of image
|
* @param string $type The category of image
|
||||||
* @param string $file The filename to look for
|
* @param string $file The filename to look for
|
||||||
* @param bool $display Whether to output the image to the server
|
* @param bool $display Whether to output the image to the server
|
||||||
* @return void
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
|
#[Route('image_proxy', '/public/images/{type}/{file}')]
|
||||||
public function cache(string $type, string $file, bool $display = TRUE): void
|
public function cache(string $type, string $file, bool $display = TRUE): void
|
||||||
{
|
{
|
||||||
$currentUrl = (string)$this->request->getUri();
|
$currentUrl = (string) $this->request->getUri();
|
||||||
|
|
||||||
$kitsuUrl = 'https://media.kitsu.io/';
|
$kitsuUrl = 'https://media.kitsu.io/';
|
||||||
$fileName = str_replace('-original', '', $file);
|
$fileName = str_replace('-original', '', $file);
|
||||||
@ -49,8 +51,8 @@ final class Images extends BaseController {
|
|||||||
|
|
||||||
// Kitsu doesn't serve webp, but for most use cases,
|
// Kitsu doesn't serve webp, but for most use cases,
|
||||||
// jpg is a safe assumption
|
// jpg is a safe assumption
|
||||||
$tryJpg = ['anime','characters','manga','people'];
|
$tryJpg = ['anime', 'characters', 'manga', 'people'];
|
||||||
if ($ext === 'webp' && \in_array($type, $tryJpg, TRUE))
|
if ($ext === 'webp' && in_array($type, $tryJpg, TRUE))
|
||||||
{
|
{
|
||||||
$ext = 'jpg';
|
$ext = 'jpg';
|
||||||
$currentUrl = str_replace('webp', 'jpg', $currentUrl);
|
$currentUrl = str_replace('webp', 'jpg', $currentUrl);
|
||||||
@ -64,8 +66,8 @@ final class Images extends BaseController {
|
|||||||
],
|
],
|
||||||
'avatars' => [
|
'avatars' => [
|
||||||
'kitsuUrl' => "users/avatars/{$id}/original.{$ext}",
|
'kitsuUrl' => "users/avatars/{$id}/original.{$ext}",
|
||||||
'width' => null,
|
'width' => NULL,
|
||||||
'height' => null,
|
'height' => NULL,
|
||||||
],
|
],
|
||||||
'characters' => [
|
'characters' => [
|
||||||
'kitsuUrl' => "characters/images/{$id}/original.{$ext}",
|
'kitsuUrl' => "characters/images/{$id}/original.{$ext}",
|
||||||
@ -79,8 +81,8 @@ final class Images extends BaseController {
|
|||||||
],
|
],
|
||||||
'people' => [
|
'people' => [
|
||||||
'kitsuUrl' => "people/images/{$id}/original.{$ext}",
|
'kitsuUrl' => "people/images/{$id}/original.{$ext}",
|
||||||
'width' => null,
|
'width' => NULL,
|
||||||
'height' => null,
|
'height' => NULL,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -89,6 +91,7 @@ final class Images extends BaseController {
|
|||||||
if (NULL === $imageType)
|
if (NULL === $imageType)
|
||||||
{
|
{
|
||||||
$this->getPlaceholder($baseSavePath, 200, 200);
|
$this->getPlaceholder($baseSavePath, 200, 200);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +115,7 @@ final class Images extends BaseController {
|
|||||||
{
|
{
|
||||||
$newUrl = str_replace($ext, $nextType[$ext], $currentUrl);
|
$newUrl = str_replace($ext, $nextType[$ext], $currentUrl);
|
||||||
$this->redirect($newUrl, 303);
|
$this->redirect($newUrl, 303);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +127,7 @@ final class Images extends BaseController {
|
|||||||
{
|
{
|
||||||
createPlaceholderImage("{$baseSavePath}/{$type}", $width, $height);
|
createPlaceholderImage("{$baseSavePath}/{$type}", $width, $height);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +149,7 @@ final class Images extends BaseController {
|
|||||||
if ($ext === 'gif')
|
if ($ext === 'gif')
|
||||||
{
|
{
|
||||||
file_put_contents("{$filePrefix}.gif", $data);
|
file_put_contents("{$filePrefix}.gif", $data);
|
||||||
\imagepalletetotruecolor($gdImg);
|
imagepalletetotruecolor($gdImg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// save the webp versions
|
// save the webp versions
|
||||||
@ -177,14 +182,10 @@ final class Images extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a placeholder for a missing image
|
* Get a placeholder for a missing image
|
||||||
*
|
|
||||||
* @param string $path
|
|
||||||
* @param int|null $width
|
|
||||||
* @param int|null $height
|
|
||||||
*/
|
*/
|
||||||
private function getPlaceholder (string $path, ?int $width = 200, ?int $height = NULL): void
|
private function getPlaceholder(string $path, ?int $width = 200, ?int $height = NULL): void
|
||||||
{
|
{
|
||||||
$height = $height ?? $width;
|
$height ??= $width;
|
||||||
|
|
||||||
$filename = $path . '/placeholder.png';
|
$filename = $path . '/placeholder.png';
|
||||||
|
|
||||||
@ -196,4 +197,4 @@ final class Images extends BaseController {
|
|||||||
header('Content-Type: image/png');
|
header('Content-Type: image/png');
|
||||||
echo file_get_contents($filename);
|
echo file_get_contents($filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,22 +6,22 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Controller;
|
namespace Aviat\AnimeClient\Controller;
|
||||||
|
|
||||||
use Aura\Router\Exception\RouteNotFound;
|
use Aura\Router\Exception\RouteNotFound;
|
||||||
use Aviat\AnimeClient\Controller;
|
|
||||||
use Aviat\AnimeClient\API\Kitsu\Transformer\MangaListTransformer;
|
use Aviat\AnimeClient\API\Kitsu\Transformer\MangaListTransformer;
|
||||||
use Aviat\AnimeClient\API\Mapping\MangaReadingStatus;
|
use Aviat\AnimeClient\API\Mapping\MangaReadingStatus;
|
||||||
|
use Aviat\AnimeClient\Controller as BaseController;
|
||||||
use Aviat\AnimeClient\Model\Manga as MangaModel;
|
use Aviat\AnimeClient\Model\Manga as MangaModel;
|
||||||
use Aviat\AnimeClient\Types\FormItem;
|
use Aviat\AnimeClient\Types\FormItem;
|
||||||
|
use Aviat\Ion\Attribute\Controller;
|
||||||
|
use Aviat\Ion\Attribute\Route;
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
||||||
use Aviat\Ion\Json;
|
use Aviat\Ion\Json;
|
||||||
@ -32,18 +32,17 @@ use Throwable;
|
|||||||
/**
|
/**
|
||||||
* Controller for manga list
|
* Controller for manga list
|
||||||
*/
|
*/
|
||||||
final class Manga extends Controller {
|
#[Controller('manga')]
|
||||||
|
final class Manga extends BaseController
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* The manga model
|
* The manga model
|
||||||
* @var MangaModel $model
|
|
||||||
*/
|
*/
|
||||||
protected MangaModel $model;
|
protected MangaModel $model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param ContainerInterface $container
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
@ -61,12 +60,8 @@ final class Manga extends Controller {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a section of the manga list
|
* Get a section of the manga list
|
||||||
*
|
|
||||||
* @param string $status
|
|
||||||
* @param string $view
|
|
||||||
* @return void
|
|
||||||
*@throws InvalidArgumentException
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('manga.list', '/list/{status}{/view}')]
|
||||||
public function index(string $status = 'all', ?string $view = ''): void
|
public function index(string $status = 'all', ?string $view = ''): void
|
||||||
{
|
{
|
||||||
if ( ! in_array($status, [
|
if ( ! in_array($status, [
|
||||||
@ -90,11 +85,11 @@ final class Manga extends Controller {
|
|||||||
|
|
||||||
$view_map = [
|
$view_map = [
|
||||||
'' => 'cover',
|
'' => 'cover',
|
||||||
'list' => 'list'
|
'list' => 'list',
|
||||||
];
|
];
|
||||||
|
|
||||||
$data = ($status !== 'all')
|
$data = ($status !== 'all')
|
||||||
? [ $statusTitle => $this->model->getList($statusTitle) ]
|
? [$statusTitle => $this->model->getList($statusTitle)]
|
||||||
: $this->model->getList('All');
|
: $this->model->getList('All');
|
||||||
|
|
||||||
$this->outputHTML('manga/' . $view_map[$view], [
|
$this->outputHTML('manga/' . $view_map[$view], [
|
||||||
@ -104,14 +99,9 @@ final class Manga extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Form to add an manga
|
* Form to add a manga
|
||||||
*
|
|
||||||
* @throws ContainerException
|
|
||||||
* @throws NotFoundException
|
|
||||||
* @throws RouteNotFound
|
|
||||||
* @throws InvalidArgumentException
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('manga.add.get', '/manga/add')]
|
||||||
public function addForm(): void
|
public function addForm(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
@ -125,21 +115,19 @@ final class Manga extends Controller {
|
|||||||
'Add'
|
'Add'
|
||||||
),
|
),
|
||||||
'action_url' => $this->url->generate('manga.add.post'),
|
'action_url' => $this->url->generate('manga.add.post'),
|
||||||
'status_list' => $statuses
|
'status_list' => $statuses,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an manga to the list
|
* Add a manga to the list
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @throws Throwable
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('manage.add.post', '/manga/add', Route::POST)]
|
||||||
public function add(): void
|
public function add(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
|
|
||||||
$data = (array)$this->request->getParsedBody();
|
$data = (array) $this->request->getParsedBody();
|
||||||
if ( ! array_key_exists('id', $data))
|
if ( ! array_key_exists('id', $data))
|
||||||
{
|
{
|
||||||
$this->redirect('manga/add', 303);
|
$this->redirect('manga/add', 303);
|
||||||
@ -150,7 +138,7 @@ final class Manga extends Controller {
|
|||||||
unset($data['mal_id']);
|
unset($data['mal_id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $this->model->createLibraryItem($data);
|
$result = $this->model->createItem($data);
|
||||||
|
|
||||||
if ($result)
|
if ($result)
|
||||||
{
|
{
|
||||||
@ -167,21 +155,14 @@ final class Manga extends Controller {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the manga edit form
|
* Show the manga edit form
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
* @param string $status
|
|
||||||
* @throws ContainerException
|
|
||||||
* @throws NotFoundException
|
|
||||||
* @throws RouteNotFound
|
|
||||||
* @throws InvalidArgumentException
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('manga.edit', '/manga/edit/{id}/{status}')]
|
||||||
public function edit(string $id, string $status = 'All'): void
|
public function edit(string $id, string $status = 'All'): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
|
|
||||||
$this->setSessionRedirect();
|
$this->setSessionRedirect();
|
||||||
$item = $this->model->getLibraryItem($id);
|
$item = $this->model->getItem($id);
|
||||||
$title = $this->formatTitle(
|
$title = $this->formatTitle(
|
||||||
$this->config->get('whose_list') . "'s Manga List",
|
$this->config->get('whose_list') . "'s Manga List",
|
||||||
'Edit'
|
'Edit'
|
||||||
@ -192,16 +173,15 @@ final class Manga extends Controller {
|
|||||||
'status_list' => MangaReadingStatus::KITSU_TO_TITLE,
|
'status_list' => MangaReadingStatus::KITSU_TO_TITLE,
|
||||||
'item' => $item,
|
'item' => $item,
|
||||||
'action' => $this->url->generate('update.post', [
|
'action' => $this->url->generate('update.post', [
|
||||||
'controller' => 'manga'
|
'controller' => 'manga',
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search for a manga to add to the list
|
* Search for a manga to add to the list
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('manga.search', '/manga/search')]
|
||||||
public function search(): void
|
public function search(): void
|
||||||
{
|
{
|
||||||
$queryParams = $this->request->getQueryParams();
|
$queryParams = $this->request->getQueryParams();
|
||||||
@ -211,21 +191,19 @@ final class Manga extends Controller {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update an manga item via a form submission
|
* Update an manga item via a form submission
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @throws Throwable
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('manga.update.post', '/manga/update', Route::POST)]
|
||||||
public function formUpdate(): void
|
public function formUpdate(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
|
|
||||||
$data = (array)$this->request->getParsedBody();
|
$data = (array) $this->request->getParsedBody();
|
||||||
|
|
||||||
// Do some minor data manipulation for
|
// Do some minor data manipulation for
|
||||||
// large form-based updates
|
// large form-based updates
|
||||||
$transformer = new MangaListTransformer();
|
$transformer = new MangaListTransformer();
|
||||||
$post_data = $transformer->untransform($data);
|
$post_data = $transformer->untransform($data);
|
||||||
$full_result = $this->model->updateLibraryItem(FormItem::from($post_data));
|
$full_result = $this->model->updateItem(FormItem::from($post_data));
|
||||||
|
|
||||||
if ($full_result['statusCode'] === 200)
|
if ($full_result['statusCode'] === 200)
|
||||||
{
|
{
|
||||||
@ -235,7 +213,6 @@ final class Manga extends Controller {
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
$this->setFlashMessage('Failed to update manga.', 'error');
|
$this->setFlashMessage('Failed to update manga.', 'error');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->sessionRedirect();
|
$this->sessionRedirect();
|
||||||
@ -243,22 +220,22 @@ final class Manga extends Controller {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment the progress of a manga item
|
* Increment the progress of a manga item
|
||||||
* @throws Throwable
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('manga.increment', '/manga/increment', Route::POST)]
|
||||||
public function increment(): void
|
public function increment(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
|
|
||||||
if (str_contains($this->request->getHeader('content-type')[0], 'application/json'))
|
if (str_contains($this->request->getHeader('content-type')[0], 'application/json'))
|
||||||
{
|
{
|
||||||
$data = Json::decode((string)$this->request->getBody());
|
$data = Json::decode((string) $this->request->getBody());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$data = $this->request->getParsedBody();
|
$data = $this->request->getParsedBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
$res = $this->model->incrementLibraryItem(FormItem::from($data));
|
$res = $this->model->incrementItem(FormItem::from($data));
|
||||||
$body = $res['body'];
|
$body = $res['body'];
|
||||||
$statusCode = $res['statusCode'];
|
$statusCode = $res['statusCode'];
|
||||||
|
|
||||||
@ -268,16 +245,14 @@ final class Manga extends Controller {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an manga from the list
|
* Remove an manga from the list
|
||||||
*
|
|
||||||
* @throws Throwable
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('manga.delete', '/manga/delete', Route::POST)]
|
||||||
public function delete(): void
|
public function delete(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
|
|
||||||
$body = (array)$this->request->getParsedBody();
|
$body = (array) $this->request->getParsedBody();
|
||||||
$response = $this->model->deleteLibraryItem($body['id'], $body['mal_id']);
|
$response = $this->model->deleteItem(FormItem::from($body));
|
||||||
|
|
||||||
if ($response)
|
if ($response)
|
||||||
{
|
{
|
||||||
@ -294,12 +269,8 @@ final class Manga extends Controller {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* View details of an manga
|
* View details of an manga
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
* @throws InvalidArgumentException
|
|
||||||
* @throws Throwable
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('manga.details', '/manga/details/{id}')]
|
||||||
public function details(string $id): void
|
public function details(string $id): void
|
||||||
{
|
{
|
||||||
$data = $this->model->getManga($id);
|
$data = $this->model->getManga($id);
|
||||||
@ -311,6 +282,7 @@ final class Manga extends Controller {
|
|||||||
'Manga not found',
|
'Manga not found',
|
||||||
'Manga Not Found'
|
'Manga Not Found'
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,11 +298,8 @@ final class Manga extends Controller {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* View details of a random manga
|
* View details of a random manga
|
||||||
*
|
|
||||||
* @throws InvalidArgumentException
|
|
||||||
* @throws Throwable
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('manga.random', '/manga/details/random')]
|
||||||
public function random(): void
|
public function random(): void
|
||||||
{
|
{
|
||||||
$data = $this->model->getRandomManga();
|
$data = $this->model->getRandomManga();
|
||||||
@ -342,6 +311,7 @@ final class Manga extends Controller {
|
|||||||
'Manga not found',
|
'Manga not found',
|
||||||
'Manga Not Found'
|
'Manga Not Found'
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,4 +325,5 @@ final class Manga extends Controller {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// End of MangaController.php
|
// End of MangaController.php
|
||||||
|
@ -6,30 +6,52 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Controller;
|
namespace Aviat\AnimeClient\Controller;
|
||||||
|
|
||||||
|
use Aviat\AnimeClient\API\Kitsu\Model;
|
||||||
|
use Aviat\AnimeClient\API\Kitsu\Transformer\CharacterTransformer;
|
||||||
|
use Aviat\AnimeClient\API\Kitsu\Transformer\PersonTransformer;
|
||||||
use Aviat\AnimeClient\Controller as BaseController;
|
use Aviat\AnimeClient\Controller as BaseController;
|
||||||
use Aviat\AnimeClient\Enum\EventType;
|
use Aviat\AnimeClient\Enum\EventType;
|
||||||
|
use Aviat\Ion\Attribute\DefaultController;
|
||||||
|
use Aviat\Ion\Attribute\Route;
|
||||||
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\Event;
|
use Aviat\Ion\Event;
|
||||||
use Aviat\Ion\View\HtmlView;
|
use Aviat\Ion\View\HtmlView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for handling routes that don't fit elsewhere
|
* Controller for handling routes that don't fit elsewhere
|
||||||
*/
|
*/
|
||||||
final class Misc extends BaseController {
|
#[DefaultController]
|
||||||
|
final class Misc extends BaseController
|
||||||
|
{
|
||||||
|
private Model $model;
|
||||||
|
|
||||||
|
public function __construct(ContainerInterface $container)
|
||||||
|
{
|
||||||
|
parent::__construct($container);
|
||||||
|
$this->model = $container->get('kitsu-model');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect to the default controller/url from an empty path
|
||||||
|
*/
|
||||||
|
#[Route('index_redirect', '/')]
|
||||||
|
public function index(): void
|
||||||
|
{
|
||||||
|
parent::redirectToDefaultRoute();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Purges the API cache
|
* Purges the API cache
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('cache_purge', '/cache_purge')]
|
||||||
public function clearCache(): void
|
public function clearCache(): void
|
||||||
{
|
{
|
||||||
$this->checkAuth();
|
$this->checkAuth();
|
||||||
@ -37,16 +59,14 @@ final class Misc extends BaseController {
|
|||||||
Event::emit(EventType::CLEAR_CACHE);
|
Event::emit(EventType::CLEAR_CACHE);
|
||||||
|
|
||||||
$this->outputHTML('blank', [
|
$this->outputHTML('blank', [
|
||||||
'title' => 'Cache cleared'
|
'title' => 'Cache cleared',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the login form
|
* Show the login form
|
||||||
*
|
|
||||||
* @param string $status
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('login', '/login')]
|
||||||
public function login(string $status = ''): void
|
public function login(string $status = ''): void
|
||||||
{
|
{
|
||||||
$message = '';
|
$message = '';
|
||||||
@ -63,22 +83,22 @@ final class Misc extends BaseController {
|
|||||||
|
|
||||||
$this->outputHTML('login', [
|
$this->outputHTML('login', [
|
||||||
'title' => 'Api login',
|
'title' => 'Api login',
|
||||||
'message' => $message
|
'message' => $message,
|
||||||
], $view);
|
], $view);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt login authentication
|
* Attempt login authentication
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('login.post', '/login', Route::POST)]
|
||||||
public function loginAction(): void
|
public function loginAction(): void
|
||||||
{
|
{
|
||||||
$post = (array)$this->request->getParsedBody();
|
$post = (array) $this->request->getParsedBody();
|
||||||
|
|
||||||
if ($this->auth->authenticate($post['password']))
|
if ($this->auth->authenticate($post['password']))
|
||||||
{
|
{
|
||||||
$this->sessionRedirect();
|
$this->sessionRedirect();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,9 +112,8 @@ final class Misc extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Deauthorize the current user
|
* Deauthorize the current user
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('logout', '/logout')]
|
||||||
public function logout(): void
|
public function logout(): void
|
||||||
{
|
{
|
||||||
$this->auth->logout();
|
$this->auth->logout();
|
||||||
@ -105,8 +124,72 @@ final class Misc extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* Check if the current user is logged in
|
* Check if the current user is logged in
|
||||||
*/
|
*/
|
||||||
|
#[Route('heartbeat', '/heartbeat')]
|
||||||
public function heartbeat(): void
|
public function heartbeat(): void
|
||||||
{
|
{
|
||||||
$this->outputJSON(['hasAuth' => $this->auth->isAuthenticated()], 200);
|
$this->outputJSON(['hasAuth' => $this->auth->isAuthenticated()], 200);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Show information about a character
|
||||||
|
*/
|
||||||
|
#[Route('character', '/character/{slug}')]
|
||||||
|
public function character(string $slug): void
|
||||||
|
{
|
||||||
|
$rawData = $this->model->getCharacter($slug);
|
||||||
|
|
||||||
|
if (( ! array_key_exists('data', $rawData)) || empty($rawData['data']))
|
||||||
|
{
|
||||||
|
$this->notFound(
|
||||||
|
$this->formatTitle(
|
||||||
|
'Characters',
|
||||||
|
'Character not found'
|
||||||
|
),
|
||||||
|
'Character Not Found'
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = (new CharacterTransformer())->transform($rawData)->toArray();
|
||||||
|
|
||||||
|
$this->outputHTML('character/details', [
|
||||||
|
'title' => $this->formatTitle(
|
||||||
|
'Characters',
|
||||||
|
$data['name']
|
||||||
|
),
|
||||||
|
'data' => $data,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show information about a person
|
||||||
|
*/
|
||||||
|
#[Route('person', '/people/{slug}')]
|
||||||
|
public function person(string $slug): void
|
||||||
|
{
|
||||||
|
$rawData = $this->model->getPerson($slug);
|
||||||
|
$data = (new PersonTransformer())->transform($rawData)->toArray();
|
||||||
|
|
||||||
|
if (( ! array_key_exists('data', $rawData)) || empty($rawData['data']))
|
||||||
|
{
|
||||||
|
$this->notFound(
|
||||||
|
$this->formatTitle(
|
||||||
|
'People',
|
||||||
|
'Person not found'
|
||||||
|
),
|
||||||
|
'Person Not Found'
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->outputHTML('person/details', [
|
||||||
|
'title' => $this->formatTitle(
|
||||||
|
'People',
|
||||||
|
$data['name']
|
||||||
|
),
|
||||||
|
'data' => $data,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,38 +6,34 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Controller;
|
namespace Aviat\AnimeClient\Controller;
|
||||||
|
|
||||||
use Aviat\AnimeClient\API\Kitsu\Model;
|
use Aviat\AnimeClient\API\Kitsu\Model;
|
||||||
use Aviat\AnimeClient\Controller as BaseController;
|
|
||||||
use Aviat\AnimeClient\API\Kitsu\Transformer\PersonTransformer;
|
use Aviat\AnimeClient\API\Kitsu\Transformer\PersonTransformer;
|
||||||
|
use Aviat\AnimeClient\Controller as BaseController;
|
||||||
|
|
||||||
|
use Aviat\Ion\Attribute\Controller;
|
||||||
|
use Aviat\Ion\Attribute\Route;
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\Di\Exception\ContainerException;
|
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
||||||
use Aviat\Ion\Di\Exception\NotFoundException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for People pages
|
* Controller for People pages
|
||||||
*/
|
*/
|
||||||
final class People extends BaseController {
|
#[Controller]
|
||||||
|
final class People extends BaseController
|
||||||
/**
|
{
|
||||||
* @var Model
|
|
||||||
*/
|
|
||||||
private Model $model;
|
private Model $model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* People constructor.
|
* People constructor.
|
||||||
*
|
*
|
||||||
* @param ContainerInterface $container
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
@ -49,10 +45,8 @@ final class People extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Show information about a person
|
* Show information about a person
|
||||||
*
|
|
||||||
* @param string $slug
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('person', '/people/{slug}')]
|
||||||
public function index(string $slug): void
|
public function index(string $slug): void
|
||||||
{
|
{
|
||||||
$rawData = $this->model->getPerson($slug);
|
$rawData = $this->model->getPerson($slug);
|
||||||
@ -79,4 +73,4 @@ final class People extends BaseController {
|
|||||||
'data' => $data,
|
'data' => $data,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Controller;
|
namespace Aviat\AnimeClient\Controller;
|
||||||
@ -20,29 +18,23 @@ use Aura\Router\Exception\RouteNotFound;
|
|||||||
use Aviat\AnimeClient\API\Anilist\Model as AnilistModel;
|
use Aviat\AnimeClient\API\Anilist\Model as AnilistModel;
|
||||||
use Aviat\AnimeClient\Controller as BaseController;
|
use Aviat\AnimeClient\Controller as BaseController;
|
||||||
use Aviat\AnimeClient\Model\Settings as SettingsModel;
|
use Aviat\AnimeClient\Model\Settings as SettingsModel;
|
||||||
|
use Aviat\Ion\Attribute\Controller;
|
||||||
|
use Aviat\Ion\Attribute\Route;
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\Di\Exception\ContainerException;
|
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
||||||
use Aviat\Ion\Di\Exception\NotFoundException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for user settings
|
* Controller for user settings
|
||||||
*/
|
*/
|
||||||
final class Settings extends BaseController {
|
#[Controller]
|
||||||
|
final class Settings extends BaseController
|
||||||
/**
|
{
|
||||||
* @var AnilistModel
|
|
||||||
*/
|
|
||||||
private AnilistModel $anilistModel;
|
private AnilistModel $anilistModel;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var SettingsModel
|
|
||||||
*/
|
|
||||||
private SettingsModel $settingsModel;
|
private SettingsModel $settingsModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings constructor.
|
* Settings constructor.
|
||||||
*
|
*
|
||||||
* @param ContainerInterface $container
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
@ -60,6 +52,7 @@ final class Settings extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* Show the user settings, if logged in
|
* Show the user settings, if logged in
|
||||||
*/
|
*/
|
||||||
|
#[Route('settings', '/settings')]
|
||||||
public function index(): void
|
public function index(): void
|
||||||
{
|
{
|
||||||
$auth = $this->container->get('auth');
|
$auth = $this->container->get('auth');
|
||||||
@ -82,9 +75,10 @@ final class Settings extends BaseController {
|
|||||||
*
|
*
|
||||||
* @throws RouteNotFound
|
* @throws RouteNotFound
|
||||||
*/
|
*/
|
||||||
|
#[Route('settings-post', '/settings/update', Route::POST)]
|
||||||
public function update(): void
|
public function update(): void
|
||||||
{
|
{
|
||||||
$post = (array)$this->request->getParsedBody();
|
$post = (array) $this->request->getParsedBody();
|
||||||
unset($post['settings-tabs']);
|
unset($post['settings-tabs']);
|
||||||
|
|
||||||
$saved = $this->settingsModel->saveSettingsFile($post);
|
$saved = $this->settingsModel->saveSettingsFile($post);
|
||||||
@ -102,6 +96,7 @@ final class Settings extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* Redirect to Anilist to start Oauth flow
|
* Redirect to Anilist to start Oauth flow
|
||||||
*/
|
*/
|
||||||
|
#[Route('anilist-redirect', '/anilist-redirect')]
|
||||||
public function anilistRedirect(): void
|
public function anilistRedirect(): void
|
||||||
{
|
{
|
||||||
$query = http_build_query([
|
$query = http_build_query([
|
||||||
@ -118,6 +113,7 @@ final class Settings extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* Oauth callback for Anilist API
|
* Oauth callback for Anilist API
|
||||||
*/
|
*/
|
||||||
|
#[Route('anilist-callback', '/anilist-oauth')]
|
||||||
public function anilistCallback(): void
|
public function anilistCallback(): void
|
||||||
{
|
{
|
||||||
$query = $this->request->getQueryParams();
|
$query = $this->request->getQueryParams();
|
||||||
@ -130,6 +126,7 @@ final class Settings extends BaseController {
|
|||||||
if (array_key_exists('error', $authData))
|
if (array_key_exists('error', $authData))
|
||||||
{
|
{
|
||||||
$this->errorPage(400, 'Error Linking Account', $authData['hint']);
|
$this->errorPage(400, 'Error Linking Account', $authData['hint']);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +144,7 @@ final class Settings extends BaseController {
|
|||||||
{
|
{
|
||||||
$newSettings[$key] = $value;
|
$newSettings[$key] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($newSettings['config']);
|
unset($newSettings['config']);
|
||||||
|
|
||||||
$saved = $this->settingsModel->saveSettingsFile($newSettings);
|
$saved = $this->settingsModel->saveSettingsFile($newSettings);
|
||||||
@ -160,4 +158,4 @@ final class Settings extends BaseController {
|
|||||||
|
|
||||||
$this->redirect($redirectUrl, 303);
|
$this->redirect($redirectUrl, 303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,10 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Controller;
|
namespace Aviat\AnimeClient\Controller;
|
||||||
@ -20,24 +18,22 @@ use Aviat\AnimeClient\API\Kitsu\Model;
|
|||||||
use Aviat\AnimeClient\API\Kitsu\Transformer\UserTransformer;
|
use Aviat\AnimeClient\API\Kitsu\Transformer\UserTransformer;
|
||||||
use Aviat\AnimeClient\Controller as BaseController;
|
use Aviat\AnimeClient\Controller as BaseController;
|
||||||
|
|
||||||
|
use Aviat\Ion\Attribute\Controller;
|
||||||
|
use Aviat\Ion\Attribute\Route;
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\Di\Exception\ContainerException;
|
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
|
||||||
use Aviat\Ion\Di\Exception\NotFoundException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for handling routes that don't fit elsewhere
|
* Controller for handling routes that don't fit elsewhere
|
||||||
*/
|
*/
|
||||||
final class User extends BaseController {
|
#[Controller]
|
||||||
|
final class User extends BaseController
|
||||||
/**
|
{
|
||||||
* @var Model
|
|
||||||
*/
|
|
||||||
private Model $kitsuModel;
|
private Model $kitsuModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User constructor.
|
* User constructor.
|
||||||
*
|
*
|
||||||
* @param ContainerInterface $container
|
|
||||||
* @throws ContainerException
|
* @throws ContainerException
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
@ -51,6 +47,7 @@ final class User extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* Show the user profile page for the configured user
|
* Show the user profile page for the configured user
|
||||||
*/
|
*/
|
||||||
|
#[Route('default_user_info', '/me')]
|
||||||
public function me(): void
|
public function me(): void
|
||||||
{
|
{
|
||||||
$this->about('me');
|
$this->about('me');
|
||||||
@ -58,10 +55,8 @@ final class User extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the user profile page
|
* Show the user profile page
|
||||||
*
|
|
||||||
* @param string $username
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
|
#[Route('user_info', '/user/{username}')]
|
||||||
public function about(string $username): void
|
public function about(string $username): void
|
||||||
{
|
{
|
||||||
$isMainUser = $username === 'me';
|
$isMainUser = $username === 'me';
|
||||||
@ -82,4 +77,4 @@ final class User extends BaseController {
|
|||||||
'data' => $data,
|
'data' => $data,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,14 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient;
|
namespace Aviat\AnimeClient;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Enum\EventType;
|
|
||||||
use Aviat\Ion\Event;
|
|
||||||
use Aviat\Ion\Json;
|
|
||||||
use Aura\Router\{
|
use Aura\Router\{
|
||||||
Map,
|
Map,
|
||||||
Matcher,
|
Matcher,
|
||||||
@ -26,9 +21,10 @@ use Aura\Router\{
|
|||||||
Rule,
|
Rule,
|
||||||
};
|
};
|
||||||
use Aviat\AnimeClient\API\FailedResponseException;
|
use Aviat\AnimeClient\API\FailedResponseException;
|
||||||
|
use Aviat\AnimeClient\Enum\EventType;
|
||||||
use Aviat\Ion\Di\ContainerInterface;
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
use Aviat\Ion\Friend;
|
|
||||||
use Aviat\Ion\Type\StringType;
|
use Aviat\Ion\Type\StringType;
|
||||||
|
use Aviat\Ion\{Event, Friend, Json};
|
||||||
use LogicException;
|
use LogicException;
|
||||||
use ReflectionException;
|
use ReflectionException;
|
||||||
|
|
||||||
@ -37,42 +33,37 @@ use function Aviat\Ion\_dir;
|
|||||||
/**
|
/**
|
||||||
* Basic routing/ dispatch
|
* Basic routing/ dispatch
|
||||||
*/
|
*/
|
||||||
final class Dispatcher extends RoutingBase {
|
final class Dispatcher extends RoutingBase
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* The route-matching object
|
* The route-matching object
|
||||||
* @var Map $router
|
|
||||||
*/
|
*/
|
||||||
protected Map $router;
|
protected Map $router;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The route matcher
|
* The route matcher
|
||||||
* @var Matcher $matcher
|
|
||||||
*/
|
*/
|
||||||
protected Matcher $matcher;
|
protected Matcher $matcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Routing array
|
* Routing array
|
||||||
* @var array
|
|
||||||
*/
|
*/
|
||||||
protected array $routes;
|
protected array $routes = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Routes added to router
|
* Routes added to router
|
||||||
* @var array $outputRoutes
|
|
||||||
*/
|
*/
|
||||||
protected array $outputRoutes;
|
protected array $outputRoutes = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
|
||||||
* @param ContainerInterface $container
|
|
||||||
*/
|
*/
|
||||||
public function __construct(ContainerInterface $container)
|
public function __construct(ContainerInterface $container)
|
||||||
{
|
{
|
||||||
parent::__construct($container);
|
parent::__construct($container);
|
||||||
$router = $this->container->get('aura-router');
|
$router = $this->container->get('aura-router');
|
||||||
$this->router = $router->getMap();
|
$this->router = $router->getMap();
|
||||||
|
|
||||||
$this->matcher = $router->getMatcher();
|
$this->matcher = $router->getMatcher();
|
||||||
$this->routes = $this->config->get('routes');
|
$this->routes = $this->config->get('routes');
|
||||||
$this->outputRoutes = $this->setupRoutes();
|
$this->outputRoutes = $this->setupRoutes();
|
||||||
@ -80,10 +71,8 @@ final class Dispatcher extends RoutingBase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current route object, if one matches
|
* Get the current route object, if one matches
|
||||||
*
|
|
||||||
* @return Route|false
|
|
||||||
*/
|
*/
|
||||||
public function getRoute(): Route | false
|
public function getRoute(): Route|false
|
||||||
{
|
{
|
||||||
$logger = $this->container->getLogger();
|
$logger = $this->container->getLogger();
|
||||||
|
|
||||||
@ -94,7 +83,7 @@ final class Dispatcher extends RoutingBase {
|
|||||||
{
|
{
|
||||||
$logger->info('Dispatcher - Routing data from get_route method');
|
$logger->info('Dispatcher - Routing data from get_route method');
|
||||||
$logger->info(print_r([
|
$logger->info(print_r([
|
||||||
'route_path' => $routePath
|
'route_path' => $routePath,
|
||||||
], TRUE));
|
], TRUE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +93,7 @@ final class Dispatcher extends RoutingBase {
|
|||||||
/**
|
/**
|
||||||
* Get list of routes applied
|
* Get list of routes applied
|
||||||
*
|
*
|
||||||
* @return array
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
public function getOutputRoutes(): array
|
public function getOutputRoutes(): array
|
||||||
{
|
{
|
||||||
@ -114,11 +103,9 @@ final class Dispatcher extends RoutingBase {
|
|||||||
/**
|
/**
|
||||||
* Handle the current route
|
* Handle the current route
|
||||||
*
|
*
|
||||||
* @param object|null $route
|
|
||||||
* @return void
|
|
||||||
* @throws ReflectionException
|
* @throws ReflectionException
|
||||||
*/
|
*/
|
||||||
public function __invoke(object $route = NULL): void
|
public function __invoke(?object $route = NULL): void
|
||||||
{
|
{
|
||||||
$logger = $this->container->getLogger();
|
$logger = $this->container->getLogger();
|
||||||
|
|
||||||
@ -142,6 +129,7 @@ final class Dispatcher extends RoutingBase {
|
|||||||
$actionMethod = $errorRoute['action_method'];
|
$actionMethod = $errorRoute['action_method'];
|
||||||
$params = $errorRoute['params'];
|
$params = $errorRoute['params'];
|
||||||
$this->call($controllerName, $actionMethod, $params);
|
$this->call($controllerName, $actionMethod, $params);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,9 +145,8 @@ final class Dispatcher extends RoutingBase {
|
|||||||
* Parse out the arguments for the appropriate controller for
|
* Parse out the arguments for the appropriate controller for
|
||||||
* the current route
|
* the current route
|
||||||
*
|
*
|
||||||
* @param Friend $route
|
|
||||||
* @throws LogicException
|
* @throws LogicException
|
||||||
* @return array
|
* @return array<string, mixed>
|
||||||
*/
|
*/
|
||||||
protected function processRoute(Friend $route): array
|
protected function processRoute(Friend $route): array
|
||||||
{
|
{
|
||||||
@ -185,6 +172,7 @@ final class Dispatcher extends RoutingBase {
|
|||||||
if ( ! empty($route->__get('tokens')))
|
if ( ! empty($route->__get('tokens')))
|
||||||
{
|
{
|
||||||
$tokens = array_keys($route->__get('tokens'));
|
$tokens = array_keys($route->__get('tokens'));
|
||||||
|
|
||||||
foreach ($tokens as $param)
|
foreach ($tokens as $param)
|
||||||
{
|
{
|
||||||
if (array_key_exists($param, $route->attributes))
|
if (array_key_exists($param, $route->attributes))
|
||||||
@ -193,6 +181,7 @@ final class Dispatcher extends RoutingBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$logger = $this->container->getLogger();
|
$logger = $this->container->getLogger();
|
||||||
if ($logger !== NULL)
|
if ($logger !== NULL)
|
||||||
{
|
{
|
||||||
@ -202,14 +191,12 @@ final class Dispatcher extends RoutingBase {
|
|||||||
return [
|
return [
|
||||||
'controller_name' => $controllerName,
|
'controller_name' => $controllerName,
|
||||||
'action_method' => $actionMethod,
|
'action_method' => $actionMethod,
|
||||||
'params' => $params
|
'params' => $params,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the type of route, to select the current controller
|
* Get the type of route, to select the current controller
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function getController(): string
|
public function getController(): string
|
||||||
{
|
{
|
||||||
@ -237,7 +224,7 @@ final class Dispatcher extends RoutingBase {
|
|||||||
/**
|
/**
|
||||||
* Get the list of controllers in the default namespace
|
* Get the list of controllers in the default namespace
|
||||||
*
|
*
|
||||||
* @return array
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
public function getControllerList(): array
|
public function getControllerList(): array
|
||||||
{
|
{
|
||||||
@ -247,6 +234,7 @@ final class Dispatcher extends RoutingBase {
|
|||||||
|
|
||||||
$path = str_replace($find, $replace, $defaultNamespace);
|
$path = str_replace($find, $replace, $defaultNamespace);
|
||||||
$path = trim($path, '/');
|
$path = trim($path, '/');
|
||||||
|
|
||||||
$actualPath = realpath(_dir(SRC_DIR, $path));
|
$actualPath = realpath(_dir(SRC_DIR, $path));
|
||||||
$classFiles = glob("{$actualPath}/*.php");
|
$classFiles = glob("{$actualPath}/*.php");
|
||||||
if ($classFiles === FALSE)
|
if ($classFiles === FALSE)
|
||||||
@ -259,7 +247,7 @@ final class Dispatcher extends RoutingBase {
|
|||||||
foreach ($classFiles as $file)
|
foreach ($classFiles as $file)
|
||||||
{
|
{
|
||||||
$rawClassName = basename(str_replace('.php', '', $file));
|
$rawClassName = basename(str_replace('.php', '', $file));
|
||||||
$path = (string)StringType::from($rawClassName)->dasherize();
|
$path = (string) StringType::from($rawClassName)->dasherize();
|
||||||
$className = trim($defaultNamespace . '\\' . $rawClassName, '\\');
|
$className = trim($defaultNamespace . '\\' . $rawClassName, '\\');
|
||||||
|
|
||||||
$controllers[$path] = $className;
|
$controllers[$path] = $className;
|
||||||
@ -272,10 +260,7 @@ final class Dispatcher extends RoutingBase {
|
|||||||
* Create the controller object and call the appropriate
|
* Create the controller object and call the appropriate
|
||||||
* method
|
* method
|
||||||
*
|
*
|
||||||
* @param string $controllerName - The full namespace of the controller class
|
* @param string $controllerName - The full namespace of the controller class
|
||||||
* @param string $method
|
|
||||||
* @param array $params
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
protected function call(string $controllerName, string $method, array $params): void
|
protected function call(string $controllerName, string $method, array $params): void
|
||||||
{
|
{
|
||||||
@ -289,16 +274,19 @@ final class Dispatcher extends RoutingBase {
|
|||||||
$logger?->debug('Dispatcher - controller arguments', $params);
|
$logger?->debug('Dispatcher - controller arguments', $params);
|
||||||
|
|
||||||
$params = array_values($params);
|
$params = array_values($params);
|
||||||
$controller->$method(...$params);
|
$controller->{$method}(...$params);
|
||||||
}
|
}
|
||||||
catch (FailedResponseException)
|
catch (FailedResponseException)
|
||||||
{
|
{
|
||||||
$controllerName = DEFAULT_CONTROLLER;
|
$controllerName = DEFAULT_CONTROLLER;
|
||||||
$controller = new $controllerName($this->container);
|
$controller = new $controllerName($this->container);
|
||||||
$controller->errorPage(500,
|
$controller->errorPage(
|
||||||
|
500,
|
||||||
'API request timed out',
|
'API request timed out',
|
||||||
'Failed to retrieve data from API (╯°□°)╯︵ ┻━┻');
|
'Failed to retrieve data from API (╯°□°)╯︵ ┻━┻'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finally
|
/* finally
|
||||||
{
|
{
|
||||||
// Log out on session/api token expiration
|
// Log out on session/api token expiration
|
||||||
@ -312,6 +300,7 @@ final class Dispatcher extends RoutingBase {
|
|||||||
/**
|
/**
|
||||||
* Get the appropriate params for the error page
|
* Get the appropriate params for the error page
|
||||||
* passed on the failed route
|
* passed on the failed route
|
||||||
|
* @return mixed[][]
|
||||||
*/
|
*/
|
||||||
protected function getErrorParams(): array
|
protected function getErrorParams(): array
|
||||||
{
|
{
|
||||||
@ -328,12 +317,12 @@ final class Dispatcher extends RoutingBase {
|
|||||||
|
|
||||||
$params = [];
|
$params = [];
|
||||||
|
|
||||||
switch($failure->failedRule) {
|
switch ($failure->failedRule) {
|
||||||
case Rule\Allows::class:
|
case Rule\Allows::class:
|
||||||
$params = [
|
$params = [
|
||||||
'http_code' => 405,
|
'http_code' => 405,
|
||||||
'title' => '405 Method Not Allowed',
|
'title' => '405 Method Not Allowed',
|
||||||
'message' => 'Invalid HTTP Verb'
|
'message' => 'Invalid HTTP Verb',
|
||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -341,7 +330,7 @@ final class Dispatcher extends RoutingBase {
|
|||||||
$params = [
|
$params = [
|
||||||
'http_code' => 406,
|
'http_code' => 406,
|
||||||
'title' => '406 Not Acceptable',
|
'title' => '406 Not Acceptable',
|
||||||
'message' => 'Unacceptable content type'
|
'message' => 'Unacceptable content type',
|
||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -353,14 +342,14 @@ final class Dispatcher extends RoutingBase {
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
'params' => $params,
|
'params' => $params,
|
||||||
'action_method' => $actionMethod
|
'action_method' => $actionMethod,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select controller based on the current url, and apply its relevant routes
|
* Select controller based on the current url, and apply its relevant routes
|
||||||
*
|
*
|
||||||
* @return array
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
protected function setupRoutes(): array
|
protected function setupRoutes(): array
|
||||||
{
|
{
|
||||||
@ -368,6 +357,7 @@ final class Dispatcher extends RoutingBase {
|
|||||||
|
|
||||||
// Add routes
|
// Add routes
|
||||||
$routes = [];
|
$routes = [];
|
||||||
|
|
||||||
foreach ($this->routes as $name => &$route)
|
foreach ($this->routes as $name => &$route)
|
||||||
{
|
{
|
||||||
$path = $route['path'];
|
$path = $route['path'];
|
||||||
@ -400,14 +390,15 @@ final class Dispatcher extends RoutingBase {
|
|||||||
// Add the route to the router object
|
// Add the route to the router object
|
||||||
if ( ! array_key_exists('tokens', $route))
|
if ( ! array_key_exists('tokens', $route))
|
||||||
{
|
{
|
||||||
$routes[] = $this->router->$verb($name, $path)->defaults($route);
|
$routes[] = $this->router->{$verb}($name, $path)->defaults($route);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tokens = $route['tokens'];
|
$tokens = $route['tokens'];
|
||||||
unset($route['tokens']);
|
unset($route['tokens']);
|
||||||
|
|
||||||
$routes[] = $this->router->$verb($name, $path)
|
$routes[] = $this->router->{$verb}($name, $path)
|
||||||
->defaults($route)
|
->defaults($route)
|
||||||
->tokens($tokens);
|
->tokens($tokens);
|
||||||
}
|
}
|
||||||
@ -415,4 +406,5 @@ final class Dispatcher extends RoutingBase {
|
|||||||
return $routes;
|
return $routes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// End of Dispatcher.php
|
|
||||||
|
// End of Dispatcher.php
|
||||||
|
@ -6,19 +6,18 @@
|
|||||||
*
|
*
|
||||||
* PHP version 8
|
* PHP version 8
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page>
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
|
||||||
* @copyright 2015 - 2021 Timothy J. Warren
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 5.2
|
* @version 5.2
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\Enum;
|
namespace Aviat\AnimeClient\Enum;
|
||||||
|
|
||||||
use Aviat\Ion\Enum;
|
use Aviat\Ion\Enum;
|
||||||
|
|
||||||
final class API extends Enum {
|
final class API extends Enum
|
||||||
|
{
|
||||||
public const ANILIST = 'anilist';
|
public const ANILIST = 'anilist';
|
||||||
public const KITSU = 'kitsu';
|
public const KITSU = 'kitsu';
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user