feat: add videodb media index with Docker stack

- Add videodb PHP/MySQL media collection manager (Blu-ray, DVD, CD)
- Dockerfile: PHP 8.1 + Apache with GD/mysqli/exif extensions
- docker-compose.yml: app on port 6761 + MySQL 8.0 with health checks
- docker-entrypoint.sh: auto-generates config.inc.php from env vars,
  waits for MySQL, initializes DB schema idempotently
- init-db.php: CLI schema installer using app's own prefix_query() logic
- Persistent volumes for DB, cache, and cover images

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-11 09:49:52 +02:00
commit f55c91276e
1230 changed files with 252321 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
/**
* General logic
*
* @package JavaScript
* @author Andreas Goetz <cpuidle@gmx.de>
* @version $Id: app.js,v 1.7 2013/03/21 16:27:57 andig2 Exp $
*/
$(document).ready(function() {
// customize forms
$("form").addClass("custom");
// add submit on click
$(".autosubmit").change(function() {
$(this).parent().submit();
});
// add submit on click
$(".submit").click(function() {
$(this).closest("form").submit();
});
// disable "disabled" buttons
$("a.button.disabled").click(function(event) {
event.stopImmediatePropagation();
return(false);
});
// allow closing reveal dialogs
$(".button.close-modal").click(function() {
$(this).closest("div.reveal-modal").find('a.close-reveal-modal').trigger('click');
return(false);
});
// focus primary element (must be only one)
$(".autofocus").focus();
// prevent tabbing through <i> tags
$('i').parent().attr('tabindex', '-1');
// lazy-load images
if (typeof jQuery == "function" && typeof jQuery().lazyload == "function") {
$("img.lazy").lazyload({threshold: 500});
}
// substitute input[file] with custom control
$("input[type=file]").each(function() {
var proxy = $('<input type="text" value="'+$(this).val()+'" />');
var context = {_this: $(this), _proxy: proxy};
var intervalFunc = $.proxy(function() {
this._proxy.val(this._this.val());
}, context);
// hide file input and watch for changes
$(this)
.css("position", "absolute")
.css("opacity", "0.000001")
.attr("size", "100")
.parent().append(proxy)
.click(function() {
setInterval(intervalFunc, 1000);
});
});
// dl.input-radio
$("dl[input-radio] dd").each(function() {
var a = $(this).find("a");
// create proxy element
if ($(this).hasClass("active") && $("#"+a.attr("href")).length == 0) {
$(this).closest("form").append(
$('<input type="hidden" name="'+a.attr("href")+'" id="'+a.attr("href")+'" value="'+a.attr("value")+'" />')
);
}
// add click function
$(this).click(function() {
$(this).siblings().removeClass("active");
$(this).addClass("active");
// set proxy value
var a = $(this).find("a");
$("#"+a.attr("href")).val(a.attr("value"));
return(false);
});
});
// dl.input-checkbox
$("dl[input-checkbox] dd").each(function() {
var a = $(this).find("a");
var id = $(this).closest("form").attr("id")+a.attr("href").replace("[]","")+a.attr("value");
// create proxy elements
if ($("#"+id).length == 0) {
// alert($(this).closest("form").attr("id"));
$(this).closest("form").append(
$('<input type="hidden" name="'+a.attr("href")+'" id="'+id+'" value="' + (
($(this).hasClass("active")) ? a.attr("value") : ''
) + '" />')
);
}
// add click function
$(this).click(function() {
$(this).toggleClass("active");
// set proxy value
var a = $(this).find("a");
var id = $(this).closest("form").attr("id")+a.attr("href").replace("[]","")+a.attr("value");
// alert($("#"+id).closest("form").attr("action") +"/"+$("#"+id).closest("form").attr("id") +" "+ "#"+id + ":" + (($(this).hasClass("active")) ? a.attr("value") : ""));
$("#"+id).val(($(this).hasClass("active")) ? a.attr("value") : "");
return(false);
});
});
$('li a.seen').each(function() {
$(this).click(function(e) {
e.preventDefault();
var a = $(this);
var u = a.attr('href').replace('id=', 'ajax_update=');
$.get(u, function() {
a.addClass('disabled');
});
});
});
});

View File

@@ -0,0 +1,53 @@
/**
* Editing logic
*
* @package JavaScript
* @author Andreas Goetz <cpuidle@gmx.de>
* @version $Id: edit.js,v 1.3 2013/03/13 08:01:01 andig2 Exp $
*/
/*
$(document).ready(function () {
$("#title").autocomplete({
source: function(request, response) {
$.ajax({
url: "edit.php",
data: {
ajax_type: "json",
ajax_autocomplete_title: request.term
},
success: function(data) {
response($.map(data, function(item) {
return {
id: item.id,
value: item.title
}
}))
}
})
},
select: function(event, ui) {
$("#imdbID").val(ui.item.id);
$("#lookup1").click();
}
});
});
*/
function lookupData(title) {
var win = open('lookup.php?find=' + encodeURIComponent(title), 'lookup',
'width=700,height=600,menubar=no,resizable=yes,scrollbars=yes,status=yes,toolbar=no');
win.focus();
}
function lookupImage(title) {
var win = open('lookup.php?find=' + encodeURIComponent(title) + '&searchtype=image&engine=google', 'lookup',
'width=450,height=500,menubar=no,resizable=yes,scrollbars=yes,status=yes,toolbar=no');
win.focus();
}
function changedId() {
if ($("#imdbID").val()) {
$('#lookup1').click();
}
}

View File

@@ -0,0 +1,28 @@
/**
* Lookup data submission logic
*
* @package JavaScript
* @author Andreas Goetz <cpuidle@gmx.de>
* @version $Id: lookup.js,v 1.2 2013/03/16 10:10:07 andig2 Exp $
*/
window.focus();
function returnData(id, title, subtitle, engine) {
window.opener.$('#imdbID').val(id);
window.opener.$('#engine').val(engine);
window.opener.$('#title').val(title);
// $('#subtitle').val(subtitle);
window.opener.$('#lookup1').click();
opener.focus();
window.close();
}
function returnImage(imgurl) {
window.opener.$('#imgurl').val(imgurl);
opener.focus();
window.close();
}

View File

@@ -0,0 +1,34 @@
/**
* Search logic
*
* @package JavaScript
* @author Andreas Goetz <cpuidle@gmx.de>
* @version $Id: search.js,v 1.1 2013/03/10 16:18:26 andig2 Exp $
*/
$(document).ready(function () {
$("#q").autocomplete({
source: function(request, response) {
$.ajax({
url: "search.php",
data: {
ajax_type: "json",
ajax_autocomplete_title: request.term
},
success: function(data) {
response($.map(data, function(item) {
return {
id: item.id,
value: item.title
}
}))
}
})
},
select: function(event, ui) {
//$("#imdbID").val(ui.item.id);
//$("#lookup1").click();
}
});
});