""" Jani's description of TUD API: - put file (i.e. call Method A with a file pointer on the local filesystem. Method A returns the file's torrent. File becomes available within the P2P network.) - get file (i.e. call Method B with a torrent and a callback handler. Method B returns a file pointer if file is locally available. If file is not locally available then Method B EITHER calls callback handler when file download is finished with the appropriate file pointer, OR Method B periodically calls the callback handler with an integer percentage value of the download progress of the file, when file is ready Method B calls the callback handler with the file pointer.) - status / torrent info (i.e. call Method C with a torrent. Method C returns an array (??) of information regarding the status of the torrent / file) - cut (i.e. call Method D with a torrent, start time and end time. Torrent identifies the file to be cut and time codes the points where it is to be cut. Needs to raise an exception and return something sensible if file doesn't exists or time codes are out of range. Returns torrent for the new file.) """ import sys sys.path.append("./tribler/") import btlaunchmany from threading import Thread, Event import shutil import time from TorrentMaker.btmakemetafile import * from traceback import print_exc, print_stack from Tribler.__init__ import tribler_done from time import sleep from BitTornado.bencode import bencode, bdecode from BitTornado.BT1.btformats import check_info from sha import sha import os import string import logging class P2PMediaspace(btlaunchmany.HeadlessDisplayer): default_torrent_dir = '/tmp' def __init__(self, install_dir=None): btlaunchmany.HeadlessDisplayer.__init__(self) self.torrent_dir = self.default_torrent_dir self.defaultCallback = None #default callback function for downloading torrents self.callbacks = {} #torrents that want to be informed self.status = {} #last status info available for torrents self.launchmany = None self.lm_event = Event() self.install_dir = install_dir #directory with configuration files self.appthread = Thread(target = self.start_Tribler) self.appthread.setDaemon(True) self.appthread.start() """wait until we get a valid reference to tribler client must be called after start_Tribler to be sure that we'll get a reference somehow""" self.lm_event.wait(10) if self.launchmany is None: logging.info( "[Tribler]ERROR: P2P engine not available") def display(self, data): return False def inform(self, data): """call the callback function for a torrent""" # should check if the status changed and only the inform the callback if data is None: return hash = data[0] self.status[hash] = data if self.callbacks.has_key(hash) and self.callbacks[hash] is not None: self.callbacks[hash](data) elif self.defaultCallback is not None: self.defaultCallback(data) def setLaunchMany(self, lm): self.launchmany = lm self.lm_event.set() def start_Tribler(self): """starts tribler in headless mode""" if self.install_dir is None: self.install_dir = "./tribler/" startup_parameters = "tribler "+self.torrent_dir+" --install_dir "+self.install_dir+" --max_upload_rate 50 --minport 6881 --saveas_style 2 --cache 1 --overlay 0 --buddycast 0 --download_help 0 --torrent_collecting 0" ## # startup_parameters = "tribler" #starts tribler in text_mode try: btlaunchmany.main(startup_parameters.split(), outputDisplay=self) #outputDisplay=self ensures two things: we are called to display information #and also the self.lauchmany is automatically set except: logging.info( "[Tribler]ERROR: P2P engine did not start") #print_exc() #something wrong happened if we got here, but at least inform the event self.launchmany = None self.lm_event.set() def stop_Tribler(self): """sends a quit to the application""" self.launchmany.doneflag.set() #informs the rawserver that should end tribler_done(self.launchmany.config['config_path']) # Particularly if we're a seeder we need to make sure that the Threads # started to tell the tracker we're stopping are allowed to run to # completion. Otherwise the tracker admin may get messed up. It gets messed # up if we use different ports on each run and we don't unregister properly. # The tracker will then think the old instance is still running and give it # to peers. # logging.info( "[Tribler]Client shutting down. Sleeping a while to allow other threads to finish") sleep(4) logging.info( "[Tribler]Client done sleeping, other threads should have finished") return 0 def setDefaultCallback(self, callbackFunction): """the default callback function to inform user of progress""" self.defaultCallback = callbackFunction def getTorrentHash(self, torrent_file): """private function used to compute the torrent identifier used by bittorrent engine; computed with sha""" hash = None try: ff = open(torrent_file, 'rb') d = bdecode(ff.read()) check_info(d['info']) hash = sha(bencode(d['info'])).digest() ff.close() except: hash=None return hash def get_file(self, torrent_path=None, torrent_name=None, torrent=None, callbackFunction=None): """gets the torrent provided as an argument and returns an id as the torrent hash the callback function, if provided, is informed with a tuple of form (torrent_hash, torrent_name, status, progress) the torrent can be provided as a path name or as a file name and torrent content""" # self.app.utility.queue.addtorrents.AddTorrentFromFile(torrent_name) # self.initReference(False) #somehow call scan for btlaunchmany.lm #save the torrent in the torrent directory #if torrent path is provided, just copy it if torrent_path!=None: shutil.copy(torrent_path, self.torrent_dir) elif torrent_name!=None and torrent!=None: #if torrent_name AND torrent are given, save torrent to directory torrent_path = os.path.join(self.torrent_dir, torrent_name) file = open(torrent_path, "w") file.write(torrent) file.close() else: return None #no required arguments provided #get the hash hash = self.getTorrentHash(torrent_path) #call scan now self.launchmany.rawserver.add_task(self.launchmany.scan, 0) if callbackFunction is not None: self.callbacks[hash] = callbackFunction return hash def put_file(self, tracker_url, file_path, torrent_path): """create a torrent for the given file path and saves it in torrent_path; integrates the provided tracker_url in torrent""" try: make_meta_file(file_path, tracker_url, {'target' : torrent_path}, progress = prog, fileCallback = file_callback) except: #print_exc() logging.info("[Tribler] cound not create torrent for "+file_path) def get_status(self, torrent_hash): """given a torrent hash, it returns it's last known status in the form (torrent_hash, torrent_name, status, progress)""" if self.status.has_key(torrent_hash): return self.status[torrent_hash] return None def cut_movie(self, in_file, out_file, start_time, stop_time=None): """cuts the in_file movie to out_file from start_time to stop_time, both expressed in seconds using ffmpeg found in mediacutting directory""" if sys.platform == 'win32': ffmpegexe="mediacutting/ffmpeg.exe" else: ffmpegexe="mediacutting/ffmpeg" command = ffmpegexe + " -y -i " + in_file + " -vcodec copy -acodec copy " + " -ss " + str(start_time) if stop_time is not None: command += " -t " + str(stop_time-start_time) command += " " + out_file os.system(command) def remove_file(self, torrent=None, hash=None): """removes a torrent from cache based on torrent name, torrent hash or full path""" try: if hash is not None: #delete the file if it's in torrent cache if self.launchmany.torrent_cache.has_key(hash): os.remove(self.launchmany.torrent_cache[hash]['path']) #call scan now self.launchmany.rawserver.add_task(self.launchmany.scan, 0) elif torrent is not None: if torrent.startswith(self.torrent_dir): os.remove(torrent) else: os.remove(os.path.join(self.torrent_dir, torrent)) #call scan now self.launchmany.rawserver.add_task(self.launchmany.scan, 0) except: logging.info("[Tribler] Could not remove file") #print_exc() def empty_cache(self): """deletes all torrents from cache directory and associated files""" shutil.rmtree(self.torrent_dir, True) try: os.mkdir(self.torrent_dir) except: pass #call scan now to notice that files were removed self.launchmany.rawserver.add_task(self.launchmany.scan, 0) def exists(self, torrent_hash): """checks if a torrent exists in the engine, that means the torrent is considering it and taking care of it""" return self.launchmany.downloads.has_hey(torrent_hash) def view_content(self, torrent_hash): """given a torrent hash, returns the files contained by the torrent in a list, with absolute file paths; if the torrent isn't yet ready, not yet checked, it returns also None like when it doesn't exists, should be used with exists function""" if self.launchmany.downloads.has_key(torrent_hash): d = self.launchmany.downloads[torrent_hash] if d.name == '': return None #name not ready yet #print "d.name=",d.name if d.response.has_key('info') and d.response['info'].has_key('files'): files = d.response['info']['files'] only_files = [] for file_dict in files: if file_dict.has_key('length'): #this is a file for file in file_dict['path']: only_files.append(os.path.join(d.name, file)) return only_files return None def video_demo(self): """ first example: splits a video file in two second example: cuts a piece from a video file""" # splitclean Johan-Oomen-metadata.mp4 55 # %FFMPEGEXE% -y -i %1 -vcodec copy -acodec copy -t %2 split1_%1 # %FFMPEGEXE% -y -i %1 -vcodec copy -acodec copy -ss %2 split2_%1 self.cut_movie("mediacutting/Johan-Oomen-metadata.mp4", "mediacutting/out/split1_Johan-Oomen-metadata.mp4", 0, 55) self.cut_movie("mediacutting/Johan-Oomen-metadata.mp4", "mediacutting/out/split2_Johan-Oomen-metadata.mp4", 55) # cutclean nava-p2p-910.mp4 120 20 self.cut_movie("mediacutting/nava-p2p-910.mp4", "mediacutting/out/cut_nava.mp4", 120, 140) def demo(self): # download a torrent file self.empty_cache() hash = self.get_file('/Users/mluc/trusted-computing.torrent') print "hash for file is:",hash while self.view_content(hash) is None: print "waiting for torrent to be considered by the engine" sleep(1) print "torrent content is:",self.view_content(hash) #wait until file is completed while self.get_status(hash) is None or self.get_status(hash)[3].find("100") == -1: status = self.get_status(hash) if status is None: print "waiting for status information" else: print "still downloading", status[3] sleep(1) if self.get_status(hash)[3].find("100") !=-1: print "file downloaded" self.put_file( "http://www.tracker1.com", '/tmp/freeculture.zip', '/Users/mluc/freeculture.zip_output/') if __name__ == '__main__': #create the p2p mediaspace object med = P2PMediaspace() #should set a callback function for status about downloads med.setDefaultCallback(None) #med.video_demo() med.demo() med.stop_Tribler() sys.exit(0)