From e886fb3d5974934c322990de9ab370d498c5e0c3 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sun, 25 Sep 2022 17:20:20 -0400 Subject: [PATCH] Version 1.0 Web interface only. Will add other files later. Just want a restore point for now. --- www/index.php | 1311 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1311 insertions(+) create mode 100755 www/index.php diff --git a/www/index.php b/www/index.php new file mode 100755 index 0000000..ca6febb --- /dev/null +++ b/www/index.php @@ -0,0 +1,1311 @@ + /dev/null#m", + "$interval * * * * $root/../bin/refresh_youtube.pl &2> /dev/null", $crontab); + } else { + $crontab .= "$interval * * * * $root/../bin/refresh_youtube.pl &2> /dev/null\n"; + } + file_put_contents("$root/.crontab.tmp", $crontab); + error(shell_exec(escapeshellcmd("/usr/bin/crontab $root/.crontab.tmp"))); + error(shell_exec(escapeshellcmd("/bin/rm $root/.crontab.tmp"))); +} + +# Refresh feeds +function refresh() +{ + global $root; + return shell_exec(escapeshellcmd("$root/../bin/refresh_youtube.pl")); +} + +# Fix quotes for SQL input +# Convert ip4 to a long int for comparison in permissions +function ip4_2_long($ip) +{ + $ips = preg_split('/\./',$ip); + return($ips[3] | $ips[2] << 8 | $ips[1] << 16 | $ips[0] << 24); +} + +# Convert ip6 to a long int for comparison in permissions +function ip6_2_long($ip) +{ + if (!function_exists('gmp_init') && !function_exists('bcadd')) { + error('

403: Permission Denied

+

Requires either GMP or BCMATH extension

'); + } + $ip_n = inet_pton($ip); + $bin = ''; + for ($bit = strlen($ip_n) - 1; $bit >= 0; $bit--) { + $bin = sprintf('%08b', ord($ip_n[$bit])) . $bin; + } + + if (function_exists('gmp_init')) { + return gmp_strval(gmp_init($bin, 2), 10); + } elseif (function_exists('bcadd')) { + $dec = '0'; + for ($i = 0; $i < strlen($bin); $i++) { + $dec = bcmul($dec, '2', 0); + $dec = bcadd($dec, $bin[$i], 0); + } + return $dec; + } else { + exit(); + trigger_error('GMP or BCMATH extension not installed!', E_USER_ERROR); + } +} + +# Check if given IP is in a ip4 CIDR range +function in_range4($allowed,$cidr,$ip) +{ + if ( ( ( ip4_2_long($ip) >= ip4_2_long($allowed) ) && ( ip4_2_long($ip) <= (ip4_2_long($allowed)+2**(32-$cidr)) ) ) || ($ip == $_SERVER['SERVER_ADDR'])) { + return 1; + } else { + return 0; + } +} + +# Check if write is outside of read range +function write_outside_read4($read4ip,$read4cidr,$write4ip,$write4cidr) { + $readtop = ip4_2_long($read4ip)+2**(32-$read4cidr); + $writetop = ip4_2_long($write4ip)+2**(32-$write4cidr); + if (!in_range4($read4ip,$read4cidr,$write4ip) || ($writetop > $readtop)) { + error("

write range ($write4ip/$write4cidr) must be contained within read range ($read4ip/$read4cidr)

"); + return 1; + } + return 0; +} + +# Check if given IP is in a ip6 CIDR range +function in_range6($allowed,$cidr,$ip) +{ + if ( ( ( ip6_2_long($ip) >= ip6_2_long($allowed) ) && ( ip6_2_long($ip) <= (ip6_2_long($allowed)+2**(32-$cidr)) ) ) || ($ip == $_SERVER['SERVER_ADDR'])) { + return 1; + } else { + return 0; + } +} + +# Strip argument key and value from current target URL and return valid updated URL +function remove_arg($target,$arg) +{ + global $debug_text; + if (preg_match("/\?$arg/",$target)) { + # First argument, leave ? and remove trailing & if it exists + $target = preg_replace("/$arg=[^&]*&?/",'',$target); + if (preg_match("/\?$/",$target)) { + $target = rtrim($target,"?"); + } + } else { + # Secondary argument, remove leading & + $target = preg_replace("/&$arg=[^&]*/",'',$target); + } + $debug_text .= "

Just removed $arg

Target is now: $target

"; + return $target; +} + +# Return whether the client IP is ip4 or ip6 +function ip_version($ip) +{ + if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { + return 4; + } elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + return 6; + } else { + return 0; + } +} + +# Return read and write permissions given client IP and preferences +function get_permissions($settings) +{ + $permissions = array(); + if ($settings['ipv'] == 4) { + $permissions['rip'] = preg_replace("/([\d\.]+)\/\d+/","$1",$settings['read4']); + $permissions['wip'] = preg_replace("/([\d\.]+)\/\d+/","$1",$settings['write4']); + $permissions['rcidr'] = preg_replace("/[\d\.]+\/(\d+)/","$1",$settings['read4']); + $permissions['wcidr'] = preg_replace("/[\d\.]+\/(\d+)/","$1",$settings['write4']); + if ($settings['enable4']) { + $permissions['readable'] = in_range4($permissions['rip'],$permissions['rcidr'],$_SERVER['REMOTE_ADDR']); + $permissions['writable'] = in_range4($permissions['wip'],$permissions['wcidr'],$_SERVER['REMOTE_ADDR']); + } else { + $permissions['readable'] = 0; + $permissions['writable'] = 0; + } + } else { + $permissions['rip'] = preg_replace("/([\d:]+)\/\d+/","$1",$settings['read6']); + $permissions['wip'] = preg_replace("/([\d:]+)\/\d+/","$1",$settings['write6']); + $permissions['rcidr'] = preg_replace("/[\d:]+\/(\d+)/","$1",$settings['read6']); + $permissions['wcidr'] = preg_replace("/[\d:]+\/(\d+)/","$1",$settings['write6']); + if ($settings['enable6']) { + $permissions['readable'] = 1; + //$permissions['readable'] = in_range6($permissions['rip'],$permissions['rcidr'],$_SERVER['REMOTE_ADDR']); + $permissions['writable'] = 0; + //$permissions['writable'] = in_range6($permissions['wip'],$permissions['wcidr'],$_SERVER['REMOTE_ADDR']); + } else { + $permissions['readable'] = 0; + $permissions['writable'] = 0; + } + } + return $permissions; +} + +# Print one row given the video details +function print_video($video,$settings,$mobile) +{ + $html = ' +
+
'; + if ($settings['player'] == 'embed') { + if (isset($settings['embed_type']) && $settings['embed_type'] == 'nocookie') { + $default .= ' + '; + } elseif (isset($settings['embed_type']) && $settings['embed_type'] == 'proxy') { + $default .= ' + '; + } else { + $default .= ' + '; + } + } elseif ($settings['player'] == 'clip') { + $default .= ' + '; + } else { + $default .= ' + '; + } + $html .= " + $default" . ' +
+ +
+

' . $video['lengthText'] . '

+
+
'; + if ($mobile) { + $html .= ' +
+
+
'; + if ($settings['embed_type'] == 'proxy') { + $html .= ' +
'; + } elseif ($settings['embed_type'] == 'nocookie') { + $html .= ' +
'; + } else { + $html .= ' +
'; + } + $html .= ' +
+
+ +
+ +

X

+
+
+
+
+ ' . $default .' +
+ +

' . $video['title'] . '

+

' . $video['shortViewCountText'] . '

+

' . $video['publishedTimeText'] . '

+
+ +
+
+
'; + } else { + $html .= ' +
+ +

' . $video['title'] . '

+

' . $video['shortViewCountText'] . '

+

' . $video['publishedTimeText'] . '

