Compare commits

...

6 Commits

Author SHA1 Message Date
CodeDevMLH
fe07fe9f5e Update manifest.json for release v1.7.1.6 [skip ci] 2026-03-08 18:33:15 +00:00
CodeDevMLH
22a7eb8dcb Update version to 1.7.1.6 and enhance changelog with new features and fixes
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 46s
2026-03-08 19:32:27 +01:00
CodeDevMLH
07658f4fbc Add Exclude Seasonal Content option to configuration and update related logic 2026-03-08 19:32:15 +01:00
CodeDevMLH
25ee5b73b4 Update field descriptions for Max Parental Rating and Max Days Recent inputs to clarify no limit options 2026-03-08 19:21:04 +01:00
CodeDevMLH
8f8e251054 Add max parental rating and max days recent filters to configuration 2026-03-08 19:19:20 +01:00
CodeDevMLH
05529e5627 add new tests 2026-03-08 19:18:30 +01:00
10 changed files with 375 additions and 20 deletions

View File

@@ -15,6 +15,8 @@ namespace Jellyfin.Plugin.MediaBarEnhanced.Configuration
public int MaxMovies { get; set; } = 15; public int MaxMovies { get; set; } = 15;
public int MaxTvShows { get; set; } = 15; public int MaxTvShows { get; set; } = 15;
public int MaxItems { get; set; } = 500; public int MaxItems { get; set; } = 500;
public int MaxParentalRating { get; set; } = 0;
public int MaxDaysRecent { get; set; } = 0;
public int PreloadCount { get; set; } = 3; public int PreloadCount { get; set; } = 3;
public int FadeTransitionDuration { get; set; } = 500; public int FadeTransitionDuration { get; set; } = 500;
public int MaxPaginationDots { get; set; } = 15; public int MaxPaginationDots { get; set; } = 15;
@@ -38,6 +40,7 @@ namespace Jellyfin.Plugin.MediaBarEnhanced.Configuration
public bool EnableCustomMediaIds { get; set; } = true; public bool EnableCustomMediaIds { get; set; } = true;
public string PreferredVideoQuality { get; set; } = "Auto"; public string PreferredVideoQuality { get; set; } = "Auto";
public bool EnableSeasonalContent { get; set; } = false; public bool EnableSeasonalContent { get; set; } = false;
public bool ExcludeSeasonalContent { get; set; } = true;
public string SeasonalSections { get; set; } = "[]"; public string SeasonalSections { get; set; } = "[]";
public bool IsEnabled { get; set; } = true; public bool IsEnabled { get; set; } = true;
public bool EnableClientSideSettings { get; set; } = false; public bool EnableClientSideSettings { get; set; } = false;

View File

