Merge remote-tracking branch 'origin/develop'
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good
Details
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good
Details
This commit is contained in:
commit
5076657b38
|
@ -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
|
|
@ -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')();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -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…
Reference in New Issue