/** * AniList Episode & Season Importer for AnimeStream */ add_action('add_meta_boxes', 'ts_anilist_importer_add_metabox'); function ts_anilist_importer_add_metabox() {    add_meta_box(        'ts-anilist-importer',        'AniList Full Importer',        'ts_anilist_importer_callback',        'anime',        'normal',        'high'    ); } function ts_anilist_importer_callback($post) {    $mal_id = get_post_meta($post->ID, 'ero_series_generate', true);    ?>
  

Fetch all data (Series info, Seasons, and Episodes) directly from AniList.

  
      
                                                             
  
     
} add_action('wp_ajax_ts_fetch_anilist_full', 'ts_handle_fetch_anilist_full'); function ts_handle_fetch_anilist_full() {    $initial_id = intval($_POST['id']);    $post_id = intval($_POST['post_id']);    if (!$initial_id) wp_send_json_error('Invalid ID');    $media = ts_get_anilist_media_details($initial_id);    if (!$media) wp_send_json_error('Anime not found');    $franchise_ids = [$initial_id];    $queue = [$initial_id];    $depth = 0;    $discovered_nodes = [$initial_id => $media];    while (!empty($queue) && $depth < 12) {        $curr_id = array_shift($queue);        $curr_node = $discovered_nodes[$curr_id] ?? ts_get_anilist_media_details($curr_id);               if ($curr_node && !empty($curr_node['relations']['edges'])) {            foreach ($curr_node['relations']['edges'] as $edge) {                $node = $edge['node'];                if (in_array($edge['relationType'], ['SEQUEL', 'PREQUEL', 'PARENT']) && !in_array($node['idMal'], $franchise_ids)) {                    if ($node['type'] === 'ANIME' && !empty($node['idMal'])) {                        $franchise_ids[] = $node['idMal'];                        $queue[] = $node['idMal'];                        $depth++;                    }                }            }        }    }    $franchise = [];    foreach ($franchise_ids as $fid) {        $node = ($fid == $initial_id) ? $media : ts_get_anilist_media_details($fid);        if ($node && in_array($node['format'], ['TV', 'TV_SHORT', 'ONA', 'MOVIE'])) {            $f_title = !empty($node['title']['romaji']) ? $node['title']['romaji'] : $node['title']['romaji'];            $franchise[] = [                'title' => $f_title,                'idMal' => $node['idMal'],                'year' => $node['startDate']['year'] ?? '?',                'status' => $node['status'],                'sort_key' => sprintf('%04d%02d%02d', $node['startDate']['year'] ?? 0, $node['startDate']['month'] ?? 0, $node['startDate']['day'] ?? 0)            ];        }    }    $episodes = [];    $existing_nums = [];    $existing_posts = get_posts(['post_type'=>'post', 'meta_key'=>'ero_seri', 'meta_value'=>$post_id, 'posts_per_page'=>-1]);    foreach ($existing_posts as $p) {        $n = get_post_meta($p->ID, 'ero_episodebaru', true);        if ($n) $existing_nums[] = (int)$n;    }    $manual_count = isset($_POST['manual_ep_count']) ? intval($_POST['manual_ep_count']) : 0;    $total = (int)$media['episodes'];    $max_stream = 0;    $next_airing = 0;       if (!empty($media['streamingEpisodes'])) {        foreach ($media['streamingEpisodes'] as $s) {            if (preg_match('/Episode (\d+)\b/i', $s['title'], $m)) {                $max_stream = max($max_stream, (int)$m[1]);            }        }    }       if (isset($media['nextAiringEpisode']['episode'])) {        $next_airing = $media['nextAiringEpisode']['episode'] - 1;    }       if ($manual_count > 0) {        $loop = $manual_count;    } else {        $loop = max($total, $max_stream, $next_airing);    }       if ($loop <= 0 && $media['status'] == 'RELEASING') $loop = 1;    for ($i = 1; $i <= $loop; $i++) {        $etitle = "Episode $i";        if (!empty($media['streamingEpisodes'])) {            foreach ($media['streamingEpisodes'] as $s) {                if (preg_match('/Episode ' . $i . '\b/i', $s['title'])) {                    $etitle = $s['title'];                    break;                }            }        }        $episodes[] = ['num' => $i, 'title' => $etitle, 'exists' => in_array($i, $existing_nums)];    }    $status_map = ['FINISHED'=>'Completed', 'RELEASING'=>'Ongoing', 'NOT_YET_RELEASED'=>'Upcoming', 'HIATUS'=>'Hiatus'];    usort($franchise, function($a, $b) {        return strcmp($a['sort_key'], $b['sort_key']);    });    $main_title = !empty($media['title']['romaji']) ? $media['title']['romaji'] : $media['title']['romaji'];    wp_send_json_success([        'title' => $main_title,        'description' => strip_tags($media['description']),        'cover' => $media['coverImage']['large'],        'banner' => $media['bannerImage'] ?? '',        'type' => $media['format'],        'status_mapped' => $status_map[$media['status']] ?? 'Ongoing',        'status_label' => $media['status'],        'year' => $media['seasonYear'],        'season' => ucfirst(strtolower($media['season'])),        'score' => $media['averageScore'] / 10,        'genres_str' => implode(', ', $media['genres']),        'studios_str' => implode(', ', array_column($media['studios']['nodes'], 'name')),        'total_ep_count' => $loop,        'episodes' => $episodes,        'relations' => $franchise,        'debug' => [            'manual_override' => $manual_count,            'episodes_field' => $total,            'max_from_streaming' => $max_stream,            'next_airing_episode' => $next_airing,            'final_count' => $loop        ]    ]); } add_action('wp_ajax_ts_create_series_from_rel', 'ts_handle_create_series_from_rel'); function ts_handle_create_series_from_rel() {    $mal_id = intval($_POST['id']);    if (!$mal_id) wp_send_json_error('Invalid MAL ID');    $exists = get_posts(['post_type'=>'anime', 'meta_key'=>'ero_series_generate', 'meta_value'=>$mal_id, 'posts_per_page'=>1]);    if ($exists) wp_send_json_error('This series already exists in your database.');    $data = ts_get_anilist_media_details($mal_id);    $main_title = ($data && !empty($data['title']['english'])) ? $data['title']['english'] : ($data ? $data['title']['romaji'] : "New Series ($mal_id)");    $desc = $data ? $data['description'] : "";    $new_id = wp_insert_post([        'post_title' => $main_title,        'post_content' => $desc,        'post_type' => 'anime',        'post_status' => 'publish'    ]);    if ($new_id) {        update_post_meta($new_id, 'ero_series_generate', $mal_id);        ts_set_yoast_seo_meta($new_id, $main_title, $desc, 'series');        wp_send_json_success(['edit_url' => get_edit_post_link($new_id, 'url')]);    }    wp_send_json_error('Failed to create series post'); } function ts_get_anilist_media_details($id) {    if (!$id) return null;    $media = ts_perform_anilist_query($id, 'id');    if (!$media) {        $media = ts_perform_anilist_query($id, 'idMal');    }    return $media; } function ts_perform_anilist_query($id, $field = 'id') {    $query = '    query ($id: Int) {      Media (' . $field . ': $id, type: ANIME) {        id idMal title { romaji english }        description episodes status averageScore format season seasonYear        nextAiringEpisode { episode }        coverImage { large }        bannerImage        genres        startDate { year month day }        studios(isMain: true) { nodes { name } }        streamingEpisodes { title url }        relations { edges { relationType node { idMal title { romaji english } type format } } }      }    }';    $response = wp_remote_post('https://graphql.anilist.co', [        'body' => json_encode(['query' => $query, 'variables' => ["id"=>$id]]),        'headers' => ['Content-Type' => 'application/json']    ]);    if (is_wp_error($response)) return null;    $body = json_decode(wp_remote_retrieve_body($response), true);    return $body['data']['Media'] ?? null; } add_action('wp_ajax_ts_process_episode_v2', 'ts_handle_process_episode_v2'); function ts_handle_process_episode_v2() {    $ep = $_POST['episode'];    $series_id = intval($_POST['series_id']);    $ep_num = intval($ep['num']);    $prev = get_posts(['post_type'=>'post', 'posts_per_page'=>1, 'meta_query'=>[['key'=>'ero_seri','value'=>$series_id],['key'=>'ero_episodebaru','value'=>$ep_num]]]);    if ($prev) wp_send_json_success('Skip');    $series_title = get_the_title($series_id);    $ep_title_clean = !empty($ep['title']) ? $ep['title'] : "Episode $ep_num";       // Series title se URL slug banao    $series_slug = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $series_title)));    // Trailing dash hatao    $series_slug = trim($series_slug, '-');    $episode_post_title = $series_title . ' Episode ' . $ep_num . ' English Subbed ';    // Unique Episode Content for SEO $post_content = "Dear Anime Lovers, {$series_title} Episode {$ep_num} English Subbed is released. You can now watch {$series_title} latest ep with Eng sub. "; $post_content .= "Aniwatchtv is best site which provides {$series_title} Ep {$ep_num} Eng Sub.";    $new_id = wp_insert_post([        'post_title' => $episode_post_title,        'post_content' => $post_content,        'post_type' => 'post',        'post_status' => 'publish',        'post_author' => get_current_user_id()    ]);    if ($new_id) {        update_post_meta($new_id, 'ero_seri', $series_id);        update_post_meta($new_id, 'ero_episodebaru', $ep_num);        update_post_meta($new_id, 'ero_episodetitle', $ep_title_clean);        update_post_meta($new_id, 'ero_subepisode', 'Sub');               $series_thumbnail_id = get_post_thumbnail_id($series_id);        if ($series_thumbnail_id) {            set_post_thumbnail($new_id, $series_thumbnail_id);        }               $cats = wp_get_post_categories($series_id);        if ($cats) {            wp_set_post_categories($new_id, $cats);        }               $genres = wp_get_post_terms($series_id, 'genres', ['fields' => 'ids']);        if (!is_wp_error($genres) && !empty($genres)) {            wp_set_post_terms($new_id, $genres, 'genres');        }               $studios = wp_get_post_terms($series_id, 'studio', ['fields' => 'ids']);        if (!is_wp_error($studios) && !empty($studios)) {            wp_set_post_terms($new_id, $studios, 'studio');        }               $seasons = wp_get_post_terms($series_id, 'season', ['fields' => 'ids']);        if (!is_wp_error($seasons) && !empty($seasons)) {            wp_set_post_terms($new_id, $seasons, 'season');        }        wp_send_json_success('Created');    }    wp_send_json_error('Fail'); } add_action('wp_ajax_ts_import_seo_full', 'ts_handle_import_seo_full'); function ts_handle_import_seo_full() {    $url = esc_url_raw($_POST['image_url']);    $banner_url = isset($_POST['banner_url']) ? esc_url_raw($_POST['banner_url']) : '';    $post_id = intval($_POST['post_id']);    $title = sanitize_text_field($_POST['title']);    $desc = sanitize_textarea_field($_POST['description']);    if (!$post_id) wp_send_json_error('Missing ID');    require_once(ABSPATH . 'wp-admin/includes/media.php');    require_once(ABSPATH . 'wp-admin/includes/file.php');    require_once(ABSPATH . 'wp-admin/includes/image.php');    if (!has_post_thumbnail($post_id) && $url) {        $seo_name = sanitize_title($title) . '-poster';        $tmp = download_url($url);        if (!is_wp_error($tmp)) {            $file_array = ['name' => $seo_name . '.jpg', 'tmp_name' => $tmp];            $att_id = media_handle_sideload($file_array, $post_id, $title);            if (!is_wp_error($att_id)) {                update_post_meta($att_id, '_wp_attachment_image_alt', $title . ' Poster');                wp_update_post(['ID' => $att_id, 'post_excerpt' => 'Poster for ' . $title]);                set_post_thumbnail($post_id, $att_id);            }        }    }    if ($banner_url) {        $banner_name = sanitize_title($title) . '-banner';        $tmp_banner = download_url($banner_url);        if (!is_wp_error($tmp_banner)) {            $file_array = ['name' => $banner_name . '.jpg', 'tmp_name' => $tmp_banner];            $banner_att_id = media_handle_sideload($file_array, $post_id, $title . ' Banner');            if (!is_wp_error($banner_att_id)) {                update_post_meta($banner_att_id, '_wp_attachment_image_alt', $title . ' Banner');                wp_update_post(['ID' => $banner_att_id, 'post_excerpt' => 'Banner for ' . $title]);                update_post_meta($post_id, 'ero_cover', $banner_att_id);                update_post_meta($post_id, 'ero_slider', '1');            }        }    }    ts_set_yoast_seo_meta($post_id, $title, $desc, 'series');    wp_send_json_success('SEO Updated'); } function ts_set_yoast_seo_meta($post_id, $title, $description, $type = 'series', $series_title = '', $ep_num = '') {    $site_name = get_bloginfo('name');       if ($type === 'series') {        $seo_title = $title . " Online - Watch " . $title . " Full Episodes";        $seo_desc = "Watch " . $title . " online for free with English sub and dub. " . wp_trim_words($description, 25);        $focus_kw = $title;    } else {        $seo_title = $series_title . " Episode " . $ep_num . " Online - " . $site_name;        $seo_desc = "Watch " . $series_title . " Episode " . $ep_num . " online for free. Full episode title: " . $title . ". Find more episodes of " . $series_title . " here.";        $focus_kw = $series_title . " Episode " . $ep_num;    }    update_post_meta($post_id, '_yoast_wpseo_title', $seo_title);    update_post_meta($post_id, '_yoast_wpseo_metadesc', $seo_desc);    update_post_meta($post_id, '_yoast_wpseo_focuskw', $focus_kw); } Nomata Noriyuki Archives - AniWatch
Switch Mode