@@ -183,6 +183,14 @@
during their active date ranges. If no season matches the current date, the default during their active date ranges. If no season matches the current date, the default
Custom Media IDs above or random selection are used as fallback.</div> Custom Media IDs above or random selection are used as fallback.</div>
</div> </div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="ExcludeSeasonalContent"
name="ExcludeSeasonalContent" />
<span>Exclude Seasonal Content from Random Lists</span>
</label>
<div class="fieldDescription">When enabled, any items defined in your Seasonal Sections below will be explicitly excluded from being shown when the plugin pulls random items from your library.</div>
</div>
<div id="seasonalContentContainer" style="display: none;"> <div id="seasonalContentContainer" style="display: none;">
<div <div
@@ -356,7 +364,7 @@
mobile).</div> mobile).</div>
</div> </div>
<h2 class="sectionTitle">Content Sorting</h2> <h2 class="sectionTitle">Content Sorting and Filtering</h2>
<div class="selectContainer"> <div class="selectContainer">
<label class="selectLabel" for="SortBy">Sort By</label> <label class="selectLabel" for="SortBy">Sort By</label>
<select is="emby-select" id="SortBy" name="SortBy" <select is="emby-select" id="SortBy" name="SortBy"
@@ -387,6 +395,16 @@
<b>Note:</b> Sorting settings apply to both Server content and Custom IDs. 'Original' <b>Note:</b> Sorting settings apply to both Server content and Custom IDs. 'Original'
preserves Custom List order. preserves Custom List order.
</div> </div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="MaxParentalRating">Max Parental Rating (Age Limit)</label>
<input is="emby-input" type="number" id="MaxParentalRating" name="MaxParentalRating" />
<div class="fieldDescription">Items exceeding this age rating will not be shown. Leave blank or set to 0 for no limit. Examples: 12, 16, 18.</div>
</div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="MaxDaysRecent">Max Days Recent</label>
<input is="emby-input" type="number" id="MaxDaysRecent" name="MaxDaysRecent" />
<div class="fieldDescription">Only show items added in the last X days. Leave blank or set to 0 for no limit. Example: 30.</div>
</div>
<h2 class="sectionTitle">Content Limits</h2> <h2 class="sectionTitle">Content Limits</h2>
<p>Leave a setting blank to use the default value.</p> <p>Leave a setting blank to use the default value.</p>
@@ -505,7 +523,8 @@
'EnableSeasonalContent', 'EnableClientSideSettings', 'SortBy', 'SortOrder', 'EnableSeasonalContent', 'EnableClientSideSettings', 'SortBy', 'SortOrder',
'PreferLocalTrailers', 'ApplyLimitsToCustomIds', 'SeasonalSections', 'PreferLocalTrailers', 'ApplyLimitsToCustomIds', 'SeasonalSections',
'PreferLocalBackdrops', 'RandomizeThemeVideos', 'RandomizeLocalTrailers', 'PreferLocalBackdrops', 'RandomizeThemeVideos', 'RandomizeLocalTrailers',
'IncludeWatchedContent', 'ShowPaginationDots' 'IncludeWatchedContent', 'ShowPaginationDots', 'MaxParentalRating',
'MaxDaysRecent', 'ExcludeSeasonalContent'
]; ];
// Manual mapping for MediaBarIsEnabled -> IsEnabled, to avoid conflicts with other plugins // Manual mapping for MediaBarIsEnabled -> IsEnabled, to avoid conflicts with other plugins
@@ -609,7 +628,8 @@
'EnableSeasonalContent', 'EnableClientSideSettings', 'SortBy', 'SortOrder', 'EnableSeasonalContent', 'EnableClientSideSettings', 'SortBy', 'SortOrder',
'PreferLocalTrailers', 'ApplyLimitsToCustomIds', 'SeasonalSections', 'PreferLocalTrailers', 'ApplyLimitsToCustomIds', 'SeasonalSections',
'PreferLocalBackdrops', 'RandomizeThemeVideos', 'RandomizeLocalTrailers', 'PreferLocalBackdrops', 'RandomizeThemeVideos', 'RandomizeLocalTrailers',
'IncludeWatchedContent', 'ShowPaginationDots' 'IncludeWatchedContent', 'ShowPaginationDots', 'MaxParentalRating',
'MaxDaysRecent', 'ExcludeSeasonalContent'
]; ];
keys.forEach(function (key) { keys.forEach(function (key) {

View File

@@ -12,7 +12,7 @@
<!-- <TreatWarningsAsErrors>false</TreatWarningsAsErrors> --> <!-- <TreatWarningsAsErrors>false</TreatWarningsAsErrors> -->
<Title>Jellyfin Media Bar Enhanced Plugin</Title> <Title>Jellyfin Media Bar Enhanced Plugin</Title>
<Authors>CodeDevMLH</Authors> <Authors>CodeDevMLH</Authors>
<Version>1.7.1.5</Version> <Version>1.7.1.6</Version>
<RepositoryUrl>https://github.com/CodeDevMLH/jellyfin-plugin-media-bar-enhanced</RepositoryUrl> <RepositoryUrl>https://github.com/CodeDevMLH/jellyfin-plugin-media-bar-enhanced</RepositoryUrl>
</PropertyGroup> </PropertyGroup>

View File

@@ -814,7 +814,6 @@
@media (max-width: 400px) { @media (max-width: 400px) {
.button-container { .button-container {
gap: 10px; gap: 10px;
/* top: calc(50% + 27vh); */
} }
.play-button, .play-button,

View File

@@ -39,6 +39,8 @@ const CONFIG = {
fadeTransitionDuration: 500, fadeTransitionDuration: 500,
maxPaginationDots: 15, maxPaginationDots: 15,
showPaginationDots: true, showPaginationDots: true,
maxParentalRating: null,
maxDaysRecent: null,
slideAnimationEnabled: true, slideAnimationEnabled: true,
enableVideoBackdrop: true, enableVideoBackdrop: true,
useSponsorBlock: true, useSponsorBlock: true,
@@ -64,6 +66,7 @@ const CONFIG = {
sortOrder: "Ascending", sortOrder: "Ascending",
applyLimitsToCustomIds: false, applyLimitsToCustomIds: false,
seasonalSections: "[]", seasonalSections: "[]",
excludeSeasonalContent: true,
isEnabled: true, isEnabled: true,
}; };
@@ -1112,12 +1115,59 @@ const ApiUtils = {
// Filter by isPlayed=False unless IncludeWatchedContent is enabled // Filter by isPlayed=False unless IncludeWatchedContent is enabled
const playedFilter = CONFIG.includeWatchedContent ? '' : '&isPlayed=False'; const playedFilter = CONFIG.includeWatchedContent ? '' : '&isPlayed=False';
const response = await fetch( let parentalFilter = '';
`${STATE.jellyfinData.serverAddress}/Items?IncludeItemTypes=Movie,Series&Recursive=true&hasOverview=true&imageTypes=Logo,Backdrop&${sortParams}${playedFilter}&enableUserData=true&Limit=${CONFIG.maxItems}&fields=Id`, if (CONFIG.maxParentalRating) {
{ parentalFilter = `&MaxOfficialRating=${CONFIG.maxParentalRating}`;
headers: this.getAuthHeaders(),
} }
);
let dateFilter = '';
if (CONFIG.maxDaysRecent) {
const pastDate = new Date();
pastDate.setDate(pastDate.getDate() - CONFIG.maxDaysRecent);
dateFilter = `&minDateLastSaved=${pastDate.toISOString()}`;
}
// Exclude seasonal content from random lists
let excludeFilter = '';
if (CONFIG.excludeSeasonalContent && CONFIG.seasonalSections) {
try {
const sections = JSON.parse(CONFIG.seasonalSections || "[]");
let allExcludedIds = [];
for (const section of sections) {
if (section.MediaIds) {
const idsInThisSection = section.MediaIds.split(/[\n,]/)
.map((line) => {
const urlMatch = line.match(/\[(.*?)\]/);
let id = line;
if (urlMatch) {
id = line.replace(/\[.*?\]/, '').trim();
const guidMatch = id.match(/([0-9a-f]{32})/i);
if (guidMatch) { id = guidMatch[1]; } else { id = id.split('|')[0].trim(); }
}
return id.trim();
})
.filter((id) => id);
allExcludedIds.push(...idsInThisSection);
}
}
if (allExcludedIds.length > 0) {
excludeFilter = `&ExcludeItemIds=${allExcludedIds.join(',')}`;
}
} catch(e) {
console.error("🎬 Media Bar:", "Error extracting seasonal IDs for exclusion:", e);
}
}
const fetchItems = async (currentDateFilter) => {
const url = `${STATE.jellyfinData.serverAddress}/Items?IncludeItemTypes=Movie,Series&Recursive=true&hasOverview=true&imageTypes=Logo,Backdrop&${sortParams}${playedFilter}${parentalFilter}${currentDateFilter}${excludeFilter}&enableUserData=true&Limit=${CONFIG.maxItems}&fields=Id,DateCreated`;
const resp = await fetch(url, { headers: this.getAuthHeaders() });
return resp;
};
let response = await fetchItems(dateFilter);
if (!response.ok) { if (!response.ok) {
console.error("🎬 Media Bar:", console.error("🎬 Media Bar:",
@@ -1126,12 +1176,32 @@ const ApiUtils = {
return []; return [];
} }
const data = await response.json(); let data = await response.json();
const items = data.Items || []; let items = data.Items || [];
console.log("🎬 Media Bar:", // Local exact DateCreated filter: minDateLastSaved pulls items that were merely modified recently (e.g. metadata updates)
`Successfully fetched ${items.length} random items from server` // explicitly discard them if their actual DateCreated is older than X days
); if (CONFIG.maxDaysRecent && dateFilter !== '') {
const pastDate = new Date();
pastDate.setDate(pastDate.getDate() - CONFIG.maxDaysRecent);
items = items.filter(item => {
if (!item.DateCreated) return true;
return new Date(item.DateCreated) >= pastDate;
});
}
// Fallback: If we have a date filter but no items are returned, try again without it
if (items.length === 0 && dateFilter !== '') {
console.warn("🎬 Media Bar:", `No items found within the last ${CONFIG.maxDaysRecent} days. Falling back to random fetching.`);
response = await fetchItems('');
if (response.ok) {
data = await response.json();
items = data.Items || [];
}
}
console.log("🎬 Media Bar:", `Successfully fetched ${items.length} random items from server`);
return items.map((item) => item.Id); return items.map((item) => item.Id);
} catch (error) { } catch (error) {

View File

@@ -9,12 +9,12 @@
"imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/raw/branch/main/logo.png", "imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/raw/branch/main/logo.png",
"versions": [ "versions": [
{ {
"version": "1.7.1.5", "version": "1.7.1.6",
"changelog": "- feat: add option to disable pagination dots/counter\n- fix button issue on mobile when using ElegantFin Theme", "changelog": "- feat: add option to disable pagination dots/counter\n- feat: add exclude seasonal content from random fetching option\n- fix button issue on mobile when using ElegantFin Theme",
"targetAbi": "10.11.0.0", "targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.7.1.5/Jellyfin.Plugin.MediaBarEnhanced.zip", "sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.7.1.6/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "f9a18cb5f38a7a8e54a45e13e5e39bd8", "checksum": "d334b961ac8c6a527dba490b5a926c40",
"timestamp": "2026-03-08T16:17:51Z" "timestamp": "2026-03-08T18:33:15Z"
}, },
{ {
"version": "1.7.0.14", "version": "1.7.0.14",

View File

@@ -0,0 +1,73 @@
(async () => {
const apiClient = window.ApiClient;
if (!apiClient) {
console.error("ApiClient not found. Are you logged in?");
return;
}
const userId = apiClient.getCurrentUserId();
const serverAddress = apiClient.serverAddress();
const maxDaysRecent = 30; // 30 Tage Limit
const pastDate = new Date();
pastDate.setDate(pastDate.getDate() - maxDaysRecent);
const dateStr = pastDate.toISOString();
console.log(`\n%c=== TEST: DateCreated Direkt-Abfrage ===`, "color: #00a4dc; font-weight: bold; font-size: 14px;");
console.log(`Wir suchen Filme, die nach dem ${dateStr} hinzugefügt wurden.\n`);
// Wir probieren alle denkbaren Parameter-Schreibweisen aus,
// die Jellyfin historisch oder in Forks für "DateCreated" akzeptieren könnte.
const testCases = [
{ name: "MinDateCreated (PascalCase)", param: `MinDateCreated=${dateStr}` },
{ name: "minDateCreated (camelCase)", param: `minDateCreated=${dateStr}` },
{ name: "DateCreatedMin", param: `DateCreatedMin=${dateStr}` },
{ name: "dateCreatedMin", param: `dateCreatedMin=${dateStr}` },
{ name: "StartDate", param: `StartDate=${dateStr}` },
{ name: "startDate", param: `startDate=${dateStr}` }
];
try {
for (let i = 0; i < testCases.length; i++) {
const test = testCases[i];
const apiUrl = `${serverAddress}/Items?IncludeItemTypes=Movie,Series&Recursive=true&enableUserData=true&Limit=5&fields=Id,DateCreated&userId=${userId}&${test.param}`;
console.log(`%cTest ${i+1}: ${test.name}`, "color: yellow;");
console.log(`URL: ${apiUrl}`);
const response = await fetch(apiUrl, {
headers: {
Authorization: `MediaBrowser Client="${apiClient.appName()}", Device="${apiClient.deviceName()}", DeviceId="${apiClient.deviceId()}", Version="${apiClient.appVersion()}", Token="${apiClient.accessToken()}"`
}
});
if (!response.ok) {
console.error(`-> ❌ HTTP Fehler: ${response.status}`);
continue;
}
const data = await response.json();
const items = data.Items || [];
// Zur Auswertung: Wenn die Abfrage ignoriert wird, liefert er oft ALLE (hier max 5) zurück.
// Filtert er wirklich, sollten es WENIGER als 5, und zwar im besten Fall genau die RICHTIGEN sein.
console.log(`-> Ergebnis: ${items.length} Items zurückgeliefert.`);
if (items.length > 0) {
// Wir checken, ob die zurückgelieferten Items WIRKLICH neu sind
const oldItems = items.filter(item => new Date(item.DateCreated) < pastDate);
if (oldItems.length > 0) {
console.log(` ❌ Filter FEHLGESCHLAGEN: Es wurden ${oldItems.length} "alte" Filme zurückgegeben (z.B. ${oldItems[0].Name}). Er ignoriert also den Parameter.`);
} else {
console.log(` ✅ Filter KÖNNTE funktionieren: Alle zurückgegebenen Filme sind neuer als unser Datum! (Erster: ${items[0].Name})`);
}
} else {
console.log(` ❓ Keine Items gefunden (entweder strenger Filter oder gar keine neuen Filme vorhanden).`);
}
console.log("\n");
}
} catch (error) {
console.error("Fehler beim Abruf:", error);
}
})();

View File

@@ -0,0 +1,56 @@
(async () => {
const apiClient = window.ApiClient;
if (!apiClient) {
console.error("ApiClient not found. Are you logged in?");
return;
}
const userId = apiClient.getCurrentUserId();
const serverAddress = apiClient.serverAddress();
const maxDaysRecent = 30; // Test: Added in last 30 days
const pastDate = new Date();
pastDate.setDate(pastDate.getDate() - maxDaysRecent);
const dateStr = pastDate.toISOString();
console.log(`Searching for items added after: ${dateStr}`);
const testUrls = [
// Test 1: minDateCreated (CamelCase)
`${serverAddress}/Items?IncludeItemTypes=Movie,Series&Recursive=true&enableUserData=true&Limit=5&fields=Id,DateCreated&userId=${userId}&minDateCreated=${dateStr}`,
// Test 2: minDateLastSaved
`${serverAddress}/Items?IncludeItemTypes=Movie,Series&Recursive=true&enableUserData=true&Limit=5&fields=Id,DateCreated&userId=${userId}&minDateLastSaved=${dateStr}`,
];
try {
for (let i = 0; i < testUrls.length; i++) {
const apiUrl = testUrls[i];
console.log(`\n%cTest ${i+1}: Testing URL:\n${apiUrl}`, "color: yellow;");
const response = await fetch(apiUrl, {
headers: {
Authorization: `MediaBrowser Client="${apiClient.appName()}", Device="${apiClient.deviceName()}", DeviceId="${apiClient.deviceId()}", Version="${apiClient.appVersion()}", Token="${apiClient.accessToken()}"`
}
});
if (!response.ok) {
console.error(`Failed to fetch items: ${response.status} ${response.statusText}`);
continue;
}
const data = await response.json();
const items = data.Items || [];
console.log(`%cErgebnis: ${items.length} Items gefunden!`, "color: #00a4dc; font-weight: bold;");
if(items.length > 0) {
console.log("Gefundene Items:");
items.forEach(item => {
console.log(`- Name: ${item.Name}, DateCreated: ${item.DateCreated}, Art: ${item.Type}`);
});
}
}
} catch (error) {
console.error("Fehler beim Abrufen der URL:", error);
}
})();

View File

@@ -0,0 +1,72 @@
(async () => {
const apiClient = window.ApiClient;
if (!apiClient) {
console.error("ApiClient not found. Are you logged in?");
return;
}
const userId = apiClient.getCurrentUserId();
const serverAddress = apiClient.serverAddress();
const maxDaysRecent = 30; // Test: Added in last 30 days
// 1. Calculate the cutoff date
const pastDate = new Date();
pastDate.setDate(pastDate.getDate() - maxDaysRecent);
const dateStr = pastDate.toISOString();
console.log(`\n%c=== TEST: 2-Stufen "Zuletzt Hinzugefügt" Filter ===`, "color: #00a4dc; font-weight: bold; font-size: 14px;");
console.log(`Suche Items neuer als: ${dateStr} (${maxDaysRecent} Tage alt)\n`);
const apiUrl = `${serverAddress}/Items?IncludeItemTypes=Movie,Series&Recursive=true&enableUserData=true&Limit=50&fields=Id,DateCreated&userId=${userId}&minDateLastSaved=${dateStr}`;
try {
console.log(`%cSchritt 1: API Call mit minDateLastSaved...`, "color: yellow;");
console.log(`URL: ${apiUrl}`);
const response = await fetch(apiUrl, {
headers: {
Authorization: `MediaBrowser Client="${apiClient.appName()}", Device="${apiClient.deviceName()}", DeviceId="${apiClient.deviceId()}", Version="${apiClient.appVersion()}", Token="${apiClient.accessToken()}"`
}
});
if (!response.ok) {
throw new Error(`Failed to fetch items: ${response.status} ${response.statusText}`);
}
const data = await response.json();
let items = data.Items || [];
console.log(`-> API lieferte ${items.length} potenziell neue/geänderte Items zurück.\n`);
if (items.length > 0) {
console.log("Die API hielt diese Items für neu/aktuell:");
items.forEach(item => console.log(` - ${item.Name} (DateCreated: ${item.DateCreated})`));
}
console.log(`\n%cSchritt 2: Lokaler DateCreated Filter (Wie das Plugin ihn jetzt nutzt)...`, "color: yellow;");
// Exakt dieser Filter-Block ist jetzt auch so in mediaBarEnhanced.js
const finalItems = items.filter(item => {
if (!item.DateCreated) return true; // Fallback falls Jellyfin kein Datum schickt
const dCreated = new Date(item.DateCreated);
return dCreated >= pastDate;
});
console.log(`%c-> FINALES ERGEBNIS: ${finalItems.length} echte Neuzugänge bleiben übrig!`, "color: #00ff00; font-weight: bold; font-size: 14px;");
if(finalItems.length > 0) {
console.log("Diese Items schaffen es in die Slideshow:");
finalItems.forEach(item => {
console.log(` 🎬 Name: ${item.Name}, DateCreated: ${item.DateCreated}`);
});
}
// Teste den Fallback
if(finalItems.length === 0 && items.length > 0) {
console.log("\n%c💡 HINWEIS: Da nach Filterung 0 Items übrig bleiben, greift in der Slideshow jetzt automatisch unser Fallback und zeigt zufällige Filme aller Jahre!", "color: orange;");
}
} catch (error) {
console.error("Fehler beim Abruf:", error);
}
})();

View File

@@ -0,0 +1,62 @@
(async () => {
const apiClient = window.ApiClient;
if (!apiClient) {
console.error("ApiClient not found. Are you logged in?");
return;
}
const userId = apiClient.getCurrentUserId();
const serverAddress = apiClient.serverAddress();
// Example test configuration flags
const maxItems = 50;
const includeWatchedContent = false; // set to false to ONLY show unplayed (newly watched)
const maxParentalRating = 12; // Test age limit
const maxDaysRecent = 30; // Test recency limit
// Build the query parameters just like in mediaBarEnhanced.js
const sortParams = "sortBy=Random";
const playedFilter = includeWatchedContent ? '' : '&isPlayed=False';
let parentalFilter = '';
if (maxParentalRating) {
parentalFilter = `&MaxOfficialRating=${maxParentalRating}`;
}
let dateFilter = '';
if (maxDaysRecent) {
const pastDate = new Date();
pastDate.setDate(pastDate.getDate() - maxDaysRecent);
dateFilter = `&MinDateCreated=${pastDate.toISOString()}`;
}
const apiUrl = `${serverAddress}/Items?IncludeItemTypes=Movie,Series&Recursive=true&hasOverview=true&imageTypes=Logo,Backdrop&${sortParams}${playedFilter}${parentalFilter}${dateFilter}&enableUserData=true&Limit=${maxItems}&fields=Id&userId=${userId}`;
try {
console.log(`Testing generated URL with filters:\n%c${apiUrl}`, "color: yellow;");
// Execute the fetch
const response = await fetch(apiUrl, {
headers: {
Authorization: `MediaBrowser Client="${apiClient.appName()}", Device="${apiClient.deviceName()}", DeviceId="${apiClient.deviceId()}", Version="${apiClient.appVersion()}", Token="${apiClient.accessToken()}"`
}
});
if (!response.ok) {
throw new Error(`Failed to fetch items: ${response.status} ${response.statusText}`);
}
const data = await response.json();
const items = data.Items || [];
console.log(`%cErgebnis: ${items.length} Items gefunden!`, "color: #00a4dc; font-weight: bold;");
if(items.length > 0) {
console.log("Erstes Item als Beispiel:");
console.dir(items[0]);
}
} catch (error) {
console.error("Fehler beim Abrufen der URL:", error);
}
})();