Back to vBulletin 3.6 Add-ons

vBISpy - AJAX real-time feed of new posts/threads
Mod Version: 1.12, by MPDev

This modification is in the archives.
vB Version: 3.6.x Rating: (75 votes - 4.73 average) Installs: 947
Released: 06 Sep 2006 Last Update: 28 Sep 2006 Downloads: 4415
Not Supported Additional Files  

After seeing the http://www.digg.com/spy application; I wondered if this could be done for vBulletin as well. I came across this http://blablist.crowdiq.com/iqueue/votespy_howto.jsp which had a "how to" on how they built a similiar application to do the same thing. Taking a page from their book (i.e. the code), I modified it for use with vBulletin.

During development, I also came across this post here on vBulletin.Org where the very subject had already been discussed.

So I put this together; a simple ZIP file with a single PHP script, three javascript files and 4 images.

Installation

. UNZIP the file into your forums directory
. That's it!

Virtually all the code to customize the page is in the vaispy.php script; there are no plugins, no templates and no phrases. You do not need to do anything further; this should work right out of the box.

In your browser, open the URL:

http://www.yourforum.com/forum/vaispy.php

You can see examples of this at:

http://www.viperalley.com/forum/vaispy.php
http://www.extremefitness.com/forum/vaispy.php

Note: I claim no ownership of this code except for the file vaispy.php - the rest of the files were using 'freely distributable' sources. As such, you may use these files as you wish, but please do not remove the copyrights.

This modification is for vBulletin 3.6 only, if you are running vBulletin 3.5 you will need to see this thread.

JOIN THE vBIspy Network!
Once you have this mod installed, you can join the http://www.vbispy.com to have your threads appear on this site; the vBIspy Network is a great way for people to see what's going on in various vBulletin communities and for forum owners to promote their sites and generate new traffic.

Optional add-ons

Who's Online mod for this: vBISpy Who's Online resolution plug-in

vBAdvanced Module: vBISpy module - live AJAX feed of new threads - for vBAdvanced CMPS

UPDATES
1.0.4
Added buro9's code from here

Spoiler (click to open)


Another minor thing.

If nothing is returned, you should return the Xml with an empty root node of <events />

This will avoid invalid Xml errors being silently thrown in the JavaScript.

Simply change this in the .php file:
PHP Code:
    if ( $output )
    {
        echo 
"<events>$output</events>";
    } 
to
PHP Code:
    if ( $output )
    {
        echo 
"<events>$output</events>";
    } else {
        echo 
"<events />";
    } 
And because that will now prevent the JavaScript exception, change this in the va_spy.js file:
Code:
	try {
		events = request.responseXML.getElementsByTagName("events")[0];
		event = events.getElementsByTagName("event");
	}
	catch (e) {
		setTimeout("getXML()", 5000);
		return;
	}
to
Code:
	try {
		events = request.responseXML.getElementsByTagName("events")[0];
		event = events.getElementsByTagName("event");
		if (event.length == 0) {
			setTimeout("getXML()", 5000);
			return;
		}
	}
	catch (e) {
		setTimeout("getXML()", 5000);
		return;
	}
We'll actually never use that catch statement now, but no harm in being extra defensive and leaving it in there

Close


1.0.5 - 9.9.06
Modified some JavaScript in va_spy.js to remove split strings

1.0.6 - 9.10.06
Added date cuffoff code from here

Spoiler (click to open)


All the credit goes to TECK ( Floren )

In order to optimize the code Replace
Code:
    $getthreads = $db->query_read("
    	SELECT thread.*, post.pagetext AS preview, post.userid AS lastpuserid
    	FROM ".TABLE_PREFIX."thread AS thread
    	LEFT JOIN ".TABLE_PREFIX."deletionlog AS deletionlog ON(thread.threadid = deletionlog.primaryid AND type = 'thread')
    	LEFT JOIN ".TABLE_PREFIX."post AS post ON(post.postid = thread.lastpostid)
    	WHERE open <> 10 AND thread.lastpostid > $lastpostid
    	AND forumid NOT IN (0$blockforums)
    	AND thread.visible = '1'
    	AND deletionlog.primaryid IS NULL
    	ORDER BY lastpost DESC LIMIT 10");
with
Code:
	// The number of days to scan the table for ...
	// 86400 represents the number of seconds in 24hrs
	$daysprune = 1;
	$datecut = "AND thread.lastpost >= " . (TIMENOW - ($daysprune * 86400));
	$getthreads = $db->query_read("
		SELECT thread.*, post.pagetext AS preview, post.userid AS lastpuserid
		FROM " . TABLE_PREFIX . "thread AS thread
		LEFT JOIN " . TABLE_PREFIX . "deletionlog AS deletionlog ON (thread.threadid = deletionlog.primaryid AND type = 'thread')
		LEFT JOIN " . TABLE_PREFIX . "post AS post ON (post.postid = thread.lastpostid)
		WHERE open <> 10 AND thread.lastpostid > $lastpostid
			AND forumid NOT IN (0$blockforums)
			AND thread.visible = '1'
			AND deletionlog.primaryid IS NULL
			$datecut
		ORDER BY thread.lastpost DESC LIMIT 10
	");

Close
and changed init() to spyinit() - changed vaispy.php and va_spy.js files.

1.0.7 - 9.12.06
va_spy.js: Added a forum url variable to allow for integration with portals or other products outside the forum directory
va_spy.js: Added xmldelay variable at top of script for easier configuration or repolling
Updated files: vaispy.php, vb_spy.js

1.0.8 - 9.13.06
vaispy.php - changed code for checking for forum permissions to include password protected forums, added javascript tag for script code

1.0.9 - 9.16.06
vaispy.php
va_spy.js
va_effects.js
- modified to allow for proper display in Opera browsers and moved more html into vaispy.php to allow for stylevars, trimmed va_effects.js to remove unused code (ForumDog's suggestions

Spoiler (click to open)


Quote by MPDev
The Opera fix would be helpful; as I am sure the others would be. Thanks for sharing.
Yes, ok ok ok. I'm still getting it up to scratch for my own site. But since you'd like to hear now, I'm not done but these are my changes so far, I will include what I already posted that has not yet currently been added for ease of reading.

The default title length as set by vBulletin is actually 85 characters not 80.

In vaispy.php

FIND:
Code:
(unhtmlspecialchars($thread['title']), 80)
REPLACE WITH:
Code:
(unhtmlspecialchars($thread['title']), 85)


I moved the HTML to a vBulletin template, it's easier to separate code from presentation that way and allows use of template caching more flexibility with conditionals and so on so I'll *assume* that's what you'll want to do. It's very easy to do manually as long as this isn't a plugin which for the time being is unnecessary.

FIND:
Code:
// pre-cache templates used by all actions
$globaltemplates = array();
REPLACE WITH:
Code:
// pre-cache templates used by all actions
$globaltemplates = array('vaispy');
Go to AdminCP > Styles & Templates > In the dropdown list for (Your Parent Style) choose 'Add new template' Name it vaispy.

Now we have to tell the page to fetch the template, and we're also going to add a couple of lines to keep the vBulletin breadcrumb going.

In vaispy.php

FIND:
Code:
eval('$navbar = "' . fetch_template('navbar') . '";');
$headinclude = process_replacement_vars($headinclude);
$navbar = process_replacement_vars($navbar);
eval('$footer = "' . fetch_template('footer') . '";');
$footer = process_replacement_vars($footer);

REPLACE WITH:
Code:
$navbits = array(); 
$navbits[$parent] = 'vaispy';
$navbits = construct_navbits($navbits);
eval('$navbar = "' . fetch_template('navbar') . '";');
$navbar = process_replacement_vars($navbar);
eval('$headinclude = "' . fetch_template('headinclude') . '";');
$headinclude = process_replacement_vars($headinclude);
eval('$footer = "' . fetch_template('footer') . '";');
$footer = process_replacement_vars($footer);
eval('print_output("' . fetch_template('vaispy') . '");');


Looking good! Now let's just transfer it over to the template.

REMOVE:
Code:
echo<<<VAPRINT
AND REMOVE:
Code:
VAPRINT;
?>
Then CUT everything that was between those two tags and PASTE it into your new template. Save the template so you don't lose it before the following template improvements.

This will allow Microstats to show up in the footer and whitespace strippers, template caches etc, makes the code valid too.

In template vaispy:

FIND:
Code:
$footer
ADD BELOW:
Code:
</body>
</html>


Because we're now in a template there's no reason not to use style-specific directories to allow people with multiple themes not to be forced to create a new top-level directory for the buttons. You must ensure your buttons are copied to each misc directory for every style you have installed. Also added is code to ensure the mouse changes to the hand icon over a button to show it is a clickable link, plus compatibility commenting for inline javascript code.

In va_spy.js

REMOVE

Code:
function pauseSpy() {
	var playimg = document.getElementById("vaplay");
	var pauseimg = document.getElementById("vapause");
	playimg.src = "images/misc/play_up.gif";
	playimg.alt = "Click to Play";
	pauseimg.src = "images/misc/pause_down.gif";
	pauseimg.alt = "Paused...";
	pause();
}
function playSpy() {
	var playimg = document.getElementById("vaplay");
	var pauseimg = document.getElementById("vapause");
	playimg.src = "images/misc/play_down.gif";
	playimg.alt = "Playing...";
	pauseimg.src = "images/misc/pause_up.gif";
	pauseimg.alt = "Click to Pause";
	resume();
}
function pause() {
	play = 0;
}
function resume() {
	play = 1;
}


In vaispy.php

FIND:

Code:
<script language="javascript" type="text/javascript">
<!--
    spymax = 25;
// -->
</script>
ADD BELOW:
Code:
<script language="javascript" type="text/javascript">
<!--
function pauseSpy() {
	var playimg = document.getElementById("vaplay");
	var pauseimg = document.getElementById("vapause");
	playimg.src = "$stylevar[imgdir_misc]/play_up.gif";
	playimg.alt = "Click to Play";
	pauseimg.src = "$stylevar[imgdir_misc]/pause_down.gif";
	pauseimg.alt = "Paused...";
	pause();
}
function playSpy() {
	var playimg = document.getElementById("vaplay");
	var pauseimg = document.getElementById("vapause");
	playimg.src = "$stylevar[imgdir_misc]/play_down.gif";
	playimg.alt = "Playing...";
	pauseimg.src = "$stylevar[imgdir_misc]/pause_up.gif";
	pauseimg.alt = "Click to Pause";
	resume();
}
function pause() {
	play = 0;
}
function resume() {
	play = 1;
}
// -->
</script>
FIND

Code:
<img id="vaplay" src="images/misc/play_up.gif" alt="Play" title="Play Comments" onclick="playSpy();" /> &nbsp;
<img id="vapause" src="images/misc/pause_up.gif" alt="Pause" title="Pause Comments" onclick="pauseSpy();" />
REPLACE WITH:
Code:
<img id="vaplay" src="$stylevar[imgdir_misc]/play_down.gif" style="cursor:pointer;" alt="Play" title="Play Comments" onclick="playSpy();" /> &nbsp;
<img id="vapause" src="$stylevar[imgdir_misc]/pause_up.gif" style="cursor:pointer;" alt="Pause" title="Pause Comments" onclick="pauseSpy();" />


Now we're going to make the opacity code which creates the nice fading effect work across all browsers instead of currently very few. I am currently pulling images into the post/thread Spy, so if you/the author decides to do this the fade effect is also already there for them too.

FIND:
Code:
opacity:.XX
(This will be in the last 5 rows of however many rows you chose to have)

REPLACE WITH:
Code:
class="spyfadeX"
(Replace the X with 1-5 for the last 5 rows, in correct numeric order)

FIND:
Code:
$headinclude
ADD AFTER:
Code:
<style type="text/css">
.spyfade1 div, .spyfade1 span,, .spyfade1 td, .spyfade1 img {
opacity:0.90;
filter:alpha(opacity=90);
-moz-opacity:0.90;
}
.spyfade2 div, .spyfade2 span, .spyfade2 td, .spyfade2 img {
opacity:0.80;
filter:alpha(opacity=80);
-moz-opacity:0.80;
}
.spyfade3 div, .spyfade3 span, .spyfade3 td, .spyfade3 img {
opacity:0.70;
filter:alpha(opacity=70);
-moz-opacity:0.70;
}
.spyfade4 div, .spyfade4 span, .spyfade4 td, .spyfade4 img {
opacity:0.50;
filter:alpha(opacity=50);
-moz-opacity:0.50;
}
.spyfade5 div, .spyfade5 span, .spyfade5 td, .spyfade5 img {
opacity:0.30;
filter:alpha(opacity=30);
-moz-opacity:0.30;
}
</style>
In va_spy.js
Code:
FIND:
			if (i + 5 > spymax) {
				document.getElementById("spy_table").rows[i].cells[0].className = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')';
				document.getElementById("spy_table").rows[i].cells[1].style.filter = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')';
				document.getElementById("spy_table").rows[i].cells[2].style.filter = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')';
				document.getElementById("spy_table").rows[i].cells[3].style.filter = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')';
			}
REPLACE WITH (or remove entirely):
Code:
			// if (i + 5 > spymax) {
				// document.getElementById("spy_table").rows[i].cells[0].className = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')';
				// document.getElementById("spy_table").rows[i].cells[1].style.filter = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')';
				// document.getElementById("spy_table").rows[i].cells[2].style.filter = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')';
				// document.getElementById("spy_table").rows[i].cells[3].style.filter = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')';
			// }


The reason Opera is failing to render properly is because it does not download elements with {display:none;}, unlike other browsers which download them but don't show them. This is actually quite a bandwidth saver at times and usually A Good Thing, but here it is causing problems because the table cells which the javascript is throwing out have no table row structure due to them having the attribute {display:none;}, so they're just piling up as lone cells without a row.

MPDev seemed to want this now , but otherwise it's fine. Since IE is already the one having trouble doing...more or less anything...and it can't handle the non-table code, we're going to continue the slightly painful IE-specific code theme.

I'm afraid I've already heavily optimised and customised the appearance to match my threadbit so I'm sorry to say this is rather vague.

In va_spy.js

FIND:
Code:
text = '<td class="alt1" align="center"><div class="smallfont"><strong>' + what + '</strong></div></td><td class="alt2"><div class="smallfont">' + poster_clip + '</div></td><td class="alt1Active">' + clip + '</td><td align="center" class="alt1"><div class="smallfont">' + where + '</div></td>';
REPLACE WITH:

***Note: I now have this working on any resolution with Opera & Firefox and hopefully every other browser, BUT I only use three cells not four like the default code so you're going to have to use my code as a template to work out the layout for four. Take note of the clears and floats and make sure you assign a % width to the thread/post section and a px width to all the others. Let me know if you need a hand.

Code:
// Did I mention IE is "special"? Help it avoid the scary clever presentation.
	if (is_ie) {
		text = '<td class="alt1 smallfont" align="center">' + ITEM + '</td>';
	} else {
		text = '<span class="alt1 smallfont" style="display:inline-block;float:left;width:30px;text-align:center;clear:left;"><img src="' + iconpath + '" alt="" border="0" /></span><span class="alt1 smallfont" style="display:inline-block;float:left;width:90%;clear:none;"><span class="alt1 smallfont" style="display:inline-block;float:right;width:200px;text-align:right;clear:none;">' + where + '</span>' + clip + '</span>';
	}
Now also surround every clip = in the IF statements above the replaced code with <span></span> tags. The divs are unnecessary for the IE code as long as they're included with the innerHTML below, I've removed them.

Now we have to add the accompanying code to the template to match. Again it's a bit vague because of my template, sorry. This is the general idea. I can only test on Opera, Firefox and IE but it works across all 3, latest release versions, and should be good across other modern browsers as tables are really only used for things like this because IE can't handle anything more complicated.

FIND:
Code:
<table class="tborder" cellpadding="6" cellspacing="1" border="0" width="100%" align="center" id="spy_table">
<thead>
<tr align="center"><td class="thead" width="100">Event</td><td class="thead" width="190">By</td><td class="thead">Thread/Post</td><td class="thead" width="190">Forum</td></tr>
</thead>
<tbody class="alt1">
<tr id="row1" style="display: none;">&nbsp;</tr>
<tr id="row2" style="display: none;">&nbsp;</tr>
<tr id="row3" style="display: none;">&nbsp;</tr>
<tr id="row4" style="display: none;">&nbsp;</tr>
<tr id="row5" style="display: none;">&nbsp;</tr>
<tr id="row6" style="display: none;">&nbsp;</tr>
<tr id="row7" style="display: none;">&nbsp;</tr>
<tr id="row8" style="display: none;">&nbsp;</tr>
<tr id="row9" style="display: none;">&nbsp;</tr>
<tr id="row10" style="display: none;">&nbsp;</tr>
<tr id="row11" style="display: none;">&nbsp;</tr>
<tr id="row12" style="display: none;">&nbsp;</tr>
<tr id="row13" style="display: none;">&nbsp;</tr>
<tr id="row14" style="display: none;">&nbsp;</tr>
<tr id="row15" style="display: none;">&nbsp;</tr>
<tr id="row16" style="display: none;">&nbsp;</tr>
<tr id="row17" style="display: none;">&nbsp;</tr>
<tr id="row18" style="display: none;">&nbsp;</tr>
<tr id="row19" style="display: none;">&nbsp;</tr>
<tr id="row20" style="display: none;">&nbsp;</tr>
<tr id="row21" style="display: none; opacity:.85">&nbsp;</tr>
<tr id="row22" style="display: none; opacity:.65">&nbsp;</tr>
<tr id="row23" style="display: none; opacity:.45">&nbsp;</tr>
<tr id="row24" style="display: none; opacity:.25">&nbsp;</tr>
<tr id="row25" style="display: none; opacity:.05">&nbsp;</tr>
</tbody>
</table>
REPLACE WITH:
Code:
<if condition="is_browser('ie')">
<table class="tborder" cellpadding="6" cellspacing="0" border="0" width="100%" align="center" id="spy_table">
<thead>
<tr align="center"><td class="thead" width="100">Event</td><td class="thead" width="190">By</td><td class="thead">Thread/Post</td><td class="thead" width="190">Forum</td></tr>
</thead>
<tbody class="alt1">
<tr id="row1" style="display:none;"></tr>
<tr id="row2" style="display:none;"></tr>
<tr id="row3" style="display:none;"></tr>
<tr id="row4" style="display:none;"></tr>
<tr id="row5" style="display:none;"></tr>
<tr id="row6" style="display:none;"></tr>
<tr id="row7" style="display:none;"></tr>
<tr id="row8" style="display:none;"></tr>
<tr id="row9" style="display:none;"></tr>
<tr id="row10" style="display:none;"></tr>
<tr id="row11" style="display:none;"></tr>
<tr id="row12" style="display:none;"></tr>
<tr id="row13" style="display:none;"></tr>
<tr id="row14" style="display:none;"></tr>
<tr id="row15" style="display:none;"></tr>
<tr id="row16" style="display:none;"></tr>
<tr id="row17" style="display:none;"></tr>
<tr id="row18" style="display:none;"></tr>
<tr id="row19" style="display:none;"></tr>
<tr id="row20" style="display:none;"></tr>
<tr id="row21" style="display:none;" class="spyfade1"></tr>
<tr id="row22" style="display:none;" class="spyfade2"></tr>
<tr id="row23" style="display:none;" class="spyfade3"></tr>
<tr id="row24" style="display:none;" class="spyfade4"></tr>
<tr id="row25" style="display:none;" class="spyfade5"></tr>
</tbody>
</table>
<else />
<table class="tborder" cellpadding="6" cellspacing="0" border="0" width="100%" align="center" id="spy_table">
<tr><td class="tcat" width="100%">
<span style="display:inline-block;float:left;width:50px;">Event</span><span style="display:inline-block;float:left;width:50px;">By</span><span style="display:inline-block;float:left;width:90%;">Thread/Post</span><span style="display:inline-block;float:left;width:200px%;">Forum</span>
</td></tr>
<tr><td>
<div id="row1" style="display:none;"></div>
<div id="row2" style="display:none;"></div>
<div id="row3" style="display:none;"></div>
<div id="row4" style="display:none;"></div>
<div id="row5" style="display:none;"></div>
<div id="row6" style="display:none;"></div>
<div id="row7" style="display:none;"></div>
<div id="row8" style="display:none;"></div>
<div id="row9" style="display:none;"></div>
<div id="row10" style="display:none;"></div>
<div id="row11" style="display:none;"></div>
<div id="row12" style="display:none;"></div>
<div id="row13" style="display:none;"></div>
<div id="row14" style="display:none;"></div>
<div id="row15" style="display:none;"></div>
<div id="row16" style="display:none;"></div>
<div id="row17" style="display:none;"></div>
<div id="row18" style="display:none;"></div>
<div id="row19" style="display:none;"></div>
<div id="row20" style="display:none;"></div>
<div id="row21" style="display:none;" class="spyfade1"></div>
<div id="row22" style="display:none;" class="spyfade2"></div>
<div id="row23" style="display:none;" class="spyfade3"></div>
<div id="row24" style="display:none;" class="spyfade4"></div>
<div id="row25" style="display:none;" class="spyfade5"></div>
</td></tr>
</table>
</if>


Finally, unless you've looked you won't be aware that the va_effects JS file contains considerably more effects than just the fade-in (called Appear) used by default. I went through most of them, I don't think any consistently worked properly (indeed, neither does the fade-in effect since it doesn't work in IE, this is probably due to the lack of varying opacity code as I mentioned earlier). However, since it's the default and obviously you can only use one effect I removed the other code from the effects file and trimmed it down to just the Appear effect. This saves 20kb from the initial download time.

The file is attached for anyone who wants it, to use it just place the attached file in your clientscript folder with the va_effects.js file and in your vaispy template just replace the words va_effects.js with va_appear.js.

Phew! Hope that helped.
Attached Files
File Type: zip va_appear.zip (3.0 KB, 27 views)

Close
, except not using templates yet), changed way threads are parsed (removes html as well)

1.0.10 - 9.17.06
va_prototype.js - removed 20kb of unused code

1.1.11 - 9.25.2006
vaispy.php
va_spy.js
- added SirAdrian's mods for thread status icons and alternating row colors
- added code to prepopulate the first 10 rows with existing threads allowing for 5 new ones to be added in scrolling mode (versus scrolling starting from the first thread).
- added option to display subscribed threads only

1.1.12 - 9.26.2006
vaispy.php
- added code to add empty rows if initial pull has less than 20 rows.

Download

This modification is archived, downloads are still allowed.

File Type: %1$s vaSpy.zip (18.4 KB, 5647 downloads)

Supporters / CoAuthors

  • buro9
  • ForumDog
  • SirAdrian

Similar Mods

Portal Software vBISpy module - live AJAX feed of new threads - for vBAdvanced CMPS vBulletin 3.6 Add-ons
vBISpy - AJAX real-time feed of new posts/threads (for vB3.5) vBulletin 3.5 Add-ons

vblts.ru supports vBulletin®, 2022-2024