Skip to content

Commit

Permalink
restrucured code, added features
Browse files Browse the repository at this point in the history
Restructured code;
Moved namespaceColors to local side;
Added Recent and Frequent Tags;
  • Loading branch information
mruac committed Jun 14, 2022
1 parent d261fe4 commit d96ba75
Show file tree
Hide file tree
Showing 6 changed files with 456 additions and 245 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
hrt_session/
__pycache__/
session.db
.vscode/launch.json
*.code-workspace
67 changes: 11 additions & 56 deletions server.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,6 @@
app.config.from_object(__name__)
Session(app)

defaultnamespaceColors = [
# ["className","regex","hexColor"], apply top to bottom
["character", "^character:.*$", "#00aa00"],
["creator", "^creator:.*$", "#ff0000"],
["meta", "^meta:.*$", "#6f6f6f"], # default #111111 in hydrus
["person", "^person:.*$", "#008000"],
["series", "^series:.*$", "#d200d2"],
["studio", "^studio:.*$", "#ff0000"],
["namespaced", "^.*:.*$", "#72a0c1"],
["unnamespaced", "^(?!.*:).*$", "#00aaff"]
]

def search_files(api_key, api_url, search_tags, fileSort, fileOrder):
cl = hydrus.Client(api_key, api_url)
fids = cl.search_files(tags=search_tags, file_service_name="my files", tag_service_name="all known tags", file_sort_asc=fileOrder, file_sort_type=fileSort)
Expand Down Expand Up @@ -70,7 +58,7 @@ def get_fids_from_sql():

@app.route('/index', methods=['GET', 'POST'])
def ad():
# try:
try:
if request.method == 'GET':
return redirect(url_for('index'))
try:
Expand Down Expand Up @@ -103,12 +91,12 @@ def ad():
session['appendTag'].append(tag.replace('_', ' ').lower())

return render_template('results.html', tagrepo=get_services(api_key, api_url), ids=total_ids, tags=post_tags)
# except hydrus.InsufficientAccess:
# return render_template('index.html', error="Insufficient access to Hydrus API", namespaces=session['namespaceColors'])
# except hydrus.ServerError:
# return render_template('index.html', error="Hydrus API encountered a server error", namespaces=session['namespaceColors'])
# except hydrus.APIError:
# return render_template('index.html', error="Hydrus API encountered an API error", namespaces=session['namespaceColors'])
except hydrus.InsufficientAccess:
return render_template('index.html', error="Insufficient access to Hydrus API")
except hydrus.ServerError:
return render_template('index.html', error="Hydrus API encountered a server error")
except hydrus.APIError:
return render_template('index.html', error="Hydrus API encountered an API error")


@app.route('/show-file/<id>', methods=['GET', 'POST'])
Expand Down Expand Up @@ -140,23 +128,8 @@ def ads(id):
if request.form.get('tagrepo') != None:
session['selectedTagRepo'] = request.form.get('tagrepo')

def checkModifiable(tag):
try:
if tag in metadata['service_names_to_statuses_to_tags'][session['selectedTagRepo']]['0']:
return True
else:
return False
except:
return False

def matchNamespace(tag):
for namespace in session['namespaceColors']:
if re.fullmatch(namespace[1], tag):
return namespace[0]
return ""

# prevent browser from loading cached page to force re-fetch tags when navigating back and forth
response = make_response(render_template('show-file.html', image=image, next_images=next_images, nid=nid, current_id=id, total_ids=total_ids, meta=metadata, selectedService=session['selectedTagRepo'], checkModifiable=checkModifiable, matchNamespace=matchNamespace, namespaces=session['namespaceColors']))
response = make_response(render_template('show-file.html', image=image, next_images=next_images, nid=nid, current_id=id, total_ids=total_ids, meta=metadata, selectedService=session['selectedTagRepo']))
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" # HTTP 1.1.
response.headers["Pragma"] = "no-cache" # HTTP 1.0.
response.headers["Expires"] = "0" # Proxies.
Expand All @@ -166,7 +139,8 @@ def matchNamespace(tag):
return redirect(url_for('index'))
except KeyError: # expired session
return redirect(url_for('index'))

except hydrus.MissingParameter: #TESTME:
return render_template('index.html', error="Search query expired - Please try again.")

@app.route('/updateTags', methods=['POST'])
def ajaxUpdate():
Expand All @@ -187,35 +161,16 @@ def ajaxUpdate():
session['appendTagIsSet'] = True
for tag in session['appendTag']:
tagsToAdd.append(tag)
matchedTags = {}
for tag in tagsToAdd:
for namespace in session['namespaceColors']:
if re.fullmatch(namespace[1], tag):
matchedTags.update({tag: namespace[0]})
break

listOfTags = {tag_repo: {"0": tagsToAdd, "1": tagsToDel}}
cl = hydrus.Client(session['api_key'], session['api_url'])
cl.add_tags([hash], service_names_to_actions_to_tags=listOfTags)
listOfTags.update({"matches": matchedTags})
# listOfTags.update({"matches": matchedTags})
return jsonify(listOfTags) # updated lsit of tags


@app.route('/updatePrefs', methods=['POST'])
def updatePrefs():
data = request.get_json()
if data['namespaceColors'] == "":
# return default namespace colors if there is no custom namespaceColors
session['namespaceColors'] = defaultnamespaceColors
return jsonify({"namespaceColors": session['namespaceColors']})
session['namespaceColors'] = data['namespaceColors']
return jsonify({"namespaceColors": session['namespaceColors']})


@app.route('/', methods=['GET'])
def index():
return render_template('index.html')


if __name__ == '__main__':
app.run(host="0.0.0.0", port=8243, debug=True)
2 changes: 1 addition & 1 deletion templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ <h5>Tag Presentation</h5>
<div class="form-floating font-monospace" id="inputText">
<textarea class="form-control" id="inputTextarea" wrap="off" style="height: 20em;"
disabled></textarea>
<label for="inputTextarea">["class-name","Python regex","#ffffff"] per line</label>
<label for="inputTextarea">["class-name","JS regex","#ffffff"] per line</label>
</div>
</div>
<div class="modal-footer">
Expand Down
70 changes: 44 additions & 26 deletions templates/show-file.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@
margin: 0;
padding: 0;
}

{% for namespace in namespaces %}
.{{namespace[0]}}{
color: {{namespace[2]}};
}
{% endfor %}

.modifiable {
font-style: italic;
Expand All @@ -43,15 +37,19 @@
<body style="background: #19191b" class="h-100 p-0 m-0 d-flex overflow-hidden">
<div class="d-flex flex-column absolute h-100 w-100 overflow-hidden">
<nav style="flex: none; z-index: 10" class="navbar navbar-expand-md navbar-dark bg-dark">
<a class="nav-link me-auto" href="/" style="font-size: 1.5em; font-weight: 600; color: white;">ψ Remote
Tagging</a>
<button type="button" class="btn btn-primary float-end ms-auto me-3" data-bs-toggle="offcanvas"
data-bs-target="#metadataSidebar"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-info-circle" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
<path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>
</svg></button>
<button type="button" class="btn btn-primary float-start me-auto ms-3 handySidebarToggle" id="handySidebarButton">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
</svg>
</button>
<a class="nav-link" href="/" style="font-size: 1.5em; font-weight: 600; color: white;">ψ Remote Tagging</a>
<button type="button" class="btn btn-primary float-end ms-auto me-3 metadataSidebarToggle">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-info-circle" viewBox="0 0 16 16" data-darkreader-inline-fill="" style="--darkreader-inline-fill:currentColor;">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"></path>
<path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"></path>
</svg>
</button>
</nav>

{% if image %}
<main class="text-center overflow-hidden m-auto mx-auto justify-content-center align-self-center">
{% if meta['mime'].startswith('image') %}
Expand Down Expand Up @@ -81,10 +79,36 @@ <h1 class="mx-auto text-white nm-text" style="align-self: center;">Not an image
</div>
{% endif %}

<div class="offcanvas offcanvas-start bg-dark text-start opacity-75" data-bs-backdrop="false" id="handySidebar"
style="width: 20%;">
<div id="handySidebarDraggable" style="width: 10px; z-index: 1; cursor: w-resize; transform: translate(50%,-50%);"
class="position-absolute top-50 end-0 h-100"></div>
<div class="p-2">
<button type="button" class="btn btn-secondary float-start" id="handyToggle">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clock-history" viewBox="0 0 16 16">
<path d="M8.515 1.019A7 7 0 0 0 8 1V0a8 8 0 0 1 .589.022l-.074.997zm2.004.45a7.003 7.003 0 0 0-.985-.299l.219-.976c.383.086.76.2 1.126.342l-.36.933zm1.37.71a7.01 7.01 0 0 0-.439-.27l.493-.87a8.025 8.025 0 0 1 .979.654l-.615.789a6.996 6.996 0 0 0-.418-.302zm1.834 1.79a6.99 6.99 0 0 0-.653-.796l.724-.69c.27.285.52.59.747.91l-.818.576zm.744 1.352a7.08 7.08 0 0 0-.214-.468l.893-.45a7.976 7.976 0 0 1 .45 1.088l-.95.313a7.023 7.023 0 0 0-.179-.483zm.53 2.507a6.991 6.991 0 0 0-.1-1.025l.985-.17c.067.386.106.778.116 1.17l-1 .025zm-.131 1.538c.033-.17.06-.339.081-.51l.993.123a7.957 7.957 0 0 1-.23 1.155l-.964-.267c.046-.165.086-.332.12-.501zm-.952 2.379c.184-.29.346-.594.486-.908l.914.405c-.16.36-.345.706-.555 1.038l-.845-.535zm-.964 1.205c.122-.122.239-.248.35-.378l.758.653a8.073 8.073 0 0 1-.401.432l-.707-.707z"/>
<path d="M8 1a7 7 0 1 0 4.95 11.95l.707.707A8.001 8.001 0 1 1 8 0v1z"/>
<path d="M7.5 3a.5.5 0 0 1 .5.5v5.21l3.248 1.856a.5.5 0 0 1-.496.868l-3.5-2A.5.5 0 0 1 7 9V3.5a.5.5 0 0 1 .5-.5z"/>
</svg>
</button>
<button type="button" class="btn btn-primary float-end handySidebarToggle">X</button>
</div>

<div class="text-nowrap overflow-auto h-100">
<div class="bg-dark text-light list-group-item">
<h5 class="mb-2 font-weight-bold" id="handySidebarTitle">Recent Tags</h5>
<div id="handylistOfTags">
<!-- Load Frequent or Recent tags here -->
</div>
</div>
</div>
</div>


<div class="offcanvas offcanvas-end bg-dark text-start opacity-75" data-bs-backdrop="false" id="metadataSidebar"
style="width: 50%;">
<div id="metadataSidebarDraggable" style="width: 10px; z-index: 1; cursor: w-resize;"
class="position-absolute top-50 start-0 translate-middle h-100"></div>
style="width: 20%;">
<div id="metadataSidebarDraggable" style="width: 10px; z-index: 1; cursor: w-resize; transform: translate(-50%,-50%);"
class="position-absolute top-50 start-0 h-100"></div>
<div class="p-2"><button type="button" class="btn btn-secondary float-start" data-bs-toggle="collapse"
data-bs-target="#file_metadata"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
fill="currentColor" class="bi bi-file-text " viewBox="0 0 16 16">
Expand All @@ -95,8 +119,7 @@ <h1 class="mx-auto text-white nm-text" style="align-self: center;">Not an image
d="M2 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2zm10-1H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1z">
</path>
</svg></button>
<button type="button" class="btn btn-primary float-end" data-bs-toggle="offcanvas"
data-bs-target="#metadataSidebar">X</button>
<button type="button" class="btn btn-primary float-end metadataSidebarToggle">X</button>
</div>

<div class="text-nowrap overflow-auto h-100">
Expand Down Expand Up @@ -128,12 +151,8 @@ <h5 class="font-weight-bold">Hash</h5>

<div class="bg-dark text-light list-group-item">
<h5 class="mb-2 font-weight-bold">All Known Tags</h5>
<div id="listOfTags">
{% for tag in meta['service_names_to_statuses_to_tags']['all known tags']['0'] %}
<span class="{% if checkModifiable(tag) %}modifiable{% endif %}
{{matchNamespace(tag)}}">{{tag}}
</span><br>
{%endfor%}
<div class="text-start" id="listOfTags">
<!-- Load tags for current file here -->
</div>
</div>
</div>
Expand All @@ -143,7 +162,6 @@ <h5 class="mb-2 font-weight-bold">All Known Tags</h5>
<script type="text/javascript">
metadata = {{ meta | tojson }};
currentRepo = "{{ selectedService }}";
namespaceColors = {{ namespaces | tojson }};
</script>

</body>
Expand Down
63 changes: 18 additions & 45 deletions templates/static/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
var defaultnamespaceColors;
var defaultNamespaceColors =
[
// ["className","regex","hexColor"], apply top to bottom
["character", "^character:.*$", "#00aa00"],
["creator", "^creator:.*$", "#ff0000"],
["meta", "^meta:.*$", "#6f6f6f"], // default #111111 in hydrus
["person", "^person:.*$", "#008000"],
["series", "^series:.*$", "#d200d2"],
["studio", "^studio:.*$", "#ff0000"],
["namespaced", "^.*:.*$", "#72a0c1"],
["unnamespaced", "^(?!.*:).*$", "#00aaff"]
];

if ((localStorage.getItem('api-url') != null) && (localStorage.getItem('api-url') != "")) {
$("#api-url-input").val(localStorage.getItem('api-url'));
$("#settings-api-url-input").val(localStorage.getItem('api-url'));
Expand All @@ -7,47 +19,17 @@ if ((localStorage.getItem('api-key') != null) && (localStorage.getItem('api-key'
$("#api-key-input").val(localStorage.getItem('api-key'));
$("#settings-api-key-input").val(localStorage.getItem('api-key'));
}
if (localStorage.getItem("sidebarToggleKey") != null){
if (localStorage.getItem("sidebarToggleKey") != null) {
$(`input[name="sidebarToggleKey"][value="${localStorage.getItem("sidebarToggleKey")}"]`).prop("checked", true);
} else {
localStorage.setItem("sidebarToggleKey", "ctrl");
$(`input[name="sidebarToggleKey"][value="${localStorage.getItem("sidebarToggleKey")}"]`).prop("checked", true);
}

$.ajax({
type: "POST",
url: "/updatePrefs",
data: `{"namespaceColors":""}`,
dataType: "json",
contentType: "application/json; charset=utf-8"
}).done(function (response) {

var res = ``;
response['namespaceColors'].forEach(function (v, i) {
res += String.raw`${JSON.stringify(v).replace(/\\\\/g, '\\')}` + `\n`;
});
defaultnamespaceColors = res;
});

if ((localStorage.getItem('tagPresentation') != null)) {
//if namespaceColors exist in localStorage, send to flask session to store.
$.ajax({
type: "POST",
url: "/updatePrefs",
data: localStorage.getItem('tagPresentation'),
dataType: "json",
contentType: "application/json; charset=utf-8"
});

var res = ``;
JSON.parse(localStorage.tagPresentation)['namespaceColors'].forEach(function (v, i) {
res += String.raw`${JSON.stringify(v).replace(/\\\\/g, '\\')}` + `\n`;
});
$("#inputTextarea").val(res);
} else {
//else load default namespaceColors from flask
$("#inputTextarea").val(defaultnamespaceColors);
if (localStorage.getItem('tagPresentation') == undefined){
localStorage.setItem('tagPresentation', JSON.stringify({"namespaceColors":defaultNamespaceColors}));
}
$("#inputTextarea").val(JSON.parse(localStorage.tagPresentation)["namespaceColors"]);


$('#modifyMode').change(function () {
Expand Down Expand Up @@ -102,18 +84,9 @@ $('#submitEntry').on('click', function () {
var tagPresentationDict = `{ "namespaceColors": [${val.replace(/\\/g, '\\\\')}] }`; //{"studio":[regex,"hex color"]}

localStorage.setItem("api-url", $("#settings-api-url-input").val());
localStorage.setItem("api-key", $("#settings-api-key-input").val());
localStorage.setItem("api-key", $("#settings-api-key-input").val());
localStorage.setItem("tagPresentation", tagPresentationDict)
//send to /updatePrefs
$.ajax({
type: "POST",
url: "/updatePrefs",
data: tagPresentationDict,
dataType: "json",
contentType: "application/json; charset=utf-8"
});
localStorage.setItem("sidebarToggleKey", $('input[name="sidebarToggleKey"]:checked').val())

}
})

Expand Down
Loading

0 comments on commit d96ba75

Please sign in to comment.