+
+ + +
'; + if ($settings['embed_type'] == 'proxy') { + $html .= ' +
'; + } elseif ($settings['embed_type'] == 'nocookie') { + $html .= ' +
'; + } else { + $html .= ' +
'; + } + $html .= ' +
+
+
+ +

X

+ '; + } + return $html; +} + +# Add a new subscription. +function add_channel($chan) +{ + global $root; + return shell_exec(escapeshellcmd("$root/../bin/add_youtube_subscription.pl $chan")); +} + +# Fix quotes for SQL input +function sql_escape($text) +{ + return preg_replace("/'/","''",$text); +} + +# Open database and fetch all settings +$no_db = 1; +if (!file_exists($database)) { + $permissions = array("readable"=>"1","writable"=>"1"); +} else { + $no_db = 0; + $handle = new SQLite3($database); + $settings_row = $handle->query('SELECT * FROM settings'); + $settings = $settings_row->fetchArray(); +} + +# If default player is 'embed' we need to select the right 'embed_type' +if (isset($settings['player']) && $settings['player'] == 'embed' && isset($settings['embed_type'])) { + $settings['player'] == $settings['embed_type']; +} + +# Fetch client IP version, then check permissions for that IP +if (!isset($permissions)) { + $settings['ipv'] = ip_version($_SERVER['REMOTE_ADDR']); + if (isset($settings['ipv'])) { + $permissions = get_permissions($settings); + # Reject connection if PHP does not support ip6 + } elseif (!defined('AF_INET6')) { + error('

403: Permission Denied

+

PHP does not support IPv6 and your address is: ' . $_SERVER['REMOTE_ADDR'] . '

'); + # Reject connection if not a valid ip4 or ip6 address (what else is it?) + } else { + error('

403: Permission Denied

+

Invalid remote IP address: ' . $_SERVER['REMOTE_ADDR'] . '

'); + } +} + +# Reject connection if not readable +if (!$permissions['readable']) { + error('

403: Permission Denied

+

You do not have readable access to this page

'); + if ($settings['ipv'] == 4) { + if ($settings['enable4']) { + error('

Your IP (' . $_SERVER['REMOTE_ADDR'] . ') falls outside of readable range (' . $settings['read4'] . ')

'); + } else { + error('

IPv4 Interface is disabled

'); + } + } else { + if ($settings['enable6']) { + error('

Your IP (' . $_SERVER['REMOTE_ADDR'] . ') falls outside of readable range (' . $settings['read6'] . ')

'); + } else { + error('

IPv6 Interface is disabled

'); + } + } +} + +# Collect URL arguments +$target = $_SERVER['REQUEST_URI']; +$args = array(); +parse_str($_SERVER['QUERY_STRING'], $args); + +# Some arguments will require the page to be reloaded after processing. +# They will set this flag which will be checked after all arguements are done. +$reload = 0; + +## STARTREAD: Read options included prior to the ENDREAD line + +if (isset($args['mobile'])) { + if ($args['mobile'] != '' && $args['mobile'] != '0') { + $mobile = 1; + } else { + $mobile = 0; + } + $target = remove_arg($target,'mobile'); + unset($args['mobile']); +} + +# Retrieve passed error message +if (isset($args['msg'])) { + if ($args['msg'] != '') { + error(urldecode($args['msg'])); + } + $target = remove_arg($target,'msg'); + unset($args['msg']); +} + +# Add parameters to SQL query to restrict by search results +if (isset($args['search'])) { + if (isset($args['search_clear']) || $args['search'] == '') { + unset($args['search_clear']); + $target = remove_arg($target,'search_clear'); + $target = remove_arg($target,'search'); + } else { + $search = urldecode($args['search']); + # If search is quoted with '/', treat it as a regex + if (preg_match('#^/.*/$#',$search)) { + $sql_search = preg_replace('#^/(.*)/$#', '$1', $search); + $regex_search = $handle->loadExtension('pcre.so'); + if ($regex_search) { + $sql_search = " videos.title REGEXP '" . $sql_search . "'"; + } else { + # emulate regex if module is unavailable + $new_search = ''; + if (preg_match('/^\^/', $sql_search)) { + $start = preg_replace('/^\^([^\.]*).*/','$1',$sql_search); + $sql_search = preg_replace('/^\^[^\.]*(.*)$/','$1',$sql_search); + $new_search .= " AND videos.title LIKE '" . $start . "%'"; + } + if (preg_match('/\$$/', $sql_search)) { + $tail = preg_replace('/^.*?([^\*]*)\$$/','$1',$sql_search); + $sql_search = preg_replace('/^(.*?)[^\*]*\$$/','$1',$sql_search); + $new_search .= " AND videos.title LIKE '%" . $tail . "'"; + } + $sql_search = preg_replace('/(\.\*)?(.*)(\.\*)?/','$2',$sql_search); + $searches = preg_split('/\.\*/', $sql_search); + foreach ($searches as $s) { + if ($s != '') { + $new_search .= " AND videos.title LIKE '%" . $s . "%'"; + } + } + $sql_search = preg_replace('/ AND(.*)/', '$1', $new_search); + error("You do not have the pcre.so extension for SQLite3."); + if ($permissions['writable']) { + error("

You will need to add the path to your extensions directory with an argument in your php.ini file like:

sqlite3.extension_dir = \"/usr/lib/sqlite3/\"

"); + } + error ("

Simulating basic wildcard (.*) and anchor (^$) expression:

$sql_search

"); + } + } else { + $sql_search = " videos.title LIKE '%" . sql_escape($search) . "%'"; + } + } + unset($args['search']); + $target = remove_arg($target,'search'); +} + +# Set flag to not hide videos marked as seen from SQL query results +if (isset($args['show_seen'])) { + $show_seen = $args['show_seen']; + unset($args['show_seen']); + $target = remove_arg($target,'show_seen'); +} + +# Remove previous filter arguments to revert to regular query results +if (isset($args['filter_clear'])) { + unset($args['filter_clear']); + $target = remove_arg($target,'filter_clear'); + unset($args['filter']); + $target = remove_arg($target,'filter'); + unset($args['filter[]']); + $target = remove_arg($target,urlencode('filter[]')); +} + +# Add claus(es) to SQL query to limit by channel or category +if (isset($args['filter'])) { + $categories = array(); + if (!is_array($args['filter'])) { + if (preg_match('/^UC[0-9a-zA-Z\_\-]{22}$/', $args['filter'])) { + $chan_filter = $args['filter']; + } elseif ($args['filter'] != '-') { + $categories[0] = $args['filter']; + } + $target = remove_arg($target,'filter'); + $target = remove_arg($target,urlencode('filter[]')); + } else { + foreach ($args['filter'] as $filter) { + $categories[] = urldecode($filter); + $target = remove_arg($target,urlencode('filter[]')); + } + $target = remove_arg($target,'filter'); + } + unset($args['filter']); + unset($args['filter[]']); +} + +## ENDREAD + +# If there are remaining arguments, ensure that the client has write permissions +if ($permissions['writable']) { + if (sizeof($args) > 0) { + $reload = 1; + } +} elseif ($permissions['readable']) { + if (sizeof($args) > 0) { + $reload = 1; + error("

You are allowed to read but not write. However, a write argument was passed.

"); + unset($args); + $target = preg_replace('/^([^\?]*)\?.*/','$1',$_SERVER['REQUEST_URI']); + } +} else { + error('
' . $debug_text . '
'); + return http_response_code(403); +} + +## IMPORTANT: Write operations to be included after this point only. + +# Initialize database +if ($no_db && isset($args['initialize'])) { + $debug_text .= "

Initializing database...

"; + $debug_text .= "

" . initialize() . "

"; + $reload = 1; + $target = remove_arg($target,'initialize'); + $handle = new SQLite3($database); + $no_db = 0; + $args['refresh'] = 15; +} + +# Delete database +if (isset($args['delete_db'])) { + $debug_text .= "

Deleting database

"; + $err = delete_db(); + if ($err) { + error("

Failed to delete db: $err

"); + } else { + $debug_text .= "

Database deleted

"; + } +} + +# Handle all change requests. +if ( !$no_db && $reload && $permissions['writable'] ) { + + # Force feeds to refresh + if (isset($args['force_refresh']) && $args['force_refresh'] == 1) { + $debug_text .= "

Refreshing feeds...

"; + # Must free database in order to insert + $handle->close(); + $debug_text .= "

" . refresh() . "

"; + $handle = new SQLite3($database); + $target = remove_arg($target,'force_refresh'); + $reload = 1; + } + + # Mark one or all videos as played. + if (isset($args['rm'])) { + if (preg_match("/^([^']{11})$/",urldecode($args['rm']))) { + $debug_text .= "

Removing " . urldecode($args['rm']) . "

"; + $rm = sql_escape(urldecode($args['rm'])); + $handle->query("UPDATE videos SET seen = 1 WHERE videoId = '$rm'"); + } elseif (urldecode($args['rm']) == '*') { + $debug_text .= "

Removing All

"; + $handle->query("UPDATE videos SET seen = 1 WHERE seen = 0"); + } + $target = remove_arg($target,'rm'); + } + + # Update the refresh interval + if (isset($args['refresh'])) { + $interval = urldecode($args['refresh']); + if (preg_match('/^[0-9]+$/',$interval) && $interval <= 60) { + $handle->query("UPDATE settings SET refresh = '$interval'"); + update_cron($interval); + $debug_text .= "

Set update interval to $interval

"; + } else { + error("

Update interval must be an integer lower than or equal to 60, $interval is not

"); + } + $target = remove_arg($target,'refresh'); + } + + # Update the default player + if (isset($args['player'])) { + if (preg_match("/^(clip|embed|web)$/",urldecode($args['player']))) { + $player = sql_escape(urldecode($args['player'])); + $handle->query("UPDATE settings SET player = '$player'"); + $debug_text .= "

Set player $player

"; + } else { + error("

" . $args['player'] . " is not a valid player option

"); + } + $target = remove_arg($target,'player'); + } + + # Update the embedded player type + if (isset($args['embed_type'])) { + if (preg_match("/^(embed|nocookie|proxy)$/",urldecode($args['embed_type']))) { + $embed_type = sql_escape(urldecode($args['embed_type'])); + $handle->query("UPDATE settings SET embed_type = '$embed_type'"); + $debug_text .= "

Set embed_type $embed_type

"; + } else { + error("

" . $args['embed_type'] . " is not a valid embed_type option

"); + } + $target = remove_arg($target,'embed_type'); + } + + # Update the theme + if (isset($args['theme'])) { + $found = 0; + $theme = urldecode($args['theme']); + foreach (glob($root.'/css/*.css') as $file) { + $file = preg_replace('/.*\/([^\/]*)\.css$/','\1',$file); + if ($args['theme'] == $file && $file != 'style') { + $handle->query("UPDATE settings SET theme = '" . sql_escape($theme) . "'"); + $debug_text .= "

Set theme $theme

"; + $found = 1; + } + } + if (!$found) { + error("

" . $theme . " is not a valid theme option

"); + } + $target = remove_arg($target,'theme'); + } + + # Subscribe to a new channel + if (isset($args['sub'])) { + $debug_text .= "

Adding " . urldecode($args['sub']) . "...

"; + # Must free database in order to insert + $handle->close(); + $debug_text .= "

" . add_channel(urldecode($args['sub'])) . "

"; + $handle = new SQLite3($database); + $reload = 1; + $target = remove_arg($target,'sub'); + } + + # Unsubscribe and remove channel's videos. + if (isset($args['unsub'])) { + $unsub = sql_escape(urldecode($args['unsub'])); + $channels = $handle->query("SELECT * FROM channels WHERE channelId = '$unsub'"); + $chan = $channels->fetchArray(); + $debug_text .= "

Removing " . $chan['channelName'] . "

"; + $handle->query("DELETE FROM channels WHERE channelId = '$unsub'"); + $handle->query("DELETE FROM videos WHERE channelId = '$unsub'"); + $target = remove_arg($target,'unsub'); + } + + # Update IPv4 writeable range + if (isset($args['write4'])) { + $write4ip = preg_replace("/([\d\.]+)\/\d+/","$1",urldecode($args['write4'])); + $write4cidr = preg_replace("/[\d\.]+\/(\d+)/","$1",urldecode($args['write4'])); + if (isset($args['read4'])) { + $read4ip = preg_replace("/([\d\.]+)\/\d+/","$1",urldecode($args['read4'])); + $read4cidr = preg_replace("/[\d\.]+\/(\d+)/","$1",urldecode($args['read4'])); + } else { + $read4ip = preg_replace("/([\d\.]+)\/\d+/","$1",$settings['read4']); + $read4cidr = preg_replace("/[\d\.]+\/(\d+)/","$1",$settings['read4']); + } + if ( write_outside_read4($read4ip,$read4cidr,$write4ip,$write4cidr) ) { + error("

Invalid read/write. Write must be completely contained within read.

"); + $target = remove_arg($target,'write4'); + $target = remove_arg($target,'read4'); + unset($args['read4']); + } elseif ( in_range4($write4ip,$write4cidr,$_SERVER['REMOTE_ADDR']) ) { + $handle->query("UPDATE settings SET write4 = '$write4ip/$write4cidr'"); + $debug_text .= "

Updated writable IPv4 to $write4ip/$write4cidr

"; + $target = remove_arg($target,'write4'); + } else { + error("

You are not allowed to remove write access from yourself. " . $_SERVER['REMOTE_ADDR'] . " is not in range $write4ip/$write4cidr

"); + $target = remove_arg($target,'write4'); + } + } + + # Update IPv4 readable range + if (isset($args['read4'])) { + # Update whether IPv4 is enabled + if (isset($args['enable4']) && $args['enable4'] == 'on') { + if (!$settings['enable4']) { + $debug_text .= "

Enabling IPv4

"; + $handle->query("UPDATE settings SET enable4 = 1"); + } + } else { + if ($settings['ipv'] == 4) { + error("

You are currently using the IPv4 interface (Your IP: " . $_SERVER['REMOTE_ADDR'] . "). You cannot remove access from yourself.

"); + } else { + $debug_text .= "

Disabling IPv4

"; + #$handle->query("UPDATE settings SET enable4 = 0"); + } + } + $target = remove_arg($target,'enable4'); + $read4ip = preg_replace("/([\d\.]+)\/\d+/","$1",urldecode($args['read4'])); + $read4cidr = preg_replace("/[\d\.]+\/(\d+)/","$1",urldecode($args['read4'])); + if ( in_range4($read4ip,$read4cidr,$_SERVER['REMOTE_ADDR']) ) { + $handle->query("UPDATE settings SET read4 = '$read4ip/$read4cidr'"); + $debug_text .= "

Updated readable IPv4 to $read4ip/$read4cidr

"; + $target = remove_arg($target,'read4'); + } else { + error("

You are not allowed to remove read access from yourself. " . $_SERVER['REMOTE_ADDR'] . " is not in range $read4ip/$read4cidr

"); + $target = remove_arg($target,'read4'); + } + } + + # Update IPv6 readable range + if (isset($args['read6'])) { + # Update whether IPv6 is enabled + if (isset($args['enable6']) && $args['enable6'] == 'on') { + if (!$settings['enable6']) { + $debug_text .= "

Enabling IPv6

"; + $handle->query("UPDATE settings SET enable6 = 1"); + } + } else { + if ($settings['ipv'] == 6) { + error("

You are currently using the IPv6 interface (Your IP: " . $_SERVER['REMOTE_ADDR'] . "). You cannot remove access from yourself.

"); + } else { + $debug_text .= "

Disabling IPv6

"; + $handle->query("UPDATE settings SET enable6 = 0"); + } + } + $target = remove_arg($target,'enable6'); + $handle->query("UPDATE settings SET read6 = '" . urldecode($args['read6']) . "'"); + $debug_text .= "

Updated readable IPv6 to " . $args['read6'] . "

"; + $target = remove_arg($target,'read6'); + } + if (isset($args['write6'])) { + $handle->query("UPDATE settings SET write6 = '" . urldecode($args['write6']) . "'"); + $debug_text .= "

Updated writable IPv6 to " . $args['write6'] . "

"; + $target = remove_arg($target,'write6'); + } + + # Update the Category for channel + if (isset($args['category'])) { + # URL arg is formatted as 'channelId category,other,third' + $category_array = preg_split('/\ /',urldecode($args['category'])); + foreach ($category_array as $item) { + # First item is the channelId + if (!isset($category_chan)) { + $category_chan = $item; + # All others are categories + } elseif (!isset($category_name)) { + $category_name = $item; + # Restore spaces removed by split + } else { + $category_name .= ' ' . $item; + } + } + $category_chan = sql_escape($category_chan); + $category_name = sql_escape($category_name); + if ($category_name != '') { + $category_name = ','.$category_name.','; + } + $debug_text .= '

Add Category - Channel: ' . $category_chan . ' Category: ' . $category_name . '

'; + $handle->query("UPDATE channels SET category = '$category_name' WHERE channelId = '$category_chan'"); + $debug_text .= '

Category updated

'; + $target = remove_arg($target,'category'); + } + + # Update the Title Filter RegExp for a channel + if (isset($args['regex'])) { + $regex_array = preg_split('/\ /',urldecode($args['regex'])); + foreach ($regex_array as $item) { + if (!isset($regex_chan)) { + $regex_chan = $item; + } elseif (!isset($regex_exp)) { + $regex_exp = $item; + } else { + $regex_exp .= ' ' . $item; + } + } + $regex_chan = sql_escape($regex_chan); + $regex_exp = sql_escape($regex_exp); + $debug_text .= '

Add Regex - Channel: ' . $regex_chan . ' Exp: ' . $regex_exp . '

'; + $handle->query("UPDATE channels SET regex = '$regex_exp' WHERE channelId = '$regex_chan'"); + $debug_text .= '

Regex updated

'; + $target = remove_arg($target,'regex'); + } + + # If there are remaining arguments, they are invalid + if (preg_match("/[^\?]*\?(.*)/",$target)) { + $remaining = preg_replace("/^(.)*\?(.*)$/",'$2',$target); + $debug_text .= "

Remaining: $remaining

"; + $bad_args = preg_split("/\&/",$remaining); + foreach ($bad_args as $arg) { + $value = preg_replace("/[^=]*=([^=]*)/","$1",$arg); + $arg = preg_replace("/([^=]*)=[^=]*/","$1",$arg); + error('

Ignoring invalid argument: ' . urldecode($arg) . ' with value ' . urldecode($value) . '

'); + $target = remove_arg($target,$arg); + } + } +} + +# Clean up target URL given intact arguments +$target = preg_replace('/[\?&]$/', '', $target); + +# Close DB then refresh the page with what should be a clean URL +if ($reload) { + if ($debug && isset($debug_text) && $debug_text != '') { + $debug_text .= '
Load ' . $target . '
'; + $debug_text = '

DEBUG MODE

' . $debug_text . '
'; + } else { + if (isset($handle)) { + $handle->close(); + } + header("Refresh:0; url=$target" . ((isset($error_text) && $error_text != '') ? "?msg=".urlencode($error_text) : '')); + exit(); + } +} + +$head = ' + + + + YouTube Subscriptions + + '; +if ($mobile) { + $head .= ' + '; +} +$head .= ' + '; +if (isset($settings['theme']) && $settings['theme'] != 'default') { + $head .= ' + '; +} +$head .= ' + + + + '; +if (isset($permissions['readable']) && $permissions['readable']) { + + # HEADER + + $header = ' + + +