Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Anime Location Viewer</title>
- <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
- <script src="https://unpkg.com/lucide@latest/dist/lucide.min.js"></script>
- </head>
- <body class="min-h-screen bg-black text-white p-4">
- <div class="max-w-6xl mx-auto">
- <h1 class="text-3xl font-bold mb-4">Anime Location Viewer</h1>
- <div class="mb-6">
- <div class="flex gap-4 mb-4">
- <select id="animeSelect" class="px-4 py-2 border rounded-lg bg-white text-black">
- <option value="">Please select anime you want to view the location</option>
- <option value="464376">負けヒロインが多すぎる!</option>
- <option value="207195">ゆるキャン△</option>
- </select>
- <button
- id="loadButton"
- class="bg-blue-500 text-white px-4 py-2 rounded-lg flex items-center gap-2 hover:bg-blue-600 transition-colors"
- disabled
- >
- <i data-lucide="search"></i>
- Load Locations
- </button>
- </div>
- </div>
- <div id="error" class="hidden bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4"></div>
- <div id="animeContent" class="space-y-6"></div>
- </div>
- <script>
- const BangumiIds = {
- "負けヒロインが多すぎる!": "464376",
- "ゆるキャン△": "207195",
- };
- const animeSelect = document.getElementById('animeSelect');
- const loadButton = document.getElementById('loadButton');
- const animeContent = document.getElementById('animeContent');
- const errorDiv = document.getElementById('error');
- let expandedLocations = {};
- const fetchData = async (id) => {
- animeContent.innerHTML = '';
- errorDiv.classList.add('hidden');
- try {
- const basicResponse = await fetch(`https://api.anitabi.cn/bangumi/${id}/lite`);
- if (!basicResponse.ok) throw new Error('Failed to fetch basic data');
- const basicData = await basicResponse.json();
- const detailResponse = await fetch(`https://api.anitabi.cn/bangumi/${id}/points/detail`);
- if (!detailResponse.ok) throw new Error('Failed to fetch detailed data');
- const detailData = await detailResponse.json();
- detailData.sort((a, b) => a.ep === 'OP' ? -1 : (parseInt(a.ep) - parseInt(b.ep)));
- displayAnimeData(basicData, detailData);
- } catch (err) {
- errorDiv.textContent = 'Failed to load anime location data. Please try again.';
- errorDiv.classList.remove('hidden');
- }
- };
- const displayAnimeData = (animeData, detailData) => {
- const animeInfo = `
- <div class="bg-white text-black rounded-lg shadow p-6">
- <div class="flex items-center gap-4">
- <img src="${animeData.cover}" alt="${animeData.title}" class="w-[10vh] h-[50] object-cover rounded">
- <div>
- <div class="text-2xl font-bold">${animeData.title}</div>
- <div class="text-gray-500">${animeData.city || 'N/A'}</div>
- </div>
- </div>
- </div>
- `;
- const locations = detailData.map(point => `
- <div class="bg-white text-black rounded-lg shadow overflow-hidden">
- <div class="relative h-48">
- <img src="${point.image.replace('h160', 'h360')}" alt="${point.name}" class="w-full h-full object-cover">
- </div>
- <div class="p-4">
- <h3 class="font-semibold mb-2">${point.name}</h3>
- ${point.origin ? `<a href="${point.originURL}" target="_blank" class="text-blue-500 hover:text-blue-600">Source: ${point.origin}</a>` : ''}
- <div class="flex items-center gap-4 text-sm text-gray-500">
- <span>Episode ${point.ep || '-'}</span>
- <span>${point.geo.map(coord => coord.toFixed(4)).join(', ')}</span>
- </div>
- ${point.moreImages ? `
- <button onclick="toggleExpandLocation('${point.id}')" class="text-blue-500 mt-2">
- ${expandedLocations[point.id] ? 'Hide Images' : 'View More Images'}
- </button>
- <div id="extra-images-${point.id}" class="grid grid-cols-2 gap-2 mt-2 ${expandedLocations[point.id] ? '' : 'hidden'}">
- ${point.moreImages.map(img => `<img src="${img.replace('h160', 'h360')}" alt="Additional view" class="w-full h-24 object-cover">`).join('')}
- </div>
- ` : ''}
- </div>
- </div>
- `).join('');
- animeContent.innerHTML = animeInfo + '<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">' + locations + '</div>';
- };
- const toggleExpandLocation = (locationId) => {
- expandedLocations[locationId] = !expandedLocations[locationId];
- document.getElementById(`extra-images-${locationId}`).classList.toggle('hidden');
- };
- animeSelect.addEventListener('change', (e) => {
- loadButton.disabled = !e.target.value;
- });
- loadButton.addEventListener('click', () => {
- if (animeSelect.value) {
- fetchData(animeSelect.value);
- }
- });
- lucide.createIcons();
- </script>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment