PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/messages.js

https://github.com/rhagigi/snarl
JavaScript | 858 lines | 718 code | 109 blank | 31 comment | 151 complexity | ba4969536ed2a8aff8e1c2917b882bf2 MD5 | raw file
  1. var rest = require('restler')
  2. , google = require('google')
  3. , ddg = require('ddg-api')
  4. , urban = require('urban')
  5. , github = require('github')
  6. , _ = require('underscore')
  7. , async = require('async')
  8. , timeago = require('timeago')
  9. , mongoose = require('mongoose')
  10. , ObjectId = mongoose.Schema.Types.ObjectId
  11. , Schema = mongoose.Schema
  12. , db = mongoose.createConnection('localhost', 'snarl');
  13. var facts = require('./facts');
  14. var personSchema = mongoose.Schema({
  15. name: { type: String, index: true }
  16. , plugID: { type: String, unique: true, sparse: true }
  17. , role: { type: Number }
  18. , karma: { type: Number, default: 0 }
  19. , points: {
  20. listener: { type: Number, default: 0 }
  21. , curator: { type: Number, default: 0 }
  22. , dj: { type: Number, default: 0 }
  23. , man: { type: Number, default: 0 }
  24. }
  25. , lastChat: { type: Date }
  26. , bio: { type: String, max: 1024 }
  27. , avatar: {
  28. 'set': String
  29. , 'key': String
  30. , 'uri': String
  31. , 'thumb': String
  32. }
  33. });
  34. var songSchema = mongoose.Schema({
  35. author: String
  36. , id: { type: String, index: true }
  37. , cid: String
  38. , plugID: String
  39. , format: String
  40. , title: String
  41. , duration: Number
  42. , lastPlay: Date
  43. , nsfw: Boolean
  44. });
  45. var historySchema = mongoose.Schema({
  46. _song: { type: ObjectId, ref: 'Song', required: true }
  47. , _dj: { type: ObjectId, ref: 'Person', required: true }
  48. , timestamp: { type: Date }
  49. , curates: [ new Schema({
  50. _person: { type: ObjectId, ref: 'Person', required: true }
  51. }) ]
  52. , downvotes: { type: Number, default: 0 }
  53. , upvotes: { type: Number, default: 0 }
  54. , votes: [ new Schema({
  55. _person: { type: ObjectId, ref: 'Person', required: true }
  56. , vote: { type: String, enum: ['up', 'down'] }
  57. }) ]
  58. });
  59. var chatSchema = mongoose.Schema({
  60. timestamp: { type: Date, default: Date.now }
  61. , _person: { type: ObjectId, ref: 'Person', required: true }
  62. , message: { type: String, required: true }
  63. });
  64. personSchema.virtual('points.total').get(function () {
  65. return this.points.dj + this.points.curator + this.points.listener;
  66. });
  67. historySchema.virtual('isoDate').get(function() {
  68. return this.timestamp.toISOString();
  69. });
  70. chatSchema.virtual('isoDate').get(function() {
  71. return this.timestamp.toISOString();
  72. });
  73. var Person = db.model('Person', personSchema);
  74. var Song = db.model('Song', songSchema);
  75. var History = db.model('History', historySchema);
  76. var Chat = db.model('Chat', chatSchema);
  77. module.exports = {
  78. snarl: "Ohaithar. I'm a bot created by @remæus. Blame him for any of my supposed mistakes."
  79. , source: "You can see all my insides (and submit modifications) here: http://github.com/martindale/snarl"
  80. , about: 'About Coding Soundtrack: http://codingsoundtrack.org/about'
  81. , afk: 'If you\'re AFK at the end of your song for longer than 30 minutes you get warning 1. One minute later you get warning 2, another minute last warning, 30 seconds [boot].'
  82. , askforseat: 'Please don\'t ask for seats here. It\'s first come, first serve, and free for all.'
  83. , bitch: 'Not a lot of things are against the rules, but bitching about the music is. Stop being a bitch.'
  84. , stfu: 'Please, shut your mouth and just enjoy the music.'
  85. , overlord: 'ALL HAIL THE OVERLORD! http://codingsoundtrack.org/boycey'
  86. , commandments: 'Coding Soundtrack\'s 10 Commandments: http://codingsoundtrack.org/ten-commandments'
  87. , rules: 'No song limits, no queues, no auto-DJ. Pure FFA. DJ\'s over 10 minutes idle (measured by chat) face the [boot]. See !music for music suggestions, though there are no defined or enforced rules on music. More: http://codingsoundtrack.org/rules' // formerly: http://goo.gl/b7UGO
  88. , selection: 'Song Selection Guide: http://codingsoundtrack.org/song-selection'
  89. , suitup: 'Suit up, motherfucker!'
  90. , netsplit: 'plug.dj has been having a lot of issues lately, especially with chat becoming fragmented. Some people can chat with each other, and others can\'t see those messages. Relax, @Boycey will have it fixed soon.'
  91. , plugin: 'Coding Soundtrack is best enjoyed with jarPlug: https://chrome.google.com/webstore/detail/jarplug/anhldmgeompmlcmdcpbgdecdokhedlaa'
  92. , tags: 'Please edit the tags of the songs on your playlists to exclude things like [VIDEO] and [OFFICIAL]. It\'s a data thing, man!'
  93. , video: 'dat video.'
  94. , smellslike: 'PISSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS'
  95. , force: '/me senses a disturbance in the force.'
  96. , smiffhour: 'Lock & Load your smiff tracks !djs for the next hour we spin strictly smiff.'
  97. , ping: 'pong!'
  98. , awesome: function(data) {
  99. var self = this;
  100. this.woot(function() {
  101. console.log('Voted.');
  102. self.chat('Agreed, this track is svelte! Wooted.');
  103. });
  104. }
  105. , lame: function(data) {
  106. var self = this;
  107. this.meh(function() {
  108. console.log('Voted.');
  109. self.chat('Mmm, not so hot. Meh\'d.');
  110. });
  111. }
  112. , notsmiff: function(data) {
  113. var self = this;
  114. this.meh(function() {
  115. console.log('Voted.');
  116. self.chat('Hey, wait a second. This isn\'t smiff. D:');
  117. });
  118. }
  119. , bio: function(data) {
  120. var self = this;
  121. if (typeof(data.params) != 'undefined' && data.params.trim().length > 0) {
  122. data.person.bio = data.params.trim();
  123. data.person.save(function(err) {
  124. self.chat('Bio saved! Profile link: http://codingsoundtrack.org/djs/' + data.fromID );
  125. });
  126. } else {
  127. if (typeof(data.person.bio) != 'undefined' && data.person.bio.length > 0) {
  128. self.chat('You must provide a string for your bio. Markdown is accepted. Your current bio is: “'+data.person.bio+'”');
  129. } else {
  130. self.chat('You must provide a string for your bio. Markdown is accepted.');
  131. }
  132. }
  133. }
  134. , catfacts: function(data) {
  135. var self = this;
  136. rest.get('http://catfacts-api.appspot.com/api/facts').on('complete', function(response) {
  137. response = JSON.parse(response);
  138. if (response.facts && response.facts.length > 0) {
  139. self.chat(response.facts[0]);
  140. }
  141. });
  142. }
  143. , topologyfacts: function(data) {
  144. var self = this;
  145. self.chat(randomFact('topology'));
  146. }
  147. , interstellafacts: function(data) {
  148. var self = this;
  149. self.chat(randomFact('interstella'));
  150. }
  151. , get smifffax () { return this.smifffacts }
  152. , smifffacts: function(data) {
  153. var self = this;
  154. self.chat(randomFact('smiff'));
  155. }
  156. , remæusfacts: function(data) {
  157. var self = this;
  158. self.chat('remæus\' third word was "combine". His first was "truck," and his second "bobtail".');
  159. }
  160. , boss: function(data) {
  161. var self = this;
  162. self.chat('The best play of all time was... @' + self.records.boss._dj.name + ' with ' + self.records.boss.curates.length + ' snags of their play of ' + self.records.boss._song.title + ' on ' + self.records.boss.timestamp + '! More: http://codingsoundtrack.org/history/' + self.records.boss._id );
  163. }
  164. , cb: function(data) {
  165. var self = this;
  166. self.chat('GTFO, @' + self.from +'!');
  167. }
  168. , count: function(data) {
  169. var self = this;
  170. self.chat('I am currently aware of ' + _.toArray(self.room.audience).length + ' audience members.');
  171. }
  172. , djs: function(data) {
  173. var self = this;
  174. var now = new Date();
  175. var idleDJs = [];
  176. _.toArray(self.room.djs).forEach(function(dj) {
  177. if (typeof(dj.lastChat) != 'undefined') {
  178. if (dj.lastChat.getTime() <= (now.getTime() - 300000)) {
  179. dj.idleTime = (now.getTime() - dj.lastChat.getTime()) / 1000;
  180. idleDJs.push(dj);
  181. }
  182. }
  183. });
  184. idleDJs = idleDJs.map(function(item) {
  185. var idleTime = secondsToTime(item.idleTime);
  186. var idleTimeString = '';
  187. var idleTimeString = (idleTime.h > 0) ? '('+ idleTime.h +'h'+ idleTime.m +'m'+idleTime.s+'s)' : '('+ idleTime.m +'m'+idleTime.s+'s)';
  188. if(item.idleTime < 600)
  189. return item.name + ' '+idleTimeString;
  190. return '@' + item.name + ' '+idleTimeString;
  191. });
  192. if (idleDJs.length > 0) {
  193. self.chat('Idle: ' + oxfordJoin(idleDJs));
  194. } else {
  195. self.chat('No idle DJs!');
  196. }
  197. }
  198. , donkeypunch: function(data) {
  199. var self = this;
  200. var randomSeed = getRandomInt(1, 100);
  201. Person.findOne({ $or: [ { plugID: data.fromID }, { name: data.from } ] }).exec(function(err, person) {
  202. if (!person) {
  203. var person = new Person({
  204. name: data.from
  205. , plugID: data.fromID
  206. });
  207. }
  208. person.points.man += randomSeed;
  209. person.save(function(err) {
  210. Person.count({}, function(err, totalPeople) {
  211. var fivePercent = Math.floor(totalPeople * 0.0006);
  212. var chanceToLose = 50;
  213. Person.find({}).sort('-points.man').limit(fivePercent).exec(function(err, manlyMen) {
  214. var manlyMenMap = manlyMen.map(function(man) {
  215. return man.plugID;
  216. });
  217. if (randomSeed <= chanceToLose) {
  218. self.chat('DONKEY PUNNNNNCH! ' + randomFact('donkey'));
  219. self.chat('/me donkeypunches ' + data.from +'.');
  220. person.points.man = 0;
  221. person.save(function(err) {
  222. if (err) { console.log(err); }
  223. });
  224. } else {
  225. if (manlyMenMap.indexOf(data.fromID) >= 0) {
  226. self.chat('@' + data.from + ' is ' + randomFact('compliment') + '.');
  227. } else if ( randomSeed > chanceToLose ) {
  228. self.chat('@' + data.from + ' is alright.');
  229. }
  230. }
  231. });
  232. });
  233. });
  234. });
  235. }
  236. , manly: function(data) {
  237. var self = this;
  238. Person.count({}, function(err, totalPeople) {
  239. var fivePercent = Math.floor(totalPeople * 0.0006);
  240. Person.find({}).sort('-points.man').limit(fivePercent).exec(function(err, manlyMen) {
  241. var manlyManMap = manlyMen.map(function(man) {
  242. return '@' + man.name;
  243. });
  244. //console.log( 'Manly: ' + manlyManMap.join(', ') )
  245. self.chat('Manly: ' + manlyManMap.join(', '));
  246. });
  247. });
  248. }
  249. , erm: function(data) {
  250. var self = this;
  251. if (typeof(data.params) != 'undefined') {
  252. self.chat(ermgerd(data.params));
  253. }
  254. }
  255. , mods: function(data) {
  256. var self = this;
  257. var onlineStaff = [];
  258. var realModerators = [];
  259. _.toArray(self.room.staff).forEach(function(staffMember) {
  260. if ( self.room.staff[staffMember.plugID].role > 1 ) {
  261. realModerators.push(staffMember);
  262. }
  263. });
  264. _.intersection(
  265. _.toArray(realModerators).map(function(staffMember) {
  266. return staffMember._id.toString();
  267. }),
  268. _.toArray(self.room.audience).map(function(audienceMember) {
  269. return audienceMember._id.toString();
  270. })
  271. ).forEach(function(staffMember) {
  272. onlineStaff.push(staffMember);
  273. });
  274. Person.find({ _id: { $in: onlineStaff } }).exec(function(err, staff) {
  275. self.chat(staff.length + ' online staff members: ' + staff.map(function(staffMember) {
  276. console.log(staffMember);
  277. console.log(self.room.staff);
  278. //return staffMember.name + self.room.staff[staffMember.plugID].role;
  279. return '@' + staffMember.name;
  280. }).join(', ') );
  281. });
  282. }
  283. , nsfw: function(data) {
  284. var self = this;
  285. var staffMap = [];
  286. _.toArray(self.room.staff).forEach(function(staffMember) {
  287. if ( self.room.staff[staffMember.plugID].role >= 1 ) {
  288. staffMap.push(staffMember.plugID);
  289. }
  290. });
  291. if (staffMap.indexOf( data.fromID ) > -1) {
  292. Song.findOne({ id: self.currentSong.id }).exec(function(err, song) {
  293. if (err) {
  294. console.log(err);
  295. }
  296. else {
  297. song.nsfw = true;
  298. song.save(function(err) {
  299. if (err) {
  300. console.log(err);
  301. }
  302. else {
  303. self.chat('Song updated. NSFW tag added.')
  304. }
  305. });
  306. }
  307. });
  308. }
  309. self.chat('Please give people who are listening at work fair warning about NSFW videos. It\'s common courtesy for people who don\'t code from home or at an awesome startup like LocalSense!');
  310. }
  311. , sfw: function(data) {
  312. var self = this;
  313. var staffMap = [];
  314. _.toArray(self.room.staff).forEach(function(staffMember) {
  315. if ( self.room.staff[staffMember.plugID].role >= 1 ) {
  316. staffMap.push(staffMember.plugID);
  317. }
  318. });
  319. if (staffMap.indexOf( data.fromID ) > -1) {
  320. Song.findOne({ id: self.currentSong.id }).exec(function(err, song) {
  321. if (err) {
  322. console.log(err);
  323. }
  324. else {
  325. song.nsfw = false;
  326. song.save(function(err) {
  327. if (err) {
  328. console.log(err);
  329. }
  330. else {
  331. self.chat('Song updated to SFW.')
  332. }
  333. });
  334. }
  335. });
  336. }
  337. else {
  338. self.chat('I\'ll take that into consideration. Maybe.');
  339. }
  340. }
  341. , permalink: function(data) {
  342. var self = this;
  343. self.chat('Song: http://codingsoundtrack.org/songs/' + self.room.track.id );
  344. }
  345. , plugid: function(data) {
  346. var self = this;
  347. self.chat('plug.dj calls you "'+ data.fromID +'". Are you gonna take that?');
  348. }
  349. , profile: function(data) {
  350. var self = this;
  351. if (typeof(data.params) != 'undefined' && data.params.trim().length > 0) {
  352. Person.findOne({ name: data.params }).exec(function(err, person) {
  353. if (!person) {
  354. self.chat('/me could not find a profile by that name.');
  355. } else {
  356. self.chat('@' + data.params + ': “'+person.bio+'” More: http://codingsoundtrack.org/djs/'+ person.plugID)
  357. }
  358. });
  359. } else {
  360. self.chat('Whose profile did you want?');
  361. }
  362. }
  363. , songtitle: function(data) {
  364. var self = this;
  365. var staffMap = [];
  366. _.toArray(self.room.staff).forEach(function(staffMember) {
  367. if ( self.room.staff[staffMember.plugID].role >= 1 ) {
  368. staffMap.push(staffMember.plugID);
  369. }
  370. });
  371. if (staffMap.indexOf( data.fromID ) == -1) {
  372. self.chat('I\'ll take that into consideration. Maybe.');
  373. } else {
  374. Song.findOne({ id: self.currentSong.id }).exec(function(err, song) {
  375. if (err) { console.log(err); } else {
  376. if (data.params.length > 0) {
  377. var previousTitle = song.title;
  378. song.title = data.params;
  379. song.save(function(err) {
  380. self.chat('Song title updated, from "'+previousTitle+ '" to "'+song.title+'". Link: http://codingsoundtrack.org/songs/' + self.room.track.id );
  381. });
  382. } else {
  383. self.chat('What do you want to set the title of this song to? I need a parameter.');
  384. }
  385. }
  386. });
  387. }
  388. }
  389. , songartist: function(data) {
  390. var self = this;
  391. var staffMap = [];
  392. _.toArray(self.room.staff).forEach(function(staffMember) {
  393. if ( self.room.staff[staffMember.plugID].role >= 1 ) {
  394. staffMap.push(staffMember.plugID);
  395. }
  396. });
  397. if (staffMap.indexOf( data.fromID ) == -1) {
  398. self.chat('I\'ll take that into consideration. Maybe.');
  399. } else {
  400. Song.findOne({ id: self.currentSong.id }).exec(function(err, song) {
  401. if (err) { console.log(err); } else {
  402. if (data.params.length > 0) {
  403. var previousAuthor = song.author;
  404. song.author = data.params;
  405. song.save(function(err) {
  406. self.chat('Song artist updated, from "'+previousAuthor+ '" to "'+song.author+'". Link: http://codingsoundtrack.org/songs/' + self.room.track.id );
  407. });
  408. } else {
  409. self.chat('What do you want to set the author of this song to? I need a parameter.');
  410. }
  411. }
  412. });
  413. }
  414. }
  415. , songplays: function(data) {
  416. var self = this;
  417. console.log('looking up: ' + JSON.stringify(self.currentSong));
  418. Song.findOne({ id: self.currentSong.id }).exec(function(err, song) {
  419. if (err) { console.log(err); } else {
  420. History.count({ _song: song._id }, function(err, count) {
  421. self.chat('This song has been played ' + count + ' times in recorded history.');
  422. });
  423. }
  424. });
  425. }
  426. , distracting: 'Try not to play songs that would be distracting to someone trying to write code. Stay on theme as much as possible!'
  427. , lastplayed: function(data) {
  428. var self = this;
  429. History.find({ _song: self.room.track._id }).sort('-timestamp').limit(2).populate('_dj').exec(function(err, history) {
  430. var lastPlay = history[1];
  431. if (lastPlay) {
  432. History.count({ _song: self.room.track._id }).exec(function(err, count) {
  433. self.chat('This song was last played ' + timeago(lastPlay.timestamp) + ' by @' + lastPlay._dj.name + '. It\'s been played ' + count + ' times in total. More: http://codingsoundtrack.org/songs/' + self.room.track.id );
  434. });
  435. } else {
  436. self.chat('I haven\'t heard this song before now.');
  437. }
  438. });
  439. }
  440. , firstplayed: function(data) {
  441. var self = this;
  442. if (typeof(self.room.track._id) != 'undefined') {
  443. History.findOne({ _song: self.room.track._id }).sort('+timestamp').populate('_dj').exec(function(err, firstPlay) {
  444. History.count({ _song: self.room.track._id }).exec(function(err, count) {
  445. self.chat('@' + firstPlay._dj.name + ' was the first person to play this song! Since then, it\'s been played ' + count + ' times. More: http://codingsoundtrack.org/songs/' + self.room.track.id );
  446. });
  447. });
  448. } else {
  449. self.chat('Hold on, I\'m still booting up. Gimme a minute.');
  450. }
  451. }
  452. , lastsong: function(data) {
  453. var self = this;
  454. History.find({}).sort('-timestamp').limit(2).populate('_song').exec(function(err, history) {
  455. if (history.length <= 1) {
  456. self.chat("I've not been alive long enough to know that, Dave.");
  457. } else {
  458. var lastSong = history[1]._song;
  459. self.chat('The last song was “'+ lastSong.title +'” by '+ lastSong.author + '.');
  460. }
  461. });
  462. }
  463. , music: function(data) {
  464. var self = this;
  465. var time = new Date().getUTCHours() - 5;
  466. if ( 0 <= time && time < 5) {
  467. self.chat("Evening! Keep the tempo up, it's the only thing keeping the all nighters going.");
  468. } else if ( 5 <= time && time < 12 ) {
  469. self.chat("AM! Chill tracks with good beats, most programmers are slow to wake so don't hit them with hard hitting tunes. Wubs are widely discouraged this early.");
  470. } else if (12 <= time && time < 17 ){
  471. self.chat('Afternoon! Fresh tracks for fresh people.');
  472. } else {
  473. self.chat("Evening! Most people are out of work so things are a lot more fluid and much less harsh. Seats are easy to get, spin a few if you want but don't hog the decks!");
  474. }
  475. }
  476. , history: function(data) {
  477. var self = this;
  478. History.count({}, function(err, count) {
  479. self.chat('There are ' + count + ' songs in recorded history: http://codingsoundtrack.org/history');
  480. });
  481. }
  482. , popular: function(data) {
  483. var self = this;
  484. Person.find().sort('-karma').limit(3).exec(function(err, people) {
  485. var names = people.map(function(person) {
  486. return '@' + person.name;
  487. });
  488. self.chat(oxfordJoin(names) + ' are all the rage these days. See more: http://codingsoundtrack.org/djs');
  489. });
  490. }
  491. , karma: function(data) {
  492. var self = this;
  493. Person.findOne({ $or: [ { plugID: data.fromID }, { name: data.from } ] }).exec(function(err, person) {
  494. if (!person) {
  495. var person = new Person({
  496. name: data.from
  497. , plugID: data.fromID
  498. });
  499. person.save(function(err) {
  500. self.chat('Karma is an arbitrary count of times that people have said your name followed by ++. You can find yours at http://codingsoundtrack.org/djs/' + data.fromID );
  501. });
  502. } else {
  503. self.chat('Karma is an arbitrary count of times that people have said your name followed by ++. You can find yours at http://codingsoundtrack.org/djs/' + data.fromID );
  504. }
  505. });
  506. }
  507. , trout: function(data) {
  508. var target = data.from;
  509. if (typeof(data.params) != 'undefined' && data.params.trim().length > 0) {
  510. target = data.params.trim();
  511. }
  512. this.chat('/me slaps ' + target + ' around a bit with a large trout.');
  513. }
  514. , falconpunch: function(data) {
  515. this.chat('/me falcon punches ' + data.from + ' out of a 13-story window.')
  516. }
  517. , brew: function(data) {
  518. var self = this;
  519. if (typeof(data.params) != 'undefined') {
  520. rest.get('http://api.brewerydb.com/v2/search?q=' + data.params + '&key=7c05e35f30f5fbb823ec4731735eb2eb').on('complete', function(api) {
  521. if (typeof(api.data) != 'undefined' && api.data.length > 0) {
  522. if (typeof(api.data[0].description) != 'undefined') {
  523. self.chat(api.data[0].name + ': ' + api.data[0].description);
  524. } else {
  525. self.chat(api.data[0].name + ' is a good beer, but I don\'t have a good way to describe it.');
  526. }
  527. } else {
  528. self.chat('Damn, I\'ve never heard of that. Where do I need to go to find it?');
  529. }
  530. });
  531. } else {
  532. self.chat('No query provided.');
  533. }
  534. }
  535. , urban: function(data) {
  536. var self = this;
  537. if (typeof(data.params) != 'undefined') {
  538. rest.get('http://api.urbandictionary.com/v0/define?term='+data.params).on('complete', function(data) {
  539. self.chat(data.list[0].definition);
  540. });
  541. } else {
  542. self.chat('No query provided.');
  543. }
  544. }
  545. , duckduckgo: function(data) {
  546. var self = this;
  547. var client = new ddg.SearchClient();
  548. if (typeof(data.params) != 'undefined') {
  549. client.search(data.params, function(error, response, ddgData) {
  550. if (!error && response.statusCode == 200) {
  551. console.log(ddgData);
  552. if (ddgData.Abstract.length > 0) {
  553. self.chat(ddgData.Abstract);
  554. } else if (ddgData.Definition.length > 0) {
  555. self.chat(ddgData.Definition);
  556. } else {
  557. self.chat('No results found.');
  558. }
  559. } else {
  560. console.log("ERROR! " + error + "/" + response.statusCode);
  561. }
  562. });
  563. } else {
  564. self.chat('No query provided.');
  565. }
  566. }
  567. ,define: function (data) {
  568. var self = this, finalMsg;
  569. if (!data.params) {
  570. finalMsg = "You have to provide the word...";
  571. self.chat(finalMsg);
  572. } else {
  573. var word = data.params.split(" ").join("").split(',');
  574. var url = "http://api.wordnik.com//v4/word.json/" + word[0] + "/definitions?includeRelated=false&includeTags=false&limit=1&useCanonical=false&api_key=4b9d570699e20d6a5d00104d9e50a041c7e8547b7f448c627";
  575. if (word[1]) {
  576. url = url + "&partOfSpeech=" + word[1];
  577. };
  578. rest.get(url).on('complete', function (msg) {
  579. if (msg[0]) {
  580. finalMsg = msg[0].text;
  581. } else {
  582. finalMsg = "No definitions found :*(";
  583. }
  584. self.chat(finalMsg);
  585. });
  586. }
  587. }
  588. , google: function(data) {
  589. var self = this;
  590. if (typeof(data.params) != 'undefined') {
  591. google(data.params, function(err, next, links) {
  592. if (err) { console.log(err); }
  593. if (typeof(links[0]) != 'undefined') {
  594. self.chat(links[0].title + ': ' + links[0].link);
  595. }
  596. });
  597. } else {
  598. self.chat('No query provided.');
  599. }
  600. }
  601. , get snarlsource () { return this.source; }
  602. , debug: function(data) { this.chat(JSON.stringify(data)) }
  603. , get afpdj () { return this.afk; }
  604. , get aftt () { return this.afk; }
  605. , get boycey () { return this.overlord; }
  606. , get ddg () { return this.duckduckgo; }
  607. , get dp () { return this.donkeypunch; }
  608. , get jarplug () { return this.plugin; }
  609. , get woot () { return this.awesome; }
  610. , get meh () { return this.lame; }
  611. }
  612. function oxfordJoin(array) {
  613. if (array instanceof Array) {
  614. } else {
  615. array = _.toArray(array).map(function(item) {
  616. return item.name;
  617. });
  618. }
  619. var string = '';
  620. if (array.length <= 1) {
  621. string = array.join();
  622. } else {
  623. string = array.slice(0, -1).join(", ") + ", and " + array[array.length-1];
  624. }
  625. return string;
  626. }
  627. function secondsToTime(secs) {
  628. var hours = Math.floor(secs / (60 * 60));
  629. var divisor_for_minutes = secs % (60 * 60);
  630. var minutes = Math.floor(divisor_for_minutes / 60);
  631. var divisor_for_seconds = divisor_for_minutes % 60;
  632. var seconds = Math.ceil(divisor_for_seconds);
  633. var obj = {
  634. "h": hours,
  635. "m": minutes,
  636. "s": seconds
  637. };
  638. return obj;
  639. }
  640. function randomFact(type) {
  641. var ar = facts[type];
  642. return ar[Math.round(Math.random()*(ar.length-1))];
  643. }
  644. function getRandomInt (min, max) {
  645. return Math.floor(Math.random() * (max - min + 1)) + min;
  646. }
  647. function ermgerd(text) {
  648. text = text.toUpperCase();
  649. var words = text.split(' '),
  650. translatedWords = [];
  651. for (var j in words) {
  652. var prefix = words[j].match(/^\W+/) || '',
  653. suffix = words[j].match(/\W+$/) || '',
  654. word = words[j].replace(prefix, '').replace(suffix, '');
  655. if (word) {
  656. // Is translatable
  657. translatedWords.push(prefix + translate(word) + suffix);
  658. } else {
  659. // Is punctuation
  660. translatedWords.push(words[j]);
  661. }
  662. }
  663. return translatedWords.join(' ');
  664. }
  665. function str_split(string, split_length) {
  666. // http://kevin.vanzonneveld.net
  667. // + original by: Martijn Wieringa
  668. // + improved by: Brett Zamir (http://brett-zamir.me)
  669. // + bugfixed by: Onno Marsman
  670. // + revised by: Theriault
  671. // + input by: Bjorn Roesbeke (http://www.bjornroesbeke.be/)
  672. // + revised by: Rafał Kukawski (http://blog.kukawski.pl/)
  673. // * example 1: str_split('Hello Friend', 3);
  674. // * returns 1: ['Hel', 'lo ', 'Fri', 'end']
  675. if (split_length === null) {
  676. split_length = 1;
  677. }
  678. if (string === null || split_length < 1) {
  679. return false;
  680. }
  681. string += '';
  682. var chunks = [],
  683. pos = 0,
  684. len = string.length;
  685. while (pos < len) {
  686. chunks.push(string.slice(pos, pos += split_length));
  687. }
  688. return chunks;
  689. };
  690. function translate(word) {
  691. // Don't translate short words
  692. if (word.length == 1) {
  693. return word;
  694. }
  695. // Handle specific words
  696. switch (word) {
  697. case 'AWESOME': return 'ERSUM';
  698. case 'BANANA': return 'BERNERNER';
  699. case 'BAYOU': return 'BERU';
  700. case 'FAVORITE':
  701. case 'FAVOURITE': return 'FRAVRIT';
  702. case 'GOOSEBUMPS': return 'GERSBERMS';
  703. case 'LONG': return 'LERNG';
  704. case 'MY': return 'MAH';
  705. case 'THE': return 'DA';
  706. case 'THEY': return 'DEY';
  707. case 'WE\'RE': return 'WER';
  708. case 'YOU': return 'U';
  709. case 'YOU\'RE': return 'YER';
  710. }
  711. // Before translating, keep a reference of the original word
  712. var originalWord = word;
  713. // Drop vowel from end of words
  714. if (originalWord.length > 2) { // Keep it for short words, like "WE"
  715. word = word.replace(/[AEIOU]$/, '');
  716. }
  717. // Reduce duplicate letters
  718. word = word.replace(/[^\w\s]|(.)(?=\1)/gi, '');
  719. // Reduce adjacent vowels to one
  720. word = word.replace(/[AEIOUY]{2,}/g, 'E'); // TODO: Keep Y as first letter
  721. // DOWN -> DERN
  722. word = word.replace(/OW/g, 'ER');
  723. // PANCAKES -> PERNKERKS
  724. word = word.replace(/AKES/g, 'ERKS');
  725. // The meat and potatoes: replace vowels with ER
  726. word = word.replace(/[AEIOUY]/g, 'ER'); // TODO: Keep Y as first letter
  727. // OH -> ER
  728. word = word.replace(/ERH/g, 'ER');
  729. // MY -> MAH
  730. word = word.replace(/MER/g, 'MAH');
  731. // FALLING -> FALERNG -> FERLIN
  732. word = word.replace('ERNG', 'IN');
  733. // POOPED -> PERPERD -> PERPED
  734. word = word.replace('ERPERD', 'ERPED');
  735. // MEME -> MAHM -> MERM
  736. word = word.replace('MAHM', 'MERM');
  737. // Keep Y as first character
  738. // YES -> ERS -> YERS
  739. if (originalWord.charAt(0) == 'Y') {
  740. word = 'Y' + word;
  741. }
  742. // Reduce duplicate letters
  743. word = word.replace(/[^\w\s]|(.)(?=\1)/gi, '');
  744. // YELLOW -> YERLER -> YERLO
  745. if ((originalWord.substr(-3) == 'LOW') && (word.substr(-3) == 'LER')) {
  746. word = word.substr(0, word.length - 3) + 'LO';
  747. }
  748. return word;
  749. };