diff --git a/.gitignore b/.gitignore index f658d81..0a3189b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,5 @@ .settings /config.php /dbconfig.conf -/webui/.htaccess -/webui/tmp/* +/public/.htaccess + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e456c05 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "externals/sihnon-js-lib"] + path = externals/sihnon-js-lib + url = ../sihnon-js-lib.git diff --git a/build/ripping-cluster-worker.conf-gentoo b/build/ripping-cluster-worker.conf-gentoo new file mode 100644 index 0000000..631bdb7 --- /dev/null +++ b/build/ripping-cluster-worker.conf-gentoo @@ -0,0 +1,5 @@ +# Which user to run the worker daemon as +USER="media" + +# File to store the running daemon's PID in +PID_FILE="/var/run/ripping-cluster-worker.pid" diff --git a/build/ripping-cluster-worker.init-gentoo b/build/ripping-cluster-worker.init-gentoo index 0abdb95..559f5fa 100644 --- a/build/ripping-cluster-worker.init-gentoo +++ b/build/ripping-cluster-worker.init-gentoo @@ -2,8 +2,6 @@ # Copyright 1999-2010 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -PID_FILE="/var/run/ripping-cluster-worker.pid" - depend() { need localmount net use dns logger puppetmaster netmount nfsmount @@ -13,7 +11,8 @@ start() { ebegin "Starting ripping-cluster-worker" start-stop-daemon --start --quiet \ --background --make-pidfile --pidfile ${PID_FILE} \ - --exec /usr/bin/php /usr/lib/ripping-cluster/worker/ripping-cluster-worker.php + --chuid ${USER} --user ${USER} \ + --exec /usr/bin/php /usr/lib/ripping-cluster/source/worker/ripping-cluster-worker.php eend $? "Failed to start ripping-cluster-worker" } @@ -22,8 +21,10 @@ stop() { start-stop-daemon --stop --quiet \ --pidfile ${PID_FILE} local ret=$? - eend ${ret} "Failed to stop puppet" - rm -f ${PID_FILE} + + eend ${ret} "Failed to stop ripping-cluster-worker" + ${ret} || rm -f ${PID_FILE} + return ${ret} } diff --git a/build/schema/mysql.sql b/build/schema/mysql.sql new file mode 100644 index 0000000..259c531 --- /dev/null +++ b/build/schema/mysql.sql @@ -0,0 +1,208 @@ +-- phpMyAdmin SQL Dump +-- version 3.3.0 +-- http://www.phpmyadmin.net +-- +-- Host: localhost:3306 +-- Generation Time: Jan 11, 2012 at 12:27 AM +-- Server version: 5.1.53 +-- PHP Version: 5.3.6-pl1-gentoo + +SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; + +-- +-- Database: `ripping-cluster` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `client_log` +-- + +DROP TABLE IF EXISTS `client_log`; +CREATE TABLE IF NOT EXISTS `client_log` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `job_id` int(10) unsigned DEFAULT NULL, + `level` varchar(32) NOT NULL, + `category` varchar(32) NOT NULL, + `ctime` int(11) NOT NULL, + `pid` int(11) NOT NULL, + `hostname` varchar(32) NOT NULL, + `progname` varchar(64) NOT NULL, + `file` text NOT NULL, + `line` int(11) NOT NULL, + `message` text NOT NULL, + PRIMARY KEY (`id`), + KEY `job_id` (`job_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `jobs` +-- + +DROP TABLE IF EXISTS `jobs`; +CREATE TABLE IF NOT EXISTS `jobs` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `source_plugin` varchar(255) NOT NULL COMMENT 'Partial classname of the plugin used to read the source', + `rip_plugin` varchar(255) NOT NULL COMMENT 'Partial classname of the plugin used to perform the rip', + `source` text NOT NULL, + `destination` text NOT NULL, + `title` varchar(64) NOT NULL, + `format` varchar(4) NOT NULL, + `video_codec` varchar(8) NOT NULL, + `video_width` int(11) DEFAULT NULL, + `video_height` int(11) DEFAULT NULL, + `quantizer` float NOT NULL, + `deinterlace` double NOT NULL, + `audio_tracks` varchar(64) NOT NULL, + `audio_codecs` varchar(64) NOT NULL, + `audio_names` varchar(255) NOT NULL, + `subtitle_tracks` varchar(64) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `job_status` +-- + +DROP TABLE IF EXISTS `job_status`; +CREATE TABLE IF NOT EXISTS `job_status` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `job_id` int(10) unsigned NOT NULL, + `status` int(10) unsigned NOT NULL, + `ctime` int(10) unsigned NOT NULL, + `mtime` int(10) unsigned NOT NULL, + `rip_progress` double DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `job_id` (`job_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `job_status_current` +-- + +DROP TABLE IF EXISTS `job_status_current`; +CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`%` SQL SECURITY DEFINER VIEW `handbrake_cluster`.`job_status_current` AS select `js`.`id` AS `id`,`js`.`job_id` AS `job_id`,`js`.`status` AS `status`,`js`.`ctime` AS `ctime`,`js`.`mtime` AS `mtime`,`js`.`rip_progress` AS `rip_progress` from (`handbrake_cluster`.`job_status` `js` join `handbrake_cluster`.`job_status_current_int` `js2`) where ((`js2`.`job_id` = `js`.`job_id`) and (`js`.`id` = `js2`.`latest`)); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `job_status_current_int` +-- + +DROP TABLE IF EXISTS `job_status_current_int`; +CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`%` SQL SECURITY DEFINER VIEW `handbrake_cluster`.`job_status_current_int` AS (select `handbrake_cluster`.`job_status`.`job_id` AS `job_id`,max(`handbrake_cluster`.`job_status`.`id`) AS `latest` from `handbrake_cluster`.`job_status` group by `handbrake_cluster`.`job_status`.`job_id`); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `settings` +-- + +DROP TABLE IF EXISTS `settings`; +CREATE TABLE IF NOT EXISTS `settings` ( + `name` varchar(255) NOT NULL, + `value` text NOT NULL, + `type` enum('bool','int','float','string','array(string)','hash') DEFAULT 'string', + PRIMARY KEY (`name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `settings` +-- + +INSERT INTO `settings` (`name`, `value`, `type`) VALUES +('debug.display_exceptions', '1', 'bool'), +('rips.nice', '15', 'int'), +('cache.base_dir', '/dev/shm/hbc/', 'string'), +('rips.cache_ttl', '86400', 'int'), +('rips.job_servers', 'localhost:7003', 'string'), +('rips.context', 'dev', 'string'), +('rips.default.output_directory', '', 'string'), +('rips.handbrake_binary', '/usr/bin/HandBrakeCLI', 'string'), +('rips.nice_binary', '/usr/bin/nice', 'string'), +('source.handbrake.dir', '', 'array(string)'), +('source.mkvinfo.dir', '', 'array(string)'), +('source.bluray.dir', '', 'array(string)'), +('logging.plugins', 'Database\nFlatFile\nConsole', 'array(string)'), +('logging.Console', 'stdout', 'array(string)'), +('logging.Console.stdout.format', '%ctime% %hostname%:%pid% %progname%:%file%[%line%] %message%', 'string'), +('logging.Console.stdout.severity', 'debug\ninfo\nwarning\nerror', 'array(string)'), +('logging.Console.stdout.category', 'client\nworker', 'array(string)'), +('logging.Database', 'webui\nworker', 'array(string)'), +('logging.Database.webui.table', 'client_log', 'string'), +('logging.Database.webui.severity', 'debug\ninfo\nwarning\ndebug', 'array(string)'), +('logging.Database.webui.category', 'batch\nclient\ndefault', 'array(string)'), +('logging.Database.worker.table', 'worker_log', 'string'), +('logging.Database.worker.severity', 'debug\ninfo\nwarning\nerror', 'array(string)'), +('logging.Database.worker.category', 'worker', 'array(string)'), +('logging.FlatFile', 'stderr\nvarlog_worker', 'array(string)'), +('logging.FlatFile.stderr.filename', 'php://stderr', 'string'), +('logging.FlatFile.stderr.format', '%timestamp% %hostname%:%pid% %progname%:%file%[%line%] %message%', 'string'), +('logging.FlatFile.stderr.severity', 'warning\nerror', 'array(string)'), +('logging.FlatFile.stderr.category', 'batch\nclient\ndefault\nworker', 'array(string)'), +('logging.FlatFile.varlog_worker.filename', '/var/log/ripping-cluster/worker.log', 'string'), +('logging.FlatFile.varlog_worker.format', '%timestamp% %hostname%:%pid% %progname%:%file%[%line%] %message%', 'string'), +('logging.FlatFile.varlog_worker.severity', 'debug\ninfo\nwarning\nerror', 'array(string)'), +('logging.FlatFile.varlog_worker.category', 'worker', 'array(string)'), +('logging.Syslog', 'local0', 'array(string)'), +('logging.Syslog.local0.facility', '128', 'int'), +('logging.Syslog.local0.severity', 'debug\ninfo\nwarning\nerror', 'array(string)'), +('logging.Syslog.local0.category', 'batch\nclient\ndefault\nworker', 'array(string)'), +('logging.Syslog.local0.format', '%file%[%line%] %message%', 'string'), +('templates.tmp_path', '/var/tmp/ripping-cluster', 'string'), +('rips.temp_dir', '/tmp', 'string'), +('job.logs.default_display_count', '30', 'int'), +('job.logs.default_order', 'DESC', 'string'), +('rips.output_directories.default', '', 'hash'), +('rips.output_directories.recent', '', 'array(string)'), +('rips.output_directories.recent_limit', '10', 'int'), +('auth', 'Config', 'string'), +('auth.admin.username', 'admin', 'string'), +('auth.admin_password', '489152af89501a7dc72f6e589123b8c337c01623', 'string'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `worker_log` +-- + +DROP TABLE IF EXISTS `worker_log`; +CREATE TABLE IF NOT EXISTS `worker_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `job_id` int(10) unsigned DEFAULT NULL, + `level` varchar(32) NOT NULL, + `category` varchar(32) NOT NULL, + `ctime` int(11) NOT NULL, + `pid` int(11) NOT NULL, + `hostname` varchar(32) NOT NULL, + `progname` varchar(64) NOT NULL, + `file` text NOT NULL, + `line` int(11) NOT NULL, + `message` text NOT NULL, + PRIMARY KEY (`id`), + KEY `job_id` (`job_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- +-- Constraints for dumped tables +-- + +-- +-- Constraints for table `client_log` +-- +ALTER TABLE `client_log` + ADD CONSTRAINT `client_log_ibfk_1` FOREIGN KEY (`job_id`) REFERENCES `jobs` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- +-- Constraints for table `job_status` +-- +ALTER TABLE `job_status` + ADD CONSTRAINT `job_status_ibfk_1` FOREIGN KEY (`job_id`) REFERENCES `jobs` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/externals/sihnon-js-lib b/externals/sihnon-js-lib new file mode 160000 index 0000000..0499e7e --- /dev/null +++ b/externals/sihnon-js-lib @@ -0,0 +1 @@ +Subproject commit 0499e7ecaa888d72c624ccec2a84c0a55b505d7c diff --git a/htaccess.dist b/private/htaccess.dist similarity index 100% rename from htaccess.dist rename to private/htaccess.dist diff --git a/webui/_inc.php b/public/_inc.php similarity index 100% rename from webui/_inc.php rename to public/_inc.php diff --git a/webui/a.php b/public/a.php similarity index 100% rename from webui/a.php rename to public/a.php diff --git a/webui/images/caution.png b/public/images/caution.png similarity index 100% rename from webui/images/caution.png rename to public/images/caution.png diff --git a/webui/images/clock.png b/public/images/clock.png similarity index 100% rename from webui/images/clock.png rename to public/images/clock.png diff --git a/webui/images/jquery.progressbar/progressbar.gif b/public/images/jquery.progressbar/progressbar.gif similarity index 100% rename from webui/images/jquery.progressbar/progressbar.gif rename to public/images/jquery.progressbar/progressbar.gif diff --git a/webui/images/jquery.progressbar/progressbg_black.gif b/public/images/jquery.progressbar/progressbg_black.gif similarity index 100% rename from webui/images/jquery.progressbar/progressbg_black.gif rename to public/images/jquery.progressbar/progressbg_black.gif diff --git a/webui/images/jquery.progressbar/progressbg_green.gif b/public/images/jquery.progressbar/progressbg_green.gif similarity index 100% rename from webui/images/jquery.progressbar/progressbg_green.gif rename to public/images/jquery.progressbar/progressbg_green.gif diff --git a/webui/images/jquery.progressbar/progressbg_orange.gif b/public/images/jquery.progressbar/progressbg_orange.gif similarity index 100% rename from webui/images/jquery.progressbar/progressbg_orange.gif rename to public/images/jquery.progressbar/progressbg_orange.gif diff --git a/webui/images/jquery.progressbar/progressbg_red.gif b/public/images/jquery.progressbar/progressbg_red.gif similarity index 100% rename from webui/images/jquery.progressbar/progressbg_red.gif rename to public/images/jquery.progressbar/progressbg_red.gif diff --git a/webui/images/jquery.progressbar/progressbg_yellow.gif b/public/images/jquery.progressbar/progressbg_yellow.gif similarity index 100% rename from webui/images/jquery.progressbar/progressbg_yellow.gif rename to public/images/jquery.progressbar/progressbg_yellow.gif diff --git a/webui/images/redo.png b/public/images/redo.png similarity index 100% rename from webui/images/redo.png rename to public/images/redo.png diff --git a/webui/images/trash.png b/public/images/trash.png similarity index 100% rename from webui/images/trash.png rename to public/images/trash.png diff --git a/webui/index.php b/public/index.php similarity index 100% rename from webui/index.php rename to public/index.php diff --git a/public/scripts/3rdparty/bootstrap-alerts.js b/public/scripts/3rdparty/bootstrap-alerts.js new file mode 100644 index 0000000..37bb430 --- /dev/null +++ b/public/scripts/3rdparty/bootstrap-alerts.js @@ -0,0 +1,113 @@ +/* ========================================================== + * bootstrap-alerts.js v1.4.0 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2011 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* CSS TRANSITION SUPPORT (https://gist.github.com/373874) + * ======================================================= */ + + var transitionEnd + + $(document).ready(function () { + + $.support.transition = (function () { + var thisBody = document.body || document.documentElement + , thisStyle = thisBody.style + , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined + return support + })() + + // set CSS transition event type + if ( $.support.transition ) { + transitionEnd = "TransitionEnd" + if ( $.browser.webkit ) { + transitionEnd = "webkitTransitionEnd" + } else if ( $.browser.mozilla ) { + transitionEnd = "transitionend" + } else if ( $.browser.opera ) { + transitionEnd = "oTransitionEnd" + } + } + + }) + + /* ALERT CLASS DEFINITION + * ====================== */ + + var Alert = function ( content, options ) { + this.settings = $.extend({}, $.fn.alert.defaults, options) + this.$element = $(content) + .delegate(this.settings.selector, 'click', this.close) + } + + Alert.prototype = { + + close: function (e) { + var $element = $(this).parent('.alert-message') + + e && e.preventDefault() + $element.removeClass('in') + + function removeElement () { + $element.remove() + } + + $.support.transition && $element.hasClass('fade') ? + $element.bind(transitionEnd, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( options ) { + + if ( options === true ) { + return this.data('alert') + } + + return this.each(function () { + var $this = $(this) + + if ( typeof options == 'string' ) { + return $this.data('alert')[options]() + } + + $(this).data('alert', new Alert( this, options )) + + }) + } + + $.fn.alert.defaults = { + selector: '.close' + } + + $(document).ready(function () { + new Alert($('body'), { + selector: '.alert-message[data-alert] .close' + }) + }) + +}( window.jQuery || window.ender ); \ No newline at end of file diff --git a/public/scripts/3rdparty/bootstrap-dropdown.js b/public/scripts/3rdparty/bootstrap-dropdown.js new file mode 100644 index 0000000..cab0ec2 --- /dev/null +++ b/public/scripts/3rdparty/bootstrap-dropdown.js @@ -0,0 +1,55 @@ +/* ============================================================ + * bootstrap-dropdown.js v1.4.0 + * http://twitter.github.com/bootstrap/javascript.html#dropdown + * ============================================================ + * Copyright 2011 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function( $ ){ + + "use strict" + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function ( selector ) { + return this.each(function () { + $(this).delegate(selector || d, 'click', function (e) { + var li = $(this).parent('li') + , isActive = li.hasClass('open') + + clearMenus() + !isActive && li.toggleClass('open') + return false + }) + }) + } + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + var d = 'a.menu, .dropdown-toggle' + + function clearMenus() { + $(d).parent('li').removeClass('open') + } + + $(function () { + $('html').bind("click", clearMenus) + $('body').dropdown( '[data-dropdown] a.menu, [data-dropdown] .dropdown-toggle' ) + }) + +}( window.jQuery || window.ender ); \ No newline at end of file diff --git a/public/scripts/3rdparty/bootstrap-modal.js b/public/scripts/3rdparty/bootstrap-modal.js new file mode 100644 index 0000000..be2315a --- /dev/null +++ b/public/scripts/3rdparty/bootstrap-modal.js @@ -0,0 +1,260 @@ +/* ========================================================= + * bootstrap-modal.js v1.4.0 + * http://twitter.github.com/bootstrap/javascript.html#modal + * ========================================================= + * Copyright 2011 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function( $ ){ + + "use strict" + + /* CSS TRANSITION SUPPORT (https://gist.github.com/373874) + * ======================================================= */ + + var transitionEnd + + $(document).ready(function () { + + $.support.transition = (function () { + var thisBody = document.body || document.documentElement + , thisStyle = thisBody.style + , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined + return support + })() + + // set CSS transition event type + if ( $.support.transition ) { + transitionEnd = "TransitionEnd" + if ( $.browser.webkit ) { + transitionEnd = "webkitTransitionEnd" + } else if ( $.browser.mozilla ) { + transitionEnd = "transitionend" + } else if ( $.browser.opera ) { + transitionEnd = "oTransitionEnd" + } + } + + }) + + + /* MODAL PUBLIC CLASS DEFINITION + * ============================= */ + + var Modal = function ( content, options ) { + this.settings = $.extend({}, $.fn.modal.defaults, options) + this.$element = $(content) + .delegate('.close', 'click.modal', $.proxy(this.hide, this)) + + if ( this.settings.show ) { + this.show() + } + + return this + } + + Modal.prototype = { + + toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + this.isShown = true + this.$element.trigger('show') + + escape.call(this) + backdrop.call(this, function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + that.$element + .appendTo(document.body) + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + transition ? + that.$element.one(transitionEnd, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + + return this + } + + , hide: function (e) { + e && e.preventDefault() + + if ( !this.isShown ) { + return this + } + + var that = this + this.isShown = false + + escape.call(this) + + this.$element + .trigger('hide') + .removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + hideWithTransition.call(this) : + hideModal.call(this) + + return this + } + + } + + + /* MODAL PRIVATE METHODS + * ===================== */ + + function hideWithTransition() { + // firefox drops transitionEnd events :{o + var that = this + , timeout = setTimeout(function () { + that.$element.unbind(transitionEnd) + hideModal.call(that) + }, 500) + + this.$element.one(transitionEnd, function () { + clearTimeout(timeout) + hideModal.call(that) + }) + } + + function hideModal (that) { + this.$element + .hide() + .trigger('hidden') + + backdrop.call(this) + } + + function backdrop ( callback ) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + if ( this.isShown && this.settings.backdrop ) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $('