No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

parrot.py 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
  5. # See LICENSE.txt for copyright info
  6. from __future__ import with_statement
  7. from frn.protocol.client import FRNClient, FRNClientFactory
  8. from frn.user import FRNUser
  9. from twisted.internet import reactor, task
  10. from twisted.internet.defer import DeferredList
  11. from twisted.python import log
  12. import os, string
  13. safe_chars = string.ascii_letters+string.digits+' :;.,+-=$@'
  14. PARROT_AUDIO_DELAY = 5.0
  15. def sanitizeFilename(name):
  16. r = ''
  17. for c in name:
  18. if c in safe_chars:
  19. r += c
  20. return r
  21. class FRNParrot(FRNClient):
  22. def getClientName(self, client_id):
  23. if self.clientsById.has_key(client_id):
  24. return self.clientsById[client_id]['ON']
  25. else:
  26. return client_id
  27. def textMessageReceived(self, client, message, target):
  28. log.msg("Type %s message from %s: %s" %
  29. (target, self.getClientName(client), message))
  30. if target == 'P': # Only reply to private messages
  31. if not message.startswith('play'):
  32. self.sendTextMessage(client, message)
  33. else:
  34. cmd = message.split()
  35. if len(cmd) > 1:
  36. message = sanitizeFilename(cmd[1])
  37. else:
  38. message = 'monkeys'
  39. filename = 'sounds/%s.wav' % message
  40. if os.path.exists(filename):
  41. log.msg("Streaming file %s" % filename)
  42. with file(filename, 'rb') as sf:
  43. sf.seek(0x3c) # Skip wav header
  44. while True:
  45. b = sf.read(325)
  46. if len(b) < 325:
  47. break
  48. self.feedStreaming(b)
  49. self.factory.reactor.callLater(0.5,
  50. self.startStreaming)
  51. else:
  52. self.sendTextMessage(client, "File not found")
  53. def stopTransmission(self):
  54. FRNClient.stopTransmission(self)
  55. log.msg("Stopped playback.")
  56. def startRepeating(self, from_id):
  57. log.msg("%s stopped talking: starting playback." %
  58. self.clients[from_id-1]['ON'])
  59. self.startStreaming()
  60. def audioFrameReceived(self, from_id, frames):
  61. recname = sanitizeFilename(self.clients[from_id-1]['ON'])
  62. with file('recordings/%s.gsm' % recname, 'ab') as f:
  63. f.write(frames)
  64. self.feedStreaming(frames)
  65. try:
  66. self.parrot_timer.reset(PARROT_AUDIO_DELAY)
  67. except:
  68. log.msg("%s started talking" %
  69. self.clients[from_id-1]['ON'])
  70. self.parrot_timer = self.factory.reactor.callLater(
  71. PARROT_AUDIO_DELAY, self.startRepeating, from_id)
  72. self.pong()
  73. def loginResponse(self, info):
  74. log.msg("Login: %s" % info['AL'])
  75. def clientsListUpdated(self, clients):
  76. self.clients = clients
  77. self.clientsById = dict([(i['ID'], i) for i in clients])
  78. class FRNParrotFactory(FRNClientFactory):
  79. protocol = FRNParrot
  80. reactor = reactor
  81. if __name__ == '__main__':
  82. import sys
  83. from os.path import dirname, join as pjoin
  84. from ConfigParser import ConfigParser
  85. log.startLogging(sys.stderr)
  86. basedir = dirname(__file__)
  87. acfg = ConfigParser()
  88. acfg.read(['/etc/grn/accounts.conf',
  89. pjoin(basedir,'accounts.conf'), 'accounts.conf'])
  90. scfg = ConfigParser()
  91. scfg.read(['/etc/grn/servers.conf',
  92. pjoin(basedir,'servers.conf'), 'servers.conf'])
  93. argc = len(sys.argv)
  94. if argc >= 3:
  95. server_name, network_name = sys.argv[2].split(':',1)
  96. account_cfg = acfg.items(sys.argv[1])+[('network', network_name)]
  97. server_cfg = scfg.items(server_name)
  98. server = scfg.get(server_name, 'server')
  99. port = scfg.getint(server_name, 'port')
  100. d = dict(account_cfg)
  101. user = FRNUser(
  102. EA=d['email'],
  103. PW=d['password'], ON=d['operator'],
  104. BC=d['transmission'], DS=d['description'],
  105. NN=d['country'], CT=d['city'], NT=d['network'])
  106. reactor.connectTCP(server, port, FRNParrotFactory(user))
  107. reactor.run()
  108. # vim: set et ai sw=4 ts=4 sts=4: