Merge branch 'settings'
This commit is contained in:
commit
3dd0371af1
118
settings.py
118
settings.py
@ -1,12 +1,17 @@
|
||||
from youtube import util, yt_app
|
||||
import ast
|
||||
import re
|
||||
import os
|
||||
import collections
|
||||
|
||||
import flask
|
||||
from flask import request
|
||||
|
||||
settings_info = collections.OrderedDict([
|
||||
('route_tor', {
|
||||
'type': bool,
|
||||
'default': False,
|
||||
'label': 'Route Tor',
|
||||
'comment': '',
|
||||
}),
|
||||
|
||||
@ -21,6 +26,7 @@ settings_info = collections.OrderedDict([
|
||||
'default': False,
|
||||
'comment': '''This will allow others to connect to your Youtube Local instance as a website.
|
||||
For security reasons, enabling this is not recommended.''',
|
||||
'hidden': True,
|
||||
}),
|
||||
|
||||
('subtitles_mode', {
|
||||
@ -29,6 +35,12 @@ For security reasons, enabling this is not recommended.''',
|
||||
'comment': '''0 - off by default
|
||||
1 - only manually created subtitles on by default
|
||||
2 - enable even if automatically generated is all that's available''',
|
||||
'label': 'Default subtitles mode',
|
||||
'options': [
|
||||
(0, 'Off'),
|
||||
(1, 'Manually created only'),
|
||||
(2, 'Automatic if manual unavailable'),
|
||||
],
|
||||
}),
|
||||
|
||||
('subtitles_language', {
|
||||
@ -42,7 +54,12 @@ For security reasons, enabling this is not recommended.''',
|
||||
'default': 1,
|
||||
'comment': '''0 - Related videos disabled
|
||||
1 - Related videos always shown
|
||||
2 - Related videos hidden; shown by clicking a button'''
|
||||
2 - Related videos hidden; shown by clicking a button''',
|
||||
'options': [
|
||||
(0, 'Disabled'),
|
||||
(1, 'Always shown'),
|
||||
(2, 'Shown by clicking button'),
|
||||
],
|
||||
}),
|
||||
|
||||
('comments_mode', {
|
||||
@ -51,6 +68,11 @@ For security reasons, enabling this is not recommended.''',
|
||||
'comment': '''0 - Video comments disabled
|
||||
1 - Video comments always shown
|
||||
2 - Video comments hidden; shown by clicking a button''',
|
||||
'options': [
|
||||
(0, 'Disabled'),
|
||||
(1, 'Always shown'),
|
||||
(2, 'Shown by clicking button'),
|
||||
],
|
||||
}),
|
||||
|
||||
('enable_comment_avatars', {
|
||||
@ -64,6 +86,10 @@ For security reasons, enabling this is not recommended.''',
|
||||
'default': 0,
|
||||
'comment': '''0 to sort by top
|
||||
1 to sort by newest''',
|
||||
'options': [
|
||||
(0, 'Top'),
|
||||
(1, 'Newest'),
|
||||
],
|
||||
}),
|
||||
|
||||
('theater_mode', {
|
||||
@ -88,18 +114,21 @@ For security reasons, enabling this is not recommended.''',
|
||||
'type': bool,
|
||||
'default': False,
|
||||
'comment': '''Developer use to debug 403s''',
|
||||
'hidden': True,
|
||||
}),
|
||||
|
||||
('debugging_save_responses', {
|
||||
'type': bool,
|
||||
'default': False,
|
||||
'comment': '''Save all responses from youtube for debugging''',
|
||||
'hidden': True,
|
||||
}),
|
||||
|
||||
('settings_version', {
|
||||
'type': int,
|
||||
'default': 2,
|
||||
'comment': '''Do not change, remove, or comment out this value, or else your settings may be lost or corrupted'''
|
||||
'comment': '''Do not change, remove, or comment out this value, or else your settings may be lost or corrupted''',
|
||||
'hidden': True,
|
||||
}),
|
||||
])
|
||||
|
||||
@ -112,6 +141,11 @@ def comment_string(comment):
|
||||
result += '# ' + line + '\n'
|
||||
return result
|
||||
|
||||
def save_settings(settings):
|
||||
with open(settings_file_path, 'w', encoding='utf-8') as file:
|
||||
for setting_name, default_setting_dict in settings_info.items():
|
||||
file.write(comment_string(default_setting_dict['comment']) + setting_name + ' = ' + repr(settings[setting_name]) + '\n\n')
|
||||
|
||||
|
||||
def create_missing_settings_string(current_settings):
|
||||
result = ''
|
||||
@ -123,6 +157,11 @@ def create_missing_settings_string(current_settings):
|
||||
def create_default_settings_string():
|
||||
return settings_to_string({})
|
||||
|
||||
def add_missing_settings(settings):
|
||||
result = default_settings()
|
||||
result.update(settings)
|
||||
return result
|
||||
|
||||
def default_settings():
|
||||
return {key: setting_info['default'] for key, setting_info in settings_info.items()}
|
||||
|
||||
@ -166,21 +205,19 @@ else:
|
||||
|
||||
settings_file_path = os.path.join(settings_dir, 'settings.txt')
|
||||
|
||||
locals().update(default_settings())
|
||||
|
||||
try:
|
||||
with open(settings_file_path, 'r', encoding='utf-8') as file:
|
||||
settings_text = file.read()
|
||||
except FileNotFoundError:
|
||||
with open(settings_file_path, 'w', encoding='utf-8') as file:
|
||||
file.write(create_default_settings_string())
|
||||
settings = default_settings()
|
||||
save_settings(settings)
|
||||
else:
|
||||
if re.fullmatch(r'\s*', settings_text): # blank file
|
||||
with open(settings_file_path, 'w', encoding='utf-8') as file:
|
||||
file.write(create_default_settings_string())
|
||||
settings = default_settings()
|
||||
save_settings(settings)
|
||||
else:
|
||||
# parse settings in a safe way, without exec
|
||||
current_settings = {}
|
||||
settings = {}
|
||||
attributes = {
|
||||
ast.NameConstant: 'value',
|
||||
ast.Num: 'n',
|
||||
@ -209,26 +246,21 @@ else:
|
||||
log_ignored_line(node.lineno, "only literals allowed for values")
|
||||
continue
|
||||
|
||||
current_settings[target.id] = node.value.__getattribute__(attributes[type(node.value)])
|
||||
settings[target.id] = node.value.__getattribute__(attributes[type(node.value)])
|
||||
|
||||
|
||||
if 'settings_version' not in current_settings:
|
||||
if 'settings_version' not in settings:
|
||||
print('Upgrading settings.txt')
|
||||
new_settings = upgrade_to_2(current_settings)
|
||||
locals().update(new_settings)
|
||||
new_settings_string = settings_to_string(new_settings)
|
||||
with open(settings_file_path, 'w', encoding='utf-8') as file:
|
||||
file.write(new_settings_string)
|
||||
settings = add_missing_settings(upgrade_to_2(settings))
|
||||
save_settings(settings)
|
||||
|
||||
# some settings not in the file, add those missing settings to the file
|
||||
elif len(settings_info.keys() - current_settings.keys()) != 0:
|
||||
elif not settings.keys() >= settings_info.keys():
|
||||
print('Adding missing settings to settings.txt')
|
||||
append_text = create_missing_settings_string(current_settings)
|
||||
with open(settings_file_path, 'a', encoding='utf-8') as file:
|
||||
file.write('\n\n' + append_text)
|
||||
locals().update(current_settings)
|
||||
else:
|
||||
locals().update(current_settings)
|
||||
settings = add_missing_settings(settings)
|
||||
save_settings(settings)
|
||||
|
||||
locals().update(settings)
|
||||
|
||||
|
||||
|
||||
@ -237,3 +269,43 @@ if route_tor:
|
||||
print("Tor routing is ON")
|
||||
else:
|
||||
print("Tor routing is OFF - your Youtube activity is NOT anonymous")
|
||||
|
||||
|
||||
|
||||
@yt_app.route('/settings', methods=['POST', 'GET'])
|
||||
def settings_page():
|
||||
if request.method == 'GET':
|
||||
return flask.render_template('settings.html',
|
||||
settings = [(setting_name, setting_info, settings[setting_name]) for setting_name, setting_info in settings_info.items()]
|
||||
)
|
||||
elif request.method == 'POST':
|
||||
for key, value in request.values.items():
|
||||
if key in settings_info:
|
||||
if settings_info[key]['type'] is bool and value == 'on':
|
||||
settings[key] = True
|
||||
else:
|
||||
settings[key] = settings_info[key]['type'](value)
|
||||
else:
|
||||
flask.abort(400)
|
||||
|
||||
# need this bullshit because browsers don't send anything when an input is unchecked
|
||||
expected_inputs = {setting_name for setting_name, setting_info in settings_info.items() if not settings_info[setting_name].get('hidden', False)}
|
||||
missing_inputs = expected_inputs - set(request.values.keys())
|
||||
for setting_name in missing_inputs:
|
||||
assert settings_info[setting_name]['type'] is bool, missing_inputs
|
||||
settings[setting_name] = False
|
||||
|
||||
globals().update(settings)
|
||||
save_settings(settings)
|
||||
return flask.redirect(util.URL_ORIGIN + '/settings', 303)
|
||||
else:
|
||||
flask.abort(400)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
64
youtube/templates/settings.html
Normal file
64
youtube/templates/settings.html
Normal file
@ -0,0 +1,64 @@
|
||||
{% set page_title = 'Settings' %}
|
||||
{% extends "base.html" %}
|
||||
{% import "common_elements.html" as common_elements %}
|
||||
{% block style %}
|
||||
.settings-form {
|
||||
margin: auto;
|
||||
padding: 10px;
|
||||
display: inline-block;
|
||||
background-color: #dadada;
|
||||
}
|
||||
.settings-list{
|
||||
list-style: none;
|
||||
padding: 0px;
|
||||
}
|
||||
.setting-item{
|
||||
margin-bottom: 10px;
|
||||
background-color: #eeeeee;
|
||||
padding: 5px;
|
||||
}
|
||||
.setting-item label{
|
||||
display: inline-block;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
{% endblock style %}
|
||||
|
||||
{% block main %}
|
||||
<form method="POST" class="settings-form">
|
||||
<ul class="settings-list">
|
||||
{% for setting_name, setting_info, value in settings %}
|
||||
{% if not setting_info.get('hidden', false) %}
|
||||
<li class="setting-item">
|
||||
{% if 'label' is in(setting_info) %}
|
||||
<label for="{{ 'setting_' + setting_name }}">{{ setting_info['label'] }}</label>
|
||||
{% else %}
|
||||
<label for="{{ 'setting_' + setting_name }}">{{ setting_name.replace('_', ' ')|capitalize }}</label>
|
||||
{% endif %}
|
||||
|
||||
{% if setting_info['type'].__name__ == 'bool' %}
|
||||
<input type="checkbox" id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}" {{ 'checked' if value else '' }}>
|
||||
{% elif setting_info['type'].__name__ == 'int' %}
|
||||
{% if 'options' is in(setting_info) %}
|
||||
<select id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}">
|
||||
{% for option in setting_info['options'] %}
|
||||
<option value="{{ option[0] }}" {{ 'selected' if option[0] == value else '' }}>{{ option[1] }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
<input type="number" id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}" value="{{ value }}" step="1">
|
||||
{% endif %}
|
||||
{% elif setting_info['type'].__name__ == 'float' %}
|
||||
|
||||
{% elif setting_info['type'].__name__ == 'str' %}
|
||||
<input type="text" id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}" value="{{ value }}">
|
||||
{% else %}
|
||||
<span>Error: Unknown setting type: setting_info['type'].__name__</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<input type="submit" value="Save settings">
|
||||
</form>
|
||||
{% endblock main %}
|
Loading…
x
Reference in New Issue
Block a user