Revert theme changes

This commit is contained in:
DariusIII
2025-04-29 22:08:42 +02:00
parent a1b2bd8984
commit 205bb068dd
5 changed files with 886 additions and 878 deletions
@@ -1,231 +0,0 @@
// NFO Modal content loading
document.addEventListener('DOMContentLoaded', function() {
const nfoModal = document.getElementById('nfoModal');
if (nfoModal) {
nfoModal.addEventListener('show.bs.modal', function(event) {
const button = event.relatedTarget;
const guid = button.getAttribute('data-guid');
const modalTitle = nfoModal.querySelector('.modal-title');
const loading = nfoModal.querySelector('.nfo-loading');
const contentElement = document.getElementById('nfoContent');
// Reset and show loading state
loading.style.display = 'block';
contentElement.classList.add('d-none');
contentElement.textContent = '';
// Fetch the NFO content via AJAX
fetch(`/nfo/${guid}`, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.text())
.then(html => {
// Extract just the NFO content from the response
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
// Look for the pre element that likely contains the NFO
let nfoText = '';
const preElement = doc.querySelector('pre');
if (preElement) {
// Found a pre element, use its content
nfoText = preElement.textContent;
} else {
// Try to find the main content area
const mainContent = doc.querySelector('.card-body, .main-content, .content-area, main');
if (mainContent) {
nfoText = mainContent.textContent;
} else {
// Fallback: use the whole page but clean it up
nfoText = doc.body.textContent;
}
}
// Update the modal
loading.style.display = 'none';
contentElement.classList.remove('d-none');
contentElement.textContent = nfoText.trim();
})
.catch(error => {
console.error('Error fetching NFO content:', error);
loading.style.display = 'none';
contentElement.classList.remove('d-none');
contentElement.textContent = 'Error loading NFO content';
});
});
}
});
// File List Modal
document.addEventListener('DOMContentLoaded', function() {
const filelistModal = document.getElementById('filelistModal');
if (filelistModal) {
filelistModal.addEventListener('show.bs.modal', function(event) {
const button = event.relatedTarget;
const guid = button.getAttribute('data-guid');
const loading = filelistModal.querySelector('.filelist-loading');
const contentElement = document.getElementById('filelistContent');
const tbody = document.getElementById('filelist-tbody');
const totalFiles = document.getElementById('total-files');
const totalSize = document.getElementById('total-size');
// Reset and show loading state
loading.style.display = 'block';
contentElement.classList.add('d-none');
tbody.innerHTML = '';
// Fetch the file list via AJAX
fetch(`/filelist/${guid}?modal=true`, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.text())
.then(html => {
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
// Extract data from the HTML response
const files = [];
const tableRows = doc.querySelectorAll('table tbody tr');
let totalSizeBytes = 0;
tableRows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length >= 5) {
const file = {
num: cells[0].textContent.trim(),
filename: cells[1].querySelector('.text-truncate').getAttribute('title'),
ext: cells[2].querySelector('.badge') ? cells[2].querySelector('.badge').textContent.trim() : '',
completion: cells[3].querySelector('.progress-bar') ?
cells[3].querySelector('.progress-bar').getAttribute('aria-valuenow') : '100',
size: cells[4].textContent.trim()
};
// Parse filesize for total calculation
const sizeMatch = file.size.match(/(\d+(\.\d+)?)\s*(KB|MB|GB|TB)/i);
if (sizeMatch) {
const size = parseFloat(sizeMatch[1]);
const unit = sizeMatch[3].toUpperCase();
let bytes = size;
if (unit === 'KB') bytes *= 1024;
else if (unit === 'MB') bytes *= 1024 * 1024;
else if (unit === 'GB') bytes *= 1024 * 1024 * 1024;
else if (unit === 'TB') bytes *= 1024 * 1024 * 1024 * 1024;
totalSizeBytes += bytes;
}
files.push(file);
}
});
// Format total size
function formatFileSize(bytes) {
if (bytes < 1024) return bytes + ' B';
else if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
else if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
else if (bytes < 1024 * 1024 * 1024 * 1024) return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
else return (bytes / (1024 * 1024 * 1024 * 1024)).toFixed(2) + ' TB';
}
// Display total information
totalFiles.textContent = files.length;
totalSize.textContent = formatFileSize(totalSizeBytes);
// Populate the modal with files
files.forEach(file => {
const row = document.createElement('tr');
row.innerHTML = `
<td class="text-center">${file.num}</td>
<td class="text-break">
<span class="d-inline-block text-truncate" style="max-width: 400px;" title="${file.filename}">${file.filename}</span>
</td>
<td class="text-center">
<span class="badge bg-secondary text-uppercase">${file.ext}</span>
</td>
<td class="text-center">
<div class="progress" style="height: 20px">
<div class="progress-bar ${file.completion < 100 ? 'bg-warning' : 'bg-success'}"
role="progressbar"
style="width: ${file.completion}%"
aria-valuenow="${file.completion}"
aria-valuemin="0"
aria-valuemax="100">
${file.completion}%
</div>
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<i class="fa fa-hdd-o text-muted me-2"></i>
<span class="fw-medium">${file.size}</span>
</div>
</td>
`;
tbody.appendChild(row);
});
// Show content, hide loading
loading.style.display = 'none';
contentElement.classList.remove('d-none');
})
.catch(error => {
console.error('Error fetching file list:', error);
loading.style.display = 'none';
contentElement.classList.remove('d-none');
tbody.innerHTML = '<tr><td colspan="5" class="text-center text-danger">Error loading file list</td></tr>';
});
});
}
});
document.addEventListener('DOMContentLoaded', function() {
// Delegate the click event to the document so it works for dynamically loaded content
document.addEventListener('click', function(e) {
// Find if the click was on a cart button or its child elements
const cartBtn = e.target.closest('a:has(.icon_cart)');
if (cartBtn) {
e.preventDefault(); // Prevent jumping to top of page
// Extract the GUID from the icon ID
const iconElement = cartBtn.querySelector('.icon_cart');
const guidId = iconElement.id;
const guid = guidId.replace('guid', '');
// Send AJAX request to add item to cart
fetch('/cart/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify({ guid: guid })
})
.then(response => response.json())
.then(data => {
// Show success message or update cart count
if (data.success) {
iconElement.classList.remove('fa-shopping-basket');
iconElement.classList.add('fa-check');
setTimeout(() => {
iconElement.classList.remove('fa-check');
iconElement.classList.add('fa-shopping-basket');
}, 1000);
}
})
.catch(error => console.error('Error:', error));
}
});
// Initialize tooltips
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
});
@@ -1,148 +0,0 @@
document.addEventListener('DOMContentLoaded', function() {
// Search type toggle functionality
const searchTypeToggle = document.getElementById('searchTypeToggle');
if (searchTypeToggle) {
searchTypeToggle.addEventListener('click', function(e) {
e.preventDefault();
const currentType = this.getAttribute('data-current-type');
const sbasic = document.getElementById('sbasic');
const sadvanced = document.getElementById('sadvanced');
if (currentType === 'advanced') {
this.textContent = 'Basic Search';
this.setAttribute('data-current-type', 'basic');
} else {
this.textContent = 'Advanced Search';
this.setAttribute('data-current-type', 'advanced');
}
sbasic.style.display = sbasic.style.display === 'none' ? 'flex' : 'none';
sadvanced.style.display = sadvanced.style.display === 'none' ? 'block' : 'none';
});
}
// File List Modal
const filelistModal = document.getElementById('filelistModal');
if (filelistModal) {
filelistModal.addEventListener('show.bs.modal', function(event) {
const button = event.relatedTarget;
const guid = button.getAttribute('data-guid');
const loading = filelistModal.querySelector('.filelist-loading');
const contentElement = document.getElementById('filelistContent');
const tbody = document.getElementById('filelist-tbody');
const totalFiles = document.getElementById('total-files');
const totalSize = document.getElementById('total-size');
// Reset and show loading state
loading.style.display = 'block';
contentElement.classList.add('d-none');
tbody.innerHTML = '';
// Fetch the file list via AJAX
fetch(`/filelist/${guid}?modal=true`, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.text())
.then(html => {
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
// Extract data from the HTML response
const files = [];
const tableRows = doc.querySelectorAll('table tbody tr');
let totalSizeBytes = 0;
tableRows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length >= 5) {
const file = {
num: cells[0].textContent.trim(),
filename: cells[1].querySelector('.text-truncate') ?
cells[1].querySelector('.text-truncate').getAttribute('title') :
cells[1].textContent.trim(),
ext: cells[2].querySelector('.badge') ?
cells[2].querySelector('.badge').textContent.trim() : '',
completion: cells[3].querySelector('.progress-bar') ?
cells[3].querySelector('.progress-bar').getAttribute('aria-valuenow') : '100',
size: cells[4].textContent.trim()
};
// Parse filesize for total calculation
const sizeMatch = file.size.match(/(\d+(\.\d+)?)\s*(KB|MB|GB|TB)/i);
if (sizeMatch) {
const size = parseFloat(sizeMatch[1]);
const unit = sizeMatch[3].toUpperCase();
let bytes = size;
if (unit === 'KB') bytes *= 1024;
else if (unit === 'MB') bytes *= 1024 * 1024;
else if (unit === 'GB') bytes *= 1024 * 1024 * 1024;
else if (unit === 'TB') bytes *= 1024 * 1024 * 1024 * 1024;
totalSizeBytes += bytes;
}
files.push(file);
}
});
// Format total size
function formatFileSize(bytes) {
if (bytes < 1024) return bytes + ' B';
else if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
else if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
else if (bytes < 1024 * 1024 * 1024 * 1024) return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
else return (bytes / (1024 * 1024 * 1024 * 1024)).toFixed(2) + ' TB';
}
// Display total information
totalFiles.textContent = files.length;
totalSize.textContent = formatFileSize(totalSizeBytes);
// Populate the modal with files
files.forEach(file => {
const row = document.createElement('tr');
row.innerHTML = `
<td class="text-center">${file.num}</td>
<td class="text-break">
<span class="d-inline-block text-truncate" style="max-width: 400px;" title="${file.filename}">${file.filename}</span>
</td>
<td class="text-center">
<span class="badge bg-secondary text-uppercase">${file.ext}</span>
</td>
<td class="text-center">
<div class="progress" style="height: 20px">
<div class="progress-bar ${file.completion < 100 ? 'bg-warning' : 'bg-success'}"
role="progressbar"
style="width: ${file.completion}%"
aria-valuenow="${file.completion}"
aria-valuemin="0"
aria-valuemax="100">
${file.completion}%
</div>
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<i class="fa fa-hdd-o text-muted me-2"></i>
<span class="fw-medium">${file.size}</span>
</div>
</td>
`;
tbody.appendChild(row);
});
// Show content, hide loading
loading.style.display = 'none';
contentElement.classList.remove('d-none');
})
.catch(error => {
console.error('Error fetching file list:', error);
loading.style.display = 'none';
contentElement.classList.remove('d-none');
tbody.innerHTML = '<tr><td colspan="5" class="text-center text-danger">Error loading file list</td></tr>';
});
});
}
});
+539 -303
View File
@@ -1,327 +1,327 @@
<div class="header">
<div class="breadcrumb-wrapper">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{url("{$site->home_link}")}}">Home</a></li>
{if $parentcat == ''}
<li class="breadcrumb-item active"><a href="{{url("/browse/$catname")}}">Browse/{$catname}</a></li>
{else}
<li class="breadcrumb-item"><a href="{{url("/{if preg_match('/^alt\.binaries|a\.b|dk\./i', $parentcat)}browse/group?g={else}browse/{/if}{if ($parentcat == 'music')}Audio{else}{$parentcat}{/if}")}}">{$parentcat}</a></li>
{if ($catname != '' && $catname != 'all')}
<li class="breadcrumb-item active"><a href="{{url("/browse/{$parentcat}/{$catname}")}}">{$catname}</a></li>
{/if}
{/if}
</ol>
</nav>
</div>
</div>
<div class="breadcrumb-wrapper">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{url("{$site->home_link}")}}">Home</a></li>
{if $parentcat == ''}
<li class="breadcrumb-item active"><a href="{{url("/browse/$catname")}}">Browse/{$catname}</a></li>
{else}
<li class="breadcrumb-item"><a href="{{url("/{if preg_match('/^alt\.binaries|a\.b|dk\./i', $parentcat)}browse/group?g={else}browse/{/if}{if ($parentcat == 'music')}Audio{else}{$parentcat}{/if}")}}">{$parentcat}</a></li>
{if ($catname != '' && $catname != 'all')}
<li class="breadcrumb-item active"><a href="{{url("/browse/{$parentcat}/{$catname}")}}">{$catname}</a></li>
{/if}
{/if}
</ol>
</nav>
</div>
</div>
{$site->adbrowse}
{$site->adbrowse}
{if count($results) > 0}
{{Form::open(['id' => 'nzb_multi_operations_form', 'method' => 'get'])}}
<div class="card-header bg-light">
<div class="row g-3">
<!-- Changed from col-md-4 to col-lg-4 for better small screen handling -->
<div class="col-lg-4 col-md-12">
{if isset($shows)}
<div class="mb-3">
<a href="{{route('series')}}" class="me-2" title="View available TV series">Series List</a> |
<a href="{{route('myshows')}}" class="mx-2" title="Manage your shows">Manage My Shows</a> |
<a href="{{url("/rss/myshows?dl=1&amp;i={$userdata.id}&amp;api_token={$userdata.api_token}")}}" class="ms-2" title="All releases in your shows as an RSS feed">RSS Feed</a>
</div>
{/if}
{if count($results) > 0}
{{Form::open(['id' => 'nzb_multi_operations_form', 'method' => 'get'])}}
<div class="card-header bg-light">
<div class="row g-3">
<!-- Changed from col-md-4 to col-lg-4 for better small screen handling -->
<div class="col-lg-4 col-md-12">
{if isset($shows)}
<div class="mb-3">
<a href="{{route('series')}}" class="me-2" title="View available TV series">Series List</a> |
<a href="{{route('myshows')}}" class="mx-2" title="Manage your shows">Manage My Shows</a> |
<a href="{{url("/rss/myshows?dl=1&amp;i={$userdata.id}&amp;api_token={$userdata.api_token}")}}" class="ms-2" title="All releases in your shows as an RSS feed">RSS Feed</a>
</div>
{/if}
{if isset($covgroup) && $covgroup != ''}
<div class="mb-3">
<span class="me-2">View:</span>
<a href="{{url("/{$covgroup}/{$category}")}}" class="me-2">Covers</a> |
<b class="ms-2">List</b>
</div>
{/if}
{if isset($covgroup) && $covgroup != ''}
<div class="mb-3">
<span class="me-2">View:</span>
<a href="{{url("/{$covgroup}/{$category}")}}" class="me-2">Covers</a> |
<b class="ms-2">List</b>
</div>
{/if}
<div class="nzb_multi_operations d-flex flex-wrap align-items-center">
<small class="me-2 mb-2">With Selected:</small>
<div class="btn-group mb-2">
<button type="button" class="nzb_multi_operations_download btn btn-sm btn-success" data-bs-toggle="tooltip" data-bs-placement="top" title="Download NZBs">
<i class="fa fa-cloud-download"></i>
</button>
<button type="button" class="nzb_multi_operations_cart btn btn-sm btn-info" data-bs-toggle="tooltip" data-bs-placement="top" title="Send to my Download Basket">
<i class="fa fa-shopping-basket"></i>
</button>
{if isset($isadmin)}
<button type="button" class="nzb_multi_operations_edit btn btn-sm btn-warning">Edit</button>
<button type="button" class="nzb_multi_operations_delete btn btn-sm btn-danger">Delete</button>
{/if}
</div>
</div>
</div>
<!-- Changed from col-md-8 to col-lg-8 and added order classes -->
<div class="col-lg-8 col-md-12 d-flex justify-content-lg-end justify-content-center align-items-center order-lg-2 order-md-1">
<div class="pagination-container overflow-auto w-100 d-flex justify-content-lg-end justify-content-center">
{$results->onEachSide(5)->links()}
</div>
</div>
</div>
</div>
<div class="nzb_multi_operations d-flex flex-wrap align-items-center">
<small class="me-2 mb-2">With Selected:</small>
<div class="btn-group mb-2">
<button type="button" class="nzb_multi_operations_download btn btn-sm btn-success" data-bs-toggle="tooltip" data-bs-placement="top" title="Download NZBs">
<i class="fa fa-cloud-download"></i>
</button>
<button type="button" class="nzb_multi_operations_cart btn btn-sm btn-info" data-bs-toggle="tooltip" data-bs-placement="top" title="Send to my Download Basket">
<i class="fa fa-shopping-basket"></i>
</button>
{if isset($isadmin)}
<button type="button" class="nzb_multi_operations_edit btn btn-sm btn-warning">Edit</button>
<button type="button" class="nzb_multi_operations_delete btn btn-sm btn-danger">Delete</button>
{/if}
</div>
</div>
</div>
<!-- Changed from col-md-8 to col-lg-8 and added order classes -->
<div class="col-lg-8 col-md-12 d-flex justify-content-lg-end justify-content-center align-items-center order-lg-2 order-md-1">
<div class="pagination-container overflow-auto w-100 d-flex justify-content-lg-end justify-content-center">
{$results->onEachSide(5)->links()}
</div>
</div>
</div>
</div>
<div class="card-body px-0 py-0">
<div class="table-responsive">
<table class="table table-striped table-hover data mb-0">
<thead class="thead-light">
<tr>
<th style="width: 30px">
<input id="check-all" type="checkbox" class="flat-all">
</th>
<th>
<div class="d-flex align-items-center gap-2">
<span>Name</span>
<div class="sort-controls">
<a href="{$orderbyname_asc}" class="sort-icon {if isset($orderby) && $orderby == 'name_asc'}active{/if}" title="Sort Ascending">
<i class="fas fa-sort-alpha-down"></i>
</a>
<a href="{$orderbyname_desc}" class="sort-icon {if isset($orderby) && $orderby == 'name_desc'}active{/if}" title="Sort Descending">
<i class="fas fa-sort-alpha-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center gap-2">
<span>Category</span>
<div class="sort-controls">
<a href="{$orderbycat_asc}" class="sort-icon {if isset($orderby) && $orderby == 'cat_asc'}active{/if}" title="Sort Ascending">
<i class="fas fa-sort-alpha-down"></i>
</a>
<a href="{$orderbycat_desc}" class="sort-icon {if isset($orderby) && $orderby == 'cat_desc'}active{/if}" title="Sort Descending">
<i class="fas fa-sort-alpha-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center gap-2">
<span>Posted</span>
<div class="sort-controls">
<a href="{$orderbyposted_asc}" class="sort-icon {if isset($orderby) && $orderby == 'posted_asc'}active{/if}" title="Sort Oldest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbyposted_desc}" class="sort-icon {if isset($orderby) && $orderby == 'posted_desc'}active{/if}" title="Sort Newest First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center justify-content-center gap-2">
<span>Size</span>
<div class="sort-controls">
<a href="{$orderbysize_asc}" class="sort-icon {if isset($orderby) && $orderby == 'size_asc'}active{/if}" title="Sort Smallest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbysize_desc}" class="sort-icon {if isset($orderby) && $orderby == 'size_desc'}active{/if}" title="Sort Largest First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center justify-content-center gap-2">
<span>Files</span>
<div class="sort-controls">
<a href="{$orderbyfiles_asc}" class="sort-icon {if isset($orderby) && $orderby == 'files_asc'}active{/if}" title="Sort Fewest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbyfiles_desc}" class="sort-icon {if isset($orderby) && $orderby == 'files_desc'}active{/if}" title="Sort Most First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center justify-content-center gap-2">
<span>Downloads</span>
<div class="sort-controls">
<a href="{$orderbystats_asc}" class="sort-icon {if isset($orderby) && $orderby == 'stats_asc'}active{/if}" title="Sort Fewest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbystats_desc}" class="sort-icon {if isset($orderby) && $orderby == 'stats_desc'}active{/if}" title="Sort Most First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</div>
</th>
<th class="text-end">Action</th>
</tr>
</thead>
<tbody>
{foreach $resultsadd as $result}
<tr id="guid{$result->guid}">
<td>
<input id="chk{$result->guid|substr:0:7}" type="checkbox" name="table_records" class="flat" value="{$result->guid}">
</td>
<td>
<div class="mb-1">
<a href="{{url("/details/{$result->guid}")}}" class="title fw-semibold">{$result->searchname|escape:"htmlall"|replace:".":" "}</a>
{if !empty($result->failed)}
<i class="fa fa-exclamation-circle text-danger ms-1" title="This release has failed to download for some users"></i>
{/if}
{if $lastvisit|strtotime < $result->adddate|strtotime}
<span class="badge bg-success ms-1">New</span>
{/if}
</div>
<div class="d-flex flex-wrap gap-2 mt-2">
<!-- Downloads indicator -->
<span class="badge bg-secondary text-white">
<div class="card-body px-0 py-0">
<div class="table-responsive">
<table class="table table-striped table-hover data mb-0">
<thead class="thead-light">
<tr>
<th style="width: 30px">
<input id="check-all" type="checkbox" class="flat-all">
</th>
<th>
<div class="d-flex align-items-center gap-2">
<span>Name</span>
<div class="sort-controls">
<a href="{$orderbyname_asc}" class="sort-icon {if isset($orderby) && $orderby == 'name_asc'}active{/if}" title="Sort Ascending">
<i class="fas fa-sort-alpha-down"></i>
</a>
<a href="{$orderbyname_desc}" class="sort-icon {if isset($orderby) && $orderby == 'name_desc'}active{/if}" title="Sort Descending">
<i class="fas fa-sort-alpha-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center gap-2">
<span>Category</span>
<div class="sort-controls">
<a href="{$orderbycat_asc}" class="sort-icon {if isset($orderby) && $orderby == 'cat_asc'}active{/if}" title="Sort Ascending">
<i class="fas fa-sort-alpha-down"></i>
</a>
<a href="{$orderbycat_desc}" class="sort-icon {if isset($orderby) && $orderby == 'cat_desc'}active{/if}" title="Sort Descending">
<i class="fas fa-sort-alpha-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center gap-2">
<span>Posted</span>
<div class="sort-controls">
<a href="{$orderbyposted_asc}" class="sort-icon {if isset($orderby) && $orderby == 'posted_asc'}active{/if}" title="Sort Oldest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbyposted_desc}" class="sort-icon {if isset($orderby) && $orderby == 'posted_desc'}active{/if}" title="Sort Newest First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center justify-content-center gap-2">
<span>Size</span>
<div class="sort-controls">
<a href="{$orderbysize_asc}" class="sort-icon {if isset($orderby) && $orderby == 'size_asc'}active{/if}" title="Sort Smallest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbysize_desc}" class="sort-icon {if isset($orderby) && $orderby == 'size_desc'}active{/if}" title="Sort Largest First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center justify-content-center gap-2">
<span>Files</span>
<div class="sort-controls">
<a href="{$orderbyfiles_asc}" class="sort-icon {if isset($orderby) && $orderby == 'files_asc'}active{/if}" title="Sort Fewest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbyfiles_desc}" class="sort-icon {if isset($orderby) && $orderby == 'files_desc'}active{/if}" title="Sort Most First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center justify-content-center gap-2">
<span>Downloads</span>
<div class="sort-controls">
<a href="{$orderbystats_asc}" class="sort-icon {if isset($orderby) && $orderby == 'stats_asc'}active{/if}" title="Sort Fewest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbystats_desc}" class="sort-icon {if isset($orderby) && $orderby == 'stats_desc'}active{/if}" title="Sort Most First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</div>
</th>
<th class="text-end">Action</th>
</tr>
</thead>
<tbody>
{foreach $resultsadd as $result}
<tr id="guid{$result->guid}">
<td>
<input id="chk{$result->guid|substr:0:7}" type="checkbox" name="table_records" class="flat" value="{$result->guid}">
</td>
<td>
<div class="mb-1">
<a href="{{url("/details/{$result->guid}")}}" class="title fw-semibold">{$result->searchname|escape:"htmlall"|replace:".":" "}</a>
{if !empty($result->failed)}
<i class="fa fa-exclamation-circle text-danger ms-1" title="This release has failed to download for some users"></i>
{/if}
{if $lastvisit|strtotime < $result->adddate|strtotime}
<span class="badge bg-success ms-1">New</span>
{/if}
</div>
<div class="d-flex flex-wrap gap-2 mt-2">
<!-- Downloads indicator -->
<span class="badge bg-secondary text-white">
<i class="fa fa-download me-1"></i>{$result->grabs} Grab{if $result->grabs != 1}s{/if}
</span>
<!-- Media badges -->
{if $result->nfoid > 0}
<a href="#" data-bs-toggle="modal" data-bs-target="#nfoModal" data-guid="{$result->guid}" class="nfo-modal-trigger badge bg-info">
<i class="fa fa-file-text-o me-1"></i>NFO
</a>
{/if}
<!-- Media badges -->
{if $result->nfoid > 0}
<a href="#" data-bs-toggle="modal" data-bs-target="#nfoModal" data-guid="{$result->guid}" class="nfo-modal-trigger badge bg-info">
<i class="fa fa-file-text-o me-1"></i>NFO
</a>
{/if}
{if $result->jpgstatus == 1 && $userdata->can('preview') == true}
<a href="{{url("/covers/sample/{$result->guid}_thumb.jpg")}}" name="name{$result->guid}" data-fancybox class="badge bg-primary" rel="preview">
<i class="fa fa-image me-1"></i>Sample
</a>
{/if}
{if $result->jpgstatus == 1 && $userdata->can('preview') == true}
<a href="{{url("/covers/sample/{$result->guid}_thumb.jpg")}}" name="name{$result->guid}" data-fancybox class="badge bg-primary" rel="preview">
<i class="fa fa-image me-1"></i>Sample
</a>
{/if}
{if $result->haspreview == 1 && $userdata->can('preview') == true}
<a href="{{url("/covers/preview/{$result->guid}_thumb.jpg")}}" name="name{$result->guid}" data-fancybox class="badge bg-primary" rel="preview">
<i class="fa fa-film me-1"></i>Preview
</a>
{/if}
{if $result->haspreview == 1 && $userdata->can('preview') == true}
<a href="{{url("/covers/preview/{$result->guid}_thumb.jpg")}}" name="name{$result->guid}" data-fancybox class="badge bg-primary" rel="preview">
<i class="fa fa-film me-1"></i>Preview
</a>
{/if}
<!-- Media type badges -->
{if $result->videos_id > 0}
<a href="{{url("/series/{$result->videos_id}")}}" class="badge bg-success" rel="series">
<i class="fa fa-tv me-1"></i>View TV
</a>
{/if}
<!-- Media type badges -->
{if $result->videos_id > 0}
<a href="{{url("/series/{$result->videos_id}")}}" class="badge bg-success" rel="series">
<i class="fa fa-tv me-1"></i>View TV
</a>
{/if}
{if !empty($result->firstaired)}
<span class="seriesinfo badge bg-warning text-dark" title="{$result->guid}">
{if !empty($result->firstaired)}
<span class="seriesinfo badge bg-warning text-dark" title="{$result->guid}">
<i class="fa fa-calendar me-1"></i>Aired {if $result->firstaired|strtotime > $smarty.now}in future{else}{$result->firstaired|daysago}{/if}
</span>
{/if}
{/if}
{if $result->anidbid > 0}
<a class="badge bg-success" href="{{url("/anime?id={$result->anidbid}")}}">
<i class="fa fa-play-circle me-1"></i>View Anime
</a>
{/if}
{if $result->anidbid > 0}
<a class="badge bg-success" href="{{url("/anime?id={$result->anidbid}")}}">
<i class="fa fa-play-circle me-1"></i>View Anime
</a>
{/if}
<!-- Stats badges -->
{if !empty($result->failed)}
<span class="badge bg-danger">
<!-- Stats badges -->
{if !empty($result->failed)}
<span class="badge bg-danger">
<i class="fa fa-exclamation-triangle me-1"></i>{$result->failed} Failed
</span>
{/if}
{/if}
<!-- Source badges -->
<span class="badge bg-dark">
<!-- Source badges -->
<span class="badge bg-dark">
<i class="fa fa-users me-1"></i>{$result->group_name}
</span>
<span class="badge bg-dark">
<span class="badge bg-dark">
<i class="fa fa-user me-1"></i>{$result->fromname}
</span>
</div>
</td>
<td>
</div>
</td>
<td>
<span class="badge bg-secondary text-white rounded-pill">
<i class="fa fa-folder-open me-1"></i>{$result->category_name}
</span>
</td>
<td>
<div class="d-flex align-items-center">
<i class="fa fa-clock-o text-muted me-2"></i>
<span title="{$result->postdate}">{$result->postdate|timeago}</span>
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<i class="fa fa-hdd-o text-muted me-2"></i>
<span class="fw-medium">{$result->size|filesize}</span>
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<a class="d-flex align-items-center text-decoration-none" title="View file list" href="#" data-bs-toggle="modal" data-bs-target="#filelistModal" data-guid="{$result.guid}">
<i class="far fa-file text-primary me-1"></i>
<span class="fw-medium">{$result->totalpart}</span>
</a>
{if $result->rarinnerfilecount > 0}
<div class="rarfilelist d-inline-block ms-2" title="View RAR contents">
<i class="fas fa-search-plus text-info"></i>
</div>
{/if}
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<i class="fa fa-download text-muted me-2"></i>
<span class="fw-medium">{$result->grabs}</span>
</div>
</td>
<td class="text-end">
<div class="d-flex justify-content-end gap-2">
<a href="{{url("/getnzb?id={$result->guid}")}}" class="btn btn-sm btn-outline-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Download NZB">
<i class="fa fa-cloud-download"></i>
</a>
<a href="{{url("/details/{$result->guid}/#comments")}}" class="btn btn-sm btn-outline-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Comments">
<i class="fa fa-comments-o"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Send to my download basket">
<i id="guid{$result->guid}" class="icon_cart fa fa-shopping-basket"></i>
</a>
</div>
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
</div>
</td>
<td>
<div class="d-flex align-items-center">
<i class="fa fa-clock-o text-muted me-2"></i>
<span title="{$result->postdate}">{$result->postdate|timeago}</span>
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<i class="fa fa-hdd-o text-muted me-2"></i>
<span class="fw-medium">{$result->size|filesize}</span>
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<a class="d-flex align-items-center text-decoration-none" title="View file list" href="#" data-bs-toggle="modal" data-bs-target="#filelistModal" data-guid="{$result.guid}">
<i class="far fa-file text-primary me-1"></i>
<span class="fw-medium">{$result->totalpart}</span>
</a>
{if $result->rarinnerfilecount > 0}
<div class="rarfilelist d-inline-block ms-2" title="View RAR contents">
<i class="fas fa-search-plus text-info"></i>
</div>
{/if}
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<i class="fa fa-download text-muted me-2"></i>
<span class="fw-medium">{$result->grabs}</span>
</div>
</td>
<td class="text-end">
<div class="d-flex justify-content-end gap-2">
<a href="{{url("/getnzb?id={$result->guid}")}}" class="btn btn-sm btn-outline-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Download NZB">
<i class="fa fa-cloud-download"></i>
</a>
<a href="{{url("/details/{$result->guid}/#comments")}}" class="btn btn-sm btn-outline-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Comments">
<i class="fa fa-comments-o"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Send to my download basket">
<i id="guid{$result->guid}" class="icon_cart fa fa-shopping-basket"></i>
</a>
</div>
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
</div>
<div class="card-footer">
<div class="row g-3">
<!-- Changed from col-md-4 to col-lg-4 to match header -->
<div class="col-lg-4 col-md-12">
<div class="nzb_multi_operations">
<div class="d-flex flex-wrap align-items-center gap-2">
<small class="me-2 mb-2">With Selected:</small>
<div class="btn-group mb-2">
<button type="button" class="nzb_multi_operations_download btn btn-sm btn-success" data-bs-toggle="tooltip" data-bs-placement="top" title="Download NZBs">
<i class="fa fa-cloud-download"></i>
</button>
<button type="button" class="nzb_multi_operations_cart btn btn-sm btn-info" data-bs-toggle="tooltip" data-bs-placement="top" title="Send to my Download Basket">
<i class="fa fa-shopping-basket"></i>
</button>
{if isset($isadmin)}
<button type="button" class="nzb_multi_operations_edit btn btn-sm btn-warning">Edit</button>
<button type="button" class="nzb_multi_operations_delete btn btn-sm btn-danger">Delete</button>
{/if}
</div>
</div>
</div>
</div>
<!-- Changed from col-md-8 to col-lg-8 and improved responsive behavior -->
<div class="col-lg-8 col-md-12 d-flex justify-content-lg-end justify-content-center align-items-center order-lg-2 order-md-1">
<div class="pagination-container overflow-auto w-100 d-flex justify-content-lg-end justify-content-center">
{$results->onEachSide(5)->links()}
</div>
</div>
</div>
</div>
</div>
{{Form::close()}}
{else}
<div class="alert alert-info">No releases indexed yet!</div>
{/if}
<div class="card-footer">
<div class="row g-3">
<!-- Changed from col-md-4 to col-lg-4 to match header -->
<div class="col-lg-4 col-md-12">
<div class="nzb_multi_operations">
<div class="d-flex flex-wrap align-items-center gap-2">
<small class="me-2 mb-2">With Selected:</small>
<div class="btn-group mb-2">
<button type="button" class="nzb_multi_operations_download btn btn-sm btn-success" data-bs-toggle="tooltip" data-bs-placement="top" title="Download NZBs">
<i class="fa fa-cloud-download"></i>
</button>
<button type="button" class="nzb_multi_operations_cart btn btn-sm btn-info" data-bs-toggle="tooltip" data-bs-placement="top" title="Send to my Download Basket">
<i class="fa fa-shopping-basket"></i>
</button>
{if isset($isadmin)}
<button type="button" class="nzb_multi_operations_edit btn btn-sm btn-warning">Edit</button>
<button type="button" class="nzb_multi_operations_delete btn btn-sm btn-danger">Delete</button>
{/if}
</div>
</div>
</div>
</div>
<!-- Changed from col-md-8 to col-lg-8 and improved responsive behavior -->
<div class="col-lg-8 col-md-12 d-flex justify-content-lg-end justify-content-center align-items-center order-lg-2 order-md-1">
<div class="pagination-container overflow-auto w-100 d-flex justify-content-lg-end justify-content-center">
{$results->onEachSide(5)->links()}
</div>
</div>
</div>
</div>
</div>
{{Form::close()}}
{else}
<div class="alert alert-info">No releases indexed yet!</div>
{/if}
<!-- NFO Modal -->
<div class="modal fade" id="nfoModal" tabindex="-1" aria-labelledby="nfoModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-scrollable">
@@ -369,16 +369,16 @@
<div class="table-responsive">
<table class="table table-striped table-hover mb-0">
<thead class="thead-light">
<tr>
<th style="width: 40px" class="text-center">#</th>
<th>Filename</th>
<th style="width: 60px" class="text-center">Type</th>
<th style="width: 120px" class="text-center">Completion</th>
<th style="width: 100px" class="text-center">Size</th>
</tr>
<tr>
<th style="width: 40px" class="text-center">#</th>
<th>Filename</th>
<th style="width: 60px" class="text-center">Type</th>
<th style="width: 120px" class="text-center">Completion</th>
<th style="width: 100px" class="text-center">Size</th>
</tr>
</thead>
<tbody id="filelist-tbody">
<!-- Files will be populated here -->
<!-- Files will be populated here -->
</tbody>
</table>
</div>
@@ -390,3 +390,239 @@
</div>
</div>
</div>
<script>
{literal}
// NFO Modal content loading
document.addEventListener('DOMContentLoaded', function() {
const nfoModal = document.getElementById('nfoModal');
if (nfoModal) {
nfoModal.addEventListener('show.bs.modal', function(event) {
const button = event.relatedTarget;
const guid = button.getAttribute('data-guid');
const modalTitle = nfoModal.querySelector('.modal-title');
const loading = nfoModal.querySelector('.nfo-loading');
const contentElement = document.getElementById('nfoContent');
// Reset and show loading state
loading.style.display = 'block';
contentElement.classList.add('d-none');
contentElement.textContent = '';
// Fetch the NFO content via AJAX
fetch(`/nfo/${guid}`, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.text())
.then(html => {
// Extract just the NFO content from the response
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
// Look for the pre element that likely contains the NFO
let nfoText = '';
const preElement = doc.querySelector('pre');
if (preElement) {
// Found a pre element, use its content
nfoText = preElement.textContent;
} else {
// Try to find the main content area
const mainContent = doc.querySelector('.card-body, .main-content, .content-area, main');
if (mainContent) {
nfoText = mainContent.textContent;
} else {
// Fallback: use the whole page but clean it up
nfoText = doc.body.textContent;
}
}
// Update the modal
loading.style.display = 'none';
contentElement.classList.remove('d-none');
contentElement.textContent = nfoText.trim();
})
.catch(error => {
console.error('Error fetching NFO content:', error);
loading.style.display = 'none';
contentElement.classList.remove('d-none');
contentElement.textContent = 'Error loading NFO content';
});
});
}
});
// File List Modal
document.addEventListener('DOMContentLoaded', function() {
const filelistModal = document.getElementById('filelistModal');
if (filelistModal) {
filelistModal.addEventListener('show.bs.modal', function(event) {
const button = event.relatedTarget;
const guid = button.getAttribute('data-guid');
const loading = filelistModal.querySelector('.filelist-loading');
const contentElement = document.getElementById('filelistContent');
const tbody = document.getElementById('filelist-tbody');
const totalFiles = document.getElementById('total-files');
const totalSize = document.getElementById('total-size');
// Reset and show loading state
loading.style.display = 'block';
contentElement.classList.add('d-none');
tbody.innerHTML = '';
// Fetch the file list via AJAX
fetch(`/filelist/${guid}?modal=true`, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.text())
.then(html => {
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
// Extract data from the HTML response
const files = [];
const tableRows = doc.querySelectorAll('table tbody tr');
let totalSizeBytes = 0;
tableRows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length >= 5) {
const file = {
num: cells[0].textContent.trim(),
filename: cells[1].querySelector('.text-truncate').getAttribute('title'),
ext: cells[2].querySelector('.badge') ? cells[2].querySelector('.badge').textContent.trim() : '',
completion: cells[3].querySelector('.progress-bar') ?
cells[3].querySelector('.progress-bar').getAttribute('aria-valuenow') : '100',
size: cells[4].textContent.trim()
};
// Parse filesize for total calculation
const sizeMatch = file.size.match(/(\d+(\.\d+)?)\s*(KB|MB|GB|TB)/i);
if (sizeMatch) {
const size = parseFloat(sizeMatch[1]);
const unit = sizeMatch[3].toUpperCase();
let bytes = size;
if (unit === 'KB') bytes *= 1024;
else if (unit === 'MB') bytes *= 1024 * 1024;
else if (unit === 'GB') bytes *= 1024 * 1024 * 1024;
else if (unit === 'TB') bytes *= 1024 * 1024 * 1024 * 1024;
totalSizeBytes += bytes;
}
files.push(file);
}
});
// Format total size
function formatFileSize(bytes) {
if (bytes < 1024) return bytes + ' B';
else if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
else if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
else if (bytes < 1024 * 1024 * 1024 * 1024) return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
else return (bytes / (1024 * 1024 * 1024 * 1024)).toFixed(2) + ' TB';
}
// Display total information
totalFiles.textContent = files.length;
totalSize.textContent = formatFileSize(totalSizeBytes);
// Populate the modal with files
files.forEach(file => {
const row = document.createElement('tr');
row.innerHTML = `
<td class="text-center">${file.num}</td>
<td class="text-break">
<span class="d-inline-block text-truncate" style="max-width: 400px;" title="${file.filename}">${file.filename}</span>
</td>
<td class="text-center">
<span class="badge bg-secondary text-uppercase">${file.ext}</span>
</td>
<td class="text-center">
<div class="progress" style="height: 20px">
<div class="progress-bar ${file.completion < 100 ? 'bg-warning' : 'bg-success'}"
role="progressbar"
style="width: ${file.completion}%"
aria-valuenow="${file.completion}"
aria-valuemin="0"
aria-valuemax="100">
${file.completion}%
</div>
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<i class="fa fa-hdd-o text-muted me-2"></i>
<span class="fw-medium">${file.size}</span>
</div>
</td>
`;
tbody.appendChild(row);
});
// Show content, hide loading
loading.style.display = 'none';
contentElement.classList.remove('d-none');
})
.catch(error => {
console.error('Error fetching file list:', error);
loading.style.display = 'none';
contentElement.classList.remove('d-none');
tbody.innerHTML = '<tr><td colspan="5" class="text-center text-danger">Error loading file list</td></tr>';
});
});
}
});
// Add this to your JavaScript file or in a script tag at the bottom of the page
document.addEventListener('DOMContentLoaded', function() {
// Delegate the click event to the document so it works for dynamically loaded content
document.addEventListener('click', function(e) {
// Find if the click was on a cart button or its child elements
const cartBtn = e.target.closest('a:has(.icon_cart)');
if (cartBtn) {
e.preventDefault(); // Prevent jumping to top of page
// Extract the GUID from the icon ID
const iconElement = cartBtn.querySelector('.icon_cart');
const guidId = iconElement.id;
const guid = guidId.replace('guid', '');
// Send AJAX request to add item to cart
fetch('/cart/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify({ guid: guid })
})
.then(response => response.json())
.then(data => {
// Show success message or update cart count
if (data.success) {
iconElement.classList.remove('fa-shopping-basket');
iconElement.classList.add('fa-check');
setTimeout(() => {
iconElement.classList.remove('fa-check');
iconElement.classList.add('fa-shopping-basket');
}, 1000);
}
})
.catch(error => console.error('Error:', error));
}
});
// Initialize tooltips
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
});
{/literal}
</script>
+344 -191
View File
@@ -177,219 +177,219 @@
<div class="table-responsive">
<table class="table table-striped table-hover data mb-0">
<thead class="thead-light">
<tr>
<th style="width: 30px">
<input id="check-all" type="checkbox" class="flat-all">
</th>
<th>
<div class="d-flex align-items-center gap-2">
<span>Name</span>
<div class="sort-controls">
<a href="{$orderbyname_asc}" class="sort-icon {if isset($orderby) && $orderby == 'name_asc'}active{/if}" title="Sort Ascending">
<i class="fas fa-sort-alpha-down"></i>
</a>
<a href="{$orderbyname_desc}" class="sort-icon {if isset($orderby) && $orderby == 'name_desc'}active{/if}" title="Sort Descending">
<i class="fas fa-sort-alpha-down-alt"></i>
</a>
</div>
<tr>
<th style="width: 30px">
<input id="check-all" type="checkbox" class="flat-all">
</th>
<th>
<div class="d-flex align-items-center gap-2">
<span>Name</span>
<div class="sort-controls">
<a href="{$orderbyname_asc}" class="sort-icon {if isset($orderby) && $orderby == 'name_asc'}active{/if}" title="Sort Ascending">
<i class="fas fa-sort-alpha-down"></i>
</a>
<a href="{$orderbyname_desc}" class="sort-icon {if isset($orderby) && $orderby == 'name_desc'}active{/if}" title="Sort Descending">
<i class="fas fa-sort-alpha-down-alt"></i>
</a>
</div>
</th>
<th>
<div class="d-flex align-items-center gap-2">
<span>Category</span>
<div class="sort-controls">
<a href="{$orderbycat_asc}" class="sort-icon {if isset($orderby) && $orderby == 'cat_asc'}active{/if}" title="Sort Ascending">
<i class="fas fa-sort-alpha-down"></i>
</a>
<a href="{$orderbycat_desc}" class="sort-icon {if isset($orderby) && $orderby == 'cat_desc'}active{/if}" title="Sort Descending">
<i class="fas fa-sort-alpha-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center gap-2">
<span>Category</span>
<div class="sort-controls">
<a href="{$orderbycat_asc}" class="sort-icon {if isset($orderby) && $orderby == 'cat_asc'}active{/if}" title="Sort Ascending">
<i class="fas fa-sort-alpha-down"></i>
</a>
<a href="{$orderbycat_desc}" class="sort-icon {if isset($orderby) && $orderby == 'cat_desc'}active{/if}" title="Sort Descending">
<i class="fas fa-sort-alpha-down-alt"></i>
</a>
</div>
</th>
<th>
<div class="d-flex align-items-center gap-2">
<span>Posted</span>
<div class="sort-controls">
<a href="{$orderbyposted_asc}" class="sort-icon {if isset($orderby) && $orderby == 'posted_asc'}active{/if}" title="Sort Oldest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbyposted_desc}" class="sort-icon {if isset($orderby) && $orderby == 'posted_desc'}active{/if}" title="Sort Newest First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center gap-2">
<span>Posted</span>
<div class="sort-controls">
<a href="{$orderbyposted_asc}" class="sort-icon {if isset($orderby) && $orderby == 'posted_asc'}active{/if}" title="Sort Oldest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbyposted_desc}" class="sort-icon {if isset($orderby) && $orderby == 'posted_desc'}active{/if}" title="Sort Newest First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</th>
<th>
<div class="d-flex align-items-center justify-content-center gap-2">
<span>Size</span>
<div class="sort-controls">
<a href="{$orderbysize_asc}" class="sort-icon {if isset($orderby) && $orderby == 'size_asc'}active{/if}" title="Sort Smallest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbysize_desc}" class="sort-icon {if isset($orderby) && $orderby == 'size_desc'}active{/if}" title="Sort Largest First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center justify-content-center gap-2">
<span>Size</span>
<div class="sort-controls">
<a href="{$orderbysize_asc}" class="sort-icon {if isset($orderby) && $orderby == 'size_asc'}active{/if}" title="Sort Smallest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbysize_desc}" class="sort-icon {if isset($orderby) && $orderby == 'size_desc'}active{/if}" title="Sort Largest First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</th>
<th>
<div class="d-flex align-items-center justify-content-center gap-2">
<span>Files</span>
<div class="sort-controls">
<a href="{$orderbyfiles_asc}" class="sort-icon {if isset($orderby) && $orderby == 'files_asc'}active{/if}" title="Sort Fewest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbyfiles_desc}" class="sort-icon {if isset($orderby) && $orderby == 'files_desc'}active{/if}" title="Sort Most First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center justify-content-center gap-2">
<span>Files</span>
<div class="sort-controls">
<a href="{$orderbyfiles_asc}" class="sort-icon {if isset($orderby) && $orderby == 'files_asc'}active{/if}" title="Sort Fewest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbyfiles_desc}" class="sort-icon {if isset($orderby) && $orderby == 'files_desc'}active{/if}" title="Sort Most First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</th>
<th>
<div class="d-flex align-items-center justify-content-center gap-2">
<span>Downloads</span>
<div class="sort-controls">
<a href="{$orderbystats_asc}" class="sort-icon {if isset($orderby) && $orderby == 'stats_asc'}active{/if}" title="Sort Fewest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbystats_desc}" class="sort-icon {if isset($orderby) && $orderby == 'stats_desc'}active{/if}" title="Sort Most First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</div>
</th>
<th>
<div class="d-flex align-items-center justify-content-center gap-2">
<span>Downloads</span>
<div class="sort-controls">
<a href="{$orderbystats_asc}" class="sort-icon {if isset($orderby) && $orderby == 'stats_asc'}active{/if}" title="Sort Fewest First">
<i class="fas fa-sort-numeric-down"></i>
</a>
<a href="{$orderbystats_desc}" class="sort-icon {if isset($orderby) && $orderby == 'stats_desc'}active{/if}" title="Sort Most First">
<i class="fas fa-sort-numeric-down-alt"></i>
</a>
</div>
</th>
<th class="text-end">Action</th>
</tr>
</div>
</th>
<th class="text-end">Action</th>
</tr>
</thead>
<tbody>
{foreach $results as $result}
<tr id="guid{$result->guid}">
<td>
<input id="chk{$result->guid|substr:0:7}" type="checkbox" name="table_records" class="flat" value="{$result->guid}">
</td>
<td>
<div class="mb-1">
<a href="{{url("/details/{$result->guid}")}}" class="title fw-semibold">{$result->searchname|escape:"htmlall"|replace:".":" "}</a>
{if !empty($result->failed)}
<i class="fa fa-exclamation-circle text-danger ms-1" title="This release has failed to download for some users"></i>
{/if}
{if $lastvisit|strtotime < $result->adddate|strtotime}
<span class="badge bg-success ms-1">New</span>
{/if}
</div>
<div class="d-flex flex-wrap gap-2 mt-2">
<!-- Downloads indicator -->
<span class="badge bg-secondary text-white">
{foreach $results as $result}
<tr id="guid{$result->guid}">
<td>
<input id="chk{$result->guid|substr:0:7}" type="checkbox" name="table_records" class="flat" value="{$result->guid}">
</td>
<td>
<div class="mb-1">
<a href="{{url("/details/{$result->guid}")}}" class="title fw-semibold">{$result->searchname|escape:"htmlall"|replace:".":" "}</a>
{if !empty($result->failed)}
<i class="fa fa-exclamation-circle text-danger ms-1" title="This release has failed to download for some users"></i>
{/if}
{if $lastvisit|strtotime < $result->adddate|strtotime}
<span class="badge bg-success ms-1">New</span>
{/if}
</div>
<div class="d-flex flex-wrap gap-2 mt-2">
<!-- Downloads indicator -->
<span class="badge bg-secondary text-white">
<i class="fa fa-download me-1"></i>{$result->grabs} Grab{if $result->grabs != 1}s{/if}
</span>
<!-- Media badges -->
{if $result->nfoid > 0}
<a href="#" data-bs-toggle="modal" data-bs-target="#nfoModal" data-guid="{$result->guid}" class="nfo-modal-trigger badge bg-info">
<i class="fa fa-file-text-o me-1"></i>NFO
</a>
{/if}
<!-- Media badges -->
{if $result->nfoid > 0}
<a href="#" data-bs-toggle="modal" data-bs-target="#nfoModal" data-guid="{$result->guid}" class="nfo-modal-trigger badge bg-info">
<i class="fa fa-file-text-o me-1"></i>NFO
</a>
{/if}
{if $result->jpgstatus == 1 && $userdata->can('preview') == true}
<a href="{{url("/covers/sample/{$result->guid}_thumb.jpg")}}" name="name{$result->guid}" data-fancybox class="badge bg-primary" rel="preview">
<i class="fa fa-image me-1"></i>Sample
</a>
{/if}
{if $result->jpgstatus == 1 && $userdata->can('preview') == true}
<a href="{{url("/covers/sample/{$result->guid}_thumb.jpg")}}" name="name{$result->guid}" data-fancybox class="badge bg-primary" rel="preview">
<i class="fa fa-image me-1"></i>Sample
</a>
{/if}
{if $result->haspreview == 1 && $userdata->can('preview') == true}
<a href="{{url("/covers/preview/{$result->guid}_thumb.jpg")}}" name="name{$result->guid}" data-fancybox class="badge bg-primary" rel="preview">
<i class="fa fa-film me-1"></i>Preview
</a>
{/if}
{if $result->haspreview == 1 && $userdata->can('preview') == true}
<a href="{{url("/covers/preview/{$result->guid}_thumb.jpg")}}" name="name{$result->guid}" data-fancybox class="badge bg-primary" rel="preview">
<i class="fa fa-film me-1"></i>Preview
</a>
{/if}
<!-- Media type badges -->
{if $result->videos_id > 0}
<a href="{{url("/series/{$result->videos_id}")}}" class="badge bg-success" rel="series">
<i class="fa fa-tv me-1"></i>View TV
</a>
{/if}
<!-- Media type badges -->
{if $result->videos_id > 0}
<a href="{{url("/series/{$result->videos_id}")}}" class="badge bg-success" rel="series">
<i class="fa fa-tv me-1"></i>View TV
</a>
{/if}
{if !empty($result->firstaired)}
<span class="seriesinfo badge bg-warning text-dark" title="{$result->guid}">
{if !empty($result->firstaired)}
<span class="seriesinfo badge bg-warning text-dark" title="{$result->guid}">
<i class="fa fa-calendar me-1"></i>Aired {if $result->firstaired|strtotime > $smarty.now}in future{else}{$result->firstaired|daysago}{/if}
</span>
{/if}
{/if}
{if $result->anidbid > 0}
<a class="badge bg-success" href="{{url("/anime?id={$result->anidbid}")}}">
<i class="fa fa-play-circle me-1"></i>View Anime
</a>
{/if}
{if $result->anidbid > 0}
<a class="badge bg-success" href="{{url("/anime?id={$result->anidbid}")}}">
<i class="fa fa-play-circle me-1"></i>View Anime
</a>
{/if}
<!-- Stats badges -->
{if !empty($result->failed)}
<span class="badge bg-danger">
<!-- Stats badges -->
{if !empty($result->failed)}
<span class="badge bg-danger">
<i class="fa fa-exclamation-triangle me-1"></i>{$result->failed} Failed
</span>
{/if}
{/if}
<!-- Source badges -->
<span class="badge bg-dark">
<!-- Source badges -->
<span class="badge bg-dark">
<i class="fa fa-users me-1"></i>{$result->group_name}
</span>
<span class="badge bg-dark">
<span class="badge bg-dark">
<i class="fa fa-user me-1"></i>{$result->fromname}
</span>
</div>
</td>
<td>
</div>
</td>
<td>
<span class="badge bg-secondary text-white rounded-pill">
<i class="fa fa-folder-open me-1"></i>{$result->category_name}
</span>
</td>
<td>
<div class="d-flex align-items-center">
<i class="fa fa-clock-o text-muted me-2"></i>
<span title="{$result->postdate}">{$result->postdate|timeago}</span>
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<i class="fa fa-hdd-o text-muted me-2"></i>
<span class="fw-medium">{$result->size|filesize}</span>
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<a class="d-flex align-items-center text-decoration-none" title="View file list" href="#" data-bs-toggle="modal" data-bs-target="#filelistModal" data-guid="{$result->guid}">
<i class="far fa-file text-primary me-1"></i>
<span class="fw-medium">{$result->totalpart}</span>
</a>
{if $result->rarinnerfilecount > 0}
<div class="rarfilelist d-inline-block ms-2" title="View RAR contents">
<i class="fas fa-search-plus text-info"></i>
</div>
{/if}
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<i class="fa fa-download text-muted me-2"></i>
<span class="fw-medium">{$result->grabs}</span>
</div>
</td>
<td class="text-end">
<div class="d-flex justify-content-end gap-2">
<a href="{{url("/getnzb?id={$result->guid}")}}" class="btn btn-sm btn-outline-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Download NZB">
<i class="fa fa-cloud-download"></i>
</a>
<a href="{{url("/details/{$result->guid}/#comments")}}" class="btn btn-sm btn-outline-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Comments">
<i class="fa fa-comments-o"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Send to my download basket">
<i id="guid{$result->guid}" class="icon_cart fa fa-shopping-basket"></i>
</a>
</div>
</td>
</tr>
{/foreach}
</td>
<td>
<div class="d-flex align-items-center">
<i class="fa fa-clock-o text-muted me-2"></i>
<span title="{$result->postdate}">{$result->postdate|timeago}</span>
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<i class="fa fa-hdd-o text-muted me-2"></i>
<span class="fw-medium">{$result->size|filesize}</span>
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<a class="d-flex align-items-center text-decoration-none" title="View file list" href="#" data-bs-toggle="modal" data-bs-target="#filelistModal" data-guid="{$result->guid}">
<i class="far fa-file text-primary me-1"></i>
<span class="fw-medium">{$result->totalpart}</span>
</a>
{if $result->rarinnerfilecount > 0}
<div class="rarfilelist d-inline-block ms-2" title="View RAR contents">
<i class="fas fa-search-plus text-info"></i>
</div>
{/if}
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<i class="fa fa-download text-muted me-2"></i>
<span class="fw-medium">{$result->grabs}</span>
</div>
</td>
<td class="text-end">
<div class="d-flex justify-content-end gap-2">
<a href="{{url("/getnzb?id={$result->guid}")}}" class="btn btn-sm btn-outline-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Download NZB">
<i class="fa fa-cloud-download"></i>
</a>
<a href="{{url("/details/{$result->guid}/#comments")}}" class="btn btn-sm btn-outline-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Comments">
<i class="fa fa-comments-o"></i>
</a>
<a href="#" class="btn btn-sm btn-outline-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Send to my download basket">
<i id="guid{$result->guid}" class="icon_cart fa fa-shopping-basket"></i>
</a>
</div>
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
@@ -475,16 +475,16 @@
<div class="table-responsive">
<table class="table table-striped table-hover mb-0">
<thead class="thead-light">
<tr>
<th style="width: 40px" class="text-center">#</th>
<th>Filename</th>
<th style="width: 60px" class="text-center">Type</th>
<th style="width: 120px" class="text-center">Completion</th>
<th style="width: 100px" class="text-center">Size</th>
</tr>
<tr>
<th style="width: 40px" class="text-center">#</th>
<th>Filename</th>
<th style="width: 60px" class="text-center">Type</th>
<th style="width: 120px" class="text-center">Completion</th>
<th style="width: 100px" class="text-center">Size</th>
</tr>
</thead>
<tbody id="filelist-tbody">
<!-- Files will be populated here -->
<!-- Files will be populated here -->
</tbody>
</table>
</div>
@@ -496,3 +496,156 @@
</div>
</div>
</div>
<script>
{literal}
document.addEventListener('DOMContentLoaded', function() {
// Search type toggle functionality
const searchTypeToggle = document.getElementById('searchTypeToggle');
if (searchTypeToggle) {
searchTypeToggle.addEventListener('click', function(e) {
e.preventDefault();
const currentType = this.getAttribute('data-current-type');
const sbasic = document.getElementById('sbasic');
const sadvanced = document.getElementById('sadvanced');
if (currentType === 'advanced') {
this.textContent = 'Basic Search';
this.setAttribute('data-current-type', 'basic');
} else {
this.textContent = 'Advanced Search';
this.setAttribute('data-current-type', 'advanced');
}
sbasic.style.display = sbasic.style.display === 'none' ? 'flex' : 'none';
sadvanced.style.display = sadvanced.style.display === 'none' ? 'block' : 'none';
});
}
// File List Modal
const filelistModal = document.getElementById('filelistModal');
if (filelistModal) {
filelistModal.addEventListener('show.bs.modal', function(event) {
const button = event.relatedTarget;
const guid = button.getAttribute('data-guid');
const loading = filelistModal.querySelector('.filelist-loading');
const contentElement = document.getElementById('filelistContent');
const tbody = document.getElementById('filelist-tbody');
const totalFiles = document.getElementById('total-files');
const totalSize = document.getElementById('total-size');
// Reset and show loading state
loading.style.display = 'block';
contentElement.classList.add('d-none');
tbody.innerHTML = '';
// Fetch the file list via AJAX
fetch(`/filelist/${guid}?modal=true`, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.text())
.then(html => {
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
// Extract data from the HTML response
const files = [];
const tableRows = doc.querySelectorAll('table tbody tr');
let totalSizeBytes = 0;
tableRows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length >= 5) {
const file = {
num: cells[0].textContent.trim(),
filename: cells[1].querySelector('.text-truncate') ?
cells[1].querySelector('.text-truncate').getAttribute('title') :
cells[1].textContent.trim(),
ext: cells[2].querySelector('.badge') ?
cells[2].querySelector('.badge').textContent.trim() : '',
completion: cells[3].querySelector('.progress-bar') ?
cells[3].querySelector('.progress-bar').getAttribute('aria-valuenow') : '100',
size: cells[4].textContent.trim()
};
// Parse filesize for total calculation
const sizeMatch = file.size.match(/(\d+(\.\d+)?)\s*(KB|MB|GB|TB)/i);
if (sizeMatch) {
const size = parseFloat(sizeMatch[1]);
const unit = sizeMatch[3].toUpperCase();
let bytes = size;
if (unit === 'KB') bytes *= 1024;
else if (unit === 'MB') bytes *= 1024 * 1024;
else if (unit === 'GB') bytes *= 1024 * 1024 * 1024;
else if (unit === 'TB') bytes *= 1024 * 1024 * 1024 * 1024;
totalSizeBytes += bytes;
}
files.push(file);
}
});
// Format total size
function formatFileSize(bytes) {
if (bytes < 1024) return bytes + ' B';
else if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
else if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
else if (bytes < 1024 * 1024 * 1024 * 1024) return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
else return (bytes / (1024 * 1024 * 1024 * 1024)).toFixed(2) + ' TB';
}
// Display total information
totalFiles.textContent = files.length;
totalSize.textContent = formatFileSize(totalSizeBytes);
// Populate the modal with files
files.forEach(file => {
const row = document.createElement('tr');
row.innerHTML = `
<td class="text-center">${file.num}</td>
<td class="text-break">
<span class="d-inline-block text-truncate" style="max-width: 400px;" title="${file.filename}">${file.filename}</span>
</td>
<td class="text-center">
<span class="badge bg-secondary text-uppercase">${file.ext}</span>
</td>
<td class="text-center">
<div class="progress" style="height: 20px">
<div class="progress-bar ${file.completion < 100 ? 'bg-warning' : 'bg-success'}"
role="progressbar"
style="width: ${file.completion}%"
aria-valuenow="${file.completion}"
aria-valuemin="0"
aria-valuemax="100">
${file.completion}%
</div>
</div>
</td>
<td class="text-center">
<div class="d-flex align-items-center justify-content-center">
<i class="fa fa-hdd-o text-muted me-2"></i>
<span class="fw-medium">${file.size}</span>
</div>
</td>
`;
tbody.appendChild(row);
});
// Show content, hide loading
loading.style.display = 'none';
contentElement.classList.remove('d-none');
})
.catch(error => {
console.error('Error fetching file list:', error);
loading.style.display = 'none';
contentElement.classList.remove('d-none');
tbody.innerHTML = '<tr><td colspan="5" class="text-center text-danger">Error loading file list</td></tr>';
});
});
}
});
{/literal}
</script>
+3 -5
View File
@@ -33,7 +33,7 @@ mix
'node_modules/pnotify/dist/PNotifyBrightTheme.css',
'node_modules/flexboxgrid2/flexboxgrid2.min.css',
'resources/assets/css/custom.css'
], 'public/assets/css/all-css.css')
], 'public/assets/css/all-css.css')
.scripts(
[
'node_modules/jquery/dist/jquery.min.js',
@@ -63,8 +63,6 @@ mix
'node_modules/icheck/icheck.min.js',
'resources/assets/js/utils-admin.js',
'resources/assets/js/custom.js',
'resources/assets/js/functions.js',
'resources/assets/js/themes/Gentele/search.js',
'resources/assets/js/themes/Gentele/browse.js',
'resources/assets/js/functions.js'
]
, 'public/assets/js/all-js.js');
, 'public/assets/js/all-js.js');