def setLocales(): try: UI.logEntering() builtins.Status.update(text = "Setting locales") if Utils.checkFile(Utils.getPath("mnt/etc/locale.gen")): for locale in builtins.Config['Board']['Locales'].split(): builtins.Status.update(text = "Configuring locale " + locale) Utils.appendFile(file = Utils.getPath("mnt/etc/locale.gen"), lines = [locale + " " + locale.split('.')[1] ] ) builtins.Status.update(text = "Running locale-gen") Utils.runChrootCommand(command = "/usr/sbin/locale-gen") builtins.Status.update(text = "Running update-locale") Utils.runChrootCommand(command = "/usr/sbin/update-locale LANG=" + builtins.Config['Board']['Locales'].split()[0] + " LC_MESSAGES=POSIX") else: for locale in builtins.Config['Board']['Locales'].split(): builtins.Status.update(text = "Generating locale " + locale) Utils.runChrootCommand(command = "/usr/sbin/locale-gen " + locale) builtins.Status.update(text = "Running update-locale") Utils.runChrootCommand(command = "/usr/sbin/update-locale LANG=" + builtins.Config['Board']['Locales'].split()[0] + " LC_MESSAGES=POSIX") builtins.Status.update(text = "Running dpkg-reconfigure locales") Utils.runChrootCommand(command = "/usr/sbin/dpkg-reconfigure locales") UI.logExiting() return True except SystemExit: pass except: logging.exception("Caught Exception") sys.exit(os.EX_SOFTWARE)
def ubootSetup(Device): try: bName = builtins.Config['Board']['model'].lower() fName = bName + ".fex" Utils.copyFiles(Utils.getPath("mnt/usr/share/armStrap-U-Boot/" + bName + "/"+ fName), Utils.getPath("mnt/boot/" + fName)) Utils.runChrootCommand(command = "/usr/bin/fex2bin /boot/" + fName + " /boot/script.bin") Utils.runCommand(command = "/bin/dd if=" + Utils.getPath("mnt/usr/share/armStrap-U-Boot/" + bName + "/u-boot-sunxi-with-spl.bin") + " of=" + Device + " bs=1024 seek=8") except SystemExit: pass except: logging.exception("Caught Exception") sys.exit(os.EX_SOFTWARE)
def setHostName(): try: UI.logEntering() builtins.Status.update(text = "Setting hostname to " + builtins.Config['Board']['HostName']) Utils.unlinkFile("mnt/etc/hostname") Utils.appendFile(file = Utils.getPath("mnt/etc/hostname"), lines = [builtins.Config['Board']['HostName'] ]) Utils.appendFile(file = Utils.getPath("mnt/etc/hosts"), lines = [ "127.0.0.1\t" + builtins.Config['Board']['HostName'] ]) UI.logExiting() return True except SystemExit: pass except: logging.exception("Caught Exception") sys.exit(os.EX_SOFTWARE)
def chrootAddUser(User, Password): try: UI.logEntering() builtins.Status.update(text = "Creating home directory for user " + User) shutil.copytree(Utils.getPath("mnt/etc/skel"), Utils.getPath("mnt/home/" + User), symlinks=True) Utils.runChrootCommand("/usr/sbin/useradd --shell /bin/bash " + User) Utils.runChrootCommand("/bin/chown " + User + ":" + User + " /home/" + User) Utils.runChrootCommand("/usr/sbin/usermod -G sudo " + User) chrootPasswd(User = User, Password = Password) UI.logExiting() return True except SystemExit: pass except: logging.exception("Caught Exception") sys.exit(os.EX_SOFTWARE)
def setSwapFile(): try: UI.logEntering() Utils.unlinkFile("mnt/etc/dphys-swapfile") lines = [] if builtins.Config.has_option('SwapFile', 'Size'): lines.append("CONF_SWAPSIZE=" + builtins.Config['SwapFile']['Size']) else: lines.append("#CONF_SWAPSIZE=") if builtins.Config.has_option('SwapFile', 'File'): lines.append("CONF_SWAPFILE=" + builtins.Config['SwapFile']['File']) else: lines.append("#CONF_SWAPFILE=/var/swap") if builtins.Config.has_option('SwapFile', 'Factor'): lines.append("CONF_SWAPFACTOR=" + builtins.Config['SwapFile']['Factor']) else: lines.append("#CONF_SWAPFACTOR=2") if builtins.Config.has_option('SwapFile', 'Maximum'): lines.append("CONF_MAXSWAP=" + builtins.Config['SwapFile']['Maximum']) else: lines.append("#CONF_MAXSWAP=2048") Utils.appendFile(file = Utils.getPath("mnt/etc/dphys-swapfile"), lines = lines) return True except SystemExit: pass except: logging.exception("Caught Exception") sys.exit(os.EX_SOFTWARE)
def setTimeZone(): try: UI.logEntering() builtins.Status.update(text = "Setting timezone to " + builtins.Config['Board']['TimeZone']) if Utils.checkFile(Utils.getPath("mnt/usr/share/zoneinfo/" + builtins.Config['Board']['TimeZone'])): Utils.runChrootCommand(command = "ln -sf /usr/share/zoneinfo/" + builtins.Config['Board']['TimeZone'] +" /etc/localtime") Utils.unlinkFile("mnt/etc/timezone") Utils.appendFile(file = Utils.getPath("mnt/etc/timezone"), lines = [ builtins.Config['Board']['TimeZone'] ]) else: MessageBox(text = "TimeZone " + builtins.Config['Board']['TimeZone'] + " not found. You will need to configure it manually.", title = "Non-Fatal Error", timeout = 10 ) return True except SystemExit: pass except: logging.exception("Caught Exception") sys.exit(os.EX_SOFTWARE)
def chrootDeconfig(): try: UI.logEntering() Disk.doUnMount("mnt/dev/pts"); Disk.doUnMount("mnt/sys"); Disk.doUnMount("mnt/proc"); Utils.unlinkFile("mnt/usr/sbin/policy-rc.d") if os.path.isfile(Utils.getPath("mnt/usr/sbin/policy-rc.d_save")): shutil.move(Utils.getPath("mnt/usr/sbin/policy-rc.d_save"), Utils.getPath("mnt/usr/sbin/policy-rc.d")) Utils.unlinkFile("mnt/usr/sbin/policy-rc.d.lock") Utils.unlinkFile("mnt/usr/bin/qemu-arm-static") UI.logExiting() return True except SystemExit: pass except: logging.exception("Caught Exception") pass
def setTTY(): try: UI.logEntering() if Utils.checkFile(Utils.getPath("mnt/etc/inittab")): builtins.Status.update(text = "Setting inittab for " + builtins.Boards['Serial']['TerminalDevice']) line = builtins.Boards['Serial']['TerminalID'] + ":" + builtins.Boards['Serial']['RunLevel'] +":respawn:/sbin/getty -L " + builtins.Boards['Serial']['TerminalDevice'] + " " + builtins.Boards['Serial']['TerminalSpeed'] + " " + builtins.Boards['Serial']['TerminalType'] Utils.appendFile(file = Utils.getPath("mnt/etc/inittab")) else: lines = [] builtins.Status.update(text = "Setting service for " + builtins.Boards['Serial']['TerminalDevice']) Utils.unlinkFile("mnt/etc/init/" + builtins.Boards['Serial']['TerminalDevice'] + ".conf") lines.append("# " + builtins.Boards['Serial']['TerminalDevice'] + " - getty") lines.append("#\n# This service maintains a getty on " + builtins.Boards['Serial']['TerminalDevice'] + " from the point the system is\n# started until it is shut down again.\n") lines.append("start on stopped rc or RUNLEVEL=[" + builtins.Boards['Serial']['RunLevel'] + "]\n") lines.append("stop on runlevel [!"+ builtins.Boards['Serial']['RunLevel'] + "]\n") lines.append("respawn\nexec /sbin/getty -L " + builtins.Boards['Serial']['TerminalSpeed'] + " " + builtins.Boards['Serial']['TerminalDevice'] + " " + builtins.Boards['Serial']['TerminalType']) Utils.appendFile(file = Utils.getPath("mnt/etc/init/" + builtins.Boards['Serial']['TerminalDevice'] + ".conf"), lines = lines) UI.logExiting() return True except SystemExit: pass except: logging.exception("Caught Exception") sys.exit(os.EX_SOFTWARE)
def chrootPasswd(User, Password): try: UI.logEntering() builtins.Status.update(text = "Setting password for user " + User) PasswordNL=Password + "\n" proc = subprocess.Popen(['/usr/sbin/chroot', Utils.getPath("mnt"), '/usr/bin/passwd', User], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc.stdin.write(PasswordNL.encode('ascii')) proc.stdin.write(Password.encode('ascii')) proc.stdin.flush() stdout,stderr = proc.communicate() UI.logExiting() return (stdout.decode('utf-8'), stderr.decode('utf-8')) except SystemExit: pass except: logging.exception("Caught Exception") sys.exit(os.EX_SOFTWARE)
def command(self, user, channel, msg): name = " ".join(msg) url = "{}{}".format(self.factory.config.rip_host, urllib.quote(name)) if name[-4:].lower() != ".mkv": self.msg(channel, "Can only rip MKVs") return response = yield Agent(reactor).request("GET", url, None, None) if response.code != 200: self.msg(channel, "{} returned non-successful HTTP code".format(url)) return self.notice(user, "Downloading {}".format(name)) guid = uuid.uuid4().hex while os.path.exists(guid): guid = uuid.uuid4().hex os.mkdir(guid) d = Deferred() dl = Downloader("{}/{}".format(guid, name), d) response.deliverBody(dl) yield d dl.done() self.notice(user, "{} downloaded".format(name)) dest = name[:-3] + "ass" exitCode = yield getProcessValue(getPath("mkvextract"), args=["tracks","{}/{}".format(guid, name),"3:{}/{}".format(guid, dest)], env=os.environ) if exitCode == 0: self.notice(user, "{} extracted".format(dest)) ftp = yield ClientCreator(reactor, FTPClient, self.factory.config.ftp_user, self.factory.config.ftp_pass).connectTCP(self.factory.config.ftp_host, self.factory.config.ftp_port) store, finish = ftp.storeFile("./{}/{}".format(self.factory.config.ftp_encode_dir, dest)) sender = yield store with open("{}/{}".format(guid, dest), "rb") as f: sender.transport.write(f.read()) sender.finish() yield finish self.notice(user, "{} uploaded".format(dest)) else: self.msg(channel, "Failed to extract subs for {}".format(name)) shutil.rmtree(guid, True)
def setFsTab(): try: UI.logEntering() partList = [] partID = 1 fFormat = "{0:<23} {1:<15} {2:<7} {3:<15} {4:<7} {5}" partList.append( fFormat.format( "# <file system>", "<mount point>", "<type>", "<options>", "<dump>", "<pass>" ) ) builtins.Status.update(text = "Configuring fstab ") for partition in builtins.Boards['Partitions']['Layout'].split( ): p = partition.split(':') partList.append( fFormat.format( builtins.Boards['Partitions']['Device'] + builtins.Boards['Partitions']['PartitionPrefix'] + str(partID), p[1], p[2], "defaults", "0", "1" ) ) partID += 1 Utils.unlinkFile("mnt/etc/fstab") Utils.appendFile(file = Utils.getPath("mnt/etc/fstab"), lines = partList) UI.logExiting() return True except SystemExit: pass except: logging.exception("Caught Exception") sys.exit(os.EX_SOFTWARE)
def setInterface(): try: UI.logEntering() interface = [] interface.append( "auto " + builtins.Boards['Network']['Interface'] ) interface.append( "allow-hotplug " + builtins.Boards['Network']['Interface'] + "\n" ) if builtins.Config.has_section("Networking"): if builtins.Config.has_option('Networking', 'Mode'): if (builtins.Config['Networking']['Mode'].lower() == "static"): interface.append( "iface " + builtins.Boards['Network']['Interface'] + " inet static" ) if builtins.Config.has_option('Networking', 'Ip'): interface.append( "\taddress " + builtins.Config['Networking']['Ip'] ) if builtins.Config.has_option('Networking', 'Mask'): interface.append( "\tnetmask " + builtins.Config['Networking']['Mask'] ) if builtins.Config.has_option('Networking', 'Gateway'): interface.append( "\tgateway " + builtins.Config['Networking']['Gateway'] ) if builtins.Config.has_option('Networking', 'DNS'): interface.append( "\tdns-nameserver " + builtins.Config['Networking']['DNS'] ) if builtins.Config.has_option('Networking', 'Domain'): interface.append( "\tdns-search " + builtins.Config['Networking']['Domain'] ) else: interface.append( "iface " + builtins.Boards['Network']['Interface'] + " inet dhcp" ) else: interface.append( "iface " + builtins.Boards['Network']['Interface'] + " inet dhcp" ) else: interface.append( "iface " + builtins.Boards['Network']['Interface'] + " inet dhcp" ) interface.append( "\thwaddress ether " + builtins.Config['Networking']['MacAddress'] ) Utils.unlinkFile("mnt/etc/network/interfaces") Utils.appendFile(file = Utils.getPath("mnt/etc/network/interfaces"), lines = interface) UI.logExiting() return True except SystemExit: pass except: logging.exception("Caught Exception") sys.exit(os.EX_SOFTWARE)
def chrootConfig(): try: UI.logEntering() shutil.copy("/usr/bin/qemu-arm-static", Utils.getPath("mnt/usr/bin/qemu-arm-static")) Utils.touch("mnt/usr/sbin/policy-rc.d.lock") if os.path.isfile(Utils.getPath("mnt/usr/sbin/policy-rc.d")): shutil.move(Utils.getPath("mnt/usr/sbin/policy-rc.d"), Utils.getPath("mnt/usr/sbin/policy-rc.d_save")) f = open(Utils.getPath("mnt/usr/sbin/policy-rc.d"), 'w') f.write("exit 101\n") f.close() os.chmod(Utils.getPath("mnt/usr/sbin/policy-rc.d"), 0o755 ) Disk.doMount(Device = "/proc", Path = "mnt/proc", Bind = True) Disk.doMount(Device = "/sys", Path = "mnt/sys", Bind = True) Disk.doMount(Device = "/dev/pts", Path = "mnt/dev/pts", Bind = True) UI.logExiting() return True except SystemExit: pass except: logging.exception("Caught Exception") sys.exit(os.EX_IOERR)
def command(self, user, channel, msg): if len(msg) < 2: self.msg(channel, "Need a filter and a showname") return name_filter = msg[0] offset = 1 while msg[-1][:2] == "--": arg = msg.pop() if arg == "--previous": offset = 0 show = self.factory.resolve(" ".join(msg[1:]), channel) if show is None: return if not show["folder"]: self.msg(channel, "No FTP folder given for {}".format(show["series"])) return if not show["xdcc_folder"]: self.msg(channel, "No XDCC folder given for {}".format(show["series"])) return episode = show["current_ep"] + offset guid = uuid.uuid4().hex while os.path.exists(guid): guid = uuid.uuid4().hex os.mkdir(guid) # Step 1: Search FTP for complete episode, or premux + xdelta ftp = yield ClientCreator(reactor, FTPClient, self.factory.config.ftp_user, self.factory.config.ftp_pass).connectTCP(self.factory.config.ftp_host, self.factory.config.ftp_port) ftp.changeDirectory("/{}/{:02d}/".format(show["folder"], episode)) filelist = FTPFileListProtocol() yield ftp.list(".", filelist) files = [x["filename"] for x in filelist.files if x["filetype"] != "d"] complete = fnmatch.filter(files, "[[]Commie[]]*{}*.mkv".format(name_filter)) xdelta = fnmatch.filter(files, "*{}*.xdelta".format(name_filter)) premux = fnmatch.filter(files, "*{}*.mkv".format(name_filter)) if complete: # Step 1a: Download completed file if len(complete) > 1: self.msg(channel, "Too many completed files match the filter: {}".format(", ".join(complete))) return else: complete = complete[0] self.notice(user, "Found complete file: {}".format(complete)) complete_len = [x["size"] for x in filelist.files if x["filename"] == complete][0] complete_downloader = Downloader("{}/{}".format(guid, complete)) yield ftp.retrieveFile(complete, complete_downloader) if complete_downloader.done() != complete_len: self.msg(channel, "Aborted releasing {}: Download of complete file had incorrect size.".format(show["series"])) yield ftp.quit() ftp.fail(None) return elif xdelta and premux: # Step 1b: Download premux + xdelta, merge into completed file if len(premux) > 1: self.msg(channel, "Too many premux files match the filter: {}".format(", ".join(premux))) return else: premux = premux[0] if len(xdelta) > 1: self.msg(channel, "Too many xdelta files match the filter: {}".format(", ".join(xdelta))) return else: xdelta = xdelta[0] self.notice(user, "Found xdelta and premux: {} and {}".format(xdelta, premux)) if not os.path.isfile("{}/{}".format(self.factory.config.premux_dir, premux)): premux_len = [x["size"] for x in filelist.files if x["filename"] == premux][0] success = yield cache(self, user, ftp, premux, premux_len) if not success: self.msg(channel, "Aborted releasing {}: Download of premux file had incorrect size.".format(show["series"])) yield ftp.quit() ftp.fail(None) return shutil.copyfile("{}/{}".format(self.factory.config.premux_dir, premux), "{}/{}".format(guid, premux)) xdelta_len = [x["size"] for x in filelist.files if x["filename"] == xdelta][0] xdelta_downloader = Downloader("{}/{}".format(guid, xdelta)) yield ftp.retrieveFile(xdelta, xdelta_downloader) if xdelta_downloader.done() != xdelta_len: self.msg(channel, "Aborted releasing {}: Download of xdelta file had incorrect size.".format(show["series"])) yield ftp.quit() ftp.fail(None) return code = yield getProcessValue(getPath("xdelta3"), args=["-f","-d","{}/{}".format(guid, xdelta)], env=os.environ) if code != 0: self.msg(channel, "Aborted releasing {}: Couldn't merge premux and xdelta.".format(show["series"])) yield ftp.quit() ftp.fail(None) return self.notice(user, "Merged premux and xdelta") complete = fnmatch.filter(os.listdir(guid), "[[]Commie[]]*.mkv") if not complete: self.msg(channel, "No completed file found") return elif len(complete) > 1: self.msg(channel, "Too many completed files found after merging: {}".format(", ".join(complete))) return else: complete = complete[0] if not complete: self.msg(channel, "Aborted releasing {}: Couldn't find completed file after merging.".format(show["series"])) yield ftp.quit() ftp.fail(None) return else: self.msg(channel, "Aborted releasing {}: Couldn't find completed episode.".format(show["series"])) yield ftp.quit() ftp.fail(None) return yield ftp.quit() ftp.fail(None) # Step 1c: Verify CRC crc = complete[-13:-5] # Extract CRC from filename try: with open("{}/{}".format(guid, complete), "rb") as f: calc = "{:08X}".format(binascii.crc32(f.read()) & 0xFFFFFFFF) except: self.msg(channel, "Aborted releasing {}: Couldn't open completed file for CRC verification.".format(show["series"])) return if crc != calc: self.msg(channel, "Aborted releasing {}: CRC failed verification. Filename = '{}', Calculated = '{}'.".format(show["series"], crc, calc)) return # Step 1d: Determine version number match = re.search("(v\d+)", complete) version = match.group(1) if match is not None else "" # Step 2: Create torrent try: torrent = makeTorrent(complete, guid) except: self.msg(channel, "Aborted releasing {}: Couldn't create torrent.".format(show["series"])) raise self.notice(user, "Created torrent") # Step 3: Upload episode to XDCC server try: ftp = yield ClientCreator(reactor, FTPClient, self.factory.config.xdcc_user, self.factory.config.xdcc_pass).connectTCP(self.factory.config.xdcc_host, self.factory.config.xdcc_port) store, finish = ftp.storeFile("./{}/{}/{}".format(self.factory.config.xdcc_folder, show["xdcc_folder"], complete)) sender = yield store with open("{}/{}".format(guid, complete), "rb") as f: sender.transport.write(f.read()) sender.finish() yield finish yield ftp.quit() ftp.fail(None) except: self.msg(channel, "Aborted releasing {}: Couldn't upload completed episode to XDCC server.".format(show["series"])) raise self.notice(user, "Uploaded to XDCC") # Step 4: Upload episode to seedbox try: ftp = yield ClientCreator(reactor, FTPClient, self.factory.config.seed_user, self.factory.config.seed_pass).connectTCP(self.factory.config.seed_host, self.factory.config.seed_port) store, finish = ftp.storeFile("./{}/{}".format(self.factory.config.seed_file_folder, complete)) sender = yield store with open("{}/{}".format(guid, complete), "rb") as f: sender.transport.write(f.read()) sender.finish() yield finish yield ftp.quit() ftp.fail(None) except: self.msg(channel, "Aborted releasing {}: Couldn't upload completed episode to seedbox.".format(show["series"])) raise self.notice(user, "Uploaded to seedbox") # Step 5: Start seeding torrent try: ftp = yield ClientCreator(reactor, FTPClient, self.factory.config.seed_user, self.factory.config.seed_pass).connectTCP(self.factory.config.seed_host, self.factory.config.seed_port) store, finish = ftp.storeFile("./{}/{}".format(self.factory.config.seed_torrent_folder, torrent)) sender = yield store with open("{}/{}".format(guid, torrent), "rb") as f: sender.transport.write(f.read()) sender.finish() yield finish yield ftp.quit() ftp.fail(None) except: self.msg(channel, "Aborted releasing {}: Couldn't upload torrent to seedbox.".format(show["series"])) raise self.notice(user, "Seeding started") # Step 6: Upload torrent to Nyaa nyaagent = CookieAgent(Agent(reactor), cookielib.CookieJar()) response = yield nyaagent.request("POST","http://www.nyaa.eu/?page=login", Headers({'Content-Type': ['application/x-www-form-urlencoded']}), FileBodyProducer(StringIO(urllib.urlencode({"loginusername": self.factory.config.nyaa_user,"loginpassword": self.factory.config.nyaa_pass})))) body = yield returnBody(response) if "Login successful" not in body: self.msg(channel, "Aborted releasing {}: Couldn't login to Nyaa.".format(show["series"])) with open("{}/{}".format(guid, "nyaa_login.html"), "wb") as f: f.write(body) return twitter_list = rheinbowify('Follow [url="https://twitter.com/RHExcelion"]@RHExcelion[/url], [url="https://twitter.com/johnnydickpants"]@jdp[/url], and the rest of Commie at [url="https://twitter.com/RHExcelion/commie-devs"]@Commie-Devs[/url].') post_data = MultiPartProducer({"torrent": "{}/{}".format(guid, torrent)},{ "name": complete, "catid": "1_37", "info": "#[email protected]", "description": "Visit us at [url]http://commiesubs.com[/url] for the latest updates and news.\n{}".format(twitter_list), "remake": "0", "anonymous": "0", "hidden": "0", "rules": "1", "submit": "Upload" }) response = yield nyaagent.request("POST","http://www.nyaa.eu/?page=upload", Headers({'Content-Type': ['multipart/form-data; boundary={}'.format(post_data.boundary)]}), post_data) if response.code != 200: nyaa_codes = { 418: "I'm a teapot (You're doing it wrong)", 460: "Missing Announce URL", 461: "Already Exists", 462: "Invalid File", 463: "Missing Data", 520: "Configuration Broken" } self.msg(channel, "Aborted releasing {}: Couldn't upload torrent to Nyaa. Error #{:d}: {}".format(show["series"], response.code, nyaa_codes[response.code])) return self.notice(user, "Uploaded to Nyaa") # Step 7: Get torrent link from Nyaa body = yield returnBody(response) match = re.search("http://www.nyaa.eu/\?page=view&tid=[0-9]+", body) if not match: self.msg(channel, "Aborted releasing {}: Couldn't find torrent link in Nyaa's response.".format(show["series"])) with open("{}/{}".format(guid, "nyaa_submit.html"), "wb") as f: f.write(body) return info_link = match.group(0).replace("&","&") download_link = info_link.replace("view","download") self.notice(user, "Got Nyaa torrent link") # Step 8: Upload torrent link to TT ttagent = CookieAgent(Agent(reactor), cookielib.CookieJar()) response = yield ttagent.request("POST","http://tokyotosho.info/login.php", Headers({'Content-Type': ['application/x-www-form-urlencoded']}), FileBodyProducer(StringIO(urllib.urlencode({"username": self.factory.config.tt_user,"password": self.factory.config.tt_pass,"submit": "Submit"})))) body = yield returnBody(response) if "Logged in." not in body: self.msg(channel, "Couldn't login to TT. Continuing to release {} regardless.".format(show["series"])) with open("{}/{}".format(guid, "tt_login.html"), "wb") as f: f.write(body) else: response = yield ttagent.request("POST","http://tokyotosho.info/new.php", Headers({'Content-Type': ['application/x-www-form-urlencoded']}), FileBodyProducer(StringIO(urllib.urlencode({ "type": "1", "url": download_link, "comment": "#[email protected]", "website": "http://www.commiesubs.com/", "send": "Submit New Torrent" })))) body = yield returnBody(response) if "Torrent Submitted" not in body: self.msg(channel, "Couldn't upload torrent to TT. Continuing to release {} regardless.".format(show["series"])) with open("{}/{}".format(guid, "tt_submit.html"), "wb") as f: f.write(body) else: self.notice(user, "Uploaded to TT") # Step 9: Create blog post blog = Proxy("http://commiesubs.com/xmlrpc.php") slug = show["blog_link"].split("/")[-2] categories = ["The Bread Lines"] result = yield blog.callRemote("wp.getTerms", 0, self.factory.config.blog_user, self.factory.config.blog_pass, "category") for term in result: if term["slug"] == slug: categories.append(term["name"]) try: yield blog.callRemote("wp.newPost", 0, # Blog ID self.factory.config.blog_user, # Username self.factory.config.blog_pass, # Password { # Content "post_type": "post", "post_status": "publish", "comment_status": "open", "post_title": "{} {:02d}{}".format(show["series"], episode, version), "post_content": "<a href=\"{}\">Torrent</a>".format(info_link), "terms_names": {"category": categories} } ) self.notice(user, "Created blog post") except: self.msg(channel, "Couldn't create blog post. Continuing to release {} regardless.".format(show["series"])) # Step 10: Mark show finished on showtimes data = yield self.factory.load("show","update", data={"id":show["id"],"method":"next_episode"}) if "status" in data and not data["status"]: self.msg(channel, data["message"]) self.msg(channel, "{} released. Torrent @ {}".format(show["series"], info_link)) # Step 11: Update the topic self.factory.update_topic() # Step 12: Clean up shutil.rmtree(guid, True)
def command(self, user, channel, msg): if len(msg) < 2: self.msg(channel, "Need a filter and show name") return offset, chapters_required = 1, True while msg[-1][:2] == "--": arg = msg.pop() if arg == "--previous": offset = 0 elif arg == "--no-chapters": chapters_required = False name_filter, show, fname = msg[0], " ".join(msg[1:]), "test.mkv" show = self.factory.resolve(show, channel) if show is None: return if not show["folder"]: self.msg(channel, "No FTP folder given for {}".format(show["series"])) return episode = show["current_ep"] + offset guid = uuid.uuid4().hex while os.path.exists(guid): guid = uuid.uuid4().hex os.mkdir(guid) # Step 1: Search FTP for premux + script ftp = yield ClientCreator( reactor, FTPClient, self.factory.config.ftp_user, self.factory.config.ftp_pass ).connectTCP(self.factory.config.ftp_host, self.factory.config.ftp_port) ftp.changeDirectory("/{}/{:02d}/".format(show["folder"], episode)) filelist = FTPFileListProtocol() yield ftp.list(".", filelist) files = [x["filename"] for x in filelist.files if x["filetype"] != "d"] premux = fnmatch.filter(files, "*{}*.mkv".format(name_filter)) script = fnmatch.filter(files, "*{}*.ass".format(name_filter)) chapters = fnmatch.filter(files, "*{}*.xml".format(name_filter)) if not premux: self.msg(channel, "No premux found") return elif len(premux) > 1: self.msg(channel, "Too many premux files match the filter: {}".format(", ".join(premux))) return else: premux = premux[0] if not script: self.msg(channel, "No script found") return elif len(script) > 1: self.msg(channel, "Too many script files match the filter: {}".format(", ".join(script))) return else: script = script[0] if chapters_required: if not chapters: self.msg(channel, "No chapters found") return elif len(chapters) > 1: self.msg(channel, "Too many chapter files match the filter: {}".format(", ".join(chapters))) return else: chapters = chapters[0] # Step 2: Download that shit if not os.path.isfile("{}/{}".format(self.factory.config.premux_dir, premux)): premux_len = [x["size"] for x in filelist.files if x["filename"] == premux][0] success = yield cache(self, user, ftp, premux, premux_len) if not success: self.msg( channel, "Aborted creating xdelta for {}: Download of premux file had incorrect size.".format(show["series"]), ) yield ftp.quit() ftp.fail(None) return shutil.copyfile("{}/{}".format(self.factory.config.premux_dir, premux), "{}/{}".format(guid, premux)) script_len = [x["size"] for x in filelist.files if x["filename"] == script][0] script_downloader = Downloader("{}/{}".format(guid, script)) yield ftp.retrieveFile(script, script_downloader) if script_downloader.done() != script_len: self.msg( channel, "Aborted creating xdelta for {}: Download of script file had incorrect size.".format(show["series"]), ) yield ftp.quit() ftp.fail(None) return if chapters_required: chapters_len = [x["size"] for x in filelist.files if x["filename"] == chapters][0] chapters_downloader = Downloader("{}/{}".format(guid, chapters)) yield ftp.retrieveFile(chapters, chapters_downloader) if chapters_downloader.done() != chapters_len: self.msg( channel, "Aborted creating xdelta for {}: Download of chapter file had incorrect size.".format(show["series"]), ) yield ftp.quit() ftp.fail(None) return self.notice(user, "Found premux, script and chapters: {}, {} and {}".format(premux, script, chapters)) else: self.notice(user, "Found premux and script: {} and {}".format(premux, script)) # Step 3: Download fonts filelist = FTPFileListProtocol() yield ftp.list("fonts", filelist) files = [x["filename"] for x in filelist.files if x["filetype"] != "d"] fonts = [] for font in files: font_len = [x["size"] for x in filelist.files if x["filename"] == font][0] font_downloader = Downloader("{}/{}".format(guid, font)) yield ftp.retrieveFile("fonts/{}".format(font), font_downloader) if font_downloader.done() != font_len: self.notice(user, "Failed to download font: {}. Proceeding without it.".format(font)) else: fonts.append(font) self.notice(user, "Fonts downloaded. ({})".format(", ".join(fonts))) # Step 4: MKVMerge arguments = ["-o", "{}/{}".format(guid, fname)] if chapters_required: arguments.extend(["--no-chapters", "--chapters", "{}/{}".format(guid, chapters)]) for font in fonts: arguments.extend( ["--attachment-mime-type", "application/x-truetype-font", "--attach-file", "{}/{}".format(guid, font)] ) arguments.extend(["{}/{}".format(guid, premux), "{}/{}".format(guid, script)]) code = yield getProcessValue(getPath("mkvmerge"), args=arguments, env=os.environ) if code != 0: self.msg(channel, "Aborted creating xdelta for {}: Couldn't merge premux and script.".format(show["series"])) yield ftp.quit() ftp.fail(None) return self.notice(user, "Merged premux and script") # Step 5: Determine filename match = re.search("(v\d+).ass", script) version = match.group(1) if match is not None else "" try: with open("{}/{}".format(guid, fname), "rb") as f: crc = "{:08X}".format(binascii.crc32(f.read()) & 0xFFFFFFFF) except: self.msg( channel, "Aborted creating xdelta for {}: Couldn't open completed file for CRC verification.".format(show["series"]), ) yield ftp.quit() ftp.fail(None) return nfname = "[Commie] {} - {:02d}{} [{}].mkv".format(show["series"], episode, version, crc) os.rename("{}/{}".format(guid, fname), "{}/{}".format(guid, nfname)) fname = nfname self.notice(user, "Determined final filename to be {}".format(fname)) # Step 5: Make that xdelta xdelta = script.replace(".ass", ".xdelta") code = yield getProcessValue( getPath("xdelta3"), args=[ "-f", "-e", "-s", "{}/{}".format(guid, premux), "{}/{}".format(guid, fname), "{}/{}".format(guid, xdelta), ], env=os.environ, ) if code != 0: self.msg(channel, "Aborted creating xdelta for {}: Couldn't create xdelta.".format(show["series"])) yield ftp.quit() ftp.fail(None) return self.notice(user, "Made xdelta") # Step 6: Upload that xdelta store, finish = ftp.storeFile("{}".format(xdelta)) sender = yield store with open("{}/{}".format(guid, xdelta), "rb") as f: sender.transport.write(f.read()) sender.finish() yield finish self.msg(channel, "xdelta for {} uploaded".format(show["series"])) # Step 7: Clean up yield ftp.quit() ftp.fail(None) shutil.rmtree(guid, True)
from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.ext.declarative import declarative_base from config import CONFIG, PATH from lib.utils import getPath engine = create_engine('sqlite:///{0}'.format(getPath(CONFIG['database'])), convert_unicode=True) dbSession = scoped_session( sessionmaker(autocommit=False, autoflush=False, bind=engine)) Base = declarative_base() Base.query = dbSession.query_property() def init_db(): # import all modules here that might define models so that # they will be registered properly on the metadata. Otherwise # you will have to import them first before calling init_db() import models.files import models.orders Base.metadata.create_all(bind=engine)