-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat(AniTilky): update activity for anitilky.com #11001
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
76d2e8f
0a5e50e
d5b7b0b
f5904c3
ae8c3e1
9d297bf
115bfcd
df10eb9
1d33446
bdd77bc
ff45ea6
52e0975
8fa4e60
d7de6a6
8c0a327
f98b794
f0cb030
b64f313
94bac12
3281f13
c5ceb32
a1fe1b5
b610889
51ba7d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import type { Anime } from '../types.js' | ||
| import { API_URL, fetchCached } from './helpers.js' | ||
|
|
||
| export async function fetchAnime(id: string): Promise<Anime | null> { | ||
| return fetchCached(`anime:${id}`, async () => { | ||
| try { | ||
| const response = await fetch(`${API_URL}/anime/${encodeURIComponent(id)}`) | ||
| if (!response.ok) | ||
| return null | ||
| return await response.json() as Anime | ||
| } | ||
| catch { | ||
| return null | ||
| } | ||
| }) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import type { UserProfile } from '../types.js' | ||
| import { API_URL, ActivityAssets, fetchCached } from './helpers.js' | ||
Check failureCode scanning / ESLint Enforce sorted named imports. Error
Expected "ActivityAssets" to come before "API_URL".
|
||
|
|
||
| export async function fetchUser(username: string): Promise<UserProfile | null> { | ||
| return fetchCached(`user:${username.toLowerCase()}`, async () => { | ||
| try { | ||
| const response = await fetch(`${API_URL}/user/profile/${encodeURIComponent(username)}`) | ||
| if (!response.ok) | ||
| return null | ||
| const data = await response.json() as UserProfile | ||
| return { | ||
| ...data, | ||
| profileImage: data.profileImage || ActivityAssets.Logo, | ||
| } | ||
| } | ||
| catch { | ||
| return null | ||
| } | ||
| }) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| import type { Anime, AnimeEpisode, AnimeSeason } from '../types.js' | ||
|
|
||
| export const BASE_URL = 'https://anitilky.com' | ||
| export const API_URL = 'https://api.anitilky.com/api' | ||
|
|
||
| export enum ActivityAssets { | ||
| Logo = 'https://cdn.rcd.gg/PreMiD/websites/A/AniTilky/assets/logo.png', | ||
| Thumbnail = 'https://cdn.rcd.gg/PreMiD/websites/A/AniTilky/assets/thumbnail.png', | ||
Check failureCode scanning / PMD Makes sure all images (logo and URLs) are exactly 512x512 pixels Error
Image URL dimensions must be exactly 512x512 pixels, got 1919x955 for URL: https://cdn.rcd.gg/PreMiD/websites/A/AniTilky/assets/thumbnail.png
|
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| } | ||
|
|
||
| const cache = new Map<string, { data: unknown, expires: number }>() | ||
| const CACHE_TTL = 60_000 | ||
|
|
||
| export async function fetchCached<T>(key: string, fetcher: () => Promise<T | null>): Promise<T | null> { | ||
| const cached = cache.get(key) | ||
| if (cached && cached.expires > Date.now()) | ||
| return cached.data as T | ||
|
|
||
| const data = await fetcher() | ||
| if (data) | ||
| cache.set(key, { data, expires: Date.now() + CACHE_TTL }) | ||
|
|
||
| return data | ||
| } | ||
|
|
||
| export function getAnimeTitle(anime?: Anime | null): string | undefined { | ||
| if (!anime?.title) | ||
| return undefined | ||
| return anime.title.romaji || anime.title.english || anime.title.native | ||
| } | ||
|
|
||
| export function findSeason(anime: Anime | null | undefined, seasonNumber: number): AnimeSeason | undefined { | ||
| return anime?.seasons?.find(s => s.seasonNumber === seasonNumber) | ||
| } | ||
|
|
||
| export function findEpisode(season: AnimeSeason | undefined, episodeNumber: number): AnimeEpisode | undefined { | ||
| return season?.episodes?.find(e => e.episodeNumber === episodeNumber) | ||
| } | ||
|
|
||
| export function getOgImage(): string | undefined { | ||
| return document.querySelector<HTMLMetaElement>('meta[property="og:image"]')?.content | ||
| || document.querySelector<HTMLMetaElement>('meta[name="twitter:image"]')?.content | ||
| } | ||
|
|
||
| export function getPageTitle(): string { | ||
| return document.title.replace(/\s*\|\s*ANITILKY.*$/i, '').trim() | ||
| } | ||
|
|
||
| export function resolveCoverImage(preferred?: string, fallback?: string): string { | ||
| return preferred || fallback || getOgImage() || ActivityAssets.Logo | ||
| } | ||
|
|
||
| export function getStoredUsername(): string | undefined { | ||
| try { | ||
| const raw = localStorage.getItem('userData') || sessionStorage.getItem('userData') | ||
| if (!raw) | ||
| return undefined | ||
| const parsed = JSON.parse(raw) as { username?: string } | ||
| return parsed.username | ||
| } | ||
| catch { | ||
| return undefined | ||
| } | ||
| } | ||
|
|
||
| export function getProfileUsernameFromDom(): string | undefined { | ||
| return document.querySelector<HTMLElement>('main h4, [class*="MuiTypography-h4"]')?.textContent?.trim() | ||
| || getStoredUsername() | ||
| } | ||
|
|
||
| export function parsePathSegments(pathname: string): string[] { | ||
| return pathname.split('/').filter(Boolean) | ||
| } | ||
|
|
||
| export function formatEpisodeState( | ||
| template: string, | ||
| season: number, | ||
| episode: number, | ||
| episodeTitle?: string, | ||
| ): string { | ||
| const base = template | ||
| .replace('{0}', String(season)) | ||
| .replace('{1}', String(episode)) | ||
|
|
||
| return episodeTitle ? `${base} — ${episodeTitle}` : base | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| import type { Presence } from 'premid' | ||
Check failureCode scanning / PMD Makes sure the TypeScript files are correct Error
Module '"premid"' has no exported member 'Presence'.
|
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
|
|
||
| export interface PresenceStrings { | ||
| play: string | ||
| pause: string | ||
| browse: string | ||
| search: string | ||
| viewPage: string | ||
| viewSeries: string | ||
| watchEpisode: string | ||
| viewProfile: string | ||
| watchingSeries: string | ||
| seasonEpisode: string | ||
| home: string | ||
| animeList: string | ||
| schedule: string | ||
| users: string | ||
| notifications: string | ||
| settings: string | ||
| donation: string | ||
| login: string | ||
| register: string | ||
| admin: string | ||
| viewingAnime: string | ||
| viewingProfile: string | ||
| ownProfile: string | ||
| tabPosts: string | ||
| tabMedia: string | ||
| tabWatchlist: string | ||
| tabFavorites: string | ||
| tabHistory: string | ||
| privacyWatching: string | ||
| privacyBrowsing: string | ||
| } | ||
|
|
||
| const SITE_STRINGS: Record<'en' | 'tr', Omit<PresenceStrings, | ||
| 'play' | 'pause' | 'browse' | 'search' | 'viewPage' | 'viewSeries' | 'watchEpisode' | 'watchingSeries' | ||
Check failureCode scanning / ESLint Having line breaks styles to object, array and named imports Error
Should not have line breaks between items, in node TSTypeParameterInstantiation
Check failureCode scanning / ESLint Having line breaks styles to object, array and named imports Error
Should not have line breaks between items, in node TSTypeParameterInstantiation
|
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| >> = { | ||
| en: { | ||
| viewProfile: 'View profile', | ||
| seasonEpisode: 'Season {0} · Episode {1}', | ||
| home: 'Home', | ||
| animeList: 'Anime catalog', | ||
| schedule: 'Release schedule', | ||
| users: 'Community', | ||
| notifications: 'Notifications', | ||
| settings: 'Account settings', | ||
| donation: 'Support AniTilky', | ||
| login: 'Signing in', | ||
| register: 'Creating account', | ||
| admin: 'Admin panel', | ||
| viewingAnime: 'Viewing anime', | ||
| viewingProfile: 'Viewing profile', | ||
| ownProfile: 'My profile', | ||
| tabPosts: 'Posts', | ||
| tabMedia: 'Media', | ||
| tabWatchlist: 'Watchlist', | ||
| tabFavorites: 'Favorites', | ||
| tabHistory: 'Watch history', | ||
| privacyWatching: 'Watching content', | ||
| privacyBrowsing: 'Browsing AniTilky', | ||
| }, | ||
| tr: { | ||
| viewProfile: 'Profile git', | ||
| seasonEpisode: 'Sezon {0} · Bölüm {1}', | ||
| home: 'Ana sayfa', | ||
| animeList: 'Anime kataloğu', | ||
| schedule: 'Yayın takvimi', | ||
| users: 'Topluluk', | ||
| notifications: 'Bildirimler', | ||
| settings: 'Hesap ayarları', | ||
| donation: 'AniTilky\'ye destek', | ||
| login: 'Giriş yapılıyor', | ||
| register: 'Hesap oluşturuluyor', | ||
| admin: 'Yönetim paneli', | ||
| viewingAnime: 'Anime inceleniyor', | ||
| viewingProfile: 'Profil görüntüleniyor', | ||
| ownProfile: 'Kendi profili', | ||
| tabPosts: 'Gönderiler', | ||
| tabMedia: 'Medya', | ||
| tabWatchlist: 'İzleme listesi', | ||
| tabFavorites: 'Favoriler', | ||
| tabHistory: 'İzleme geçmişi', | ||
| privacyWatching: 'İçerik izleniyor', | ||
| privacyBrowsing: 'AniTilky\'de geziniyor', | ||
| }, | ||
| } | ||
|
|
||
| export async function getStrings(presence: Presence, lang: string): Promise<PresenceStrings> { | ||
| const normalized = lang.startsWith('tr') ? 'tr' : 'en' | ||
| const general = await presence.getStrings( | ||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| { | ||
| play: 'general.playing', | ||
| pause: 'general.paused', | ||
| browse: 'general.browsing', | ||
| search: 'general.search', | ||
| viewPage: 'general.viewPage', | ||
| viewSeries: 'general.buttonViewSeries', | ||
| watchEpisode: 'general.buttonViewEpisode', | ||
| watchingSeries: 'general.watchingSeries', | ||
| }, | ||
| lang, | ||
| ) | ||
|
|
||
| return { ...general, ...SITE_STRINGS[normalized] } | ||
| } | ||
|
|
||
| export type ProfileTabKey = keyof Pick<PresenceStrings, | ||
| 'tabPosts' | 'tabMedia' | 'tabWatchlist' | 'tabFavorites' | 'tabHistory' | ||
Check failureCode scanning / ESLint Having line breaks styles to object, array and named imports Error
Should not have line breaks between items, in node TSTypeParameterInstantiation
Check failureCode scanning / ESLint Having line breaks styles to object, array and named imports Error
Should not have line breaks between items, in node TSTypeParameterInstantiation
|
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| > | ||
|
|
||
| export const PROFILE_TABS: Record<string, ProfileTabKey> = { | ||
| posts: 'tabPosts', | ||
| media: 'tabMedia', | ||
| watchlist: 'tabWatchlist', | ||
| favorites: 'tabFavorites', | ||
| history: 'tabHistory', | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.