airtime-import 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. #!/usr/bin/python2 import sys
  2. import os
  3. import logging
  4. from configobj import ConfigObj
  5. from optparse import OptionParser, OptionValueError
  6. from api_clients import api_client as apc
  7. import json
  8. import shutil
  9. import commands
  10. #sys.path.append('/usr/lib/airtime/media-monitor/mm2/')
  11. from mm2.media.monitor.pure import is_file_supported
  12. # create logger
  13. logger = logging.getLogger()
  14. # no logging
  15. ch = logging.StreamHandler()
  16. logging.disable(50)
  17. # add ch to logger
  18. logger.addHandler(ch)
  19. if (os.geteuid() != 0):
  20. print 'Must be a root user.'
  21. sys.exit()
  22. # loading config file
  23. try:
  24. config = ConfigObj('/etc/airtime/airtime.conf')
  25. except Exception, e:
  26. print('Error loading config file: %s', e)
  27. sys.exit()
  28. api_client = apc.AirtimeApiClient(config)
  29. #helper functions
  30. # copy or move files
  31. # flag should be 'copy' or 'move'
  32. def copy_or_move_files_to(paths, dest, flag):
  33. try:
  34. for path in paths:
  35. if (path[0] == "/" or path[0] == "~"):
  36. path = os.path.realpath(path)
  37. else:
  38. path = currentDir+path
  39. path = apc.encode_to(path, 'utf-8')
  40. dest = apc.encode_to(dest, 'utf-8')
  41. if(os.path.exists(path)):
  42. if(os.path.isdir(path)):
  43. path = format_dir_string(path)
  44. #construct full path
  45. sub_path = []
  46. for temp in os.listdir(path):
  47. sub_path.append(path+temp)
  48. copy_or_move_files_to(sub_path, dest, flag)
  49. elif(os.path.isfile(path)):
  50. #copy file to dest
  51. if(is_file_supported(path)):
  52. destfile = dest+os.path.basename(path)
  53. if(flag == 'copy'):
  54. print "Copying %(src)s to %(dest)s..." % {'src':path, 'dest':destfile}
  55. shutil.copyfile(path, destfile)
  56. elif(flag == 'move'):
  57. print "Moving %(src)s to %(dest)s..." % {'src':path, 'dest':destfile}
  58. shutil.move(path, destfile)
  59. else:
  60. print "Cannot find file or path: %s" % path
  61. except Exception as e:
  62. print "Error: ", e
  63. def format_dir_string(path):
  64. if(path[-1] != '/'):
  65. path = path+'/'
  66. return path
  67. def helper_get_stor_dir():
  68. try:
  69. res = api_client.list_all_watched_dirs()
  70. except Exception, e:
  71. return res
  72. if(res['dirs']['1'][-1] != '/'):
  73. out = res['dirs']['1']+'/'
  74. return out
  75. else:
  76. return res['dirs']['1']
  77. def checkOtherOption(args):
  78. for i in args:
  79. if(i[0] == '-'):
  80. return True
  81. def errorIfMultipleOption(args, msg=''):
  82. if(checkOtherOption(args)):
  83. if(msg != ''):
  84. raise OptionValueError(msg)
  85. else:
  86. raise OptionValueError("This option cannot be combined with other options")
  87. def printHelp():
  88. storage_dir = helper_get_stor_dir()
  89. if(storage_dir is None):
  90. storage_dir = "Unknown"
  91. else:
  92. storage_dir += "imported/"
  93. print """
  94. ========================
  95. Airtime Import Script
  96. ========================
  97. There are two ways to import audio files into Airtime:
  98. 1) Use airtime-import to copy or move files into the storage folder.
  99. Copied or moved files will be placed into the folder:
  100. %s
  101. Files will be automatically organized into the structure
  102. "Artist/Album/TrackNumber-TrackName-Bitrate.file_extension".
  103. 2) Use airtime-import to add a folder to the Airtime library ("watch" a folder).
  104. All the files in the watched folder will be imported to Airtime and the
  105. folder will be monitored to automatically detect any changes. Hence any
  106. changes done in the folder(add, delete, edit a file) will trigger
  107. updates in Airtime library.
  108. """ % storage_dir
  109. parser.print_help()
  110. print ""
  111. def CopyAction(option, opt, value, parser):
  112. errorIfMultipleOption(parser.rargs)
  113. if(len(parser.rargs) == 0 ):
  114. raise OptionValueError("No argument found. This option requires at least one argument.")
  115. stor = helper_get_stor_dir()
  116. if(stor is None):
  117. print "Unable to connect to the Airtime server."
  118. return
  119. dest = stor+"organize/"
  120. copy_or_move_files_to(parser.rargs, dest, 'copy')
  121. def MoveAction(option, opt, value, parser):
  122. errorIfMultipleOption(parser.rargs)
  123. if(len(parser.rargs) == 0 ):
  124. raise OptionValueError("No argument found. This option requires at least one argument.")
  125. stor = helper_get_stor_dir()
  126. if(stor is None):
  127. exit("Unable to connect to the Airtime server.")
  128. dest = stor+"organize/"
  129. copy_or_move_files_to(parser.rargs, dest, 'move')
  130. def WatchAddAction(option, opt, value, parser):
  131. errorIfMultipleOption(parser.rargs)
  132. if(len(parser.rargs) > 1):
  133. raise OptionValueError("Too many arguments. This option requires exactly one argument.")
  134. elif(len(parser.rargs) == 0 ):
  135. raise OptionValueError("No argument found. This option requires exactly one argument.")
  136. path = parser.rargs[0]
  137. if (path[0] == "/" or path[0] == "~"):
  138. path = os.path.realpath(path)
  139. else:
  140. path = currentDir+path
  141. path = apc.encode_to(path, 'utf-8')
  142. if(os.path.isdir(path)):
  143. #os.chmod(path, 0765)
  144. try:
  145. res = api_client.add_watched_dir(path)
  146. except Exception, e:
  147. exit("Unable to connect to the server.")
  148. # sucess
  149. if(res['msg']['code'] == 0):
  150. print "%s added to watched folder list successfully" % path
  151. else:
  152. print "Adding a watched folder failed: %s" % res['msg']['error']
  153. print "This error most likely caused by wrong permissions"
  154. print "Try fixing this error by chmodding the parent directory(ies)"
  155. else:
  156. print "Given path is not a directory: %s" % path
  157. def WatchListAction(option, opt, value, parser):
  158. errorIfMultipleOption(parser.rargs)
  159. if(len(parser.rargs) > 0):
  160. raise OptionValueError("This option doesn't take any arguments.")
  161. try:
  162. res = api_client.list_all_watched_dirs()
  163. except Exception, e:
  164. exit("Unable to connect to the Airtime server.")
  165. dirs = res["dirs"].items()
  166. # there will be always 1 which is storage folder
  167. if(len(dirs) == 1):
  168. print "No watch folders found"
  169. else:
  170. for key, v in dirs:
  171. if(key != '1'):
  172. print v
  173. def WatchRemoveAction(option, opt, value, parser):
  174. errorIfMultipleOption(parser.rargs)
  175. if(len(parser.rargs) > 1):
  176. raise OptionValueError("Too many arguments. This option requires exactly one argument.")
  177. elif(len(parser.rargs) == 0 ):
  178. raise OptionValueError("No argument found. This option requires exactly one argument.")
  179. path = parser.rargs[0]
  180. if (path[0] == "/" or path[0] == "~"):
  181. path = os.path.realpath(path)
  182. else:
  183. path = currentDir+path
  184. path = apc.encode_to(path, 'utf-8')
  185. if(os.path.isdir(path)):
  186. try:
  187. res = api_client.remove_watched_dir(path)
  188. except Exception, e:
  189. exit("Unable to connect to the Airtime server.")
  190. # sucess
  191. if(res['msg']['code'] == 0):
  192. print "%s removed from watch folder list successfully." % path
  193. else:
  194. print "Removing the watch folder failed: %s" % res['msg']['error']
  195. else:
  196. print "The given path is not a directory: %s" % path
  197. def StorageSetAction(option, opt, value, parser):
  198. bypass = False
  199. isF = '-f' in parser.rargs
  200. isForce = '--force' in parser.rargs
  201. if(isF or isForce ):
  202. bypass = True
  203. if(isF):
  204. parser.rargs.remove('-f')
  205. if(isForce):
  206. parser.rargs.remove('--force')
  207. if(not bypass):
  208. errorIfMultipleOption(parser.rargs, "Only [-f] and [--force] option is allowed with this option.")
  209. possibleInput = ['y','Y','n','N']
  210. confirm = raw_input("Are you sure you want to change the storage direcory? (y/N)")
  211. confirm = confirm or 'N'
  212. while(confirm not in possibleInput):
  213. print "Not an acceptable input: %s\n" % confirm
  214. confirm = raw_input("Are you sure you want to change the storage direcory? (y/N) ")
  215. confirm = confirm or 'N'
  216. if(confirm == 'n' or confirm =='N'):
  217. sys.exit(1)
  218. if(len(parser.rargs) > 1):
  219. raise OptionValueError("Too many arguments. This option requires exactly one argument.")
  220. elif(len(parser.rargs) == 0 ):
  221. raise OptionValueError("No argument found. This option requires exactly one argument.")
  222. path = parser.rargs[0]
  223. if (path[0] == "/" or path[0] == "~"):
  224. path = os.path.realpath(path)
  225. else:
  226. path = currentDir+path
  227. path = apc.encode_to(path, 'utf-8')
  228. if(os.path.isdir(path)):
  229. try:
  230. res = api_client.set_storage_dir(path)
  231. except Exception, e:
  232. exit("Unable to connect to the Airtime server.")
  233. # success
  234. if(res['msg']['code'] == 0):
  235. print "Successfully set storage folder to %s" % path
  236. else:
  237. print "Setting storage folder failed: %s" % res['msg']['error']
  238. else:
  239. print "The given path is not a directory: %s" % path
  240. def StorageGetAction(option, opt, value, parser):
  241. errorIfMultipleOption(parser.rargs)
  242. if(len(parser.rargs) > 0):
  243. raise OptionValueError("This option does not take any arguments.")
  244. print helper_get_stor_dir()
  245. class OptionValueError(RuntimeError):
  246. def __init__(self, msg):
  247. self.msg = msg
  248. usage = """[-c|--copy FILE/DIR [FILE/DIR...]] [-m|--move FILE/DIR [FILE/DIR...]]
  249. [--watch-add DIR] [--watch-list] [--watch-remove DIR]
  250. [--storage-dir-set DIR] [--storage-dir-get]"""
  251. parser = OptionParser(usage=usage, add_help_option=False)
  252. parser.add_option('-c','--copy', action='callback', callback=CopyAction, metavar='FILE', help='Copy FILE(s) into the storage directory.\nYou can specify multiple files or directories.')
  253. parser.add_option('-m','--move', action='callback', callback=MoveAction, metavar='FILE', help='Move FILE(s) into the storage directory.\nYou can specify multiple files or directories.')
  254. parser.add_option('--watch-add', action='callback', callback=WatchAddAction, help='Add DIR to the watched folders list.')
  255. parser.add_option('--watch-list', action='callback', callback=WatchListAction, help='Show the list of folders that are watched.')
  256. parser.add_option('--watch-remove', action='callback', callback=WatchRemoveAction, help='Remove DIR from the watched folders list.')
  257. parser.add_option('--storage-dir-set', action='callback', callback=StorageSetAction, help='Set storage dir to DIR.')
  258. parser.add_option('--storage-dir-get', action='callback', callback=StorageGetAction, help='Show the current storage dir.')
  259. parser.add_option('-h', '--help', dest='help', action='store_true', help='show this help message and exit')
  260. # pop "--dir"
  261. #sys.argv.pop(1)
  262. # pop "invoked pwd"
  263. currentDir = os.getcwd() #sys.argv.pop(1)+'/'
  264. if('-l' in sys.argv or '--link' in sys.argv):
  265. print "\nThe [-l][--link] option is deprecated. Please use the --watch-add option.\nTry 'airtime-import -h' for more detail.\n"
  266. sys.exit()
  267. if('-h' in sys.argv):
  268. printHelp()
  269. sys.exit()
  270. if(len(sys.argv) == 1 or '-' not in sys.argv[1]):
  271. printHelp()
  272. sys.exit()
  273. try:
  274. (option, args) = parser.parse_args()
  275. except Exception, e:
  276. printHelp()
  277. if hasattr(e, 'msg'):
  278. print "Error: "+e.msg
  279. else:
  280. print "Error: ",e
  281. sys.exit()
  282. except SystemExit:
  283. printHelp()
  284. sys.exit()
  285. if option.help:
  286. printHelp()
  287. sys.exit()