diff --git a/websites/H/Hami Video/Hami Video.json b/websites/H/Hami Video/Hami Video.json new file mode 100644 index 000000000000..f5cfa956d445 --- /dev/null +++ b/websites/H/Hami Video/Hami Video.json @@ -0,0 +1,126 @@ +{ + "hamivideo.watchingMovie": { + "description": "Shown as the details line while watching a movie", + "message": "Watching Movie" + }, + "hamivideo.watchingSeries": { + "description": "Shown as the details line while watching a TV series episode", + "message": "Watching TV Series" + }, + "hamivideo.watchingAnime": { + "description": "Shown as the details line while watching an anime episode", + "message": "Watching Anime" + }, + "hamivideo.watchingDocumentary": { + "description": "Shown as the details line while watching a documentary", + "message": "Watching Documentary" + }, + "hamivideo.watchingKids": { + "description": "Shown as the details line while watching kids' content", + "message": "Watching Kids Content" + }, + "hamivideo.watchingVariety": { + "description": "Shown as the details line while watching a variety show", + "message": "Watching Variety Show" + }, + "hamivideo.watchingSportsLive": { + "description": "Shown as the details line while watching a live sports broadcast whose sport could not be identified", + "message": "Watching Live Sports" + }, + "hamivideo.watchingSportsReplay": { + "description": "Shown as the details line while watching a sports replay", + "message": "Watching Sports Replay" + }, + "hamivideo.watchingTV": { + "description": "Shown as the details line while watching a live TV channel that isn't a sports broadcast (e.g. cartoons, news, movies, variety, kids channels)", + "message": "Watching TV" + }, + "hamivideo.watchingBaseball": { + "description": "Shown as the details line while watching a live baseball broadcast (MLB, CPBL, etc.)", + "message": "Watching Baseball" + }, + "hamivideo.watchingBasketball": { + "description": "Shown as the details line while watching a live basketball broadcast (NBA, WNBA, etc.)", + "message": "Watching Basketball" + }, + "hamivideo.watchingFormula1": { + "description": "Shown as the details line while watching a live Formula 1 broadcast", + "message": "Watching Formula 1" + }, + "hamivideo.watchingMotorcycleRacing": { + "description": "Shown as the details line while watching a live MotoGP broadcast", + "message": "Watching Motorcycle Racing" + }, + "hamivideo.watchingMMA": { + "description": "Shown as the details line while watching a live UFC/MMA broadcast", + "message": "Watching MMA" + }, + "hamivideo.watchingBadminton": { + "description": "Shown as the details line while watching a live badminton broadcast (BWF, etc.)", + "message": "Watching Badminton" + }, + "hamivideo.watchingGolf": { + "description": "Shown as the details line while watching a live golf broadcast (PGA, LPGA, etc.)", + "message": "Watching Golf" + }, + "hamivideo.watchingFootball": { + "description": "Shown as the details line while watching a live football/soccer broadcast", + "message": "Watching Football" + }, + "hamivideo.watchingAmericanFootball": { + "description": "Shown as the details line while watching a live NFL broadcast", + "message": "Watching American Football" + }, + "hamivideo.watchingIceHockey": { + "description": "Shown as the details line while watching a live NHL broadcast", + "message": "Watching Ice Hockey" + }, + "hamivideo.watchingTennis": { + "description": "Shown as the details line while watching a live tennis broadcast (ATP, WTA, etc.)", + "message": "Watching Tennis" + }, + "hamivideo.watchingVolleyball": { + "description": "Shown as the details line while watching a live volleyball broadcast", + "message": "Watching Volleyball" + }, + "hamivideo.watchingEsports": { + "description": "Shown as the details line while watching a live esports broadcast", + "message": "Watching Esports" + }, + "hamivideo.liveEventFallback": { + "description": "Shown as the state line for a live sports broadcast when no event name could be parsed", + "message": "LIVE Event" + }, + "hamivideo.browsingCategory": { + "description": "Shown while browsing a content category listing", + "message": "Browsing Category" + }, + "hamivideo.browsingAnime": { + "description": "Shown while browsing the anime section", + "message": "Browsing Anime" + }, + "hamivideo.searching": { + "description": "Shown while searching, followed by the search keyword", + "message": "Searching" + }, + "hamivideo.watchButton": { + "description": "Button label linking to the movie/show on Hami Video", + "message": "Watch on Hami Video" + }, + "hamivideo.watchEpisodeButton": { + "description": "Button label linking to the currently playing episode", + "message": "Watch Episode" + }, + "hamivideo.viewSeriesButton": { + "description": "Button label linking to the series' homepage", + "message": "View Series" + }, + "hamivideo.watchLiveButton": { + "description": "Button label linking to the current live sports broadcast", + "message": "Watch Live" + }, + "hamivideo.watchReplayButton": { + "description": "Button label linking to the current sports replay", + "message": "Watch Replay" + } +} diff --git a/websites/H/Hami Video/img/logo.png b/websites/H/Hami Video/img/logo.png new file mode 100644 index 000000000000..be8b8db8b435 Binary files /dev/null and b/websites/H/Hami Video/img/logo.png differ diff --git a/websites/H/Hami Video/img/logo_dark.png b/websites/H/Hami Video/img/logo_dark.png new file mode 100644 index 000000000000..be8b8db8b435 Binary files /dev/null and b/websites/H/Hami Video/img/logo_dark.png differ diff --git a/websites/H/Hami Video/metadata.json b/websites/H/Hami Video/metadata.json new file mode 100644 index 000000000000..c43f849498f8 --- /dev/null +++ b/websites/H/Hami Video/metadata.json @@ -0,0 +1,85 @@ +{ + "$schema": "https://schemas.premid.app/metadata/1.16", + "apiVersion": 1, + "author": { + "name": "Baidairay", + "id": "774619334646824960" + }, + + "service": "Hami Video", + "altnames": ["HamiVideo", "台灣大哥大 Hami Video", "中華電信 Hami Video", "hamivideo"], + "description": { + "en": "Automatically shows what you're watching on Hami Video — movies, TV series, anime, documentaries, kids' content, variety shows, and live or replayed sports." + }, + "url": "hamivideo.hinet.net", + "regExp": "^https:\\/\\/(?:www\\.)?hamivideo\\.hinet\\.net\\/.*$", + "version": "1.0.0", + "logo": "https://i.imgur.com/eCsBmqZ.png", + "thumbnail": "https://i.imgur.com/pUTIwh1.jpeg", + "color": "#EE1B58", + "category": "videos", + "tags": ["video", "streaming", "movies", "tv", "anime", "documentary", "kids", "variety", "sports", "taiwan", "hinet", "live"], + "settings": [ + { + "id": "privacyMode", + "title": "Privacy Mode", + "icon": "fas fa-user-secret", + "value": false, + "description": "Hide titles, episode info, poster art, and buttons — only shows that you're watching something" + }, + { + "id": "showTitle", + "title": "Show Title", + "icon": "fas fa-heading", + "value": true, + "description": "Show the movie or series title", + "if": { "privacyMode": false } + }, + { + "id": "showEpisodeNumber", + "title": "Show Episode Number", + "icon": "fas fa-list-ol", + "value": true, + "description": "Show the season/episode number (e.g. S01E05)", + "if": { "privacyMode": false } + }, + { + "id": "showEpisodeTitle", + "title": "Show Episode Title", + "icon": "fas fa-closed-captioning", + "value": true, + "description": "Show the episode's own title, if available", + "if": { "privacyMode": false } + }, + { + "id": "showLiveBadge", + "title": "Show Live Badge", + "icon": "fas fa-broadcast-tower", + "value": true, + "description": "Show a LIVE badge as the small image during live broadcasts", + "if": { "privacyMode": false } + }, + { + "id": "showButtons", + "title": "Show Buttons", + "icon": "fas fa-compress-arrows-alt", + "value": true, + "description": "Show the \"Watch on Hami Video\" button", + "if": { "privacyMode": false } + }, + { + "id": "showTimestamp", + "title": "Show Timestamp", + "icon": "fas fa-clock", + "value": true, + "description": "Show elapsed/remaining playback time" + }, + { + "id": "showPauseState", + "title": "Show Pause State", + "icon": "fas fa-pause", + "value": true, + "description": "Update the presence to show \"Paused\" when playback is paused" + } + ] +} diff --git a/websites/H/Hami Video/presence.ts b/websites/H/Hami Video/presence.ts new file mode 100644 index 000000000000..14f1e9696507 --- /dev/null +++ b/websites/H/Hami Video/presence.ts @@ -0,0 +1,1254 @@ +import { ActivityType, Assets, getTimestamps } from 'premid' + +const presence = new Presence({ + clientId: '1394513095367463043', +}) + +enum ActivityAssets { + Logo = 'https://i.imgur.com/eCsBmqZ.png', +} + +enum ContentType { + Movie = 'movie', + Series = 'series', + Anime = 'anime', + Documentary = 'documentary', + Kids = 'kids', + Variety = 'variety', + SportsLive = 'sportsLive', + SportsReplay = 'sportsReplay', + // Live /channel/ pages that aren't a sports broadcast — Hami Video uses + // /channel/ for every TV channel (cartoons, news, movies, variety, kids, + // sports, etc.), not just sports, so this is the generic fallback for + // "live channel, not sports". + TV = 'tv', + Unknown = 'unknown', +} + +enum SportType { + Baseball = 'baseball', + Basketball = 'basketball', + Formula1 = 'formula1', + MotorcycleRacing = 'motorcycleRacing', + MMA = 'mma', + Badminton = 'badminton', + Golf = 'golf', + Football = 'football', + AmericanFootball = 'americanFootball', + IceHockey = 'iceHockey', + Tennis = 'tennis', + Volleyball = 'volleyball', + Esports = 'esports', + Unknown = 'unknown', +} + +/** + * =========================================================================== + * Rich Presence flicker prevention + * =========================================================================== + * `setActivity`/`clearActivity` calls are cheap to *call* but each one still + * causes a visible refresh of the Discord status. `UpdateData` can fire many + * times per second (DOM mutations, timers, etc.), so we only forward a call + * to the SDK when the serialized payload actually changed since last time. + */ +let lastSnapshot = '' + +function setActivityIfChanged(data: PresenceData): void { + const snapshot = JSON.stringify(data) + if (snapshot !== lastSnapshot) { + lastSnapshot = snapshot + presence.setActivity(data) + } +} + +function clearActivityAndReset(): void { + // Reset the snapshot so that the *next* setActivity call (even if it is + // identical to whatever was showing before clearActivity) is not + // incorrectly swallowed as a "no change" no-op. + lastSnapshot = '' + presence.clearActivity() +} + +/** + * =========================================================================== + * Player access + * =========================================================================== + * All direct access to the `