mirror of
https://github.com/chibicitiberiu/ytsm.git
synced 2024-02-24 05:43:31 +00:00
Merged changes from master
This commit is contained in:
@ -0,0 +1,24 @@
|
||||
{% if config_errors %}
|
||||
<div class="alert alert-danger alert-card mx-auto">
|
||||
<p>Attention! Some critical configuration errors have been found!</p>
|
||||
<ul>
|
||||
{% for err in config_errors %}
|
||||
<li>{{ err }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<p>Until these problems are fixed, the server may have encounter serious problems while running.
|
||||
Please correct these errors, and then restart the server.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if config_warnings %}
|
||||
<div class="alert alert-warning alert-card mx-auto">
|
||||
<p>Warning: some configuration problems have been found!</p>
|
||||
<ul>
|
||||
{% for err in config_warnings %}
|
||||
<li>{{ err }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<p>We recommend that you fix these issues before continuing.</p>
|
||||
</div>
|
||||
{% endif %}
|
@ -0,0 +1,22 @@
|
||||
{% extends 'YtManagerApp/controls/modal.html' %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block modal_title %}
|
||||
Import subscriptions
|
||||
{% endblock modal_title %}
|
||||
|
||||
{% block modal_content %}
|
||||
<form action="{% url 'modal_import_subscriptions' %}" method="post"
|
||||
enctype="multipart/form-data">
|
||||
{{ block.super }}
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block modal_body %}
|
||||
{% crispy form %}
|
||||
{% endblock modal_body %}
|
||||
|
||||
{% block modal_footer %}
|
||||
<input class="btn btn-primary" type="submit" value="Import">
|
||||
<input class="btn btn-secondary" type="button" value="Cancel" data-dismiss="modal" aria-label="Cancel">
|
||||
{% endblock modal_footer %}
|
@ -0,0 +1,12 @@
|
||||
{% extends "YtManagerApp/master_default.html" %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="container">
|
||||
<h1>Done!</h1>
|
||||
<p>The setup is finished, and the application is now ready to use!</p>
|
||||
{% crispy form %}
|
||||
</div>
|
||||
|
||||
{% endblock body %}
|
@ -0,0 +1,15 @@
|
||||
{% extends "YtManagerApp/master_default.html" %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="container">
|
||||
|
||||
{% include "YtManagerApp/controls/setup_errors_banner.html" %}
|
||||
|
||||
<h1>Welcome</h1>
|
||||
<p>This wizard will guide you through setting up the application.</p>
|
||||
{% crispy form %}
|
||||
</div>
|
||||
|
||||
{% endblock body %}
|
@ -0,0 +1,64 @@
|
||||
{% extends "YtManagerApp/master_default.html" %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load static %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="container">
|
||||
|
||||
<h1>Step 1: Set up YouTube API key (optional)</h1>
|
||||
<p>This program uses the YouTube API in order to obtain information about videos, channels and playlists.
|
||||
To access this API, YouTube requires users to register on their site and request an API key. YouTube
|
||||
uses this key to control access and limit the number of requests made to their platform, in order to prevent abuses.</p>
|
||||
|
||||
<p>To use this program, it is <em>recommended</em>, but not required, that you create an API key for your own account. While a key
|
||||
is already provided the developer, there is a chance that the quota limits will be reached, which will prevent
|
||||
this program from reaching YouTube. Follow the steps below, or press <strong>Skip</strong> to use the provided key.</p>
|
||||
|
||||
<h4>
|
||||
<a data-toggle="collapse" href="#HowToObtainKey" role="button" aria-expanded="false" aria-controls="HowToObtainKey">
|
||||
<span class="typcn typcn-arrow-sorted-down"></span>How to obtain a key
|
||||
</a>
|
||||
</h4>
|
||||
|
||||
<div class="collapse" id="HowToObtainKey">
|
||||
<ol>
|
||||
<li>Visit <a href="https://developers.google.com/">https://developers.google.com/</a>, log in or create an account, if necessary.</li>
|
||||
<li>Go to <a href="https://console.developers.google.com/project"></a>, and click on the <strong>Create project</strong> button.
|
||||
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_create_project.png' %}">
|
||||
</li>
|
||||
<li>Give a name to the project, and then click on <strong>Create</strong>. Wait for a few seconds, until Google finishes creating the project.
|
||||
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_project_name.png' %}">
|
||||
</li>
|
||||
<li>Make sure the newly created project is selected in the top bar and then, in the left sidebar,
|
||||
go to <strong>APIs & Services</strong> - <strong>Library</strong>.
|
||||
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_goto_apis.png' %}">
|
||||
</li>
|
||||
<li>Find and click on the <strong>YouTube Data API v3</strong> from the list.
|
||||
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_select_ytapi.png' %}">
|
||||
</li>
|
||||
<li>Click <strong>Enable</strong> to enable the YouTube API for your account.
|
||||
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_enable_ytapi.png' %}">
|
||||
</li>
|
||||
<li>In the navigation sidebar, go to the <strong>Credentials</strong> page.
|
||||
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_goto_credentials.png' %}">
|
||||
</li>
|
||||
<li>Click on <strong>Create credentials</strong>.
|
||||
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_create_credential.png' %}">
|
||||
</li>
|
||||
<li>Fill the requested information; we will need access to the <strong>YouTube Data v3</strong>,
|
||||
we will be calling the API from a <strong>Web server</strong>, and we will access the <strong>Public data</strong>.
|
||||
After filling the information, click on the <strong>What credentials do I need?</strong> button.
|
||||
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_create_credential_options.png' %}">
|
||||
</li>
|
||||
<li>Copy the created key in the box below, and then hit <strong>Done</strong>.
|
||||
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_done.png' %}">
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
{% crispy form %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock body %}
|
@ -0,0 +1,15 @@
|
||||
{% extends "YtManagerApp/master_default.html" %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load static %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="container">
|
||||
|
||||
<h1>Step 2: Create an administrator account</h1>
|
||||
|
||||
{% crispy form %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock body %}
|
@ -0,0 +1,17 @@
|
||||
{% extends "YtManagerApp/master_default.html" %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load static %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="container">
|
||||
|
||||
<h1>Step 3: Configure the server</h1>
|
||||
|
||||
<p>Here you can customize some basic options for the application. There are many more options which can be changed in the settings page.</p>
|
||||
|
||||
{% crispy form %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock body %}
|
@ -3,11 +3,11 @@
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" />
|
||||
<link rel="stylesheet" href="{% static 'YtManagerApp/import/jstree/dist/themes/default/style.min.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
|
||||
<script src="{% static 'YtManagerApp/import/jstree/dist/jstree.min.js' %}"></script>
|
||||
<script>
|
||||
let LAST_NOTIFICATION_ID = {{ current_notification_id }};
|
||||
|
||||
@ -26,24 +26,34 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include 'YtManagerApp/controls/setup_errors_banner.html' %}
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-3">
|
||||
{# Tree toolbar #}
|
||||
<div class="btn-toolbar" role="toolbar" aria-label="Subscriptions toolbar">
|
||||
<div class="btn-group btn-group-sm mr-2" role="group">
|
||||
<button id="btn_create_sub" type="button" class="btn btn-secondary" >
|
||||
<div class="btn-group mr-2" role="group">
|
||||
<button id="btn_create_sub" type="button" class="btn btn-light"
|
||||
data-toggle="tooltip" title="Add subscription...">
|
||||
<span class="typcn typcn-plus" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button id="btn_create_folder" type="button" class="btn btn-secondary">
|
||||
<button id="btn_create_folder" type="button" class="btn btn-light"
|
||||
data-toggle="tooltip" title="Add folder...">
|
||||
<span class="typcn typcn-folder-add" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button id="btn_import" type="button" class="btn btn-light"
|
||||
data-toggle="tooltip" title="Import from file...">
|
||||
<span class="typcn typcn-document-add" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm mr-2" role="group">
|
||||
<button id="btn_edit_node" type="button" class="btn btn-secondary" >
|
||||
<div class="btn-group mr-2" role="group">
|
||||
<button id="btn_edit_node" type="button" class="btn btn-light"
|
||||
data-toggle="tooltip" title="Edit selection">
|
||||
<span class="typcn typcn-edit" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button id="btn_delete_node" type="button" class="btn btn-secondary" >
|
||||
<button id="btn_delete_node" type="button" class="btn btn-light"
|
||||
data-toggle="tooltip" title="Delete selection">
|
||||
<span class="typcn typcn-trash" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
{% block body %}
|
||||
|
||||
{% include 'YtManagerApp/controls/setup_errors_banner.html' %}
|
||||
|
||||
<h1>Hello</h1>
|
||||
<h2>Please log in to continue</h2>
|
||||
|
||||
|
@ -58,4 +58,38 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="pagination row">
|
||||
<div class="btn-toolbar mx-auto">
|
||||
<div class="btn-group mr-2" role="group">
|
||||
<button id="btn_page_first" type="button" class="btn btn-light btn-paging"
|
||||
data-toggle="tooltip" title="First page"
|
||||
{% if videos.has_previous %} data-navigation-page="1" {% else %} disabled {% endif %}>
|
||||
<span class="typcn typcn-chevron-left-outline" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button id="btn_page_prev" type="button" class="btn btn-light btn-paging"
|
||||
data-toggle="tooltip" title="Previous"
|
||||
{% if videos.has_previous %} data-navigation-page="{{ videos.previous_page_number }}" {% else %} disabled {% endif %} >
|
||||
<span class="typcn typcn-chevron-left" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<small class="my-auto mx-2">
|
||||
Page {{ videos.number }} of {{ videos.paginator.num_pages }}
|
||||
</small>
|
||||
|
||||
<div class="btn-group mx-2" role="group">
|
||||
<button id="btn_page_next" type="button" class="btn btn-light btn-paging"
|
||||
data-toggle="tooltip" title="Next"
|
||||
{% if videos.has_next %} data-navigation-page="{{ videos.next_page_number }}" {% else %} disabled {% endif %} >
|
||||
<span class="typcn typcn-chevron-right" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button id="btn_page_last" type="button" class="btn btn-light btn-paging"
|
||||
data-toggle="tooltip" title="Last"
|
||||
{% if videos.has_next %} data-navigation-page="{{ videos.paginator.num_pages }}" {% else %} disabled {% endif %} >
|
||||
<span class="typcn typcn-chevron-right-outline" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -53,7 +53,21 @@ class AjaxModal
|
||||
_submit(e) {
|
||||
let pThis = this;
|
||||
let url = this.form.attr('action');
|
||||
$.post(url, this.form.serialize())
|
||||
let ajax_settings = {
|
||||
url: url,
|
||||
};
|
||||
|
||||
if (this.form.attr('enctype') === 'multipart/form-data') {
|
||||
ajax_settings.data = new FormData(this.form[0]);
|
||||
ajax_settings.contentType = false;
|
||||
ajax_settings.processData = false;
|
||||
ajax_settings.cache = false;
|
||||
}
|
||||
else {
|
||||
ajax_settings.data = this.form.serialize();
|
||||
}
|
||||
|
||||
$.post(ajax_settings)
|
||||
.done(function(result) {
|
||||
pThis._submitDone(result);
|
||||
})
|
||||
|
@ -123,16 +123,33 @@ function videos_Reload()
|
||||
|
||||
let videos_timeout = null;
|
||||
|
||||
function videos_ReloadWithTimer()
|
||||
function videos_ResetPageAndReloadWithTimer()
|
||||
{
|
||||
let filters_form = $("#form_video_filter");
|
||||
filters_form.find('input[name=page]').val("1");
|
||||
|
||||
clearTimeout(videos_timeout);
|
||||
videos_timeout = setTimeout(function()
|
||||
{
|
||||
videos_Submit.call($('#form_video_filter'));
|
||||
videos_Reload();
|
||||
videos_timeout = null;
|
||||
}, 200);
|
||||
}
|
||||
|
||||
function videos_PageClicked()
|
||||
{
|
||||
// Obtain page from button
|
||||
let page = $(this).data('navigation-page');
|
||||
|
||||
// Set page
|
||||
let filters_form = $("#form_video_filter");
|
||||
filters_form.find('input[name=page]').val(page);
|
||||
|
||||
// Reload
|
||||
videos_Reload();
|
||||
$("html, body").animate({ scrollTop: 0 }, "slow");
|
||||
}
|
||||
|
||||
function videos_Submit(e)
|
||||
{
|
||||
let loadingDiv = $('#videos-loading');
|
||||
@ -145,6 +162,7 @@ function videos_Submit(e)
|
||||
.done(function(result) {
|
||||
$("#videos-wrapper").html(result);
|
||||
$(".ajax-link").on("click", ajaxLink_Clicked);
|
||||
$(".btn-paging").on("click", videos_PageClicked);
|
||||
})
|
||||
.fail(function() {
|
||||
$("#videos-wrapper").html('<div class="alert alert-danger">An error occurred while retrieving the video list!</div>');
|
||||
@ -186,6 +204,9 @@ function get_and_process_notifications()
|
||||
///
|
||||
$(document).ready(function ()
|
||||
{
|
||||
// Initialize tooltips
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
|
||||
tree_Initialize();
|
||||
|
||||
// Subscription toolbar
|
||||
@ -199,16 +220,23 @@ $(document).ready(function ()
|
||||
modal.setSubmitCallback(tree_Refresh);
|
||||
modal.loadAndShow();
|
||||
});
|
||||
$("#btn_import").on("click", function () {
|
||||
let modal = new AjaxModal("{% url 'modal_import_subscriptions' %}");
|
||||
modal.setSubmitCallback(tree_Refresh);
|
||||
modal.loadAndShow();
|
||||
});
|
||||
$("#btn_edit_node").on("click", treeNode_Edit);
|
||||
$("#btn_delete_node").on("click", treeNode_Delete);
|
||||
|
||||
// Videos filters
|
||||
let filters_form = $("#form_video_filter");
|
||||
filters_form.submit(videos_Submit);
|
||||
filters_form.find('input[name=query]').on('change', videos_ReloadWithTimer);
|
||||
filters_form.find('select[name=sort]').on('change', videos_ReloadWithTimer);
|
||||
filters_form.find('select[name=show_watched]').on('change', videos_ReloadWithTimer);
|
||||
filters_form.find('select[name=show_downloaded]').on('change', videos_ReloadWithTimer);
|
||||
filters_form.find('input[name=query]').on('change', videos_ResetPageAndReloadWithTimer);
|
||||
filters_form.find('select[name=sort]').on('change', videos_ResetPageAndReloadWithTimer);
|
||||
filters_form.find('select[name=show_watched]').on('change', videos_ResetPageAndReloadWithTimer);
|
||||
filters_form.find('select[name=show_downloaded]').on('change', videos_ResetPageAndReloadWithTimer);
|
||||
filters_form.find('select[name=results_per_page]').on('change', videos_ResetPageAndReloadWithTimer);
|
||||
|
||||
videos_Reload();
|
||||
|
||||
// Notification manager
|
||||
|
@ -6,21 +6,15 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>{% block title %}YouTube Subscription Manager{% endblock %}</title>
|
||||
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="{% static 'YtManagerApp/favicon.ico' %}"/>
|
||||
|
||||
<link rel="stylesheet" href="{% static 'YtManagerApp/import/bootstrap/css/bootstrap.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'YtManagerApp/import/typicons/typicons.min.css' %}" />
|
||||
<link rel="stylesheet" href="{% static 'YtManagerApp/css/style.css' %}">
|
||||
{% block stylesheets %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
{% include 'YtManagerApp/js/common.js' %}
|
||||
</script>
|
||||
{% block scripts %}
|
||||
{% endblock %}
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<a class="navbar-brand" href="{% url 'home' %}">YouTube Manager</a>
|
||||
@ -44,6 +38,9 @@
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userDropdown">
|
||||
<a class="dropdown-item" href="{% url 'settings' %}">Settings</a>
|
||||
{% if request.user.is_superuser %}
|
||||
<a class="dropdown-item" href="{% url 'admin_settings' %}">Admin settings</a>
|
||||
{% endif %}
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="{% url 'logout' %}">Log out</a>
|
||||
</div>
|
||||
@ -52,9 +49,11 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'login' %}">Login</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'register' %}">Register</a>
|
||||
</li>
|
||||
{% if global_preferences.general__allow_registrations %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'register' %}">Register</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
@ -72,5 +71,14 @@
|
||||
<span class="typcn typcn-arrow-sync" aria-hidden="true"></span>
|
||||
</button>
|
||||
</footer>
|
||||
|
||||
<script src="{% static 'YtManagerApp/import/jquery/jquery-3.3.1.min.js' %}"></script>
|
||||
<script src="{% static 'YtManagerApp/import/popper/popper.min.js' %}"></script>
|
||||
<script src="{% static 'YtManagerApp/import/bootstrap/js/bootstrap.min.js' %}"></script>
|
||||
<script>
|
||||
{% include 'YtManagerApp/js/common.js' %}
|
||||
</script>
|
||||
{% block scripts %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
19
app/YtManagerApp/templates/YtManagerApp/settings_admin.html
Normal file
19
app/YtManagerApp/templates/YtManagerApp/settings_admin.html
Normal file
@ -0,0 +1,19 @@
|
||||
{% extends "YtManagerApp/master_default.html" %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="container">
|
||||
|
||||
<h1>Admin settings</h1>
|
||||
|
||||
{% if not request.user.is_authenticated or not request.user.is_superuser %}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
You must be an administrator to access this page!
|
||||
</div>
|
||||
{% else %}
|
||||
{% crispy form %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock body %}
|
@ -24,15 +24,17 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_first_user %}
|
||||
<div class="alert alert-info" role="alert">
|
||||
Since this is the first user to register, it will be the system administrator.
|
||||
{% if not global_preferences.general__allow_registrations %}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
Registrations are disabled by the administrator!
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
|
||||
<h5>Register</h5>
|
||||
{% crispy form %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
<h5>Register</h5>
|
||||
|
||||
{% crispy form %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
Reference in New Issue
Block a user