mirror of
https://github.com/WonderAliceUwU/OmniArr.git
synced 2026-11-11 04:01:01 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0672b8c72b | ||
|
|
591fac51b2 | ||
|
|
a926964834 | ||
|
|
fb07b27675 | ||
|
|
9f1d50b35d |
No files matched your search
@@ -43,7 +43,7 @@ Create a directory for OmniArr and add this `docker-compose.yml`:
|
||||
```yaml
|
||||
services:
|
||||
omniarr:
|
||||
image: wonderalice/omniarr:1.2.2
|
||||
image: wonderalice/omniarr:1.2.4
|
||||
container_name: omniarr
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
@@ -90,11 +90,11 @@ the mount loses that state when the container is replaced.
|
||||
The current release is available as:
|
||||
|
||||
```text
|
||||
wonderalice/omniarr:1.2.2
|
||||
wonderalice/omniarr:1.2.4
|
||||
wonderalice/omniarr:latest
|
||||
```
|
||||
|
||||
Pin `1.2.2` in production for repeatable updates. Use `latest` only when you want
|
||||
Pin `1.2.4` in production for repeatable updates. Use `latest` only when you want
|
||||
Compose to follow the newest published image.
|
||||
|
||||
## Build locally
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
omniarr:
|
||||
image: wonderalice/omniarr:1.2.2
|
||||
image: wonderalice/omniarr:1.2.4
|
||||
# Para construir desde código fuente en su lugar, descomenta estas líneas:
|
||||
# build:
|
||||
# context: .
|
||||
|
||||
+5
-2
@@ -817,14 +817,17 @@ async function serveApp(pathname: string, response: ServerResponse): Promise<voi
|
||||
try {
|
||||
const content = await readFile(filePath);
|
||||
response.writeHead(200, {
|
||||
'Content-Type': contentType(filePath)
|
||||
'Content-Type': contentType(filePath),
|
||||
// Hashed bundles never change; the entry page must always be revalidated so a new release reaches every browser.
|
||||
'Cache-Control': relativePath.startsWith('/assets/') ? 'public, max-age=31536000, immutable' : 'no-cache'
|
||||
});
|
||||
response.end(content);
|
||||
} catch {
|
||||
try {
|
||||
const indexHtml = await readFile(resolve(process.cwd(), 'dist', 'index.html'));
|
||||
response.writeHead(200, {
|
||||
'Content-Type': 'text/html; charset=utf-8'
|
||||
'Content-Type': 'text/html; charset=utf-8',
|
||||
'Cache-Control': 'no-cache'
|
||||
});
|
||||
response.end(indexHtml);
|
||||
} catch {
|
||||
|
||||
@@ -4153,7 +4153,10 @@ function jellyfinToCard(
|
||||
const backdropItemId = item.ParentBackdropItemId || item.Id;
|
||||
const backdropTag = item.ParentBackdropImageTags?.[0] || item.BackdropImageTags?.[0] || posterTag;
|
||||
const progress = Math.round(item.UserData?.PlayedPercentage || 0);
|
||||
const tmdbId = Number(item.ProviderIds?.Tmdb) || (item.SeriesId ? tmdbIdByItemId?.get(item.SeriesId) : undefined);
|
||||
// An episode's own TMDb id is not its series' id, and artwork is looked up per series.
|
||||
const tmdbId = item.Type === 'Episode'
|
||||
? (item.SeriesId ? tmdbIdByItemId?.get(item.SeriesId) : undefined)
|
||||
: Number(item.ProviderIds?.Tmdb) || (item.SeriesId ? tmdbIdByItemId?.get(item.SeriesId) : undefined);
|
||||
const episodeCode = formatEpisodeCode(item.ParentIndexNumber, item.IndexNumber);
|
||||
|
||||
return {
|
||||
|
||||
+23
-3
@@ -1786,7 +1786,7 @@ function MediaTile(props: {
|
||||
</div>
|
||||
) : null}
|
||||
{props.card.hoverLabel && !continueEpisodeMeta ? <div className="media-hover-label">{props.card.hoverLabel}</div> : null}
|
||||
{props.card.progress ? <div className="tile-progress"><div className="tile-progress-fill" style={{ width: `${props.card.progress}%` }} /></div> : null}
|
||||
{props.isContinueWatching && props.card.progress ? <div className="tile-progress"><div className="tile-progress-fill" style={{ width: `${props.card.progress}%` }} /></div> : null}
|
||||
</button>
|
||||
{!props.isContinueWatching && (props.styleType === 'landscape' || props.styleType === 'poster') ? <WishlistHeart card={props.card} className="media-wishlist-button" /> : null}
|
||||
</article>
|
||||
@@ -2108,6 +2108,26 @@ function TitleDetailsModal(props: {
|
||||
const backgroundImage = details?.backdropUrl || props.card.backdropUrl || props.card.posterUrl
|
||||
const logoUrl = details?.logoUrl || props.card.logoUrl
|
||||
const displayTitle = details?.title || props.card.title
|
||||
// Titles opened from Continue Watching arrive as a Jellyfin episode card, which
|
||||
// cannot be wishlisted; the series the details resolved to can.
|
||||
const wishlistCard: MediaCard = props.card.mediaType === 'episode' && details?.mediaType === 'series'
|
||||
? {
|
||||
...props.card,
|
||||
id: details.providerId ? `jellyfin-${details.providerId}` : details.id,
|
||||
tmdbId: details.tmdbId ?? props.card.tmdbId,
|
||||
providerId: details.providerId ?? props.card.providerId,
|
||||
title: details.title,
|
||||
subtitle: '',
|
||||
overview: details.overview,
|
||||
mediaType: 'series',
|
||||
posterUrl: details.posterUrl,
|
||||
backdropUrl: details.backdropUrl,
|
||||
logoUrl: details.logoUrl ?? props.card.logoUrl,
|
||||
progress: undefined,
|
||||
secondaryValue: undefined,
|
||||
hoverLabel: undefined
|
||||
}
|
||||
: props.card
|
||||
const displaySubtitle = details?.subtitle || props.card.subtitle
|
||||
const displayOverview = details?.overview || props.card.overview || 'No details available yet.'
|
||||
const displayYear = props.card.releaseDate?.slice(0, 4)
|
||||
@@ -2716,7 +2736,7 @@ function TitleDetailsModal(props: {
|
||||
</p>
|
||||
<div className="title-details-summary-header">
|
||||
{details?.mediaType !== 'series' ? (
|
||||
<WishlistHeart card={props.card} className="title-season-action title-wishlist-button" divider="after" />
|
||||
<WishlistHeart card={wishlistCard} className="title-season-action title-wishlist-button" divider="after" />
|
||||
) : null}
|
||||
{canPlay && details?.mediaType !== 'series' ? (
|
||||
<ActionButton className="title-summary-header-play" onClick={() => setPlayerTarget({ id: playId!, title: playLabel })} variant="play">
|
||||
@@ -2838,7 +2858,7 @@ function TitleDetailsModal(props: {
|
||||
</div>
|
||||
<>
|
||||
<div className="title-season-actions">
|
||||
<WishlistHeart card={props.card} className="title-season-action title-wishlist-button" divider="before" />
|
||||
<WishlistHeart card={wishlistCard} className="title-season-action title-wishlist-button" divider="before" />
|
||||
{shouldShowDownloadSeasonAction || activeSeasonMeta?.isDownloading ? <div className="title-season-divider title-season-action-divider" aria-hidden="true" /> : null}
|
||||
{shouldShowDownloadSeasonAction || activeSeasonMeta?.isDownloading ? (
|
||||
activeSeasonDownloadStatus === 'downloading' ? (
|
||||
|
||||
+4
-3
@@ -6041,10 +6041,11 @@ img {
|
||||
color: #ff5c7a;
|
||||
}
|
||||
|
||||
/* Touch screens have no hover, so the heart is always visible there. */
|
||||
@media (hover: none) {
|
||||
/* Phones and touch screens have no hover, and a heart on every poster is noise;
|
||||
the wishlist stays reachable from the title details. */
|
||||
@media (hover: none), (max-width: 980px) {
|
||||
.media-wishlist-button {
|
||||
opacity: 1;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user