Upgraded Digital DJ Pool

August 14, 2008

DigitalDJPool.com is the online equivalent of a "record pool" more commonly known now as a "Digital Pool." For those who aren't aware, a record pool is a source for DJ's to get promotional music from record labels for use in clubs/radio/etc... The record labels provide the music to "the pool" and the pool can then provide feedback to the label. Now that MP3's are being used more than vinyl, DigitalDJPool.com provides DJ's with promotional MP3's rather than shipping crates of records!

The new site has streamlined some of the major issues members have reported in the past:

  • New, simpler, rating system 
  • Longer previews
  • Grouped tracks
  • and more

DigitalDJPool.com has been around for a few years now and it was due for a major overhaul! The site was originaly powered on the Community Server 1.0 platform and has been upgraded to most of the major CS release up to now. As of now it is running on Community Server 2007.1. If you check out the site you will notice that it isn't using much of Community Server's features and you are correct. As the site has grown we realized that the end users want to download music, not blog or participate in other community oriented things. We weren't ready to jump ship on CS with this release, but it is the most likely scenario. We have a professional license, but with the never ending increase in license costs it doesn't seem like a good path to continue down.

 

Everyone (?) knows that Community Server uses Lucene for its Enterprise Search. The one problem I found is that I couldn't find any search syntax documentation in the CS Docs. Here is a list of all index fields that CS uses:

app: (forums|photos|files|weblogs)
applicationkey: The application key the post is in
applicationtype: (Forum|Gallery|FileGallery|Weblog)
attachementname: Any attachement name
date: The date the post was made

user: The username of the poster
userid: The userid of the poster

settingsid: The settings id the post was made in
groupid: The group id the post was made in
sectionid: The section the post was made
threadid: The thread id of the post
parentid: The parent post if
postid: The post id

name: The name of the post
title: The Title of the post
body: The Body of the post (stripped of HTML)
rawbody: The Body of the post
tag: The tags on the post
tagkeyword: the lowercase version of the tags
url: The relative URL to the post

role:
exact: ?
link: ?

To search on these fields, just user something like "user:CarKnee" to see all carknee's posts.

With [csl], when a registered user makes a blog comment it is very common to show their avatar next to their comment. If the person making the comment is not a registered user, then typically the "anonymous avatar" would be shown. I had gone and implemented an Identicon control for anonymous comments and now I am going another step and implementing a Gravatar.

The PostGravatar control (in the [bundle]) can be used within a WeblogFeedbackList to show the Gravatar of the person who commented.

The last three blogs posts I made have all the pieces of the puzzle, now lets put them together!

  1. We need to store the persons email address if they are an anonymos user.
    See here:
  2. We need to show different items based on some criteria
    See here:
    • If registered --> Show Avatar
    • If not registered and specified email address --> Use PostGravatar control
    • If not registered and didn't specify an email --> Use Identicon control

I attached the code for a /themes/blogs/default/post.aspx page. If you are using a different theme you will need to modify it as needed.

I was working a new control for the [bundle] and was in need of a condition control within [csl] that didn't appear to exist. What I needed was a condition control that checked against a WeblogPost's ExtendedAttributes. What I came up with was the "PostExtendedAttributeComparison."

I use this comparison as follows:

<CSControl:ConditionalContent runat="server">
    <ContentConditions>
        <SK:PostExtendedAttributeComparison runat="server" ExtendedAttribute="AuthorEmail" Operator="IsSetOrTrue" />                                        
    </ContentConditions>
    <TrueContentTemplate>
        <SK:PostGravatar runat="server" Rating="R" ExtendedAttribute="AuthorEmail" Width="80" BorderWidth="1" />
    </TrueContentTemplate>
    <FalseContentTemplate>
       <SK:Identicon ID="Identicon1" runat="server" width="80" BorderWidth="1" Text="identicon"  />                                      
    </FalseContentTemplate>
</CSControl:ConditionalContent>

This checks to see if the extended attribute "AuthorEmail" is set in the blog comment. If it is set, then we will show the person's Gravatar, otherwise we will show the Identicon.

The WeblogPostFeedbackExtendedAttributeComparison control can be found in the [bundle]. Remember to register the control as:

<%@ Register TagPrefix="SKB" Namespace="CarKnee.CS.Bundle.Blogs.Controls" Assembly="CarKnee.CS.Bundle" %>

Related Articles:

I am working on a control for [csl] where I need to capture the email address of the person making a comment. However, I don't need to store the email address if the person is already a registered member of the site since this information is stored already. What I did was utilize the CustomAction feature for the WeblogPostCommentForm and set the "AuthorEmail" extended attribute.

Here is how you can do it.

On the /themes/blogs/[default]/Post.aspx page locate your WeblogPostCommentForm and set the following:

<SuccessActions>
...

<
CSControl:CustomAction runat="server" OnCustomEvent="CommentFormSuccess" />
</SuccessActions>

This will wireup the call to this function that you must add to the top of the page:

protected void CommentFormSuccess(System.Web.UI.Control sender, object parameter)
{
CommunityServer.Blogs.Components.WeblogPost post = parameter as CommunityServer.Blogs.Components.WeblogPost;
if (post == null)
return;
if (!post.User.IsAnonymous)
return;
CommunityServer.Blogs.Controls.WeblogPostCommentForm form = sender as CommunityServer.Blogs.Controls.WeblogPostCommentForm;
if (form == null)
return;
System.Web.UI.WebControls.TextBox email = WeblogControlUtility.Instance().FindControl(form, "tbEmail") as System.Web.UI.WebControls.TextBox;
if (email == null)
return;
if (String.IsNullOrEmpty(email.Text))
return;
post.SetExtendedAttribute("AuthorEmail", email.Text);
WeblogPosts.Update(post);
}

The final step would be to add in the TextBox to prompt for the users email. What I did was wrap it up in a placeholder and only show it for non-RegisteredUsers.

<CSControl:PlaceHolder runat="server">
<DisplayConditions Operator="Not">
<CSControl:UserInRoleCondition runat="server" Role="Registered Users" UseAccessingUser="true" />
</DisplayConditions>
<ContentTemplate>
<div class="CommonFormFieldName">
Email:
<em>(<CSControl:ResourceControl runat="server" ResourceName="Optional" />)</em>
</div>
<div class="CommonFormField">
<asp:TextBox id="tbEmail" runat="server" Columns="60" />
<asp:RequiredFieldValidator id="emailValidator" runat="server" ControlToValidate="tbEmail" Cssclass="validationWarning">*</asp:RequiredFieldValidator>
</div>
</ContentTemplate>
</CSControl:PlaceHolder>

Now, when someone enters in their email address it will be stored in the ExtendedAttributes of the post.

Read on to see how I use this information.

 

Now that [csl] 2007 has been out for a while I figured it was time to update the [bundle]! The Jobs have become Tasks, the Identicon control now has implicit databinding and the CSModules have some little upgrades ;p The new version is now 3.0 to keep in step with the official version of CS2007 [3.0]

Some new features worth noting are:

1. The BlogRssSignature CSModule now supports the use of a “global” signature as well as the previously available per-blog basis signatures. This will allow the main site to also tag their blogs content. For instance, say Billy Bob is a blogger on blogs.acme.com and has added his own signature via the Control Panel to say “Written by Billy Bob.” Now, the Administrator of blogs.acme.com can set the master signature (in the communityserver.config file) to say “Copyright ACME.”

2. The Identicon Control can now bind to the containing Chameleon control. You would typically want to use the Identicon handler in a “Feedback List” (WeblogFeedbackList, GalleryPostFeedbackList, or EntryCommentList) to be used in place of an anonymous avatar. For example, edit your /themes/blogs/[default]/post.aspx where you would normally have the commenters avatar and change it to this: (This is how this site operates... make a comment to see your Identicon)

 

<CSControl:ConditionalContent runat="server">
<ContentConditions>
<CSControl:UserPropertyComparison ComparisonProperty1="HasAvatar" Operator="IsSetOrTrue" runat="server" />
</ContentConditions>
<TrueContentTemplate>
<CSControl:UserAvatar runat="server" BorderWidth="1" />&nbsp;
</TrueContentTemplate>
<FalseContentTemplate>
<SK:Identicon runat="server" width="80" BorderWidth="1" Text="identicon" />
</FalseContentTemplate>
</CSControl:ConditionalContent>

Remember to register the tag as follows:

<%@ Register TagPrefix="SK" Namespace="CarKnee.CS.Bundle.Controls" Assembly="CarKnee.CS.Bundle" %>

You can also override the implicit binding and manually specify an IP to use as follows:

<SK:Identicon runat="server" width="80" IP="255.255.255.255" BorderWidth="1" /> 

Finally, you have the option to use the IP address of the person viewing the page as follows:

<SK:Identicon runat="server" width="80" UseAccessingIP="true" BorderWidth="1" /> 

3. The flash MP3Player used in the module has been upgraded from 2.1 to 3.7! With this upgrade I have passed down a lot more flexibility to the site owner and blog poster! You can now specify default values in the communityserver.config file and the blog poster can manually specify width and height in their post! To embed an MP3 player you can add it using the content part notation as follows:
[ mp3 width=300 height=78]/some/path/file.mp3[/mp3 ]

Feel free to download the updated [bundle] and let me know what you think!

This site was upgraded to [cs] 2007 in all of about 10 minutes! The CS team made it real easy to upgrade with the new config file overrides! Nice job.

I will be upgrading and testing the [bundle] to work with CS 2007 and publish it asap!

 

 

A few members, myself included, are looking for some sort of "content manager" capability with the blog system of [cs]. By "Content Manager" I am meaning that I do not want the individual people to actually make the posts. Rather, I would like to have a "manager" that will publish the post on the authors behalf.

In order to do this with [cs] 2007 you do need to modify some core files. I will show what needs to be done ;p

/ControlPanel/Blogs/CreateEditBlogPost.ascx page

Around line #166 add in the following:

<!-- CarKnee Author Mod-->
<asp:Panel ID="AuthorPanel" runat="server" Visible="false">
    <div class="CommonFormFieldName">
        Author:
    </div>
    <div class="CommonFormField">
        <asp:textbox id="AuthorName" cssclass="ControlPanelTextInputBig" maxlength="256" runat="server" />
    </div>
</asp:Panel>
<!-- END CarKnee -->

In the code behind (/ControlPanel/Blogs/CreateEditBlogPost.ascx.cs) modify it in the following places:

Line 47 Add:

protected TextBox AuthorName;
protected Panel AuthorPanel;

Around Line 176 add this in:

if (CSContext.Current.User.IsBlogAdministrator)
    AuthorPanel.Visible = true;
else
    AuthorPanel.Visible = false;

Line 277 Add:

AuthorName.Text = CommunityServer.Users.GetUser(CurrentWeblogPost.AuthorID, false).Username;
AuthorName.ReadOnly = true;

Around Line 504 look for this: postID = context.PostID; and add this right under it:

string authorname = String.IsNullOrEmpty(AuthorName.Text) ? CommunityServer.Users.GetAnonymousUser().Username : AuthorName.Text;
if (CommunityServer.Users.GetUser(authorname) == null || CommunityServer.Users.GetUser(authorname).IsAnonymous)
  authorname = context.User.Username;
CommunityServer.Components.User u = CommunityServer.Users.GetUser(authorname);

post.AuthorID = u.UserID;
post.Username = authorname;

Around Line 524 look for this:

result = WeblogPosts.Add(post, context.User, out postID);

and change it to this:

result = WeblogPosts.Add(post, u, out postID);

You will need to recompile the core if you make the change to the .cs file.

Another day, another [csl] add-on!

A member in the [cs] forums needs a way to add a statement to every blog post that is syndicated in order to prevent scrapers from "using" their content with no mention of the rightful owner. This seems like a real good idea for anyone, including me, who syndicates their content. Jose Lema came through with the basic idea of how to handle this situation so I figured I would run with it.

The code, as Jose provided, is real simple however I wanted to make it easy to change the "RSS Signature." I figured we could store the signature text in an ExtendedAttribute rather than a config file so here is what I have:

public void Init(CSApplication csa, XmlNode node)
{
  csa.PreRenderPost += new CSPostEventHandler(csa_PreRenderPost);
}

void csa_PreRenderPost(IContent content, CSPostEventArgs e)
{
  WeblogPost post = content as WeblogPost;
  if (post == null)
    return;
  if (e.ApplicationType == ApplicationType.Weblog && e.Target == PostTarget.Syndication)
  {
    string sig = post.Section.GetExtendedAttribute("BlogRssSignature");
    if (String.IsNullOrEmpty(sig))
      return;
    post.FormattedBody = String.Concat(post.FormattedBody, sig);
  }
}

Now for the Control Panel Administration of the signature. I do not like modifying the core code for [cs]; it makes it a pain to handle updates. So what I did was create a new page to handle the setting of the extended attribute, with the codebehind residing in my [bundle]. The result is a simple page to create/edit the signature text used for your blog. I should also mention that I dislike having to edit language xml files for basic text. Again, this is just a pain for installing quick modules, but if you are using any language other than English you will have to manually edit the aspx file.

Create your signature:

And here it is:

To install this, download the [bundle] and follow the instructions in the readme.txt file.

A member on the [csl] forums asked about embedding an MP3 player in his blog posts and I thought this would be a great addition to the [bundle]!

To implement this we are going to create a basic CSModule that works off of the PreRenderPost event. In our module we will try to match text that looks like this 

[ mp3]*Some Uri*[/mp3 ]

and turn it into a Flash MP3 Player pointing to the specified Uri.

Our code is very simple and looks like this:

Post post = content as Post;
if ((post != null) && (e.Target == PostTarget.Web))
{
Match Mp3Match = Regex.Match(post.FormattedBody, @"\[mp3\](.*?)\[/mp3\]", RegexOptions.IgnoreCase);

if (Mp3Match.Success)
{
string uri = Mp3Match.Value;
uri = uri.Substring(5, uri.Length - 11);
post.FormattedBody = Regex.Replace(post.FormattedBody, @"\[mp3\](.*?)\[/mp3\]", CreatePlayerCode(uri), RegexOptions.IgnoreCase);
}
}

The MP3 Player I decided to use for this can be found here. There are MANY different Flash based MP3 players on the Web, but I have used this one for digitaldjpool.com and it has worked great!

To use this module all you need to do is insert the following code into your post:

[mp3 ]http://www.example.com/File.mp3[/mp3 ] 

It will automatically turn your link into a flash based MP3 player as shown here:

[mp3 width=300 height=78]/blogs/files/test.mp3[/mp3]

There is an issue with cross site loading of MP3 files though. If you are linking to a file that resides outside of your domain you will need to have a crossdomain.xml file on the domain you are linking to. This is a security feature built into the Flash Player.

To install this, download the [bundle] and follow the directions in the readme.txt file.

The [cs] module used to show this player has been updated. Please read this post for the updated version