package com.tubeonfire.entity;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import com.google.appengine.api.datastore.Text;
import com.google.gdata.data.youtube.CommentEntry;
import com.google.gdata.data.youtube.CommentFeed;
import com.google.gdata.data.youtube.VideoEntry;
import com.google.gdata.data.youtube.VideoFeed;
import com.google.gdata.util.ServiceException;
import com.tubeonfire.model.CategoryModel;
import com.tubeonfire.model.TagModel;
import com.tubeonfire.model.TubeModel;
import com.tubeonfire.service.TubeService;
import com.tubeonfire.util.JavaCacheHandle;
import com.tubeonfire.util.StringHelper;
@PersistenceCapable
public class Tube {
public void print() {
System.out.println("Tube Id : " + this.tubeId);
System.out.println("Category : " + this.categoryName);
System.out.println("Published : " + this.published);
System.out.println("Updated : " + this.updated);
System.out.println("Title : " + this.title);
System.out.println("Sub title : " + this.subTitle);
System.out.println("Description : " + this.description);
System.out.println("Alias : " + this.alias);
System.out.println("ThumbImageUrl : " + this.thumbImageUrl);
System.out.println("Duration : " + this.duration);
System.out.println("TotalTime : " + this.totalTime);
System.out.println("RelatedTubes : ");
if (this.relatedTubes != null) {
for (Text relate : this.relatedTubes) {
System.out.println(relate.getValue());
}
} else {
System.out.println("null");
}
System.out.println("Keywords : ");
if (this.keywords != null) {
for (Text keyword : this.keywords) {
System.out.println(keyword.getValue());
}
} else {
System.out.println("null");
}
System.out.println("Comments : ");
if (this.comments != null) {
for (Text comment : this.comments) {
System.out.println(comment.getValue());
}
} else {
System.out.println("null");
}
System.out.println("TotalComment : " + this.totalComment);
System.out.println("Author Name : " + this.authorName);
System.out.println("Author Url : " + this.authorUrl);
System.out.println("View Count : " + this.viewCount);
System.out.println("Number Likes : " + this.numLikes);
System.out.println("Number dis Likes : " + this.numDisLikes);
System.out.println("Number rate : " + this.numRate);
System.out.println("Min rate : " + this.minRate);
System.out.println("Max rate : " + this.maxRate);
System.out.println("Average Rate : " + this.averageRate);
System.out.println("Status : " + this.status);
}
@PrimaryKey
@Persistent
private String tubeId; // id from youtube, use to get video.
@Persistent
private String categoryName;
@Persistent
private Date published; // created date from youtube.
@Persistent
private Date updated; // update date.
@Persistent
private Text title; // video title.
@Persistent
private Text subTitle; // title with shorter length. Substring from title.
// Used to display in search result.
@Persistent
private Text description; // video description.
@Persistent
private Text alias; // video alias, from title replace string.
@Persistent
private Text thumbImageUrl; // image will display in search result.
@Persistent
private Long duration; // video duration, how many seconds.
@Persistent
private Text totalTime; // calculate by duration. example : 2:36:30.
@Persistent
private List<Text> relatedTubes;
@Persistent
private List<Text> keywords; // video tags.
// videoEntry.getMediaGroup().getKeywords().getKeywords()
@Persistent
private List<Text> otherKeywords; // video other tags.
@Persistent
private List<Text> comments;
@Persistent
private Text totalComment; // comment count;
@Persistent
private Text authorName; // author name.
@Persistent
private String authorUrl; // author url.
@Persistent
private Text viewCount; // total view of video.
@Persistent
private Text numLikes; // number of people like.
@Persistent
private Text numDisLikes; // number of people dislike.
@Persistent
private Text numRate; // video rate.
@Persistent
private Text minRate; // min point of rate.
@Persistent
private Text maxRate; // max point of rate.
@Persistent
private Text averageRate; // average point.
@Persistent
private int status;
public List<Text> getOtherKeywords() {
return otherKeywords;
}
public void setOtherKeywords(List<Text> otherKeywords) {
this.otherKeywords = otherKeywords;
}
public String getTubeId() {
return tubeId;
}
public void setTubeId(String tubeId) {
this.tubeId = tubeId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public Date getPublished() {
return published;
}
public void setPublished(Date published) {
this.published = published;
}
public Date getUpdated() {
return updated;
}
public void setUpdated(Date updated) {
this.updated = updated;
}
public Text getTitle() {
return title;
}
public void setTitle(Text title) {
this.title = title;
}
public Text getSubTitle() {
return subTitle;
}
public void setSubTitle(Text subTitle) {
this.subTitle = subTitle;
}
public Text getDescription() {
return description;
}
public void setDescription(Text description) {
this.description = description;
}
public Text getAlias() {
return alias;
}
public void setAlias(Text alias) {
this.alias = alias;
}
public Text getThumbImageUrl() {
return thumbImageUrl;
}
public void setThumbImageUrl(Text thumbImageUrl) {
this.thumbImageUrl = thumbImageUrl;
}
public Long getDuration() {
return duration;
}
public void setDuration(Long duration) {
this.duration = duration;
}
public Text getTotalTime() {
return totalTime;
}
public void setTotalTime(Text totalTime) {
this.totalTime = totalTime;
}
public List<Text> getRelatedTubes() {
return relatedTubes;
}
public void setRelatedTubes(List<Text> relatedTubes) {
this.relatedTubes = relatedTubes;
}
public List<Text> getKeywords() {
return keywords;
}
public void setKeywords(List<Text> keywords) {
this.keywords = keywords;
}
public List<Text> getComments() {
return comments;
}
public void setComments(List<Text> comments) {
this.comments = comments;
}
public Text getTotalComment() {
return totalComment;
}
public void setTotalComment(Text totalComment) {
this.totalComment = totalComment;
}
public Text getAuthorName() {
return authorName;
}
public void setAuthorName(Text authorName) {
this.authorName = authorName;
}
public String getAuthorUrl() {
return authorUrl;
}
public void setAuthorUrl(String authorUrl) {
this.authorUrl = authorUrl;
}
public Text getViewCount() {
return viewCount;
}
public void setViewCount(Text viewCount) {
this.viewCount = viewCount;
}
public Text getNumLikes() {
return numLikes;
}
public void setNumLikes(Text numLikes) {
this.numLikes = numLikes;
}
public Text getNumDisLikes() {
return numDisLikes;
}
public void setNumDisLikes(Text numDisLikes) {
this.numDisLikes = numDisLikes;
}
public Text getNumRate() {
return numRate;
}
public void setNumRate(Text numRate) {
this.numRate = numRate;
}
public Text getMinRate() {
return minRate;
}
public void setMinRate(Text minRate) {
this.minRate = minRate;
}
public Text getMaxRate() {
return maxRate;
}
public void setMaxRate(Text maxRate) {
this.maxRate = maxRate;
}
public Text getAverageRate() {
return averageRate;
}
public void setAverageRate(Text averageRate) {
this.averageRate = averageRate;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String generateAlias(String title) {
String alias = title;
return alias;
}
/*
* check if this key had been search more than 1 day, if >= 1 day return
* false, if < 1 day return true.
*/
public boolean isUpdate() {
if (this.updated != null) {
Calendar today = Calendar.getInstance();
Calendar updated = Calendar.getInstance();
updated.setTime(this.updated);
if ((today.getTimeInMillis() - updated.getTimeInMillis())
/ (60 * 60 * 24000) >= 10) {
return false;
}
return true;
}
return false;
}
/*
* This method convert Tube object to String. Need when save relate Videos
* to Appengine DB. Object fields will be saved in String with XML Format.
*/
public String toString() {
StringBuilder content = new StringBuilder();
if (this.tubeId != null) {
content.append("<tubeId>" + this.tubeId + "</tubeId>\n");
}
if (this.thumbImageUrl != null) {
content.append("<thumbImageUrl>" + this.thumbImageUrl.getValue()
+ "</thumbImageUrl>\n");
}
if (this.title != null) {
content.append("<title>" + this.title.getValue() + "</title>\n");
}
if (this.alias != null) {
content.append("<alias>" + this.alias.getValue() + "</alias>\n");
}
if (this.authorName != null) {
content.append("<authorName>" + this.authorName.getValue()
+ "</authorName>\n");
}
if (this.viewCount != null) {
content.append("<viewCount>" + this.viewCount.getValue()
+ "</viewCount>\n");
}
if (this.totalTime != null) {
content.append("<totalTime>" + this.totalTime.getValue()
+ "</totalTime>\n");
}
return content.toString();
}
/*
* This method tranform String with xml format to Tube object (Use java
* regex) Be used when get relate Videos from DB to display.
*/
public void transformString(String tubeString) {
Document doc = Jsoup.parse(tubeString);
Elements tmp;
tmp = doc.select("tubeId");
if (tmp != null) {
this.tubeId = (tmp.text());
}
tmp = doc.select("thumbImageUrl");
if (tmp != null) {
this.thumbImageUrl = (new Text(tmp.text()));
}
tmp = doc.select("title");
if (tmp != null) {
this.title = (new Text(tmp.text()));
}
if (this.title.getValue().length() > 33) {
String[] split = this.title.getValue().substring(0, 33).split(" ");
String subTitle = "";
for (int i = 0; i < (split.length - 1); i++) {
subTitle += " " + split[i];
}
if (subTitle.length() > 33) {
subTitle = subTitle.substring(0, 33);
}
this.subTitle = new Text(subTitle + "...");
} else {
this.subTitle = this.title;
}
tmp = doc.select("alias");
if (tmp != null) {
this.alias = (new Text(tmp.text()));
}
tmp = doc.select("authorName");
if (tmp != null) {
this.authorName = (new Text(tmp.text()));
}
tmp = doc.select("viewCount");
if (tmp != null) {
try {
DecimalFormat nf = (DecimalFormat) DecimalFormat.getInstance();
nf.setDecimalSeparatorAlwaysShown(true);
Long view = Long.parseLong(tmp.text());
this.viewCount = (new Text(nf.format(view)));
} catch (Exception e) {
this.viewCount = (new Text("1"));
}
}
tmp = doc.select("totalTime");
if (tmp != null) {
this.totalTime = (new Text(tmp.text()));
}
}
/*
* This method tranform VideoEntry (from Gdata - Youtube api) to Tube
* Object.
*/
public void transformVideoEntry(VideoEntry videoEntry)
throws MalformedURLException, IOException, ServiceException {
this.published = (new Date(videoEntry.getPublished().getValue()));
this.updated = (Calendar.getInstance().getTime());
if (videoEntry.getRelatedVideosLink() != null) {
List<Text> related = new ArrayList<Text>();
List<Tube> listSave2DB = new ArrayList<Tube>();
VideoFeed feeds = TubeService.service.getFeed(new URL(videoEntry
.getRelatedVideosLink().getHref()), VideoFeed.class);
for (VideoEntry entry : feeds.getEntries()) {
Tube item = new Tube();
item.transformHalfVideoEntry(entry);
item.setStatus(2);
item.setUpdated(Calendar.getInstance().getTime());
related.add(new Text(item.toString()));
if (TubeModel.getByTubeId(item.getTubeId()) == null) {
listSave2DB.add(item);
System.out.println(item.getTitle() + " ready to save !");
}
}
if (listSave2DB.size() > 0) {
System.out.println("Save : " + listSave2DB.size()
+ " videos success !");
TubeModel.addAll(listSave2DB);
}
this.relatedTubes = (related);
}
JavaCacheHandle.initCache();
if (videoEntry.getMediaGroup().getKeywords() != null) {
List<Text> listKey = new ArrayList<Text>();
for (String keyword : videoEntry.getMediaGroup().getKeywords()
.getKeywords()) {
Tag tmpTag = null;
listKey.add(new Text(keyword));
TagModel tagModel = new TagModel();
String tagAlias = keyword;
tmpTag = tagModel.getByAlias(tagAlias);
List<Text> listTubeId = new ArrayList<Text>();
if (tmpTag != null) {
tmpTag.setCount(tmpTag.getCount() + 1);
listTubeId.addAll(tmpTag.getListTubeId());
listTubeId.add(new Text(this.tubeId));
tmpTag.setListTubeId(listTubeId);
tagModel.update(tmpTag);
tagModel.closePM();
} else {
tmpTag = new Tag();
listTubeId.add(new Text(this.tubeId));
tmpTag.setListTubeId(listTubeId);
tmpTag.setAlias(tagAlias);
tmpTag.setCount(1);
tmpTag.setTitle(new Text(tagAlias));
tmpTag.setType("N");
tagModel.add(tmpTag);
}
}
this.keywords = listKey;
JavaCacheHandle.addKeywords(listKey);
}
// get other tag.
this.otherKeywords = JavaCacheHandle.getRandomKeywords();
if (videoEntry.getComments() != null) {
List<Text> listComment = new ArrayList<Text>();
CommentFeed commentFeed = TubeService.service.getFeed(new URL(
videoEntry.getComments().getFeedLink().getHref()),
CommentFeed.class);
for (CommentEntry cmtEntry : commentFeed.getEntries()) {
StringBuilder content = new StringBuilder();
content.append("<commentId>" + cmtEntry.getId()
+ "</commentId>\n");
content.append("<content>" + cmtEntry.getPlainTextContent()
+ "</content>\n");
content.append("<author>"
+ cmtEntry.getAuthors().get(0).getName()
+ "</author>\n");
content.append("<punished>"
+ new Date(cmtEntry.getPublished().getValue())
+ "</punished>\n");
listComment.add(new Text(content.toString()));
}
this.comments = (listComment);
this.totalComment = (new Text((videoEntry.getComments()
.getFeedLink().getCountHint()).toString()));
}
if (videoEntry.getStatistics() != null) {
this.viewCount = (new Text(String.valueOf(videoEntry
.getStatistics().getViewCount())));
}
if (videoEntry.getYtRating() != null) {
this.numLikes = (new Text(String.valueOf(videoEntry.getYtRating()
.getNumLikes())));
this.numDisLikes = (new Text(String.valueOf(videoEntry
.getYtRating().getNumDislikes())));
}
if (videoEntry.getRating() != null) {
this.numRate = (new Text(String.valueOf(videoEntry.getRating()
.getNumRaters())));
this.minRate = (new Text(String.valueOf(videoEntry.getRating()
.getMin())));
this.maxRate = (new Text(String.valueOf(videoEntry.getRating()
.getMax())));
this.averageRate = (new Text(String.valueOf(videoEntry.getRating()
.getAverage())));
}
this.status = (1);
this.updated = (Calendar.getInstance().getTime());
}
/*
* This method tranform only important field VideoEntry (from youtube api)
* to Tube
*/
public void transformHalfVideoEntry(VideoEntry entry) {
this.tubeId = (entry.getMediaGroup().getVideoId());
if (entry.getMediaGroup().getThumbnails() != null
&& entry.getMediaGroup().getThumbnails().size() > 1) {
this.thumbImageUrl = (new Text(entry.getMediaGroup()
.getThumbnails().get(1).getUrl()));
}
this.title = (new Text(entry.getMediaGroup().getTitle()
.getPlainTextContent()));
if (this.title.getValue().length() > 33) {
String[] split = this.title.getValue().substring(0, 33).split(" ");
String subTitle = "";
for (int i = 0; i < (split.length - 1); i++) {
subTitle += " " + split[i];
}
if (subTitle.length() > 33) {
subTitle = subTitle.substring(0, 33);
}
this.subTitle = new Text(subTitle + "...");
} else {
this.subTitle = this.title;
}
if (entry.getMediaGroup().getDescription() != null) {
this.description = (new Text(entry.getMediaGroup().getDescription()
.getPlainTextContent()));
}
this.alias = (new Text(StringHelper.getAliasByLanguage(this.getTitle()
.getValue())));
this.authorName = (new Text(entry.getAuthors().get(0).getName()));
this.authorUrl = (entry.getAuthors().get(0).getUri());
if (entry.getStatistics() != null) {
this.viewCount = (new Text(String.valueOf(entry.getStatistics()
.getViewCount())));
}
if (entry.getMediaGroup().getDuration() != null) {
Long duration = entry.getMediaGroup().getDuration();
int hours = (int) (duration / 3600);
int remainder = (int) (duration - hours * 3600);
int minutes = remainder / 60;
remainder = remainder - minutes * 60;
int second = remainder;
this.duration = (duration);
this.totalTime = (new Text(((hours > 0) ? (hours + ":") : "")
+ ((minutes > 9) ? minutes : ("0" + minutes)) + ":"
+ ((second > 9) ? second : ("0" + second))));
}
this.categoryName = (entry.getMediaGroup().getCategories().get(0)
.getLabel());
Category cate = CategoryModel.getByCateAlias(StringHelper
.replace(this.categoryName));
List<Text> listTubes = new ArrayList<Text>();
if (cate != null) {
boolean had = false;
listTubes = cate.getListTubes();
for (Text textTube : listTubes) {
if (textTube.getValue().equalsIgnoreCase(this.toString())) {
had = true;
}
}
if (!had) {
listTubes.add(new Text(this.toString()));
cate.setListTubes(listTubes);
cate.setCount(cate.getCount() + 1);
CategoryModel.update(cate);
CategoryModel.closePM();
}
} else {
cate = new Category();
cate.setAlias(StringHelper.replace(this.categoryName));
cate.setTitle(new Text(this.categoryName));
cate.setCount(1);
cate.setStatus(1);
listTubes.add(new Text(this.toString()));
cate.setListTubes(listTubes);
CategoryModel.add(cate);
}
}
}