danmuManager.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. var viewport_height = $(window).height();
  2. var webpage_height = $(document).height();
  3. var current_postion = $(document).scrollTop();
  4. var page = 1;
  5. /**
  6. * 弹幕数据生成器
  7. * @param danmuListUrl 弹幕数据获取的url
  8. * @param art_id 弹幕对应的文章id
  9. */
  10. var DanmuManager = function(opt) {
  11. this.q = []; // store danmu collection
  12. this.danmu_list_url = opt.danmu_list_url;
  13. this.entity_id = opt.entity_id; //文章ID
  14. this.entity = opt.entity; //文章ID
  15. this.pos_current = 0; //进度
  16. this.pos_last_time = 0; //上次请求的文章进度
  17. this.fetch_size = opt.fetch_size || 20; //ajax获取弹幕时的数量
  18. this.is_fetching = false; //是否正在ajax获取
  19. this.pos_sections = []; //文章进度所属的部分
  20. this.has_next = true; //是否存在下一页
  21. this.has_next_pos_section = -1; //是否存在下一页的数据点
  22. this.last_dm_ids = {};
  23. };
  24. DanmuManager.prototype.push = function(dm) {
  25. if(!dm){
  26. return this.log('push, NULL data pushed');
  27. }
  28. dm.avatar = dm.avatar || '../image/default/avatar.png';
  29. dm.type = 'realtime';
  30. this.q.unshift(dm);
  31. this.log('EVENT push_fired EMITTED:' + DM_ToString.call(dm));
  32. };
  33. /**
  34. * 取出一条需要显示的数据
  35. */
  36. DanmuManager.prototype.read = function(cb) {
  37. //始终返回队列顶部数据
  38. var dm = this.q.shift();
  39. //检查队列长度以判断是否需要拉取新的弹幕列表
  40. var len = this.q.length;
  41. //如果队列有数据
  42. if(len == 0){
  43. //如果队列没有数据了
  44. this.log('read, dm=null, len=' + this.len);
  45. this.get_list();
  46. return cb(null, len);
  47. }
  48. if(dm && dm.id){
  49. this.log('read, dm=' + dm.id + ', dm.avatar=' + dm.avatar);
  50. dm.avatar = this.optimizeImg(dm.avatar);
  51. return cb(dm, len);
  52. } else {
  53. return cb(null, len);
  54. }
  55. }
  56. DanmuManager.prototype.optimizeImg = function(url){
  57. if(url && url.search('qzapp.qlogo.cn/') > 0){ // QQ avatar
  58. url = url.replace(/\/100$/,'\/30');
  59. }
  60. if(url && url.search('sinaimg.cn') > 0){ // Weibo avatar
  61. url = url.replace(/\/50\//, '\/30\/');
  62. }
  63. return url;
  64. }
  65. /**
  66. * 取出一条需要显示的数据
  67. */
  68. DanmuManager.prototype.readSync = function() {
  69. //始终返回队列顶部数据
  70. var dm = this.q.shift();
  71. //检查队列长度以判断是否需要拉取新的弹幕列表
  72. var len = this.q.length;
  73. //如果队列有数据
  74. if(dm){
  75. dm.avatar = this.optimizeImg(dm.avatar);
  76. dm.content = this.filterContent(dm.content);
  77. this.log('read, dm=' + dm.id + ', dm.avatar=' + dm.avatar);
  78. return {'dm': dm, 'len': len};
  79. }
  80. //如果队列里没有数据
  81. this.log('read, dm=null, len=' + this.len);
  82. this.get_list();
  83. return {'dm': null, 'len': 0};
  84. }
  85. var kw = [/兼职/,/淘宝/,/扣扣/,/结算/,/结算/,/加Q/,/天猫/,/傔职/,/掏宝/,/在线客服/,/诚聘/,/贝兼/,/间职/,/空余时间/,/日結/,/加q/,/蒹职/,/上班族/];
  86. DanmuManager.prototype.filterContent = function(str){
  87. for(var len = kw.length, i=0; i< len; i++){
  88. if(str.match(kw[i])){
  89. return "笑Cry!";
  90. break;
  91. }
  92. }
  93. return str;
  94. };
  95. DanmuManager.prototype.get_current_pos = function(){
  96. var _tmp = parseInt($(document).scrollTop() / $(document).height() * 100, 10);
  97. if(_tmp < 0){
  98. _tmp = 0;
  99. }
  100. return _tmp;
  101. };
  102. DanmuManager.prototype.get_pos_section = function(_tmp_pos){
  103. _tmp_pos = _tmp_pos || this.get_current_pos();
  104. var _pos = 0;
  105. for(var i=0, len=this.pos_sections.length; i < len; i++){
  106. if(_tmp_pos >= this.pos_sections[i]){
  107. _pos++;
  108. } else {
  109. break;
  110. }
  111. }
  112. this.log('get_pos_section, pos_current=' + _tmp_pos + ', _pos=' + _pos);
  113. return _pos < 1 ? 1 : _pos;
  114. };
  115. DanmuManager.prototype.prepare_pos_section = function(pos_arr){
  116. // 不重复设置值
  117. if(this.pos_sections && this.pos_sections.length > 0){
  118. return;
  119. }
  120. if(pos_arr && pos_arr.length > 0){
  121. this.pos_sections = pos_arr;
  122. } else {
  123. this.pos_sections = [0, 100]; //如果服务器端没有返回,设置默认值
  124. }
  125. };
  126. /**
  127. * 向服务器端获取列表数据
  128. */
  129. DanmuManager.prototype.get_list = function() {
  130. // 如果ajax正在执行,直接跳过
  131. if(this.is_fetching){
  132. return this.log('get_list, is_fetching=true');
  133. }
  134. // 如果在当期位置的分区上没有下一页了,直接跳过
  135. var _current_section = this.get_pos_section();
  136. if(_current_section == this.has_next_pos_section){
  137. if(!this.has_next){
  138. return this.log('get_list, no more data on section=' + _current_section);
  139. }
  140. } else {
  141. //如果已经更换了当前的区域
  142. this.log('get_list, changed from section=' + this.has_next_pos_section + ' to section=' + _current_section);
  143. this.has_next = true;
  144. }
  145. this.is_fetching = true;
  146. // 设置位置
  147. this.pos_current = this.get_current_pos();
  148. this.log('get_list, pos_current=' + this.pos_current);
  149. this.log('get_list, ' + this.danmu_list_url);
  150. var that = this;
  151. if(!this.danmu_list_url){
  152. throw Error('this.danmu_list_url is null');
  153. return;
  154. }
  155. var ts = (new Date).valueOf();
  156. this.fetch_latest_ts = ts;
  157. // 获取当前进度的最后一次获取的弹幕ID
  158. var _last_dm_id = this.last_dm_ids[_current_section + ''] || 0;
  159. var post_data = {
  160. entity_id : that.entity_id,
  161. entity : that.entity,
  162. bpos: that.pos_last_time,
  163. epos: that.pos_current,
  164. pagesize: that.fetch_size,
  165. last_id: _last_dm_id,
  166. time: ts,
  167. page:page
  168. };
  169. this.log('---start ajax---');
  170. jlog(post_data);
  171. $.ajax({
  172. url : that.danmu_list_url,
  173. dataType : 'json',
  174. data: post_data,
  175. type: 'post',
  176. success:function(data) {
  177. that.is_fetching = false;
  178. if(!data){
  179. return that.log('get_list, ajax, null result');
  180. }
  181. if(_current_section != that.get_pos_section()){
  182. return that.log('give up, cause pos_section has been changed');
  183. }
  184. page++;
  185. var dm_list = that.transform(data, _current_section);
  186. that.append_data(dm_list);
  187. that.log('get_list, has_next=' + data.hasNext);
  188. that.prepare_pos_section(data.posSection);
  189. that.has_next = data.hasNext;
  190. that.has_next_pos_section = _current_section;
  191. },
  192. error: function(err){
  193. that.log('get_list err: ' + err);
  194. jlog(err);
  195. that.append_data(null);
  196. that.is_fetching = false;
  197. that.has_next = false;
  198. that.has_next_pos_section = _current_section;
  199. }
  200. });
  201. // Set pos_last_time = pos_current;
  202. that.pos_last_time = that.pos_current;
  203. };
  204. DanmuManager.prototype.transform = function(data, curr_section){
  205. var arr = data.list || [];
  206. if(arr){
  207. var dm = arr[arr.length - 1];
  208. if(dm){
  209. this.last_dm_ids[curr_section + ''] = dm.id;
  210. }
  211. }
  212. return arr;
  213. };
  214. DanmuManager.prototype.append_data = function(data) {
  215. this.log('append_data, data.length=' + (!data ? 'null' : data.length));
  216. this.is_fetching = false;
  217. if(data && data.length > 0){
  218. this.q = this.q.concat(data);
  219. this.log('append_data, add new, q.length=' + this.q.length);
  220. } else {
  221. this.log('append_data, empty');
  222. this.stop_fetch = true;
  223. }
  224. };
  225. DanmuManager.prototype.log = function(text) {
  226. jlog('[DanmuManager] ' + text);
  227. };