mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-01-23 02:35:14 +00:00
Pre Alpha Changes
Removed .DS_Store and added to gitignore M3U add created M3U delete fixed Removed unused files Django admin not so ugly now
This commit is contained in:
parent
b4031321d1
commit
7ae7dbe175
38 changed files with 158 additions and 6492 deletions
BIN
.DS_Store
vendored
BIN
.DS_Store
vendored
Binary file not shown.
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
.DS_Store
|
||||
__pycache__/
|
||||
77
FileTree.py
77
FileTree.py
|
|
@ -1,77 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
|
||||
# Specify the names of the script file and output file to exclude them
|
||||
SCRIPT_NAME = "FileTree.py"
|
||||
OUTPUT_FILE = "FileTree.txt"
|
||||
EXCLUDED_FILES = {SCRIPT_NAME, OUTPUT_FILE, ".DS_Store", "__init__.py", "FileTree.old.txt"}
|
||||
EXCLUDED_DIRS = {"__pycache__", "migrations", "static", "staticfiles", "media", ".venv", ".idea"} # Exclude directories like __pycache__
|
||||
|
||||
def generate_file_tree(output_file):
|
||||
"""Generate a pretty file tree of the current directory and subdirectories."""
|
||||
with open(output_file, 'w') as f:
|
||||
for root, dirs, files in os.walk('.'): # Walk through the directory tree
|
||||
# Remove excluded directories from the traversal
|
||||
dirs[:] = [d for d in dirs if d not in EXCLUDED_DIRS]
|
||||
level = root.count(os.sep)
|
||||
indent = '│ ' * level
|
||||
f.write(f"{indent}├── {os.path.basename(root)}/\n")
|
||||
sub_indent = '│ ' * (level + 1)
|
||||
for i, file in enumerate(files):
|
||||
if file not in EXCLUDED_FILES:
|
||||
connector = '└── ' if i == len(files) - 1 else '├── '
|
||||
f.write(f"{sub_indent}{connector}{file}\n")
|
||||
|
||||
def append_file_contents(output_file):
|
||||
"""Append contents of each file in the current directory and subdirectories to the output file, excluding specified files."""
|
||||
# Determine the maximum width for the boxes
|
||||
max_width = 20 # Default minimum width
|
||||
file_paths = []
|
||||
for root, dirs, files in os.walk('.'): # Walk through the directory tree
|
||||
# Remove excluded directories from the traversal
|
||||
dirs[:] = [d for d in dirs if d not in EXCLUDED_DIRS]
|
||||
for file_name in files:
|
||||
if file_name not in EXCLUDED_FILES:
|
||||
file_path = os.path.join(root, file_name)
|
||||
relative_path = os.path.relpath(file_path, start='.')
|
||||
directory = os.path.dirname(relative_path)
|
||||
base_name = os.path.basename(relative_path)
|
||||
file_paths.append((directory, base_name))
|
||||
max_width = max(max_width, len(directory) + 10, len(base_name) + 10)
|
||||
|
||||
max_width += 4 # Add padding for aesthetics
|
||||
|
||||
# Append file contents with uniform box size
|
||||
with open(output_file, 'a') as f:
|
||||
for directory, base_name in file_paths:
|
||||
# Add the formatted header for the file
|
||||
horizontal_line = f"┌{'─' * max_width}┐"
|
||||
directory_line = f"│ Directory: {directory:<{max_width - 12}}│"
|
||||
file_line = f"│ File: {base_name:<{max_width - 12}}│"
|
||||
bottom_line = f"└{'─' * max_width}┘"
|
||||
|
||||
f.write(f"\n{horizontal_line}\n")
|
||||
f.write(f"{directory_line}\n")
|
||||
f.write(f"{file_line}\n")
|
||||
f.write(f"{bottom_line}\n\n")
|
||||
|
||||
# Append the contents of the file
|
||||
file_path = os.path.join(directory, base_name)
|
||||
try:
|
||||
with open(file_path, 'r', errors='ignore') as file:
|
||||
f.write(file.read())
|
||||
except Exception as e:
|
||||
f.write(f"Error reading {file_path}: {e}\n")
|
||||
|
||||
# Add a visually distinct footer to signify the end of the file
|
||||
f.write(f"\n========= END OF FILE =========\n")
|
||||
f.write(f"File: {base_name}\n")
|
||||
f.write(f"===============================\n\n")
|
||||
|
||||
def main():
|
||||
generate_file_tree(OUTPUT_FILE)
|
||||
append_file_contents(OUTPUT_FILE)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
6348
FileTree.txt
6348
FileTree.txt
File diff suppressed because it is too large
Load diff
BIN
apps/.DS_Store
vendored
BIN
apps/.DS_Store
vendored
Binary file not shown.
BIN
apps/accounts/.DS_Store
vendored
BIN
apps/accounts/.DS_Store
vendored
Binary file not shown.
BIN
apps/api/.DS_Store
vendored
BIN
apps/api/.DS_Store
vendored
Binary file not shown.
BIN
apps/channels/.DS_Store
vendored
BIN
apps/channels/.DS_Store
vendored
Binary file not shown.
BIN
apps/channels/management/.DS_Store
vendored
BIN
apps/channels/management/.DS_Store
vendored
Binary file not shown.
BIN
apps/dashboard/.DS_Store
vendored
BIN
apps/dashboard/.DS_Store
vendored
Binary file not shown.
BIN
apps/epg/.DS_Store
vendored
BIN
apps/epg/.DS_Store
vendored
Binary file not shown.
BIN
apps/hdhr/.DS_Store
vendored
BIN
apps/hdhr/.DS_Store
vendored
Binary file not shown.
BIN
apps/m3u/.DS_Store
vendored
BIN
apps/m3u/.DS_Store
vendored
Binary file not shown.
BIN
dispatcharr/.DS_Store
vendored
BIN
dispatcharr/.DS_Store
vendored
Binary file not shown.
|
|
@ -13,7 +13,6 @@ WORKDIR /app
|
|||
# Install Python dependencies
|
||||
COPY requirements.txt /app/
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
RUN pip install gevent # Install gevent for async workers with Gunicorn
|
||||
|
||||
# Copy application files
|
||||
COPY . /app/
|
||||
|
|
@ -21,6 +20,7 @@ COPY . /app/
|
|||
# Set environment variables
|
||||
ENV DJANGO_SETTINGS_MODULE=dispatcharr.settings
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
# Run Django commands
|
||||
RUN python manage.py collectstatic --noinput || true
|
||||
|
|
|
|||
BIN
media/.DS_Store
vendored
BIN
media/.DS_Store
vendored
Binary file not shown.
BIN
media/epg_uploads/.DS_Store
vendored
BIN
media/epg_uploads/.DS_Store
vendored
Binary file not shown.
BIN
media/logos/.DS_Store
vendored
BIN
media/logos/.DS_Store
vendored
Binary file not shown.
BIN
media/m3u_uploads/.DS_Store
vendored
BIN
media/m3u_uploads/.DS_Store
vendored
Binary file not shown.
BIN
static/.DS_Store
vendored
BIN
static/.DS_Store
vendored
Binary file not shown.
BIN
static/admin/.DS_Store
vendored
BIN
static/admin/.DS_Store
vendored
Binary file not shown.
BIN
static/admin/css/.DS_Store
vendored
BIN
static/admin/css/.DS_Store
vendored
Binary file not shown.
BIN
static/admin/img/.DS_Store
vendored
BIN
static/admin/img/.DS_Store
vendored
Binary file not shown.
BIN
static/admin/js/.DS_Store
vendored
BIN
static/admin/js/.DS_Store
vendored
Binary file not shown.
BIN
static/ts_buffers/.DS_Store
vendored
BIN
static/ts_buffers/.DS_Store
vendored
Binary file not shown.
BIN
staticfiles/.DS_Store
vendored
BIN
staticfiles/.DS_Store
vendored
Binary file not shown.
BIN
staticfiles/admin/.DS_Store
vendored
BIN
staticfiles/admin/.DS_Store
vendored
Binary file not shown.
BIN
staticfiles/admin/css/.DS_Store
vendored
BIN
staticfiles/admin/css/.DS_Store
vendored
Binary file not shown.
BIN
staticfiles/admin/img/.DS_Store
vendored
BIN
staticfiles/admin/img/.DS_Store
vendored
Binary file not shown.
BIN
staticfiles/admin/js/.DS_Store
vendored
BIN
staticfiles/admin/js/.DS_Store
vendored
Binary file not shown.
BIN
staticfiles/drf-yasg/.DS_Store
vendored
BIN
staticfiles/drf-yasg/.DS_Store
vendored
Binary file not shown.
BIN
staticfiles/rest_framework/.DS_Store
vendored
BIN
staticfiles/rest_framework/.DS_Store
vendored
Binary file not shown.
BIN
templates/.DS_Store
vendored
BIN
templates/.DS_Store
vendored
Binary file not shown.
BIN
templates/admin/.DS_Store
vendored
BIN
templates/admin/.DS_Store
vendored
Binary file not shown.
|
|
@ -112,7 +112,7 @@
|
|||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#" class="nav-link">
|
||||
<a href="{% url 'dashboard:settings' %}" class="nav-link">
|
||||
<i class="nav-icon bi bi-gear"></i>
|
||||
<p>Settings</p>
|
||||
</a>
|
||||
|
|
@ -127,7 +127,8 @@
|
|||
<main class="app-main">
|
||||
<div class="app-content">
|
||||
<div class="container-fluid">
|
||||
<!-- Content Wrapper -->
|
||||
|
||||
<!-- Content Wrapper -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Page Header -->
|
||||
<section class="content-header">
|
||||
BIN
templates/channels/.DS_Store
vendored
BIN
templates/channels/.DS_Store
vendored
Binary file not shown.
BIN
templates/channels/modals/.DS_Store
vendored
BIN
templates/channels/modals/.DS_Store
vendored
Binary file not shown.
|
|
@ -10,6 +10,7 @@
|
|||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addM3UModal">Add M3U</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- The table body will be populated via AJAX -->
|
||||
<table id="m3uTable" class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
|
|
@ -19,28 +20,7 @@
|
|||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for m3u in m3u_accounts %}
|
||||
<tr>
|
||||
<td>{{ m3u.name }}</td>
|
||||
<td>
|
||||
{% if m3u.server_url %}
|
||||
<a href="{{ m3u.server_url }}" target="_blank">M3U URL</a>
|
||||
{% elif m3u.uploaded_file and m3u.uploaded_file.url %}
|
||||
<a href="{{ m3u.uploaded_file.url }}" download>Download File</a>
|
||||
{% else %}
|
||||
No URL or file
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ m3u.max_streams|default:"N/A" }}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-warning" onclick="editM3U({{ m3u.id }})">Edit</button>
|
||||
<button class="btn btn-sm btn-danger" onclick="deleteM3U({{ m3u.id }})">Delete</button>
|
||||
<button class="btn btn-sm btn-info" onclick="refreshM3U({{ m3u.id }})">Refresh</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -55,22 +35,24 @@
|
|||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="m3uForm">
|
||||
<!-- Note: The form does not submit normally; JavaScript handles submission -->
|
||||
<form id="m3uForm" enctype="multipart/form-data" action="/api/m3u/accounts/">
|
||||
{% csrf_token %}
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Name</label>
|
||||
<input type="text" class="form-control" id="m3uName" required>
|
||||
<input type="text" class="form-control" id="m3uName" name="name" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">M3U URL</label>
|
||||
<input type="url" class="form-control" id="m3uURL">
|
||||
<input type="url" class="form-control" id="m3uURL" name="server_url">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Upload File</label>
|
||||
<input type="file" class="form-control" id="m3uFile">
|
||||
<input type="file" class="form-control" id="m3uFile" name="uploaded_file">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Max Streams</label>
|
||||
<input type="number" class="form-control" id="m3uMaxStreams" value="0">
|
||||
<input type="number" class="form-control" id="m3uMaxStreams" name="max_streams" value="0">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">Save</button>
|
||||
</form>
|
||||
|
|
@ -82,49 +64,155 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<!-- DataTables CSS/JS -->
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css">
|
||||
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('#m3uTable').DataTable();
|
||||
|
||||
function getCookie(name) {
|
||||
let cookieValue = null;
|
||||
if (document.cookie && document.cookie !== "") {
|
||||
const cookies = document.cookie.split(';');
|
||||
for (let i=0; i < cookies.length; i++) {
|
||||
const cookie = cookies[i].trim();
|
||||
// Does this cookie string begin with the name we want?
|
||||
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookieValue;
|
||||
}
|
||||
const csrftoken = getCookie('csrftoken');
|
||||
|
||||
$.ajaxSetup({
|
||||
headers: { "X-CSRFToken": csrftoken }
|
||||
});
|
||||
|
||||
$(document).ready(function () {
|
||||
// Initialize the DataTable with an AJAX source.
|
||||
var m3uTable = $('#m3uTable').DataTable({
|
||||
ajax: {
|
||||
url: "/api/m3u/accounts/",
|
||||
dataSrc: ""
|
||||
},
|
||||
columns: [
|
||||
{ data: "name" },
|
||||
{
|
||||
data: null,
|
||||
render: function(data) {
|
||||
if (data.server_url) {
|
||||
return '<a href="' + data.server_url + '" target="_blank">M3U URL</a>';
|
||||
} else if (data.uploaded_file) {
|
||||
return '<a href="' + data.uploaded_file + '" download>Download File</a>';
|
||||
} else {
|
||||
return 'No URL or file';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
data: "max_streams",
|
||||
render: function(data) {
|
||||
return data ? data : "N/A";
|
||||
}
|
||||
},
|
||||
{
|
||||
data: "id",
|
||||
orderable: false,
|
||||
render: function(data, type, row) {
|
||||
return '<button class="btn btn-sm btn-warning" onclick="editM3U('+data+')">Edit</button> ' +
|
||||
'<button class="btn btn-sm btn-danger" onclick="deleteM3U('+data+')">Delete</button> ' +
|
||||
'<button class="btn btn-sm btn-info" onclick="refreshM3U('+data+')">Refresh</button>';
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
function deleteM3U(id) {
|
||||
Swal.fire({
|
||||
title: "Are you sure?",
|
||||
text: "You won't be able to revert this!",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Yes, delete it!"
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
$.ajax({
|
||||
url: `/m3u/${id}/delete/`,
|
||||
method: "POST",
|
||||
success: function () {
|
||||
Swal.fire("Deleted!", "The M3U account has been deleted.", "success")
|
||||
.then(() => location.reload());
|
||||
},
|
||||
error: function () {
|
||||
Swal.fire("Error", "Failed to delete the M3U account.", "error");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
// Handle form submission to add a new M3U account via AJAX.
|
||||
$('#m3uForm').submit(function(e){
|
||||
e.preventDefault(); // Prevent normal submission
|
||||
|
||||
function refreshM3U(id) {
|
||||
$.ajax({
|
||||
url: `/m3u/${id}/refresh/`,
|
||||
method: "POST",
|
||||
success: function () {
|
||||
Swal.fire("Refreshed!", "The M3U has been refreshed.", "success")
|
||||
.then(() => location.reload());
|
||||
},
|
||||
error: function () {
|
||||
Swal.fire("Error", "Failed to refresh the M3U.", "error");
|
||||
var form = this;
|
||||
var formData = new FormData(form);
|
||||
|
||||
fetch(form.action, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
credentials: 'same-origin'
|
||||
})
|
||||
.then(response => {
|
||||
if(!response.ok) {
|
||||
throw new Error("Failed to save M3U account.");
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
Swal.fire("Success", "M3U account saved successfully!", "success");
|
||||
// Reload the DataTable data without reloading the whole page.
|
||||
m3uTable.ajax.reload();
|
||||
// Hide the modal (using Bootstrap 5)
|
||||
var addModal = bootstrap.Modal.getInstance(document.getElementById("addM3UModal"));
|
||||
if(addModal) addModal.hide();
|
||||
form.reset();
|
||||
})
|
||||
.catch(error => {
|
||||
Swal.fire("Error", error.message, "error");
|
||||
console.error("Error:", error);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function deleteM3U(id) {
|
||||
Swal.fire({
|
||||
title: "Are you sure?",
|
||||
text: "You won't be able to revert this!",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Yes, delete it!"
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
$.ajax({
|
||||
url: `/api/m3u/accounts/${id}/`, // Updated URL
|
||||
method: "DELETE", // Use DELETE method
|
||||
success: function () {
|
||||
Swal.fire("Deleted!", "The M3U account has been deleted.", "success")
|
||||
.then(() => {
|
||||
$('#m3uTable').DataTable().ajax.reload();
|
||||
});
|
||||
},
|
||||
error: function () {
|
||||
Swal.fire("Error", "Failed to delete the M3U account.", "error");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function refreshM3U(id) {
|
||||
$.ajax({
|
||||
url: `/m3u/${id}/refresh/`,
|
||||
method: "POST",
|
||||
success: function () {
|
||||
Swal.fire("Refreshed!", "The M3U has been refreshed.", "success")
|
||||
.then(() => {
|
||||
$('#m3uTable').DataTable().ajax.reload();
|
||||
});
|
||||
},
|
||||
error: function () {
|
||||
Swal.fire("Error", "Failed to refresh the M3U.", "error");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function editM3U(id) {
|
||||
// Implement the edit functionality here.
|
||||
Swal.fire("Info", "Edit functionality not implemented yet.", "info");
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue