mirror of
https://github.com/ceratic/MediaCollectorLibary.git
synced 2026-05-14 08:06:47 +02:00
206 lines
11 KiB
Twig
206 lines
11 KiB
Twig
{% extends 'admin/layout.twig' %}
|
|
|
|
{% block title %}Media Sources - Admin{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h1 class="h3 mb-0">Media Sources</h1>
|
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addSourceModal">
|
|
<i class="bi bi-plus-circle me-2"></i>Add Source
|
|
</button>
|
|
</div>
|
|
|
|
{% if sources is not empty %}
|
|
<div class="card shadow mb-4">
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Type</th>
|
|
<th>Path/URL</th>
|
|
<th>Status</th>
|
|
<th>Last Sync</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for source in sources %}
|
|
<tr>
|
|
<td>{{ source.name }}</td>
|
|
<td>
|
|
<span class="badge bg-{{ source.type == 'jellyfin' ? 'info' : 'success' }}">
|
|
{{ source.type|upper }}
|
|
</span>
|
|
</td>
|
|
<td>{{ source.path }}</td>
|
|
<td>
|
|
<span class="badge bg-{{ source.is_active ? 'success' : 'secondary' }}">
|
|
{{ source.is_active ? 'Active' : 'Inactive' }}
|
|
</span>
|
|
</td>
|
|
<td>{{ source.last_sync ? source.last_sync|date('Y-m-d H:i:s') : 'Never' }}</td>
|
|
<td>
|
|
<div class="btn-group btn-group-sm">
|
|
<button class="btn btn-outline-primary"
|
|
data-bs-toggle="tooltip"
|
|
title="Edit"
|
|
onclick="editSource({{ source|json_encode|e('js') }});">
|
|
<i class="bi bi-pencil"></i>
|
|
</button>
|
|
<a href="{{ path_for('admin.sync', {'id': source.id}) }}"
|
|
class="btn btn-outline-success"
|
|
data-bs-toggle="tooltip"
|
|
title="Sync Now">
|
|
<i class="bi bi-arrow-repeat"></i>
|
|
</a>
|
|
<button class="btn btn-outline-danger"
|
|
data-bs-toggle="tooltip"
|
|
title="Delete"
|
|
onclick="confirmDelete({{ source.id }}, '{{ source.name }}')">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div class="card shadow">
|
|
<div class="card-body text-center py-5">
|
|
<i class="bi bi-hdd-rack display-1 text-muted mb-4"></i>
|
|
<h3>No Media Sources Found</h3>
|
|
<p class="text-muted">Add your first media source to get started.</p>
|
|
<button type="button" class="btn btn-primary mt-3" data-bs-toggle="modal" data-bs-target="#addSourceModal">
|
|
<i class="bi bi-plus-circle me-2"></i>Add Media Source
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Add/Edit Source Modal -->
|
|
<div class="modal fade" id="sourceModal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<form id="sourceForm" method="post">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="modalTitle">Add Media Source</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<input type="hidden" name="id" id="sourceId">
|
|
<div class="mb-3">
|
|
<label for="name" class="form-label">Name</label>
|
|
<input type="text" class="form-control" id="name" name="name" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="type" class="form-label">Type</label>
|
|
<select class="form-select" id="type" name="type" required>
|
|
<option value="jellyfin">Jellyfin</option>
|
|
<option value="local">Local Filesystem</option>
|
|
<option value="samba">Samba Share</option>
|
|
<option value="nfs">NFS Share</option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="path" class="form-label">Path/URL</label>
|
|
<input type="text" class="form-control" id="path" name="path" required>
|
|
<div class="form-text">
|
|
For Jellyfin: http(s)://server:port<br>
|
|
For local: /path/to/media<br>
|
|
For network shares: //server/share or nfs://server/path
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="username" class="form-label">Username (if required)</label>
|
|
<input type="text" class="form-control" id="username" name="username">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="password" class="form-label">Password (if required)</label>
|
|
<input type="password" class="form-control" id="password" name="password">
|
|
</div>
|
|
<div class="form-check form-switch mb-3">
|
|
<input class="form-check-input" type="checkbox" id="isActive" name="is_active" checked>
|
|
<label class="form-check-label" for="isActive">Active</label>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Save</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Delete Confirmation Modal -->
|
|
<div class="modal fade" id="deleteModal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Confirm Deletion</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>Are you sure you want to delete <strong id="sourceName"></strong>?</p>
|
|
<p class="text-danger">This action cannot be undone and will remove all associated media data.</p>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<form id="deleteForm" method="post" action="">
|
|
<button type="submit" class="btn btn-danger">Delete</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
// Initialize tooltips
|
|
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
|
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
|
return new bootstrap.Tooltip(tooltipTriggerEl)
|
|
});
|
|
|
|
// Handle add source button
|
|
document.getElementById('addSourceBtn').addEventListener('click', function() {
|
|
document.getElementById('modalTitle').textContent = 'Add Media Source';
|
|
document.getElementById('sourceForm').reset();
|
|
document.getElementById('sourceId').value = '';
|
|
document.getElementById('sourceForm').action = '{{ path_for("admin.sources.store") }}';
|
|
var modal = new bootstrap.Modal(document.getElementById('sourceModal'));
|
|
modal.show();
|
|
});
|
|
|
|
// Handle edit source
|
|
function editSource(source) {
|
|
document.getElementById('modalTitle').textContent = 'Edit Media Source';
|
|
document.getElementById('sourceId').value = source.id;
|
|
document.getElementById('name').value = source.name;
|
|
document.getElementById('type').value = source.type;
|
|
document.getElementById('path').value = source.path;
|
|
document.getElementById('username').value = source.username || '';
|
|
document.getElementById('isActive').checked = source.is_active;
|
|
document.getElementById('sourceForm').action = '{{ path_for("admin.sources.update", {id: 0}) }}'.replace('/0', '/' + source.id);
|
|
|
|
var modal = new bootstrap.Modal(document.getElementById('sourceModal'));
|
|
modal.show();
|
|
}
|
|
|
|
// Handle delete confirmation
|
|
function confirmDelete(id, name) {
|
|
document.getElementById('sourceName').textContent = name;
|
|
document.getElementById('deleteForm').action = '{{ path_for("admin.sources.destroy", {id: 0}) }}'.replace('/0', '/' + id);
|
|
var modal = new bootstrap.Modal(document.getElementById('deleteModal'));
|
|
modal.show();
|
|
}
|
|
</script>
|
|
{% endblock %}
|