diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | module/database/File.py | 875 | ||||
-rw-r--r-- | module/plugins/Addon.py | 185 | ||||
-rw-r--r-- | module/plugins/Captcha.py | 51 | ||||
-rw-r--r-- | module/plugins/OCR.py | 318 | ||||
-rw-r--r-- | module/plugins/accounts/BackinNet.py | 16 | ||||
-rw-r--r-- | module/plugins/accounts/CloudzillaTo.py | 37 | ||||
-rw-r--r-- | module/plugins/accounts/DropboxCom.py | 38 | ||||
-rw-r--r-- | module/plugins/accounts/ExashareCom.py | 16 | ||||
-rw-r--r-- | module/plugins/accounts/JunkyvideoCom.py | 16 | ||||
-rw-r--r-- | module/plugins/accounts/MultihostersCom.py | 16 | ||||
-rw-r--r-- | module/plugins/accounts/NoPremiumPl.py | 81 | ||||
-rw-r--r-- | module/plugins/accounts/PutdriveCom.py | 16 | ||||
-rw-r--r-- | module/plugins/accounts/RapideoPl.py | 80 | ||||
-rw-r--r-- | module/plugins/accounts/RapiduNet.py | 66 | ||||
-rw-r--r-- | module/plugins/accounts/SmoozedCom.py | 62 | ||||
-rw-r--r-- | module/plugins/accounts/UploadableCh.py | 34 | ||||
-rw-r--r-- | module/plugins/accounts/WebshareCz.py | 68 | ||||
-rw-r--r-- | module/plugins/addon/ClickAndLoad.py | 74 | ||||
-rw-r--r-- | module/plugins/addon/ExtractArchive.py | 509 | ||||
-rw-r--r-- | module/plugins/addon/MergeFiles.py | 85 | ||||
-rw-r--r-- | module/plugins/addon/SkipRev.py | 98 | ||||
-rw-r--r-- | module/plugins/addon/UnSkipOnFail.py | 95 | ||||
-rw-r--r-- | module/plugins/addon/UpdateManager.py | 306 | ||||
-rw-r--r-- | module/plugins/captcha/AdYouLike.py | 107 | ||||
-rw-r--r-- | module/plugins/captcha/AdsCaptcha.py | 77 | ||||
-rw-r--r-- | module/plugins/captcha/ReCaptcha.py | 73 | ||||
-rw-r--r-- | module/plugins/captcha/SolveMedia.py | 50 | ||||
-rw-r--r-- | module/plugins/container/CCF.py | 49 | ||||
-rw-r--r-- | module/plugins/container/DLC.py | 72 | ||||
-rw-r--r-- | module/plugins/container/LinkList.py | 69 | ||||
-rw-r--r-- | module/plugins/container/RSDF.py | 52 | ||||
-rw-r--r-- | module/plugins/crypter/BitshareCom.py | 24 | ||||
-rw-r--r-- | module/plugins/crypter/C1NeonCom.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/CloudzillaToFolder.py | 39 | ||||
-rw-r--r-- | module/plugins/crypter/CrockoCom.py | 23 | ||||
-rw-r--r-- | module/plugins/crypter/CryptItCom.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/DataHu.py | 43 | ||||
-rw-r--r-- | module/plugins/crypter/DdlstorageCom.py | 20 | ||||
-rw-r--r-- | module/plugins/crypter/DepositfilesCom.py | 23 | ||||
-rw-r--r-- | module/plugins/crypter/Dereferer.py | 17 | ||||
-rw-r--r-- | module/plugins/crypter/DevhostStFolder.py | 57 | ||||
-rw-r--r-- | module/plugins/crypter/DlProtectCom.py | 68 | ||||
-rw-r--r-- | module/plugins/crypter/DontKnowMe.py | 17 | ||||
-rw-r--r-- | module/plugins/crypter/DuploadOrg.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/EasybytezCom.py | 23 | ||||
-rw-r--r-- | module/plugins/crypter/FilebeerInfo.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/FilecloudIo.py | 24 | ||||
-rw-r--r-- | module/plugins/crypter/FilecryptCc.py | 182 | ||||
-rw-r--r-- | module/plugins/crypter/FilefactoryCom.py | 31 | ||||
-rw-r--r-- | module/plugins/crypter/FilerNet.py | 27 | ||||
-rw-r--r-- | module/plugins/crypter/FilesonicCom.py | 18 | ||||
-rw-r--r-- | module/plugins/crypter/FilestubeCom.py | 24 | ||||
-rw-r--r-- | module/plugins/crypter/FiletramCom.py | 25 | ||||
-rw-r--r-- | module/plugins/crypter/FiredriveCom.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/FreakhareCom.py | 41 | ||||
-rw-r--r-- | module/plugins/crypter/FreetexthostCom.py | 30 | ||||
-rw-r--r-- | module/plugins/crypter/FshareVn.py | 23 | ||||
-rw-r--r-- | module/plugins/crypter/Go4UpCom.py | 49 | ||||
-rw-r--r-- | module/plugins/crypter/HotfileCom.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/ILoadTo.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/ImgurComAlbum.py | 30 | ||||
-rw-r--r-- | module/plugins/crypter/LinkSaveIn.py | 22 | ||||
-rw-r--r-- | module/plugins/crypter/LofCc.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/MBLinkInfo.py | 20 | ||||
-rw-r--r-- | module/plugins/crypter/MegaCoNzFolder.py | 32 | ||||
-rw-r--r-- | module/plugins/crypter/MegaRapidCz.py | 23 | ||||
-rw-r--r-- | module/plugins/crypter/MegauploadCom.py | 18 | ||||
-rw-r--r-- | module/plugins/crypter/Movie2KTo.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/MultiUpOrg.py | 41 | ||||
-rw-r--r-- | module/plugins/crypter/MultiuploadCom.py | 18 | ||||
-rw-r--r-- | module/plugins/crypter/NetfolderIn.py | 73 | ||||
-rw-r--r-- | module/plugins/crypter/NosvideoCom.py | 24 | ||||
-rw-r--r-- | module/plugins/crypter/OronCom.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/PastebinCom.py | 24 | ||||
-rw-r--r-- | module/plugins/crypter/RSLayerCom.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/RelinkUs.py | 293 | ||||
-rw-r--r-- | module/plugins/crypter/SecuredIn.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/SharingmatrixCom.py | 18 | ||||
-rw-r--r-- | module/plugins/crypter/SpeedLoadOrg.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/StealthTo.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/TnyCz.py | 30 | ||||
-rw-r--r-- | module/plugins/crypter/TrailerzoneInfo.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/TurbobitNet.py | 47 | ||||
-rw-r--r-- | module/plugins/crypter/TusfilesNet.py | 46 | ||||
-rw-r--r-- | module/plugins/crypter/UploadableCh.py | 27 | ||||
-rw-r--r-- | module/plugins/crypter/UploadedTo.py | 37 | ||||
-rw-r--r-- | module/plugins/crypter/WiiReloadedOrg.py | 19 | ||||
-rw-r--r-- | module/plugins/crypter/WuploadCom.py | 18 | ||||
-rw-r--r-- | module/plugins/crypter/XFileSharingPro.py | 55 | ||||
-rw-r--r-- | module/plugins/hooks/AlldebridCom.py | 29 | ||||
-rw-r--r-- | module/plugins/hooks/AndroidPhoneNotify.py | 80 | ||||
-rw-r--r-- | module/plugins/hooks/BypassCaptcha.py | 135 | ||||
-rw-r--r-- | module/plugins/hooks/Captcha9Kw.py | 251 | ||||
-rw-r--r-- | module/plugins/hooks/CaptchaBrotherhood.py | 167 | ||||
-rw-r--r-- | module/plugins/hooks/ClickAndLoad.py | 124 | ||||
-rw-r--r-- | module/plugins/hooks/DeathByCaptcha.py | 214 | ||||
-rw-r--r-- | module/plugins/hooks/DebridItaliaCom.py | 28 | ||||
-rw-r--r-- | module/plugins/hooks/EasybytezCom.py | 32 | ||||
-rw-r--r-- | module/plugins/hooks/ExpertDecoders.py | 96 | ||||
-rw-r--r-- | module/plugins/hooks/FastixRu.py | 31 | ||||
-rw-r--r-- | module/plugins/hooks/FreeWayMe.py | 27 | ||||
-rw-r--r-- | module/plugins/hooks/ImageTyperz.py | 153 | ||||
-rw-r--r-- | module/plugins/hooks/JustPremium.py | 46 | ||||
-rw-r--r-- | module/plugins/hooks/LinkdecrypterCom.py | 25 | ||||
-rw-r--r-- | module/plugins/hooks/LinksnappyCom.py | 29 | ||||
-rw-r--r-- | module/plugins/hooks/MegaDebridEu.py | 35 | ||||
-rw-r--r-- | module/plugins/hooks/MultihostersCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hooks/MultishareCz.py | 31 | ||||
-rw-r--r-- | module/plugins/hooks/MyfastfileCom.py | 30 | ||||
-rw-r--r-- | module/plugins/hooks/NoPremiumPl.py | 31 | ||||
-rw-r--r-- | module/plugins/hooks/OverLoadMe.py | 31 | ||||
-rw-r--r-- | module/plugins/hooks/PremiumTo.py | 29 | ||||
-rw-r--r-- | module/plugins/hooks/PremiumizeMe.py | 40 | ||||
-rw-r--r-- | module/plugins/hooks/PutdriveCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hooks/RPNetBiz.py | 38 | ||||
-rw-r--r-- | module/plugins/hooks/RapideoPl.py | 31 | ||||
-rw-r--r-- | module/plugins/hooks/RealdebridCom.py | 29 | ||||
-rw-r--r-- | module/plugins/hooks/RehostTo.py | 29 | ||||
-rw-r--r-- | module/plugins/hooks/SimplyPremiumCom.py | 31 | ||||
-rw-r--r-- | module/plugins/hooks/SimplydebridCom.py | 26 | ||||
-rw-r--r-- | module/plugins/hooks/SmoozedCom.py | 26 | ||||
-rw-r--r-- | module/plugins/hooks/UnrestrictLi.py | 30 | ||||
-rw-r--r-- | module/plugins/hooks/WindowsPhoneNotify.py | 96 | ||||
-rw-r--r-- | module/plugins/hooks/XFileSharingPro.py | 110 | ||||
-rw-r--r-- | module/plugins/hooks/ZeveraCom.py | 27 | ||||
-rw-r--r-- | module/plugins/hoster/AlldebridCom.py | 78 | ||||
-rw-r--r-- | module/plugins/hoster/AndroidfilehostCom.py | 63 | ||||
-rw-r--r-- | module/plugins/hoster/BasketbuildCom.py | 61 | ||||
-rw-r--r-- | module/plugins/hoster/BayfilesCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/BezvadataCz.py | 94 | ||||
-rw-r--r-- | module/plugins/hoster/BillionuploadsCom.py | 22 | ||||
-rw-r--r-- | module/plugins/hoster/BitshareCom.py | 158 | ||||
-rw-r--r-- | module/plugins/hoster/BoltsharingCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/CatShareNet.py | 62 | ||||
-rw-r--r-- | module/plugins/hoster/CloudzerNet.py | 20 | ||||
-rw-r--r-- | module/plugins/hoster/CloudzillaTo.py | 61 | ||||
-rw-r--r-- | module/plugins/hoster/CramitIn.py | 23 | ||||
-rw-r--r-- | module/plugins/hoster/CrockoCom.py | 66 | ||||
-rw-r--r-- | module/plugins/hoster/CyberlockerCh.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/CzshareCom.py | 161 | ||||
-rw-r--r-- | module/plugins/hoster/DataHu.py | 34 | ||||
-rw-r--r-- | module/plugins/hoster/DataportCz.py | 57 | ||||
-rw-r--r-- | module/plugins/hoster/DateiTo.py | 82 | ||||
-rw-r--r-- | module/plugins/hoster/DdlstorageCom.py | 19 | ||||
-rw-r--r-- | module/plugins/hoster/DebridItaliaCom.py | 43 | ||||
-rw-r--r-- | module/plugins/hoster/DepositfilesCom.py | 115 | ||||
-rw-r--r-- | module/plugins/hoster/DevhostSt.py | 36 | ||||
-rw-r--r-- | module/plugins/hoster/DlFreeFr.py | 140 | ||||
-rw-r--r-- | module/plugins/hoster/DodanePl.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/DuploadOrg.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/EasybytezCom.py | 24 | ||||
-rw-r--r-- | module/plugins/hoster/EdiskCz.py | 56 | ||||
-rw-r--r-- | module/plugins/hoster/EgoFilesCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/EnteruploadCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/EpicShareNet.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/EuroshareEu.py | 67 | ||||
-rw-r--r-- | module/plugins/hoster/ExashareCom.py | 38 | ||||
-rw-r--r-- | module/plugins/hoster/ExtabitCom.py | 78 | ||||
-rw-r--r-- | module/plugins/hoster/FastixRu.py | 66 | ||||
-rw-r--r-- | module/plugins/hoster/FastshareCz.py | 79 | ||||
-rw-r--r-- | module/plugins/hoster/FileApeCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/FileSharkPl.py | 133 | ||||
-rw-r--r-- | module/plugins/hoster/FileStoreTo.py | 37 | ||||
-rw-r--r-- | module/plugins/hoster/FilebeerInfo.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/FilecloudIo.py | 126 | ||||
-rw-r--r-- | module/plugins/hoster/FileomCom.py | 33 | ||||
-rw-r--r-- | module/plugins/hoster/FilepostCom.py | 133 | ||||
-rw-r--r-- | module/plugins/hoster/FilepupNet.py | 47 | ||||
-rw-r--r-- | module/plugins/hoster/FilerNet.py | 74 | ||||
-rw-r--r-- | module/plugins/hoster/FilerioCom.py | 23 | ||||
-rw-r--r-- | module/plugins/hoster/FileserveCom.py | 216 | ||||
-rw-r--r-- | module/plugins/hoster/FileshareInUa.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/FilesonicCom.py | 19 | ||||
-rw-r--r-- | module/plugins/hoster/FilezyNet.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/FiredriveCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/FourSharedCom.py | 62 | ||||
-rw-r--r-- | module/plugins/hoster/FreakshareCom.py | 180 | ||||
-rw-r--r-- | module/plugins/hoster/FreeWayMe.py | 53 | ||||
-rw-r--r-- | module/plugins/hoster/FreevideoCz.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/GigapetaCom.py | 64 | ||||
-rw-r--r-- | module/plugins/hoster/GooIm.py | 37 | ||||
-rw-r--r-- | module/plugins/hoster/GoogledriveCom.py | 65 | ||||
-rw-r--r-- | module/plugins/hoster/HellshareCz.py | 35 | ||||
-rw-r--r-- | module/plugins/hoster/HellspyCz.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/HotfileCom.py | 21 | ||||
-rw-r--r-- | module/plugins/hoster/HugefilesNet.py | 25 | ||||
-rw-r--r-- | module/plugins/hoster/HundredEightyUploadCom.py | 19 | ||||
-rw-r--r-- | module/plugins/hoster/IFileWs.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/IcyFilesCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/IfileIt.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/IfolderRu.py | 76 | ||||
-rw-r--r-- | module/plugins/hoster/JumbofilesCom.py | 36 | ||||
-rw-r--r-- | module/plugins/hoster/JunocloudMe.py | 24 | ||||
-rw-r--r-- | module/plugins/hoster/Keep2ShareCc.py | 112 | ||||
-rw-r--r-- | module/plugins/hoster/KickloadCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/KingfilesNet.py | 78 | ||||
-rw-r--r-- | module/plugins/hoster/LemUploadsCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/LetitbitNet.py | 155 | ||||
-rw-r--r-- | module/plugins/hoster/LinksnappyCom.py | 58 | ||||
-rw-r--r-- | module/plugins/hoster/LoadTo.py | 68 | ||||
-rw-r--r-- | module/plugins/hoster/LomafileCom.py | 19 | ||||
-rw-r--r-- | module/plugins/hoster/LuckyShareNet.py | 74 | ||||
-rw-r--r-- | module/plugins/hoster/MegaCoNz.py | 217 | ||||
-rw-r--r-- | module/plugins/hoster/MegaDebridEu.py | 89 | ||||
-rw-r--r-- | module/plugins/hoster/MegaFilesSe.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/MegaRapidCz.py | 65 | ||||
-rw-r--r-- | module/plugins/hoster/MegareleaseOrg.py | 19 | ||||
-rw-r--r-- | module/plugins/hoster/MegasharesCom.py | 113 | ||||
-rw-r--r-- | module/plugins/hoster/MegauploadCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/MegavideoCom.py | 19 | ||||
-rw-r--r-- | module/plugins/hoster/MovReelCom.py | 21 | ||||
-rw-r--r-- | module/plugins/hoster/MultihostersCom.py | 15 | ||||
-rw-r--r-- | module/plugins/hoster/MultishareCz.py | 54 | ||||
-rw-r--r-- | module/plugins/hoster/MyfastfileCom.py | 39 | ||||
-rw-r--r-- | module/plugins/hoster/MystoreTo.py | 45 | ||||
-rw-r--r-- | module/plugins/hoster/NahrajCz.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/NarodRu.py | 66 | ||||
-rw-r--r-- | module/plugins/hoster/NitroflareCom.py | 107 | ||||
-rw-r--r-- | module/plugins/hoster/NoPremiumPl.py | 103 | ||||
-rw-r--r-- | module/plugins/hoster/NosuploadCom.py | 42 | ||||
-rw-r--r-- | module/plugins/hoster/NovafileCom.py | 29 | ||||
-rw-r--r-- | module/plugins/hoster/NowDownloadSx.py | 64 | ||||
-rw-r--r-- | module/plugins/hoster/NowVideoSx.py | 44 | ||||
-rw-r--r-- | module/plugins/hoster/OneFichierCom.py | 61 | ||||
-rw-r--r-- | module/plugins/hoster/OronCom.py | 19 | ||||
-rw-r--r-- | module/plugins/hoster/OverLoadMe.py | 76 | ||||
-rw-r--r-- | module/plugins/hoster/PandaplaNet.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/PotloadCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/PremiumTo.py | 55 | ||||
-rw-r--r-- | module/plugins/hoster/PremiumizeMe.py | 60 | ||||
-rw-r--r-- | module/plugins/hoster/PromptfileCom.py | 45 | ||||
-rw-r--r-- | module/plugins/hoster/PrzeklejPl.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/PutdriveCom.py | 15 | ||||
-rw-r--r-- | module/plugins/hoster/QuickshareCz.py | 89 | ||||
-rw-r--r-- | module/plugins/hoster/RPNetBiz.py | 80 | ||||
-rw-r--r-- | module/plugins/hoster/RapideoPl.py | 103 | ||||
-rw-r--r-- | module/plugins/hoster/RapidfileshareNet.py | 25 | ||||
-rw-r--r-- | module/plugins/hoster/RapidgatorNet.py | 172 | ||||
-rw-r--r-- | module/plugins/hoster/RapiduNet.py | 86 | ||||
-rw-r--r-- | module/plugins/hoster/RarefileNet.py | 23 | ||||
-rw-r--r-- | module/plugins/hoster/RealdebridCom.py | 79 | ||||
-rw-r--r-- | module/plugins/hoster/RehostTo.py | 28 | ||||
-rw-r--r-- | module/plugins/hoster/RemixshareCom.py | 60 | ||||
-rw-r--r-- | module/plugins/hoster/RgHostNet.py | 26 | ||||
-rw-r--r-- | module/plugins/hoster/SafesharingEu.py | 21 | ||||
-rw-r--r-- | module/plugins/hoster/SecureUploadEu.py | 21 | ||||
-rw-r--r-- | module/plugins/hoster/SendspaceCom.py | 61 | ||||
-rw-r--r-- | module/plugins/hoster/Share4WebCom.py | 22 | ||||
-rw-r--r-- | module/plugins/hoster/Share76Com.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/ShareFilesCo.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/SharebeesCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/ShareonlineBiz.py | 187 | ||||
-rw-r--r-- | module/plugins/hoster/SharingmatrixCom.py | 19 | ||||
-rw-r--r-- | module/plugins/hoster/ShragleCom.py | 19 | ||||
-rw-r--r-- | module/plugins/hoster/SimplyPremiumCom.py | 81 | ||||
-rw-r--r-- | module/plugins/hoster/SimplydebridCom.py | 48 | ||||
-rw-r--r-- | module/plugins/hoster/SmoozedCom.py | 63 | ||||
-rw-r--r-- | module/plugins/hoster/SockshareCom.py | 20 | ||||
-rw-r--r-- | module/plugins/hoster/SpeedLoadOrg.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/SpeedfileCz.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/SpeedyshareCom.py | 44 | ||||
-rw-r--r-- | module/plugins/hoster/StorageTo.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/StreamcloudEu.py | 31 | ||||
-rw-r--r-- | module/plugins/hoster/TurbobitNet.py | 167 | ||||
-rw-r--r-- | module/plugins/hoster/TurbouploadCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/TusfilesNet.py | 40 | ||||
-rw-r--r-- | module/plugins/hoster/TwoSharedCom.py | 32 | ||||
-rw-r--r-- | module/plugins/hoster/UlozTo.py | 158 | ||||
-rw-r--r-- | module/plugins/hoster/UloziskoSk.py | 71 | ||||
-rw-r--r-- | module/plugins/hoster/UnibytesCom.py | 73 | ||||
-rw-r--r-- | module/plugins/hoster/UnrestrictLi.py | 85 | ||||
-rw-r--r-- | module/plugins/hoster/UpleaCom.py | 59 | ||||
-rw-r--r-- | module/plugins/hoster/UploadStationCom.py | 19 | ||||
-rw-r--r-- | module/plugins/hoster/UploadableCh.py | 79 | ||||
-rw-r--r-- | module/plugins/hoster/UploadboxCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/UploadedTo.py | 120 | ||||
-rw-r--r-- | module/plugins/hoster/UploadhereCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/UploadheroCom.py | 76 | ||||
-rw-r--r-- | module/plugins/hoster/UploadingCom.py | 99 | ||||
-rw-r--r-- | module/plugins/hoster/UploadkingCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/UpstoreNet.py | 72 | ||||
-rw-r--r-- | module/plugins/hoster/UptoboxCom.py | 32 | ||||
-rw-r--r-- | module/plugins/hoster/VeohCom.py | 54 | ||||
-rw-r--r-- | module/plugins/hoster/VidPlayNet.py | 24 | ||||
-rw-r--r-- | module/plugins/hoster/VimeoCom.py | 74 | ||||
-rw-r--r-- | module/plugins/hoster/Vipleech4UCom.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/WarserverCz.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/WebshareCz.py | 63 | ||||
-rw-r--r-- | module/plugins/hoster/WrzucTo.py | 52 | ||||
-rw-r--r-- | module/plugins/hoster/WuploadCom.py | 19 | ||||
-rw-r--r-- | module/plugins/hoster/X7To.py | 18 | ||||
-rw-r--r-- | module/plugins/hoster/XFileSharingPro.py | 62 | ||||
-rw-r--r-- | module/plugins/hoster/XdadevelopersCom.py | 38 | ||||
-rw-r--r-- | module/plugins/hoster/YibaishiwuCom.py | 59 | ||||
-rw-r--r-- | module/plugins/hoster/ZShareNet.py | 19 | ||||
-rw-r--r-- | module/plugins/hoster/ZeveraCom.py | 34 | ||||
-rw-r--r-- | module/plugins/hoster/ZippyshareCom.py | 65 | ||||
-rw-r--r-- | module/plugins/internal/BasePlugin.py | 95 | ||||
-rw-r--r-- | module/plugins/internal/CaptchaService.py | 522 | ||||
-rw-r--r-- | module/plugins/internal/DeadCrypter.py | 31 | ||||
-rw-r--r-- | module/plugins/internal/DeadHoster.py | 31 | ||||
-rw-r--r-- | module/plugins/internal/Extractor.py | 139 | ||||
-rw-r--r-- | module/plugins/internal/MultiHook.py | 308 | ||||
-rw-r--r-- | module/plugins/internal/MultiHoster.py | 85 | ||||
-rw-r--r-- | module/plugins/internal/SevenZip.py | 155 | ||||
-rw-r--r-- | module/plugins/internal/SimpleCrypter.py | 157 | ||||
-rw-r--r-- | module/plugins/internal/SimpleDereferer.py | 98 | ||||
-rw-r--r-- | module/plugins/internal/SimpleHoster.py | 701 | ||||
-rw-r--r-- | module/plugins/internal/UnRar.py | 248 | ||||
-rw-r--r-- | module/plugins/internal/UnZip.py | 68 | ||||
-rw-r--r-- | module/plugins/internal/UpdateManager.py | 300 | ||||
-rw-r--r-- | module/plugins/internal/XFSCrypter.py | 45 | ||||
-rw-r--r-- | module/plugins/internal/XFSHoster.py | 326 | ||||
-rw-r--r-- | pyload/Core.py (renamed from module/Core.py) | 0 | ||||
-rw-r--r-- | pyload/__init__.py (renamed from module/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/api/__init__.py (renamed from module/api/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/api/types.py (renamed from module/api/types.py) | 0 | ||||
-rw-r--r-- | pyload/cli/AddPackage.py (renamed from module/cli/AddPackage.py) | 0 | ||||
-rw-r--r-- | pyload/cli/Cli.py (renamed from module/cli/Cli.py) | 0 | ||||
-rw-r--r-- | pyload/cli/Handler.py (renamed from module/cli/Handler.py) | 0 | ||||
-rw-r--r-- | pyload/cli/ManageFiles.py (renamed from module/cli/ManageFiles.py) | 0 | ||||
-rw-r--r-- | pyload/cli/__init__.py (renamed from module/cli/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/config/Parser.py (renamed from module/config/Parser.py) | 0 | ||||
-rw-r--r-- | pyload/config/Setup.py (renamed from module/config/Setup.py) | 0 | ||||
-rw-r--r-- | pyload/config/__init__.py (renamed from module/config/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/config/default.conf (renamed from module/config/default.conf) | 0 | ||||
-rw-r--r-- | pyload/database/DatabaseBackend.py (renamed from module/database/DatabaseBackend.py) | 0 | ||||
-rw-r--r-- | pyload/database/File.py | 875 | ||||
-rw-r--r-- | pyload/database/Storage.py (renamed from module/database/Storage.py) | 0 | ||||
-rw-r--r-- | pyload/database/User.py (renamed from module/database/User.py) | 0 | ||||
-rw-r--r-- | pyload/database/__init__.py (renamed from module/database/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/datatype/File.py (renamed from module/datatype/File.py) | 0 | ||||
-rw-r--r-- | pyload/datatype/Package.py (renamed from module/datatype/Package.py) | 0 | ||||
-rw-r--r-- | pyload/datatype/__init__.py (renamed from module/datatype/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/manager/Account.py (renamed from module/manager/Account.py) | 0 | ||||
-rw-r--r-- | pyload/manager/Addon.py (renamed from module/manager/Addon.py) | 0 | ||||
-rw-r--r-- | pyload/manager/Captcha.py (renamed from module/manager/Captcha.py) | 0 | ||||
-rw-r--r-- | pyload/manager/Event.py (renamed from module/manager/Event.py) | 0 | ||||
-rw-r--r-- | pyload/manager/Plugin.py (renamed from module/manager/Plugin.py) | 0 | ||||
-rw-r--r-- | pyload/manager/Remote.py (renamed from module/manager/Remote.py) | 0 | ||||
-rw-r--r-- | pyload/manager/Thread.py (renamed from module/manager/Thread.py) | 0 | ||||
-rw-r--r-- | pyload/manager/__init__.py (renamed from module/manager/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/manager/event/Scheduler.py (renamed from module/manager/event/Scheduler.py) | 0 | ||||
-rw-r--r-- | pyload/manager/event/__init__.py (renamed from module/manager/event/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/manager/thread/Addon.py (renamed from module/manager/thread/Addon.py) | 0 | ||||
-rw-r--r-- | pyload/manager/thread/Decrypter.py (renamed from module/manager/thread/Decrypter.py) | 0 | ||||
-rw-r--r-- | pyload/manager/thread/Download.py (renamed from module/manager/thread/Download.py) | 0 | ||||
-rw-r--r-- | pyload/manager/thread/Info.py (renamed from module/manager/thread/Info.py) | 0 | ||||
-rw-r--r-- | pyload/manager/thread/Plugin.py (renamed from module/manager/thread/Plugin.py) | 0 | ||||
-rw-r--r-- | pyload/manager/thread/Server.py (renamed from module/manager/thread/Server.py) | 0 | ||||
-rw-r--r-- | pyload/manager/thread/__init__.py (renamed from module/manager/thread/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/network/Browser.py (renamed from module/network/Browser.py) | 0 | ||||
-rw-r--r-- | pyload/network/Bucket.py (renamed from module/network/Bucket.py) | 0 | ||||
-rw-r--r-- | pyload/network/CookieJar.py (renamed from module/network/CookieJar.py) | 0 | ||||
-rw-r--r-- | pyload/network/HTTPChunk.py (renamed from module/network/HTTPChunk.py) | 0 | ||||
-rw-r--r-- | pyload/network/HTTPDownload.py (renamed from module/network/HTTPDownload.py) | 0 | ||||
-rw-r--r-- | pyload/network/HTTPRequest.py (renamed from module/network/HTTPRequest.py) | 0 | ||||
-rw-r--r-- | pyload/network/JsEngine.py (renamed from module/network/JsEngine.py) | 0 | ||||
-rw-r--r-- | pyload/network/RequestFactory.py (renamed from module/network/RequestFactory.py) | 0 | ||||
-rw-r--r-- | pyload/network/XDCCRequest.py (renamed from module/network/XDCCRequest.py) | 0 | ||||
-rw-r--r-- | pyload/network/__init__.py (renamed from module/network/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/Account.py (renamed from module/plugins/Account.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/Addon.py | 182 | ||||
-rw-r--r-- | pyload/plugin/Captcha.py | 34 | ||||
-rw-r--r-- | pyload/plugin/Container.py (renamed from module/plugins/Container.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/Crypter.py (renamed from module/plugins/Crypter.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/Extractor.py | 140 | ||||
-rw-r--r-- | pyload/plugin/Hook.py | 15 | ||||
-rw-r--r-- | pyload/plugin/Hoster.py (renamed from module/plugins/Hoster.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/OCR.py | 319 | ||||
-rw-r--r-- | pyload/plugin/Plugin.py (renamed from module/plugins/Plugin.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/__init__.py (renamed from module/plugins/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/AlldebridCom.py (renamed from module/plugins/accounts/AlldebridCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/BackinNet.py | 16 | ||||
-rw-r--r-- | pyload/plugin/account/BillionuploadsCom.py (renamed from module/plugins/accounts/BillionuploadsCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/BitshareCom.py (renamed from module/plugins/accounts/BitshareCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/CatShareNet.py (renamed from module/plugins/accounts/CatShareNet.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/CloudzillaTo.py | 37 | ||||
-rw-r--r-- | pyload/plugin/account/CramitIn.py (renamed from module/plugins/accounts/CramitIn.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/CzshareCom.py (renamed from module/plugins/accounts/CzshareCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/DebridItaliaCom.py (renamed from module/plugins/accounts/DebridItaliaCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/DepositfilesCom.py (renamed from module/plugins/accounts/DepositfilesCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/DropboxCom.py | 35 | ||||
-rw-r--r-- | pyload/plugin/account/EasybytezCom.py (renamed from module/plugins/accounts/EasybytezCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/EuroshareEu.py (renamed from module/plugins/accounts/EuroshareEu.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/ExashareCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/account/FastixRu.py (renamed from module/plugins/accounts/FastixRu.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FastshareCz.py (renamed from module/plugins/accounts/FastshareCz.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/File4SafeCom.py (renamed from module/plugins/accounts/File4SafeCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FileParadoxIn.py (renamed from module/plugins/accounts/FileParadoxIn.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FilecloudIo.py (renamed from module/plugins/accounts/FilecloudIo.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FilefactoryCom.py (renamed from module/plugins/accounts/FilefactoryCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FilejungleCom.py (renamed from module/plugins/accounts/FilejungleCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FileomCom.py (renamed from module/plugins/accounts/FileomCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FilerNet.py (renamed from module/plugins/accounts/FilerNet.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FilerioCom.py (renamed from module/plugins/accounts/FilerioCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FilesMailRu.py (renamed from module/plugins/accounts/FilesMailRu.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FileserveCom.py (renamed from module/plugins/accounts/FileserveCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FourSharedCom.py (renamed from module/plugins/accounts/FourSharedCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FreakshareCom.py (renamed from module/plugins/accounts/FreakshareCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FreeWayMe.py (renamed from module/plugins/accounts/FreeWayMe.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/FshareVn.py (renamed from module/plugins/accounts/FshareVn.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/Ftp.py (renamed from module/plugins/accounts/Ftp.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/HellshareCz.py (renamed from module/plugins/accounts/HellshareCz.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/Http.py (renamed from module/plugins/accounts/Http.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/HugefilesNet.py (renamed from module/plugins/accounts/HugefilesNet.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/HundredEightyUploadCom.py (renamed from module/plugins/accounts/HundredEightyUploadCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/JunkyvideoCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/account/JunocloudMe.py (renamed from module/plugins/accounts/JunocloudMe.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/Keep2ShareCc.py (renamed from module/plugins/accounts/Keep2ShareCc.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/LetitbitNet.py (renamed from module/plugins/accounts/LetitbitNet.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/LinestorageCom.py (renamed from module/plugins/accounts/LinestorageCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/LinksnappyCom.py (renamed from module/plugins/accounts/LinksnappyCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/MegaDebridEu.py (renamed from module/plugins/accounts/MegaDebridEu.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/MegaRapidCz.py (renamed from module/plugins/accounts/MegaRapidCz.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/MegasharesCom.py (renamed from module/plugins/accounts/MegasharesCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/MovReelCom.py (renamed from module/plugins/accounts/MovReelCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/MultihostersCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/account/MultishareCz.py (renamed from module/plugins/accounts/MultishareCz.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/MyfastfileCom.py (renamed from module/plugins/accounts/MyfastfileCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/NetloadIn.py (renamed from module/plugins/accounts/NetloadIn.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/NoPremiumPl.py | 82 | ||||
-rw-r--r-- | pyload/plugin/account/NosuploadCom.py (renamed from module/plugins/accounts/NosuploadCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/NovafileCom.py (renamed from module/plugins/accounts/NovafileCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/NowVideoSx.py (renamed from module/plugins/accounts/NowVideoSx.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/OboomCom.py (renamed from module/plugins/accounts/OboomCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/OneFichierCom.py (renamed from module/plugins/accounts/OneFichierCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/OverLoadMe.py (renamed from module/plugins/accounts/OverLoadMe.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/PremiumTo.py (renamed from module/plugins/accounts/PremiumTo.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/PremiumizeMe.py (renamed from module/plugins/accounts/PremiumizeMe.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/PutdriveCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/account/QuickshareCz.py (renamed from module/plugins/accounts/QuickshareCz.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/RPNetBiz.py (renamed from module/plugins/accounts/RPNetBiz.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/RapideoPl.py | 81 | ||||
-rw-r--r-- | pyload/plugin/account/RapidfileshareNet.py (renamed from module/plugins/accounts/RapidfileshareNet.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/RapidgatorNet.py (renamed from module/plugins/accounts/RapidgatorNet.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/RapiduNet.py | 66 | ||||
-rw-r--r-- | pyload/plugin/account/RarefileNet.py (renamed from module/plugins/accounts/RarefileNet.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/RealdebridCom.py (renamed from module/plugins/accounts/RealdebridCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/RehostTo.py (renamed from module/plugins/accounts/RehostTo.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/RyushareCom.py (renamed from module/plugins/accounts/RyushareCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/SafesharingEu.py (renamed from module/plugins/accounts/SafesharingEu.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/SecureUploadEu.py (renamed from module/plugins/accounts/SecureUploadEu.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/SendmywayCom.py (renamed from module/plugins/accounts/SendmywayCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/ShareonlineBiz.py (renamed from module/plugins/accounts/ShareonlineBiz.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/SimplyPremiumCom.py (renamed from module/plugins/accounts/SimplyPremiumCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/SimplydebridCom.py (renamed from module/plugins/accounts/SimplydebridCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/SmoozedCom.py | 62 | ||||
-rw-r--r-- | pyload/plugin/account/StahnuTo.py (renamed from module/plugins/accounts/StahnuTo.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/StreamcloudEu.py (renamed from module/plugins/accounts/StreamcloudEu.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/TurbobitNet.py (renamed from module/plugins/accounts/TurbobitNet.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/TusfilesNet.py (renamed from module/plugins/accounts/TusfilesNet.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/UlozTo.py (renamed from module/plugins/accounts/UlozTo.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/UnrestrictLi.py (renamed from module/plugins/accounts/UnrestrictLi.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/UploadableCh.py | 34 | ||||
-rw-r--r-- | pyload/plugin/account/UploadcCom.py (renamed from module/plugins/accounts/UploadcCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/UploadedTo.py (renamed from module/plugins/accounts/UploadedTo.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/UploadheroCom.py (renamed from module/plugins/accounts/UploadheroCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/UploadingCom.py (renamed from module/plugins/accounts/UploadingCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/UptoboxCom.py (renamed from module/plugins/accounts/UptoboxCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/VidPlayNet.py (renamed from module/plugins/accounts/VidPlayNet.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/WebshareCz.py | 68 | ||||
-rw-r--r-- | pyload/plugin/account/XFileSharingPro.py (renamed from module/plugins/accounts/XFileSharingPro.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/YibaishiwuCom.py (renamed from module/plugins/accounts/YibaishiwuCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/ZeveraCom.py (renamed from module/plugins/accounts/ZeveraCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/account/__init__.py (renamed from module/plugins/accounts/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/addon/AndroidPhoneNotify.py | 75 | ||||
-rw-r--r-- | pyload/plugin/addon/Checksum.py (renamed from module/plugins/addon/Checksum.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/addon/ClickAndLoad.py | 119 | ||||
-rw-r--r-- | pyload/plugin/addon/DeleteFinished.py (renamed from module/plugins/addon/DeleteFinished.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/addon/DownloadScheduler.py (renamed from module/plugins/addon/DownloadScheduler.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/addon/ExternalScripts.py (renamed from module/plugins/addon/ExternalScripts.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/addon/ExtractArchive.py | 504 | ||||
-rw-r--r-- | pyload/plugin/addon/HotFolder.py (renamed from module/plugins/addon/HotFolder.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/addon/IRCInterface.py (renamed from module/plugins/addon/IRCInterface.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/addon/JustPremium.py | 46 | ||||
-rw-r--r-- | pyload/plugin/addon/MergeFiles.py | 85 | ||||
-rw-r--r-- | pyload/plugin/addon/MultiHome.py (renamed from module/plugins/addon/MultiHome.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/addon/RestartFailed.py (renamed from module/plugins/addon/RestartFailed.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/addon/RestartSlow.py (renamed from module/plugins/addon/RestartSlow.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/addon/SkipRev.py | 93 | ||||
-rw-r--r-- | pyload/plugin/addon/UnSkipOnFail.py | 90 | ||||
-rw-r--r-- | pyload/plugin/addon/UpdateManager.py | 306 | ||||
-rw-r--r-- | pyload/plugin/addon/WindowsPhoneNotify.py | 91 | ||||
-rw-r--r-- | pyload/plugin/addon/XMPPInterface.py (renamed from module/plugins/addon/XMPPInterface.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/addon/__init__.py (renamed from module/plugins/addon/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/captcha/AdYouLike.py | 108 | ||||
-rw-r--r-- | pyload/plugin/captcha/AdsCaptcha.py | 79 | ||||
-rw-r--r-- | pyload/plugin/captcha/ReCaptcha.py | 208 | ||||
-rw-r--r-- | pyload/plugin/captcha/SolveMedia.py | 113 | ||||
-rw-r--r-- | pyload/plugin/captcha/__init__.py (renamed from module/plugins/captcha/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/container/CCF.py | 49 | ||||
-rw-r--r-- | pyload/plugin/container/DLC.py | 72 | ||||
-rw-r--r-- | pyload/plugin/container/RSDF.py | 52 | ||||
-rw-r--r-- | pyload/plugin/container/TXT.py | 69 | ||||
-rw-r--r-- | pyload/plugin/container/__init__.py (renamed from module/plugins/container/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/BitshareCom.py | 21 | ||||
-rw-r--r-- | pyload/plugin/crypter/C1NeonCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/ChipDe.py (renamed from module/plugins/crypter/ChipDe.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/CloudzillaTo.py | 36 | ||||
-rw-r--r-- | pyload/plugin/crypter/CrockoCom.py | 20 | ||||
-rw-r--r-- | pyload/plugin/crypter/CryptItCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/CzshareCom.py (renamed from module/plugins/crypter/CzshareCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/DDLMusicOrg.py (renamed from module/plugins/crypter/DDLMusicOrg.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/DailymotionBatch.py (renamed from module/plugins/crypter/DailymotionBatch.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/DataHu.py | 40 | ||||
-rw-r--r-- | pyload/plugin/crypter/DdlstorageCom.py | 17 | ||||
-rw-r--r-- | pyload/plugin/crypter/DepositfilesCom.py | 20 | ||||
-rw-r--r-- | pyload/plugin/crypter/Dereferer.py | 17 | ||||
-rw-r--r-- | pyload/plugin/crypter/DevhostSt.py | 54 | ||||
-rw-r--r-- | pyload/plugin/crypter/DlProtectCom.py | 65 | ||||
-rw-r--r-- | pyload/plugin/crypter/DontKnowMe.py | 17 | ||||
-rw-r--r-- | pyload/plugin/crypter/DuckCryptInfo.py (renamed from module/plugins/crypter/DuckCryptInfo.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/DuploadOrg.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/EasybytezCom.py | 20 | ||||
-rw-r--r-- | pyload/plugin/crypter/EmbeduploadCom.py (renamed from module/plugins/crypter/EmbeduploadCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/FilebeerInfo.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/FilecloudIo.py | 21 | ||||
-rw-r--r-- | pyload/plugin/crypter/FilecryptCc.py | 182 | ||||
-rw-r--r-- | pyload/plugin/crypter/FilefactoryCom.py | 28 | ||||
-rw-r--r-- | pyload/plugin/crypter/FilerNet.py | 24 | ||||
-rw-r--r-- | pyload/plugin/crypter/FileserveCom.py (renamed from module/plugins/crypter/FileserveCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/FilesonicCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/crypter/FilestubeCom.py | 21 | ||||
-rw-r--r-- | pyload/plugin/crypter/FiletramCom.py | 22 | ||||
-rw-r--r-- | pyload/plugin/crypter/FiredriveCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/FourChanOrg.py (renamed from module/plugins/crypter/FourChanOrg.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/FreakhareCom.py | 38 | ||||
-rw-r--r-- | pyload/plugin/crypter/FreetexthostCom.py | 27 | ||||
-rw-r--r-- | pyload/plugin/crypter/FshareVn.py | 20 | ||||
-rw-r--r-- | pyload/plugin/crypter/Go4UpCom.py | 46 | ||||
-rw-r--r-- | pyload/plugin/crypter/GooGl.py (renamed from module/plugins/crypter/GooGl.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/HoerbuchIn.py (renamed from module/plugins/crypter/HoerbuchIn.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/HotfileCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/ILoadTo.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/ImgurComAlbum.py | 27 | ||||
-rw-r--r-- | pyload/plugin/crypter/LetitbitNet.py (renamed from module/plugins/crypter/LetitbitNet.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/LinkCryptWs.py (renamed from module/plugins/crypter/LinkCryptWs.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/LinkSaveIn.py | 22 | ||||
-rw-r--r-- | pyload/plugin/crypter/LinkdecrypterCom.py (renamed from module/plugins/crypter/LinkdecrypterCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/LixIn.py (renamed from module/plugins/crypter/LixIn.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/LofCc.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/MBLinkInfo.py | 17 | ||||
-rw-r--r-- | pyload/plugin/crypter/MediafireCom.py (renamed from module/plugins/crypter/MediafireCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/MegaCoNz.py | 32 | ||||
-rw-r--r-- | pyload/plugin/crypter/MegaRapidCz.py | 20 | ||||
-rw-r--r-- | pyload/plugin/crypter/MegauploadCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/crypter/Movie2KTo.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/MultiUpOrg.py | 38 | ||||
-rw-r--r-- | pyload/plugin/crypter/MultiloadCz.py (renamed from module/plugins/crypter/MultiloadCz.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/MultiuploadCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/crypter/NCryptIn.py (renamed from module/plugins/crypter/NCryptIn.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/NetfolderIn.py | 70 | ||||
-rw-r--r-- | pyload/plugin/crypter/NosvideoCom.py | 21 | ||||
-rw-r--r-- | pyload/plugin/crypter/OneKhDe.py (renamed from module/plugins/crypter/OneKhDe.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/OronCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/PastebinCom.py | 21 | ||||
-rw-r--r-- | pyload/plugin/crypter/QuickshareCz.py (renamed from module/plugins/crypter/QuickshareCz.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/RSLayerCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/RelinkUs.py | 293 | ||||
-rw-r--r-- | pyload/plugin/crypter/SafelinkingNet.py (renamed from module/plugins/crypter/SafelinkingNet.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/SecuredIn.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/SexuriaCom.py (renamed from module/plugins/crypter/SexuriaCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/ShareLinksBiz.py (renamed from module/plugins/crypter/ShareLinksBiz.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/SharingmatrixCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/crypter/SpeedLoadOrg.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/StealthTo.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/TnyCz.py | 27 | ||||
-rw-r--r-- | pyload/plugin/crypter/TrailerzoneInfo.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/TurbobitNet.py | 44 | ||||
-rw-r--r-- | pyload/plugin/crypter/TusfilesNet.py | 43 | ||||
-rw-r--r-- | pyload/plugin/crypter/UlozTo.py (renamed from module/plugins/crypter/UlozTo.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/UploadableCh.py | 24 | ||||
-rw-r--r-- | pyload/plugin/crypter/UploadedTo.py | 34 | ||||
-rw-r--r-- | pyload/plugin/crypter/WiiReloadedOrg.py | 16 | ||||
-rw-r--r-- | pyload/plugin/crypter/WuploadCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/crypter/XFileSharingPro.py | 52 | ||||
-rw-r--r-- | pyload/plugin/crypter/XupPl.py (renamed from module/plugins/crypter/XupPl.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/YoutubeBatch.py (renamed from module/plugins/crypter/YoutubeBatch.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/crypter/__init__.py (renamed from module/plugins/crypter/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/extractor/SevenZip.py | 155 | ||||
-rw-r--r-- | pyload/plugin/extractor/UnRar.py | 248 | ||||
-rw-r--r-- | pyload/plugin/extractor/UnZip.py | 68 | ||||
-rw-r--r-- | pyload/plugin/extractor/__init__.py (renamed from module/plugins/hooks/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hook/AlldebridCom.py | 29 | ||||
-rw-r--r-- | pyload/plugin/hook/BypassCaptcha.py | 135 | ||||
-rw-r--r-- | pyload/plugin/hook/Captcha9Kw.py | 251 | ||||
-rw-r--r-- | pyload/plugin/hook/CaptchaBrotherhood.py | 167 | ||||
-rw-r--r-- | pyload/plugin/hook/DeathByCaptcha.py | 214 | ||||
-rw-r--r-- | pyload/plugin/hook/DebridItaliaCom.py | 28 | ||||
-rw-r--r-- | pyload/plugin/hook/EasybytezCom.py | 32 | ||||
-rw-r--r-- | pyload/plugin/hook/ExpertDecoders.py | 96 | ||||
-rw-r--r-- | pyload/plugin/hook/FastixRu.py | 31 | ||||
-rw-r--r-- | pyload/plugin/hook/FreeWayMe.py | 27 | ||||
-rw-r--r-- | pyload/plugin/hook/ImageTyperz.py | 153 | ||||
-rw-r--r-- | pyload/plugin/hook/LinkdecrypterCom.py | 25 | ||||
-rw-r--r-- | pyload/plugin/hook/LinksnappyCom.py | 29 | ||||
-rw-r--r-- | pyload/plugin/hook/MegaDebridEu.py | 35 | ||||
-rw-r--r-- | pyload/plugin/hook/MultihostersCom.py | 18 | ||||
-rw-r--r-- | pyload/plugin/hook/MultishareCz.py | 31 | ||||
-rw-r--r-- | pyload/plugin/hook/MyfastfileCom.py | 30 | ||||
-rw-r--r-- | pyload/plugin/hook/NoPremiumPl.py | 31 | ||||
-rw-r--r-- | pyload/plugin/hook/OverLoadMe.py | 31 | ||||
-rw-r--r-- | pyload/plugin/hook/PremiumTo.py | 29 | ||||
-rw-r--r-- | pyload/plugin/hook/PremiumizeMe.py | 40 | ||||
-rw-r--r-- | pyload/plugin/hook/PutdriveCom.py | 18 | ||||
-rw-r--r-- | pyload/plugin/hook/RPNetBiz.py | 38 | ||||
-rw-r--r-- | pyload/plugin/hook/RapideoPl.py | 31 | ||||
-rw-r--r-- | pyload/plugin/hook/RealdebridCom.py | 29 | ||||
-rw-r--r-- | pyload/plugin/hook/RehostTo.py | 29 | ||||
-rw-r--r-- | pyload/plugin/hook/SimplyPremiumCom.py | 31 | ||||
-rw-r--r-- | pyload/plugin/hook/SimplydebridCom.py | 26 | ||||
-rw-r--r-- | pyload/plugin/hook/SmoozedCom.py | 26 | ||||
-rw-r--r-- | pyload/plugin/hook/UnrestrictLi.py | 30 | ||||
-rw-r--r-- | pyload/plugin/hook/XFileSharingPro.py | 110 | ||||
-rw-r--r-- | pyload/plugin/hook/ZeveraCom.py | 27 | ||||
-rw-r--r-- | pyload/plugin/hook/__init__.py (renamed from module/plugins/hoster/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/AlldebridCom.py | 75 | ||||
-rw-r--r-- | pyload/plugin/hoster/AndroidfilehostCom.py | 60 | ||||
-rw-r--r-- | pyload/plugin/hoster/BasketbuildCom.py | 58 | ||||
-rw-r--r-- | pyload/plugin/hoster/BayfilesCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/BezvadataCz.py | 91 | ||||
-rw-r--r-- | pyload/plugin/hoster/BillionuploadsCom.py | 19 | ||||
-rw-r--r-- | pyload/plugin/hoster/BitshareCom.py | 155 | ||||
-rw-r--r-- | pyload/plugin/hoster/BoltsharingCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/CatShareNet.py | 59 | ||||
-rw-r--r-- | pyload/plugin/hoster/CloudzerNet.py | 17 | ||||
-rw-r--r-- | pyload/plugin/hoster/CloudzillaTo.py | 58 | ||||
-rw-r--r-- | pyload/plugin/hoster/CramitIn.py | 20 | ||||
-rw-r--r-- | pyload/plugin/hoster/CrockoCom.py | 63 | ||||
-rw-r--r-- | pyload/plugin/hoster/CyberlockerCh.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/CzshareCom.py | 158 | ||||
-rw-r--r-- | pyload/plugin/hoster/DailymotionCom.py (renamed from module/plugins/hoster/DailymotionCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/DataHu.py | 31 | ||||
-rw-r--r-- | pyload/plugin/hoster/DataportCz.py | 54 | ||||
-rw-r--r-- | pyload/plugin/hoster/DateiTo.py | 79 | ||||
-rw-r--r-- | pyload/plugin/hoster/DdlstorageCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/hoster/DebridItaliaCom.py | 40 | ||||
-rw-r--r-- | pyload/plugin/hoster/DepositfilesCom.py | 112 | ||||
-rw-r--r-- | pyload/plugin/hoster/DevhostSt.py | 33 | ||||
-rw-r--r-- | pyload/plugin/hoster/DlFreeFr.py | 137 | ||||
-rw-r--r-- | pyload/plugin/hoster/DodanePl.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/DuploadOrg.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/EasybytezCom.py | 21 | ||||
-rw-r--r-- | pyload/plugin/hoster/EdiskCz.py | 53 | ||||
-rw-r--r-- | pyload/plugin/hoster/EgoFilesCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/EnteruploadCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/EpicShareNet.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/EuroshareEu.py | 64 | ||||
-rw-r--r-- | pyload/plugin/hoster/ExashareCom.py | 35 | ||||
-rw-r--r-- | pyload/plugin/hoster/ExtabitCom.py | 75 | ||||
-rw-r--r-- | pyload/plugin/hoster/FastixRu.py | 63 | ||||
-rw-r--r-- | pyload/plugin/hoster/FastshareCz.py | 76 | ||||
-rw-r--r-- | pyload/plugin/hoster/FileApeCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/FileSharkPl.py | 130 | ||||
-rw-r--r-- | pyload/plugin/hoster/FileStoreTo.py | 34 | ||||
-rw-r--r-- | pyload/plugin/hoster/FilebeerInfo.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/FilecloudIo.py | 123 | ||||
-rw-r--r-- | pyload/plugin/hoster/FilefactoryCom.py (renamed from module/plugins/hoster/FilefactoryCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/FilejungleCom.py (renamed from module/plugins/hoster/FilejungleCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/FileomCom.py | 30 | ||||
-rw-r--r-- | pyload/plugin/hoster/FilepostCom.py | 130 | ||||
-rw-r--r-- | pyload/plugin/hoster/FilepupNet.py | 44 | ||||
-rw-r--r-- | pyload/plugin/hoster/FilerNet.py | 71 | ||||
-rw-r--r-- | pyload/plugin/hoster/FilerioCom.py | 20 | ||||
-rw-r--r-- | pyload/plugin/hoster/FilesMailRu.py (renamed from module/plugins/hoster/FilesMailRu.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/FileserveCom.py | 216 | ||||
-rw-r--r-- | pyload/plugin/hoster/FileshareInUa.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/FilesonicCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/hoster/FilezyNet.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/FiredriveCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/FlyFilesNet.py (renamed from module/plugins/hoster/FlyFilesNet.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/FourSharedCom.py | 59 | ||||
-rw-r--r-- | pyload/plugin/hoster/FreakshareCom.py | 180 | ||||
-rw-r--r-- | pyload/plugin/hoster/FreeWayMe.py | 50 | ||||
-rw-r--r-- | pyload/plugin/hoster/FreevideoCz.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/FshareVn.py (renamed from module/plugins/hoster/FshareVn.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/Ftp.py (renamed from module/plugins/hoster/Ftp.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/GamefrontCom.py (renamed from module/plugins/hoster/GamefrontCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/GigapetaCom.py | 61 | ||||
-rw-r--r-- | pyload/plugin/hoster/GooIm.py | 34 | ||||
-rw-r--r-- | pyload/plugin/hoster/GoogledriveCom.py | 62 | ||||
-rw-r--r-- | pyload/plugin/hoster/HellshareCz.py | 32 | ||||
-rw-r--r-- | pyload/plugin/hoster/HellspyCz.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/HotfileCom.py | 18 | ||||
-rw-r--r-- | pyload/plugin/hoster/HugefilesNet.py | 22 | ||||
-rw-r--r-- | pyload/plugin/hoster/HundredEightyUploadCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/IFileWs.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/IcyFilesCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/IfileIt.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/IfolderRu.py | 73 | ||||
-rw-r--r-- | pyload/plugin/hoster/JumbofilesCom.py | 33 | ||||
-rw-r--r-- | pyload/plugin/hoster/JunocloudMe.py | 21 | ||||
-rw-r--r-- | pyload/plugin/hoster/Keep2ShareCc.py | 109 | ||||
-rw-r--r-- | pyload/plugin/hoster/KickloadCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/KingfilesNet.py | 75 | ||||
-rw-r--r-- | pyload/plugin/hoster/LemUploadsCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/LetitbitNet.py | 155 | ||||
-rw-r--r-- | pyload/plugin/hoster/LinksnappyCom.py | 55 | ||||
-rw-r--r-- | pyload/plugin/hoster/LoadTo.py | 65 | ||||
-rw-r--r-- | pyload/plugin/hoster/LomafileCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/hoster/LuckyShareNet.py | 71 | ||||
-rw-r--r-- | pyload/plugin/hoster/MediafireCom.py (renamed from module/plugins/hoster/MediafireCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/MegaCoNz.py | 217 | ||||
-rw-r--r-- | pyload/plugin/hoster/MegaDebridEu.py | 86 | ||||
-rw-r--r-- | pyload/plugin/hoster/MegaFilesSe.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/MegaRapidCz.py | 65 | ||||
-rw-r--r-- | pyload/plugin/hoster/MegacrypterCom.py (renamed from module/plugins/hoster/MegacrypterCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/MegareleaseOrg.py | 16 | ||||
-rw-r--r-- | pyload/plugin/hoster/MegasharesCom.py | 110 | ||||
-rw-r--r-- | pyload/plugin/hoster/MegauploadCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/MegavideoCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/hoster/MovReelCom.py | 18 | ||||
-rw-r--r-- | pyload/plugin/hoster/MultihostersCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/MultishareCz.py | 51 | ||||
-rw-r--r-- | pyload/plugin/hoster/MyfastfileCom.py | 36 | ||||
-rw-r--r-- | pyload/plugin/hoster/MystoreTo.py | 42 | ||||
-rw-r--r-- | pyload/plugin/hoster/MyvideoDe.py (renamed from module/plugins/hoster/MyvideoDe.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/NahrajCz.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/NarodRu.py | 63 | ||||
-rw-r--r-- | pyload/plugin/hoster/NetloadIn.py (renamed from module/plugins/hoster/NetloadIn.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/NitroflareCom.py | 107 | ||||
-rw-r--r-- | pyload/plugin/hoster/NoPremiumPl.py | 103 | ||||
-rw-r--r-- | pyload/plugin/hoster/NosuploadCom.py | 39 | ||||
-rw-r--r-- | pyload/plugin/hoster/NovafileCom.py | 26 | ||||
-rw-r--r-- | pyload/plugin/hoster/NowDownloadSx.py | 61 | ||||
-rw-r--r-- | pyload/plugin/hoster/NowVideoSx.py | 41 | ||||
-rw-r--r-- | pyload/plugin/hoster/OboomCom.py (renamed from module/plugins/hoster/OboomCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/OneFichierCom.py | 58 | ||||
-rw-r--r-- | pyload/plugin/hoster/OronCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/hoster/OverLoadMe.py | 73 | ||||
-rw-r--r-- | pyload/plugin/hoster/PandaplaNet.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/PornhostCom.py (renamed from module/plugins/hoster/PornhostCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/PornhubCom.py (renamed from module/plugins/hoster/PornhubCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/PotloadCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/PremiumTo.py | 52 | ||||
-rw-r--r-- | pyload/plugin/hoster/PremiumizeMe.py | 57 | ||||
-rw-r--r-- | pyload/plugin/hoster/PromptfileCom.py | 42 | ||||
-rw-r--r-- | pyload/plugin/hoster/PrzeklejPl.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/PutdriveCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/QuickshareCz.py | 86 | ||||
-rw-r--r-- | pyload/plugin/hoster/RPNetBiz.py | 77 | ||||
-rw-r--r-- | pyload/plugin/hoster/RapideoPl.py | 103 | ||||
-rw-r--r-- | pyload/plugin/hoster/RapidfileshareNet.py | 22 | ||||
-rw-r--r-- | pyload/plugin/hoster/RapidgatorNet.py | 169 | ||||
-rw-r--r-- | pyload/plugin/hoster/RapiduNet.py | 83 | ||||
-rw-r--r-- | pyload/plugin/hoster/RarefileNet.py | 20 | ||||
-rw-r--r-- | pyload/plugin/hoster/RealdebridCom.py | 76 | ||||
-rw-r--r-- | pyload/plugin/hoster/RedtubeCom.py (renamed from module/plugins/hoster/RedtubeCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/RehostTo.py | 25 | ||||
-rw-r--r-- | pyload/plugin/hoster/RemixshareCom.py | 57 | ||||
-rw-r--r-- | pyload/plugin/hoster/RgHostNet.py | 23 | ||||
-rw-r--r-- | pyload/plugin/hoster/SafesharingEu.py | 18 | ||||
-rw-r--r-- | pyload/plugin/hoster/SecureUploadEu.py | 18 | ||||
-rw-r--r-- | pyload/plugin/hoster/SendspaceCom.py | 58 | ||||
-rw-r--r-- | pyload/plugin/hoster/Share4WebCom.py | 18 | ||||
-rw-r--r-- | pyload/plugin/hoster/Share76Com.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/ShareFilesCo.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/SharebeesCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/ShareonlineBiz.py | 184 | ||||
-rw-r--r-- | pyload/plugin/hoster/ShareplaceCom.py (renamed from module/plugins/hoster/ShareplaceCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/SharingmatrixCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/hoster/ShragleCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/hoster/SimplyPremiumCom.py | 78 | ||||
-rw-r--r-- | pyload/plugin/hoster/SimplydebridCom.py | 45 | ||||
-rw-r--r-- | pyload/plugin/hoster/SmoozedCom.py | 63 | ||||
-rw-r--r-- | pyload/plugin/hoster/SockshareCom.py | 17 | ||||
-rw-r--r-- | pyload/plugin/hoster/SoundcloudCom.py (renamed from module/plugins/hoster/SoundcloudCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/SpeedLoadOrg.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/SpeedfileCz.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/SpeedyshareCom.py | 41 | ||||
-rw-r--r-- | pyload/plugin/hoster/StorageTo.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/StreamCz.py (renamed from module/plugins/hoster/StreamCz.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/StreamcloudEu.py | 28 | ||||
-rw-r--r-- | pyload/plugin/hoster/TurbobitNet.py | 164 | ||||
-rw-r--r-- | pyload/plugin/hoster/TurbouploadCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/TusfilesNet.py | 37 | ||||
-rw-r--r-- | pyload/plugin/hoster/TwoSharedCom.py | 29 | ||||
-rw-r--r-- | pyload/plugin/hoster/UlozTo.py | 155 | ||||
-rw-r--r-- | pyload/plugin/hoster/UloziskoSk.py | 68 | ||||
-rw-r--r-- | pyload/plugin/hoster/UnibytesCom.py | 70 | ||||
-rw-r--r-- | pyload/plugin/hoster/UnrestrictLi.py | 82 | ||||
-rw-r--r-- | pyload/plugin/hoster/UpleaCom.py | 56 | ||||
-rw-r--r-- | pyload/plugin/hoster/UploadStationCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/hoster/UploadableCh.py | 76 | ||||
-rw-r--r-- | pyload/plugin/hoster/UploadboxCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/UploadedTo.py | 117 | ||||
-rw-r--r-- | pyload/plugin/hoster/UploadhereCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/UploadheroCom.py | 73 | ||||
-rw-r--r-- | pyload/plugin/hoster/UploadingCom.py | 96 | ||||
-rw-r--r-- | pyload/plugin/hoster/UploadkingCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/UpstoreNet.py | 69 | ||||
-rw-r--r-- | pyload/plugin/hoster/UptoboxCom.py | 29 | ||||
-rw-r--r-- | pyload/plugin/hoster/VeehdCom.py (renamed from module/plugins/hoster/VeehdCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/VeohCom.py | 51 | ||||
-rw-r--r-- | pyload/plugin/hoster/VidPlayNet.py | 21 | ||||
-rw-r--r-- | pyload/plugin/hoster/VimeoCom.py | 71 | ||||
-rw-r--r-- | pyload/plugin/hoster/Vipleech4UCom.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/WarserverCz.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/WebshareCz.py | 60 | ||||
-rw-r--r-- | pyload/plugin/hoster/WrzucTo.py | 49 | ||||
-rw-r--r-- | pyload/plugin/hoster/WuploadCom.py | 16 | ||||
-rw-r--r-- | pyload/plugin/hoster/X7To.py | 15 | ||||
-rw-r--r-- | pyload/plugin/hoster/XFileSharingPro.py | 59 | ||||
-rw-r--r-- | pyload/plugin/hoster/XHamsterCom.py (renamed from module/plugins/hoster/XHamsterCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/XVideosCom.py (renamed from module/plugins/hoster/XVideosCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/XdadevelopersCom.py | 35 | ||||
-rw-r--r-- | pyload/plugin/hoster/Xdcc.py (renamed from module/plugins/hoster/Xdcc.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/YibaishiwuCom.py | 56 | ||||
-rw-r--r-- | pyload/plugin/hoster/YoupornCom.py (renamed from module/plugins/hoster/YoupornCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/YourfilesTo.py (renamed from module/plugins/hoster/YourfilesTo.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/YoutubeCom.py (renamed from module/plugins/hoster/YoutubeCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/ZDF.py (renamed from module/plugins/hoster/ZDF.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/hoster/ZShareNet.py | 16 | ||||
-rw-r--r-- | pyload/plugin/hoster/ZeveraCom.py | 31 | ||||
-rw-r--r-- | pyload/plugin/hoster/ZippyshareCom.py | 62 | ||||
-rw-r--r-- | pyload/plugin/hoster/__init__.py (renamed from module/plugins/internal/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/internal/BasePlugin.py | 92 | ||||
-rw-r--r-- | pyload/plugin/internal/DeadCrypter.py | 27 | ||||
-rw-r--r-- | pyload/plugin/internal/DeadHoster.py | 27 | ||||
-rw-r--r-- | pyload/plugin/internal/MultiHook.py | 308 | ||||
-rw-r--r-- | pyload/plugin/internal/MultiHoster.py | 85 | ||||
-rw-r--r-- | pyload/plugin/internal/SimpleCrypter.py | 157 | ||||
-rw-r--r-- | pyload/plugin/internal/SimpleDereferer.py | 98 | ||||
-rw-r--r-- | pyload/plugin/internal/SimpleHoster.py | 701 | ||||
-rw-r--r-- | pyload/plugin/internal/UpdateManager.py | 306 | ||||
-rw-r--r-- | pyload/plugin/internal/XFSAccount.py (renamed from module/plugins/internal/XFSAccount.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/internal/XFSCrypter.py | 45 | ||||
-rw-r--r-- | pyload/plugin/internal/XFSHoster.py | 326 | ||||
-rw-r--r-- | pyload/plugin/internal/__init__.py (renamed from module/plugins/ocr/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/ocr/GigasizeCom.py (renamed from module/plugins/ocr/GigasizeCom.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/ocr/LinksaveIn.py (renamed from module/plugins/ocr/LinksaveIn.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/ocr/NetloadIn.py (renamed from module/plugins/ocr/NetloadIn.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/ocr/ShareonlineBiz.py (renamed from module/plugins/ocr/ShareonlineBiz.py) | 0 | ||||
-rw-r--r-- | pyload/plugin/ocr/__init__.py (renamed from module/remote/socketbackend/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/remote/ClickAndLoadBackend.py (renamed from module/remote/ClickAndLoadBackend.py) | 0 | ||||
-rw-r--r-- | pyload/remote/SocketBackend.py (renamed from module/remote/SocketBackend.py) | 0 | ||||
-rw-r--r-- | pyload/remote/ThriftBackend.py (renamed from module/remote/ThriftBackend.py) | 0 | ||||
-rw-r--r-- | pyload/remote/__init__.py (renamed from module/remote/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/remote/socketbackend/__init__.py (renamed from module/remote/thriftbackend/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/remote/socketbackend/create_ttypes.py (renamed from module/remote/socketbackend/create_ttypes.py) | 0 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/Processor.py (renamed from module/remote/thriftbackend/Processor.py) | 0 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/Protocol.py (renamed from module/remote/thriftbackend/Protocol.py) | 0 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/Socket.py (renamed from module/remote/thriftbackend/Socket.py) | 0 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/ThriftClient.py (renamed from module/remote/thriftbackend/ThriftClient.py) | 0 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/ThriftTest.py (renamed from module/remote/thriftbackend/ThriftTest.py) | 0 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/Transport.py (renamed from module/remote/thriftbackend/Transport.py) | 0 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/__init__.py (renamed from module/remote/thriftbackend/thriftgen/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/pyload.thrift (renamed from module/remote/thriftbackend/pyload.thrift) | 0 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/thriftgen/__init__.py | 1 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/thriftgen/pyload/Pyload-remote (renamed from module/remote/thriftbackend/thriftgen/pyload/Pyload-remote) | 0 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/thriftgen/pyload/Pyload.py (renamed from module/remote/thriftbackend/thriftgen/pyload/Pyload.py) | 0 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/thriftgen/pyload/__init__.py (renamed from module/remote/thriftbackend/thriftgen/pyload/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/thriftgen/pyload/constants.py (renamed from module/remote/thriftbackend/thriftgen/pyload/constants.py) | 0 | ||||
-rw-r--r-- | pyload/remote/thriftbackend/thriftgen/pyload/ttypes.py (renamed from module/remote/thriftbackend/thriftgen/pyload/ttypes.py) | 0 | ||||
-rw-r--r-- | pyload/utils/__init__.py (renamed from module/utils/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/utils/packagetools.py (renamed from module/utils/packagetools.py) | 0 | ||||
-rw-r--r-- | pyload/utils/printer.py (renamed from module/utils/printer.py) | 0 | ||||
-rw-r--r-- | pyload/utils/pylgettext.py (renamed from module/utils/pylgettext.py) | 0 | ||||
-rw-r--r-- | pyload/webui/__init__.py (renamed from module/webui/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/webui/app/__init__.py (renamed from module/webui/app/__init__.py) | 0 | ||||
-rw-r--r-- | pyload/webui/app/api.py (renamed from module/webui/app/api.py) | 0 | ||||
-rw-r--r-- | pyload/webui/app/cnl.py (renamed from module/webui/app/cnl.py) | 0 | ||||
-rw-r--r-- | pyload/webui/app/json.py (renamed from module/webui/app/json.py) | 0 | ||||
-rw-r--r-- | pyload/webui/app/pyload.py (renamed from module/webui/app/pyload.py) | 0 | ||||
-rw-r--r-- | pyload/webui/app/utils.py (renamed from module/webui/app/utils.py) | 0 | ||||
-rw-r--r-- | pyload/webui/filters.py (renamed from module/webui/filters.py) | 0 | ||||
-rw-r--r-- | pyload/webui/middlewares.py (renamed from module/webui/middlewares.py) | 0 | ||||
-rw-r--r-- | pyload/webui/servers/lighttpd_default.conf (renamed from module/webui/servers/lighttpd_default.conf) | 0 | ||||
-rw-r--r-- | pyload/webui/servers/nginx_default.conf (renamed from module/webui/servers/nginx_default.conf) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/css/MooDialog.css (renamed from module/webui/themes/Dark/css/MooDialog.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/css/base.css (renamed from module/webui/themes/Dark/css/base.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/css/log.css (renamed from module/webui/themes/Dark/css/log.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/css/pathchooser.css (renamed from module/webui/themes/Dark/css/pathchooser.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/css/window.css (renamed from module/webui/themes/Dark/css/window.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/img/MooDialog/dialog-close.png (renamed from module/webui/themes/Dark/img/MooDialog/dialog-close.png) | bin | 689 -> 689 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/MooDialog/dialog-error.png (renamed from module/webui/themes/Dark/img/MooDialog/dialog-error.png) | bin | 1472 -> 1472 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/MooDialog/dialog-question.png (renamed from module/webui/themes/Dark/img/MooDialog/dialog-question.png) | bin | 2073 -> 2073 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/MooDialog/dialog-warning.png (renamed from module/webui/themes/Dark/img/MooDialog/dialog-warning.png) | bin | 1651 -> 1651 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/button.png (renamed from module/webui/themes/Dark/img/button.png) | bin | 569 -> 569 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/dark-bg.jpg (renamed from module/webui/themes/Dark/img/dark-bg.jpg) | bin | 40930 -> 40930 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/add_folder.png (renamed from module/webui/themes/Dark/img/default/add_folder.png) | bin | 571 -> 571 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/ajax-loader.gif (renamed from module/webui/themes/Dark/img/default/ajax-loader.gif) | bin | 404 -> 404 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/arrow_refresh.png (renamed from module/webui/themes/Dark/img/default/arrow_refresh.png) | bin | 685 -> 685 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/arrow_right.png (renamed from module/webui/themes/Dark/img/default/arrow_right.png) | bin | 349 -> 349 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/big_button.gif (renamed from module/webui/themes/Dark/img/default/big_button.gif) | bin | 1905 -> 1905 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/big_button_over.gif (renamed from module/webui/themes/Dark/img/default/big_button_over.gif) | bin | 728 -> 728 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/body.png (renamed from module/webui/themes/Dark/img/default/body.png) | bin | 402 -> 402 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/closebtn.gif (renamed from module/webui/themes/Dark/img/default/closebtn.gif) | bin | 254 -> 254 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/cog.png (renamed from module/webui/themes/Dark/img/default/cog.png) | bin | 512 -> 512 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/control_add.png (renamed from module/webui/themes/Dark/img/default/control_add.png) | bin | 446 -> 446 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/control_add_blue.png (renamed from module/webui/themes/Dark/img/default/control_add_blue.png) | bin | 845 -> 845 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/control_cancel.png (renamed from module/webui/themes/Dark/img/default/control_cancel.png) | bin | 3349 -> 3349 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/control_cancel_blue.png (renamed from module/webui/themes/Dark/img/default/control_cancel_blue.png) | bin | 787 -> 787 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/control_pause.png (renamed from module/webui/themes/Dark/img/default/control_pause.png) | bin | 598 -> 598 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/control_pause_blue.png (renamed from module/webui/themes/Dark/img/default/control_pause_blue.png) | bin | 721 -> 721 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/control_play.png (renamed from module/webui/themes/Dark/img/default/control_play.png) | bin | 592 -> 592 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/control_play_blue.png (renamed from module/webui/themes/Dark/img/default/control_play_blue.png) | bin | 717 -> 717 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/control_stop.png (renamed from module/webui/themes/Dark/img/default/control_stop.png) | bin | 403 -> 403 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/control_stop_blue.png (renamed from module/webui/themes/Dark/img/default/control_stop_blue.png) | bin | 695 -> 695 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/delete.png (renamed from module/webui/themes/Dark/img/default/delete.png) | bin | 715 -> 715 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/drag_corner.gif (renamed from module/webui/themes/Dark/img/default/drag_corner.gif) | bin | 76 -> 76 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/error.png (renamed from module/webui/themes/Dark/img/default/error.png) | bin | 701 -> 701 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/folder.png (renamed from module/webui/themes/Dark/img/default/folder.png) | bin | 537 -> 537 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/full.png (renamed from module/webui/themes/Dark/img/default/full.png) | bin | 3543 -> 3543 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/head-login.png (renamed from module/webui/themes/Dark/img/default/head-login.png) | bin | 1288 -> 1288 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/head-menu-collector.png (renamed from module/webui/themes/Dark/img/default/head-menu-collector.png) | bin | 1953 -> 1953 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/head-menu-config.png (renamed from module/webui/themes/Dark/img/default/head-menu-config.png) | bin | 1802 -> 1802 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/head-menu-development.png (renamed from module/webui/themes/Dark/img/default/head-menu-development.png) | bin | 876 -> 876 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/head-menu-download.png (renamed from module/webui/themes/Dark/img/default/head-menu-download.png) | bin | 721 -> 721 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/head-menu-home.png (renamed from module/webui/themes/Dark/img/default/head-menu-home.png) | bin | 920 -> 920 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/head-menu-index.png (renamed from module/webui/themes/Dark/img/default/head-menu-index.png) | bin | 482 -> 482 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/head-menu-news.png (renamed from module/webui/themes/Dark/img/default/head-menu-news.png) | bin | 628 -> 628 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/head-menu-queue.png (renamed from module/webui/themes/Dark/img/default/head-menu-queue.png) | bin | 2629 -> 2629 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/head-menu-recent.png (renamed from module/webui/themes/Dark/img/default/head-menu-recent.png) | bin | 932 -> 932 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/head-menu-wiki.png (renamed from module/webui/themes/Dark/img/default/head-menu-wiki.png) | bin | 1204 -> 1204 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/head-search-noshadow.png (renamed from module/webui/themes/Dark/img/default/head-search-noshadow.png) | bin | 1187 -> 1187 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/head_bg1.png (renamed from module/webui/themes/Dark/img/default/head_bg1.png) | bin | 125 -> 125 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/images.png (renamed from module/webui/themes/Dark/img/default/images.png) | bin | 661 -> 661 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/notice.png (renamed from module/webui/themes/Dark/img/default/notice.png) | bin | 778 -> 778 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/package_go.png (renamed from module/webui/themes/Dark/img/default/package_go.png) | bin | 898 -> 898 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/page-tools-backlinks.png (renamed from module/webui/themes/Dark/img/default/page-tools-backlinks.png) | bin | 540 -> 540 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/page-tools-edit.png (renamed from module/webui/themes/Dark/img/default/page-tools-edit.png) | bin | 574 -> 574 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/page-tools-revisions.png (renamed from module/webui/themes/Dark/img/default/page-tools-revisions.png) | bin | 603 -> 603 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/parseUri.png (renamed from module/webui/themes/Dark/img/default/parseUri.png) | bin | 666 -> 666 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/pencil.png (renamed from module/webui/themes/Dark/img/default/pencil.png) | bin | 450 -> 450 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/reconnect.png (renamed from module/webui/themes/Dark/img/default/reconnect.png) | bin | 755 -> 755 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/status_None.png (renamed from module/webui/themes/Dark/img/default/status_None.png) | bin | 7613 -> 7613 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/status_downloading.png (renamed from module/webui/themes/Dark/img/default/status_downloading.png) | bin | 943 -> 943 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/status_failed.png (renamed from module/webui/themes/Dark/img/default/status_failed.png) | bin | 701 -> 701 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/status_finished.png (renamed from module/webui/themes/Dark/img/default/status_finished.png) | bin | 781 -> 781 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/status_offline.png (renamed from module/webui/themes/Dark/img/default/status_offline.png) | bin | 700 -> 700 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/status_proc.png (renamed from module/webui/themes/Dark/img/default/status_proc.png) | bin | 512 -> 512 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/status_queue.png (renamed from module/webui/themes/Dark/img/default/status_queue.png) | bin | 7613 -> 7613 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/status_waiting.png (renamed from module/webui/themes/Dark/img/default/status_waiting.png) | bin | 889 -> 889 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/success.png (renamed from module/webui/themes/Dark/img/default/success.png) | bin | 781 -> 781 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/tabs-border-bottom.png (renamed from module/webui/themes/Dark/img/default/tabs-border-bottom.png) | bin | 163 -> 163 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/user-actions-logout.png (renamed from module/webui/themes/Dark/img/default/user-actions-logout.png) | bin | 799 -> 799 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/user-actions-profile.png (renamed from module/webui/themes/Dark/img/default/user-actions-profile.png) | bin | 628 -> 628 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/default/user-info.png (renamed from module/webui/themes/Dark/img/default/user-info.png) | bin | 3963 -> 3963 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/pyload-logo.png (renamed from module/webui/themes/Dark/img/pyload-logo.png) | bin | 6947 -> 6947 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/img/tab-background.png (renamed from module/webui/themes/Dark/img/tab-background.png) | bin | 3044 -> 3044 bytes | |||
-rw-r--r-- | pyload/webui/themes/Dark/js/render/admin.coffee (renamed from module/webui/themes/Dark/js/render/admin.coffee) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/render/admin.min.js (renamed from module/webui/themes/Dark/js/render/admin.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/render/base.coffee (renamed from module/webui/themes/Dark/js/render/base.coffee) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/render/base.min.js (renamed from module/webui/themes/Dark/js/render/base.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/render/package.js (renamed from module/webui/themes/Dark/js/render/package.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/render/settings.coffee (renamed from module/webui/themes/Dark/js/render/settings.coffee) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/render/settings.min.js (renamed from module/webui/themes/Dark/js/render/settings.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/static/MooDialog.js (renamed from module/webui/themes/Dark/js/static/MooDialog.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/static/MooDialog.min.js (renamed from module/webui/themes/Dark/js/static/MooDialog.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/static/MooDropMenu.js (renamed from module/webui/themes/Dark/js/static/MooDropMenu.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/static/MooDropMenu.min.js (renamed from module/webui/themes/Dark/js/static/MooDropMenu.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/static/mootools-core.js (renamed from module/webui/themes/Dark/js/static/mootools-core.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/static/mootools-core.min.js (renamed from module/webui/themes/Dark/js/static/mootools-core.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/static/mootools-more.js (renamed from module/webui/themes/Dark/js/static/mootools-more.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/static/mootools-more.min.js (renamed from module/webui/themes/Dark/js/static/mootools-more.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/static/purr.js (renamed from module/webui/themes/Dark/js/static/purr.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/static/purr.min.js (renamed from module/webui/themes/Dark/js/static/purr.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/static/tinytab.js (renamed from module/webui/themes/Dark/js/static/tinytab.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/js/static/tinytab.min.js (renamed from module/webui/themes/Dark/js/static/tinytab.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/admin.html (renamed from module/webui/themes/Dark/tml/admin.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/base.html (renamed from module/webui/themes/Dark/tml/base.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/captcha.html (renamed from module/webui/themes/Dark/tml/captcha.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/downloads.html (renamed from module/webui/themes/Dark/tml/downloads.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/folder.html (renamed from module/webui/themes/Dark/tml/folder.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/home.html (renamed from module/webui/themes/Dark/tml/home.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/info.html (renamed from module/webui/themes/Dark/tml/info.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/login.html (renamed from module/webui/themes/Dark/tml/login.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/logout.html (renamed from module/webui/themes/Dark/tml/logout.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/logs.html (renamed from module/webui/themes/Dark/tml/logs.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/pathchooser.html (renamed from module/webui/themes/Dark/tml/pathchooser.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/queue.html (renamed from module/webui/themes/Dark/tml/queue.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/settings.html (renamed from module/webui/themes/Dark/tml/settings.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/settings_item.html (renamed from module/webui/themes/Dark/tml/settings_item.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Dark/tml/window.html (renamed from module/webui/themes/Dark/tml/window.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/css/MooDialog.css (renamed from module/webui/themes/Default/css/MooDialog.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/css/base.css (renamed from module/webui/themes/Default/css/base.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/css/log.css (renamed from module/webui/themes/Default/css/log.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/css/pathchooser.css (renamed from module/webui/themes/Default/css/pathchooser.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/css/window.css (renamed from module/webui/themes/Default/css/window.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/img/MooDialog/dialog-close.png (renamed from module/webui/themes/Default/img/MooDialog/dialog-close.png) | bin | 689 -> 689 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/MooDialog/dialog-error.png (renamed from module/webui/themes/Default/img/MooDialog/dialog-error.png) | bin | 1472 -> 1472 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/MooDialog/dialog-question.png (renamed from module/webui/themes/Default/img/MooDialog/dialog-question.png) | bin | 2073 -> 2073 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/MooDialog/dialog-warning.png (renamed from module/webui/themes/Default/img/MooDialog/dialog-warning.png) | bin | 1651 -> 1651 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/add_folder.png (renamed from module/webui/themes/Default/img/add_folder.png) | bin | 571 -> 571 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/ajax-loader.gif (renamed from module/webui/themes/Default/img/ajax-loader.gif) | bin | 404 -> 404 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/arrow_refresh.png (renamed from module/webui/themes/Default/img/arrow_refresh.png) | bin | 685 -> 685 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/arrow_right.png (renamed from module/webui/themes/Default/img/arrow_right.png) | bin | 349 -> 349 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/big_button.gif (renamed from module/webui/themes/Default/img/big_button.gif) | bin | 1905 -> 1905 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/big_button_over.gif (renamed from module/webui/themes/Default/img/big_button_over.gif) | bin | 728 -> 728 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/body.png (renamed from module/webui/themes/Default/img/body.png) | bin | 402 -> 402 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/button.png (renamed from module/webui/themes/Default/img/button.png) | bin | 452 -> 452 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/closebtn.gif (renamed from module/webui/themes/Default/img/closebtn.gif) | bin | 254 -> 254 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/cog.png (renamed from module/webui/themes/Default/img/cog.png) | bin | 512 -> 512 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/control_add.png (renamed from module/webui/themes/Default/img/control_add.png) | bin | 446 -> 446 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/control_add_blue.png (renamed from module/webui/themes/Default/img/control_add_blue.png) | bin | 845 -> 845 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/control_cancel.png (renamed from module/webui/themes/Default/img/control_cancel.png) | bin | 3349 -> 3349 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/control_cancel_blue.png (renamed from module/webui/themes/Default/img/control_cancel_blue.png) | bin | 787 -> 787 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/control_pause.png (renamed from module/webui/themes/Default/img/control_pause.png) | bin | 598 -> 598 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/control_pause_blue.png (renamed from module/webui/themes/Default/img/control_pause_blue.png) | bin | 721 -> 721 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/control_play.png (renamed from module/webui/themes/Default/img/control_play.png) | bin | 592 -> 592 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/control_play_blue.png (renamed from module/webui/themes/Default/img/control_play_blue.png) | bin | 717 -> 717 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/control_stop.png (renamed from module/webui/themes/Default/img/control_stop.png) | bin | 403 -> 403 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/control_stop_blue.png (renamed from module/webui/themes/Default/img/control_stop_blue.png) | bin | 695 -> 695 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/delete.png (renamed from module/webui/themes/Default/img/delete.png) | bin | 715 -> 715 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/drag_corner.gif (renamed from module/webui/themes/Default/img/drag_corner.gif) | bin | 76 -> 76 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/error.png (renamed from module/webui/themes/Default/img/error.png) | bin | 701 -> 701 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/folder.png (renamed from module/webui/themes/Default/img/folder.png) | bin | 537 -> 537 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/full.png (renamed from module/webui/themes/Default/img/full.png) | bin | 3543 -> 3543 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/head-login.png (renamed from module/webui/themes/Default/img/head-login.png) | bin | 1288 -> 1288 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/head-menu-collector.png (renamed from module/webui/themes/Default/img/head-menu-collector.png) | bin | 1953 -> 1953 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/head-menu-config.png (renamed from module/webui/themes/Default/img/head-menu-config.png) | bin | 1802 -> 1802 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/head-menu-development.png (renamed from module/webui/themes/Default/img/head-menu-development.png) | bin | 876 -> 876 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/head-menu-download.png (renamed from module/webui/themes/Default/img/head-menu-download.png) | bin | 721 -> 721 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/head-menu-home.png (renamed from module/webui/themes/Default/img/head-menu-home.png) | bin | 920 -> 920 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/head-menu-index.png (renamed from module/webui/themes/Default/img/head-menu-index.png) | bin | 482 -> 482 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/head-menu-news.png (renamed from module/webui/themes/Default/img/head-menu-news.png) | bin | 628 -> 628 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/head-menu-queue.png (renamed from module/webui/themes/Default/img/head-menu-queue.png) | bin | 2629 -> 2629 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/head-menu-recent.png (renamed from module/webui/themes/Default/img/head-menu-recent.png) | bin | 932 -> 932 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/head-menu-wiki.png (renamed from module/webui/themes/Default/img/head-menu-wiki.png) | bin | 1204 -> 1204 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/head-search-noshadow.png (renamed from module/webui/themes/Default/img/head-search-noshadow.png) | bin | 1187 -> 1187 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/head_bg1.png (renamed from module/webui/themes/Default/img/head_bg1.png) | bin | 125 -> 125 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/images.png (renamed from module/webui/themes/Default/img/images.png) | bin | 661 -> 661 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/notice.png (renamed from module/webui/themes/Default/img/notice.png) | bin | 778 -> 778 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/package_go.png (renamed from module/webui/themes/Default/img/package_go.png) | bin | 898 -> 898 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/page-tools-backlinks.png (renamed from module/webui/themes/Default/img/page-tools-backlinks.png) | bin | 540 -> 540 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/page-tools-edit.png (renamed from module/webui/themes/Default/img/page-tools-edit.png) | bin | 574 -> 574 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/page-tools-revisions.png (renamed from module/webui/themes/Default/img/page-tools-revisions.png) | bin | 603 -> 603 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/parseUri.png (renamed from module/webui/themes/Default/img/parseUri.png) | bin | 666 -> 666 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/pencil.png (renamed from module/webui/themes/Default/img/pencil.png) | bin | 450 -> 450 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/pyload-logo.png (renamed from module/webui/themes/Default/img/pyload-logo.png) | bin | 8457 -> 8457 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/reconnect.png (renamed from module/webui/themes/Default/img/reconnect.png) | bin | 755 -> 755 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/status_None.png (renamed from module/webui/themes/Default/img/status_None.png) | bin | 7613 -> 7613 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/status_downloading.png (renamed from module/webui/themes/Default/img/status_downloading.png) | bin | 943 -> 943 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/status_failed.png (renamed from module/webui/themes/Default/img/status_failed.png) | bin | 701 -> 701 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/status_finished.png (renamed from module/webui/themes/Default/img/status_finished.png) | bin | 781 -> 781 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/status_offline.png (renamed from module/webui/themes/Default/img/status_offline.png) | bin | 700 -> 700 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/status_proc.png (renamed from module/webui/themes/Default/img/status_proc.png) | bin | 512 -> 512 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/status_queue.png (renamed from module/webui/themes/Default/img/status_queue.png) | bin | 7613 -> 7613 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/status_waiting.png (renamed from module/webui/themes/Default/img/status_waiting.png) | bin | 889 -> 889 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/success.png (renamed from module/webui/themes/Default/img/success.png) | bin | 781 -> 781 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/tab-background.png (renamed from module/webui/themes/Default/img/tab-background.png) | bin | 179 -> 179 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/tabs-border-bottom.png (renamed from module/webui/themes/Default/img/tabs-border-bottom.png) | bin | 163 -> 163 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/user-actions-logout.png (renamed from module/webui/themes/Default/img/user-actions-logout.png) | bin | 799 -> 799 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/user-actions-profile.png (renamed from module/webui/themes/Default/img/user-actions-profile.png) | bin | 628 -> 628 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/img/user-info.png (renamed from module/webui/themes/Default/img/user-info.png) | bin | 3963 -> 3963 bytes | |||
-rw-r--r-- | pyload/webui/themes/Default/js/render/admin.coffee (renamed from module/webui/themes/Default/js/render/admin.coffee) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/render/admin.min.js (renamed from module/webui/themes/Default/js/render/admin.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/render/base.coffee (renamed from module/webui/themes/Default/js/render/base.coffee) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/render/base.min.js (renamed from module/webui/themes/Default/js/render/base.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/render/package.js (renamed from module/webui/themes/Default/js/render/package.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/render/settings.coffee (renamed from module/webui/themes/Default/js/render/settings.coffee) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/render/settings.min.js (renamed from module/webui/themes/Default/js/render/settings.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/static/MooDialog.js (renamed from module/webui/themes/Default/js/static/MooDialog.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/static/MooDialog.min.js (renamed from module/webui/themes/Default/js/static/MooDialog.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/static/MooDropMenu.js (renamed from module/webui/themes/Default/js/static/MooDropMenu.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/static/MooDropMenu.min.js (renamed from module/webui/themes/Default/js/static/MooDropMenu.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/static/mootools-core.js (renamed from module/webui/themes/Default/js/static/mootools-core.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/static/mootools-core.min.js (renamed from module/webui/themes/Default/js/static/mootools-core.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/static/mootools-more.js (renamed from module/webui/themes/Default/js/static/mootools-more.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/static/mootools-more.min.js (renamed from module/webui/themes/Default/js/static/mootools-more.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/static/purr.js (renamed from module/webui/themes/Default/js/static/purr.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/static/purr.min.js (renamed from module/webui/themes/Default/js/static/purr.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/static/tinytab.js (renamed from module/webui/themes/Default/js/static/tinytab.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/js/static/tinytab.min.js (renamed from module/webui/themes/Default/js/static/tinytab.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/admin.html (renamed from module/webui/themes/Default/tml/admin.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/base.html (renamed from module/webui/themes/Default/tml/base.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/captcha.html (renamed from module/webui/themes/Default/tml/captcha.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/downloads.html (renamed from module/webui/themes/Default/tml/downloads.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/filemanager.html (renamed from module/webui/themes/Default/tml/filemanager.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/folder.html (renamed from module/webui/themes/Default/tml/folder.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/home.html (renamed from module/webui/themes/Default/tml/home.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/info.html (renamed from module/webui/themes/Default/tml/info.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/login.html (renamed from module/webui/themes/Default/tml/login.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/logout.html (renamed from module/webui/themes/Default/tml/logout.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/logs.html (renamed from module/webui/themes/Default/tml/logs.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/pathchooser.html (renamed from module/webui/themes/Default/tml/pathchooser.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/queue.html (renamed from module/webui/themes/Default/tml/queue.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/settings.html (renamed from module/webui/themes/Default/tml/settings.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/settings_item.html (renamed from module/webui/themes/Default/tml/settings_item.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Default/tml/window.html (renamed from module/webui/themes/Default/tml/window.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/css/MooDialog.css (renamed from module/webui/themes/Flat/css/MooDialog.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/css/base.css (renamed from module/webui/themes/Flat/css/base.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/css/log.css (renamed from module/webui/themes/Flat/css/log.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/css/pathchooser.css (renamed from module/webui/themes/Flat/css/pathchooser.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/css/window.css (renamed from module/webui/themes/Flat/css/window.css) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/img/MooDialog/dialog-close.png (renamed from module/webui/themes/Flat/img/MooDialog/dialog-close.png) | bin | 689 -> 689 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/MooDialog/dialog-error.png (renamed from module/webui/themes/Flat/img/MooDialog/dialog-error.png) | bin | 1472 -> 1472 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/MooDialog/dialog-question.png (renamed from module/webui/themes/Flat/img/MooDialog/dialog-question.png) | bin | 2073 -> 2073 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/MooDialog/dialog-warning.png (renamed from module/webui/themes/Flat/img/MooDialog/dialog-warning.png) | bin | 1651 -> 1651 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/arrow_refresh.png (renamed from module/webui/themes/Flat/img/arrow_refresh.png) | bin | 119032 -> 119032 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/arrow_right.png (renamed from module/webui/themes/Flat/img/arrow_right.png) | bin | 136967 -> 136967 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/button.png (renamed from module/webui/themes/Flat/img/button.png) | bin | 569 -> 569 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/cog.png (renamed from module/webui/themes/Flat/img/cog.png) | bin | 137406 -> 137406 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/control_add.png (renamed from module/webui/themes/Flat/img/control_add.png) | bin | 116941 -> 116941 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/control_add_blue.png (renamed from module/webui/themes/Flat/img/control_add_blue.png) | bin | 116941 -> 116941 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/control_cancel.png (renamed from module/webui/themes/Flat/img/control_cancel.png) | bin | 116939 -> 116939 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/control_cancel_blue.png (renamed from module/webui/themes/Flat/img/control_cancel_blue.png) | bin | 116939 -> 116939 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/control_pause.png (renamed from module/webui/themes/Flat/img/control_pause.png) | bin | 134855 -> 134855 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/control_pause_blue.png (renamed from module/webui/themes/Flat/img/control_pause_blue.png) | bin | 134855 -> 134855 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/control_play.png (renamed from module/webui/themes/Flat/img/control_play.png) | bin | 134904 -> 134904 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/control_play_blue.png (renamed from module/webui/themes/Flat/img/control_play_blue.png) | bin | 134904 -> 134904 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/control_stop.png (renamed from module/webui/themes/Flat/img/control_stop.png) | bin | 134835 -> 134835 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/control_stop_blue.png (renamed from module/webui/themes/Flat/img/control_stop_blue.png) | bin | 134835 -> 134835 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/add_folder.png (renamed from module/webui/themes/Flat/img/default/add_folder.png) | bin | 571 -> 571 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/ajax-loader.gif (renamed from module/webui/themes/Flat/img/default/ajax-loader.gif) | bin | 404 -> 404 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/big_button.gif (renamed from module/webui/themes/Flat/img/default/big_button.gif) | bin | 1905 -> 1905 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/big_button_over.gif (renamed from module/webui/themes/Flat/img/default/big_button_over.gif) | bin | 728 -> 728 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/body.png (renamed from module/webui/themes/Flat/img/default/body.png) | bin | 402 -> 402 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/closebtn.gif (renamed from module/webui/themes/Flat/img/default/closebtn.gif) | bin | 254 -> 254 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/drag_corner.gif (renamed from module/webui/themes/Flat/img/default/drag_corner.gif) | bin | 76 -> 76 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/full.png (renamed from module/webui/themes/Flat/img/default/full.png) | bin | 3543 -> 3543 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/head-menu-recent.png (renamed from module/webui/themes/Flat/img/default/head-menu-recent.png) | bin | 932 -> 932 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/head_bg1.png (renamed from module/webui/themes/Flat/img/default/head_bg1.png) | bin | 125 -> 125 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/images.png (renamed from module/webui/themes/Flat/img/default/images.png) | bin | 661 -> 661 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/parseUri.png (renamed from module/webui/themes/Flat/img/default/parseUri.png) | bin | 666 -> 666 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/pyload-logo.png (renamed from module/webui/themes/Flat/img/default/pyload-logo.png) | bin | 8457 -> 8457 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/tab-background.png (renamed from module/webui/themes/Flat/img/default/tab-background.png) | bin | 179 -> 179 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/default/tabs-border-bottom.png (renamed from module/webui/themes/Flat/img/default/tabs-border-bottom.png) | bin | 163 -> 163 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/delete.png (renamed from module/webui/themes/Flat/img/delete.png) | bin | 117658 -> 117658 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/error.png (renamed from module/webui/themes/Flat/img/error.png) | bin | 137673 -> 137673 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/folder.png (renamed from module/webui/themes/Flat/img/folder.png) | bin | 134669 -> 134669 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/head-login.png (renamed from module/webui/themes/Flat/img/head-login.png) | bin | 137406 -> 137406 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/head-menu-collector.png (renamed from module/webui/themes/Flat/img/head-menu-collector.png) | bin | 134985 -> 134985 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/head-menu-config.png (renamed from module/webui/themes/Flat/img/head-menu-config.png) | bin | 137664 -> 137664 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/head-menu-development.png (renamed from module/webui/themes/Flat/img/head-menu-development.png) | bin | 135818 -> 135818 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/head-menu-download.png (renamed from module/webui/themes/Flat/img/head-menu-download.png) | bin | 137664 -> 137664 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/head-menu-home.png (renamed from module/webui/themes/Flat/img/head-menu-home.png) | bin | 139387 -> 139387 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/head-menu-index.png (renamed from module/webui/themes/Flat/img/head-menu-index.png) | bin | 136511 -> 136511 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/head-menu-news.png (renamed from module/webui/themes/Flat/img/head-menu-news.png) | bin | 136511 -> 136511 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/head-menu-queue.png (renamed from module/webui/themes/Flat/img/head-menu-queue.png) | bin | 136269 -> 136269 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/head-menu-wiki.png (renamed from module/webui/themes/Flat/img/head-menu-wiki.png) | bin | 137217 -> 137217 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/head-search-noshadow.png (renamed from module/webui/themes/Flat/img/head-search-noshadow.png) | bin | 137217 -> 137217 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/notice.png (renamed from module/webui/themes/Flat/img/notice.png) | bin | 3061 -> 3061 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/package_go.png (renamed from module/webui/themes/Flat/img/package_go.png) | bin | 136299 -> 136299 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/page-tools-backlinks.png (renamed from module/webui/themes/Flat/img/page-tools-backlinks.png) | bin | 138112 -> 138112 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/page-tools-edit.png (renamed from module/webui/themes/Flat/img/page-tools-edit.png) | bin | 138112 -> 138112 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/page-tools-revisions.png (renamed from module/webui/themes/Flat/img/page-tools-revisions.png) | bin | 138112 -> 138112 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/pencil.png (renamed from module/webui/themes/Flat/img/pencil.png) | bin | 138112 -> 138112 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/reconnect.png (renamed from module/webui/themes/Flat/img/reconnect.png) | bin | 3063 -> 3063 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/status_None.png (renamed from module/webui/themes/Flat/img/status_None.png) | bin | 138112 -> 138112 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/status_downloading.png (renamed from module/webui/themes/Flat/img/status_downloading.png) | bin | 3061 -> 3061 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/status_failed.png (renamed from module/webui/themes/Flat/img/status_failed.png) | bin | 137673 -> 137673 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/status_finished.png (renamed from module/webui/themes/Flat/img/status_finished.png) | bin | 117658 -> 117658 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/status_offline.png (renamed from module/webui/themes/Flat/img/status_offline.png) | bin | 137673 -> 137673 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/status_proc.png (renamed from module/webui/themes/Flat/img/status_proc.png) | bin | 137406 -> 137406 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/status_queue.png (renamed from module/webui/themes/Flat/img/status_queue.png) | bin | 138112 -> 138112 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/status_waiting.png (renamed from module/webui/themes/Flat/img/status_waiting.png) | bin | 138112 -> 138112 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/success.png (renamed from module/webui/themes/Flat/img/success.png) | bin | 117658 -> 117658 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/user-actions-logout.png (renamed from module/webui/themes/Flat/img/user-actions-logout.png) | bin | 138112 -> 138112 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/user-actions-profile.png (renamed from module/webui/themes/Flat/img/user-actions-profile.png) | bin | 138112 -> 138112 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/img/user-info.png (renamed from module/webui/themes/Flat/img/user-info.png) | bin | 3080 -> 3080 bytes | |||
-rw-r--r-- | pyload/webui/themes/Flat/js/render/admin.coffee (renamed from module/webui/themes/Flat/js/render/admin.coffee) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/render/admin.min.js (renamed from module/webui/themes/Flat/js/render/admin.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/render/base.coffee (renamed from module/webui/themes/Flat/js/render/base.coffee) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/render/base.min.js (renamed from module/webui/themes/Flat/js/render/base.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/render/filemanager.js (renamed from module/webui/themes/Flat/js/render/filemanager.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/render/package.js (renamed from module/webui/themes/Flat/js/render/package.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/render/settings.coffee (renamed from module/webui/themes/Flat/js/render/settings.coffee) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/render/settings.min.js (renamed from module/webui/themes/Flat/js/render/settings.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/static/MooDialog.js (renamed from module/webui/themes/Flat/js/static/MooDialog.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/static/MooDialog.min.js (renamed from module/webui/themes/Flat/js/static/MooDialog.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/static/MooDropMenu.js (renamed from module/webui/themes/Flat/js/static/MooDropMenu.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/static/MooDropMenu.min.js (renamed from module/webui/themes/Flat/js/static/MooDropMenu.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/static/mootools-core.js (renamed from module/webui/themes/Flat/js/static/mootools-core.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/static/mootools-core.min.js (renamed from module/webui/themes/Flat/js/static/mootools-core.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/static/mootools-more.js (renamed from module/webui/themes/Flat/js/static/mootools-more.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/static/mootools-more.min.js (renamed from module/webui/themes/Flat/js/static/mootools-more.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/static/purr.js (renamed from module/webui/themes/Flat/js/static/purr.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/static/purr.min.js (renamed from module/webui/themes/Flat/js/static/purr.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/static/tinytab.js (renamed from module/webui/themes/Flat/js/static/tinytab.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/js/static/tinytab.min.js (renamed from module/webui/themes/Flat/js/static/tinytab.min.js) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/admin.html (renamed from module/webui/themes/Flat/tml/admin.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/base.html (renamed from module/webui/themes/Flat/tml/base.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/captcha.html (renamed from module/webui/themes/Flat/tml/captcha.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/downloads.html (renamed from module/webui/themes/Flat/tml/downloads.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/filemanager.html (renamed from module/webui/themes/Flat/tml/filemanager.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/folder.html (renamed from module/webui/themes/Flat/tml/folder.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/home.html (renamed from module/webui/themes/Flat/tml/home.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/info.html (renamed from module/webui/themes/Flat/tml/info.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/login.html (renamed from module/webui/themes/Flat/tml/login.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/logout.html (renamed from module/webui/themes/Flat/tml/logout.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/logs.html (renamed from module/webui/themes/Flat/tml/logs.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/pathchooser.html (renamed from module/webui/themes/Flat/tml/pathchooser.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/queue.html (renamed from module/webui/themes/Flat/tml/queue.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/settings.html (renamed from module/webui/themes/Flat/tml/settings.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/settings_item.html (renamed from module/webui/themes/Flat/tml/settings_item.html) | 0 | ||||
-rw-r--r-- | pyload/webui/themes/Flat/tml/window.html (renamed from module/webui/themes/Flat/tml/window.html) | 0 |
1190 files changed, 19400 insertions, 20474 deletions
diff --git a/.gitignore b/.gitignore index 47e309ac3..ebd084ced 100644 --- a/.gitignore +++ b/.gitignore @@ -78,5 +78,5 @@ eggs *.pydevproject *.rej _build/ -#module/ +module/ paver-minilib.zip diff --git a/module/database/File.py b/module/database/File.py deleted file mode 100644 index 2b7c6cad9..000000000 --- a/module/database/File.py +++ /dev/null @@ -1,875 +0,0 @@ -# -*- coding: utf-8 -*- -# @author: RaNaN, mkaay - -from threading import RLock -from time import time - -from pyload.utils import formatSize, lock -from pyload.manager.Event import InsertEvent, ReloadAllEvent, RemoveEvent, UpdateEvent -from pyload.datatype.Package import PyPackage -from pyload.datatype.File import PyFile -from pyload.database import style, DatabaseBackend - -try: - from pysqlite2 import dbapi2 as sqlite3 -except Exception: - import sqlite3 - - -class FileHandler(object): - """Handles all request made to obtain information, - modify status or other request for links or packages""" - - def __init__(self, core): - """Constructor""" - self.core = core - - # translations - self.statusMsg = [_("finished"), _("offline"), _("online"), _("queued"), _("skipped"), _("waiting"), _("temp. offline"), _("starting"), _("failed"), _("aborted"), _("decrypting"), _("custom"), _("downloading"), _("processing"), _("unknown")] - - self.cache = {} #holds instances for files - self.packageCache = {} # same for packages - #@TODO: purge the cache - - self.jobCache = {} - - self.lock = RLock() #@TODO should be a Lock w/o R - #self.lock._Verbose__verbose = True - - self.filecount = -1 # if an invalid value is set get current value from db - self.queuecount = -1 #number of package to be loaded - self.unchanged = False #determines if any changes was made since last call - - self.db = self.core.db - - def change(func): - def new(*args): - args[0].unchanged = False - args[0].filecount = -1 - args[0].queuecount = -1 - args[0].jobCache = {} - return func(*args) - return new - - #-------------------------------------------------------------------------- - def save(self): - """saves all data to backend""" - self.db.commit() - - #-------------------------------------------------------------------------- - def syncSave(self): - """saves all data to backend and waits until all data are written""" - pyfiles = self.cache.values() - for pyfile in pyfiles: - pyfile.sync() - - pypacks = self.packageCache.values() - for pypack in pypacks: - pypack.sync() - - self.db.syncSave() - - @lock - def getCompleteData(self, queue=1): - """gets a complete data representation""" - - data = self.db.getAllLinks(queue) - packs = self.db.getAllPackages(queue) - - data.update([(x.id, x.toDbDict()[x.id]) for x in self.cache.values()]) - - for x in self.packageCache.itervalues(): - if x.queue != queue or x.id not in packs: continue - packs[x.id].update(x.toDict()[x.id]) - - for key, value in data.iteritems(): - if value["package"] in packs: - packs[value["package"]]["links"][key] = value - - return packs - - @lock - def getInfoData(self, queue=1): - """gets a data representation without links""" - - packs = self.db.getAllPackages(queue) - for x in self.packageCache.itervalues(): - if x.queue != queue or x.id not in packs: continue - packs[x.id].update(x.toDict()[x.id]) - - return packs - - @lock - @change - def addLinks(self, urls, package): - """adds links""" - - self.core.addonManager.dispatchEvent("links-added", urls, package) - - data = self.core.pluginManager.parseUrls(urls) - - self.db.addLinks(data, package) - self.core.threadManager.createInfoThread(data, package) - - #@TODO change from reloadAll event to package update event - self.core.pullManager.addEvent(ReloadAllEvent("collector")) - - #-------------------------------------------------------------------------- - @lock - @change - def addPackage(self, name, folder, queue=0): - """adds a package, default to link collector""" - lastID = self.db.addPackage(name, folder, queue) - p = self.db.getPackage(lastID) - e = InsertEvent("pack", lastID, p.order, "collector" if not queue else "queue") - self.core.pullManager.addEvent(e) - return lastID - - #-------------------------------------------------------------------------- - @lock - @change - def deletePackage(self, id): - """delete package and all contained links""" - - p = self.getPackage(id) - if not p: - if id in self.packageCache: del self.packageCache[id] - return - - oldorder = p.order - queue = p.queue - - e = RemoveEvent("pack", id, "collector" if not p.queue else "queue") - - pyfiles = self.cache.values() - - for pyfile in pyfiles: - if pyfile.packageid == id: - pyfile.abortDownload() - pyfile.release() - - self.db.deletePackage(p) - self.core.pullManager.addEvent(e) - self.core.addonManager.dispatchEvent("package-deleted", id) - - if id in self.packageCache: - del self.packageCache[id] - - packs = self.packageCache.values() - for pack in packs: - if pack.queue == queue and pack.order > oldorder: - pack.order -= 1 - pack.notifyChange() - - #-------------------------------------------------------------------------- - @lock - @change - def deleteLink(self, id): - """deletes links""" - - f = self.getFile(id) - if not f: - return None - - pid = f.packageid - e = RemoveEvent("file", id, "collector" if not f.package().queue else "queue") - - oldorder = f.order - - if id in self.core.threadManager.processingIds(): - self.cache[id].abortDownload() - - if id in self.cache: - del self.cache[id] - - self.db.deleteLink(f) - - self.core.pullManager.addEvent(e) - - p = self.getPackage(pid) - if not len(p.getChildren()): - p.delete() - - pyfiles = self.cache.values() - for pyfile in pyfiles: - if pyfile.packageid == pid and pyfile.order > oldorder: - pyfile.order -= 1 - pyfile.notifyChange() - - #-------------------------------------------------------------------------- - def releaseLink(self, id): - """removes pyfile from cache""" - if id in self.cache: - del self.cache[id] - - #-------------------------------------------------------------------------- - def releasePackage(self, id): - """removes package from cache""" - if id in self.packageCache: - del self.packageCache[id] - - #-------------------------------------------------------------------------- - def updateLink(self, pyfile): - """updates link""" - self.db.updateLink(pyfile) - - e = UpdateEvent("file", pyfile.id, "collector" if not pyfile.package().queue else "queue") - self.core.pullManager.addEvent(e) - - #-------------------------------------------------------------------------- - def updatePackage(self, pypack): - """updates a package""" - self.db.updatePackage(pypack) - - e = UpdateEvent("pack", pypack.id, "collector" if not pypack.queue else "queue") - self.core.pullManager.addEvent(e) - - #-------------------------------------------------------------------------- - def getPackage(self, id): - """return package instance""" - - if id in self.packageCache: - return self.packageCache[id] - else: - return self.db.getPackage(id) - - #-------------------------------------------------------------------------- - def getPackageData(self, id): - """returns dict with package information""" - pack = self.getPackage(id) - - if not pack: - return None - - pack = pack.toDict()[id] - - data = self.db.getPackageData(id) - - tmplist = [] - - cache = self.cache.values() - for x in cache: - if int(x.toDbDict()[x.id]["package"]) == int(id): - tmplist.append((x.id, x.toDbDict()[x.id])) - data.update(tmplist) - - pack["links"] = data - - return pack - - #-------------------------------------------------------------------------- - def getFileData(self, id): - """returns dict with file information""" - if id in self.cache: - return self.cache[id].toDbDict() - - return self.db.getLinkData(id) - - #-------------------------------------------------------------------------- - def getFile(self, id): - """returns pyfile instance""" - if id in self.cache: - return self.cache[id] - else: - return self.db.getFile(id) - - #-------------------------------------------------------------------------- - @lock - def getJob(self, occ): - """get suitable job""" - - #@TODO clean mess - #@TODO improve selection of valid jobs - - if occ in self.jobCache: - if self.jobCache[occ]: - id = self.jobCache[occ].pop() - if id == "empty": - pyfile = None - self.jobCache[occ].append("empty") - else: - pyfile = self.getFile(id) - else: - jobs = self.db.getJob(occ) - jobs.reverse() - if not jobs: - self.jobCache[occ].append("empty") - pyfile = None - else: - self.jobCache[occ].extend(jobs) - pyfile = self.getFile(self.jobCache[occ].pop()) - - else: - self.jobCache = {} #better not caching to much - jobs = self.db.getJob(occ) - jobs.reverse() - self.jobCache[occ] = jobs - - if not jobs: - self.jobCache[occ].append("empty") - pyfile = None - else: - pyfile = self.getFile(self.jobCache[occ].pop()) - - #@TODO: maybe the new job has to be approved... - - - #pyfile = self.getFile(self.jobCache[occ].pop()) - return pyfile - - @lock - def getDecryptJob(self): - """return job for decrypting""" - if "decrypt" in self.jobCache: - return None - - plugins = self.core.pluginManager.crypterPlugins.keys() + self.core.pluginManager.containerPlugins.keys() - plugins = str(tuple(plugins)) - - jobs = self.db.getPluginJob(plugins) - if jobs: - return self.getFile(jobs[0]) - else: - self.jobCache["decrypt"] = "empty" - return None - - def getFileCount(self): - """returns number of files""" - - if self.filecount == -1: - self.filecount = self.db.filecount(1) - - return self.filecount - - def getQueueCount(self, force=False): - """number of files that have to be processed""" - if self.queuecount == -1 or force: - self.queuecount = self.db.queuecount(1) - - return self.queuecount - - def checkAllLinksFinished(self): - """checks if all files are finished and dispatch event""" - - if not self.getQueueCount(True): - self.core.addonManager.dispatchEvent("all_downloads-finished") - self.core.log.debug("All downloads finished") - return True - - return False - - def checkAllLinksProcessed(self, fid): - """checks if all files was processed and pyload would idle now, needs fid which will be ignored when counting""" - - # reset count so statistic will update (this is called when dl was processed) - self.resetCount() - - if not self.db.processcount(1, fid): - self.core.addonManager.dispatchEvent("all_downloads-processed") - self.core.log.debug("All downloads processed") - return True - - return False - - def resetCount(self): - self.queuecount = -1 - - @lock - @change - def restartPackage(self, id): - """restart package""" - pyfiles = self.cache.values() - for pyfile in pyfiles: - if pyfile.packageid == id: - self.restartFile(pyfile.id) - - self.db.restartPackage(id) - - if id in self.packageCache: - self.packageCache[id].setFinished = False - - e = UpdateEvent("pack", id, "collector" if not self.getPackage(id).queue else "queue") - self.core.pullManager.addEvent(e) - - @lock - @change - def restartFile(self, id): - """ restart file""" - if id in self.cache: - self.cache[id].status = 3 - self.cache[id].name = self.cache[id].url - self.cache[id].error = "" - self.cache[id].abortDownload() - - - self.db.restartFile(id) - - e = UpdateEvent("file", id, "collector" if not self.getFile(id).package().queue else "queue") - self.core.pullManager.addEvent(e) - - @lock - @change - def setPackageLocation(self, id, queue): - """push package to queue""" - - p = self.db.getPackage(id) - oldorder = p.order - - e = RemoveEvent("pack", id, "collector" if not p.queue else "queue") - self.core.pullManager.addEvent(e) - - self.db.clearPackageOrder(p) - - p = self.db.getPackage(id) - - p.queue = queue - self.db.updatePackage(p) - - self.db.reorderPackage(p, -1, True) - - packs = self.packageCache.values() - for pack in packs: - if pack.queue != queue and pack.order > oldorder: - pack.order -= 1 - pack.notifyChange() - - self.db.commit() - self.releasePackage(id) - p = self.getPackage(id) - - e = InsertEvent("pack", id, p.order, "collector" if not p.queue else "queue") - self.core.pullManager.addEvent(e) - - @lock - @change - def reorderPackage(self, id, position): - p = self.getPackage(id) - - e = RemoveEvent("pack", id, "collector" if not p.queue else "queue") - self.core.pullManager.addEvent(e) - self.db.reorderPackage(p, position) - - packs = self.packageCache.values() - for pack in packs: - if pack.queue != p.queue or pack.order < 0 or pack == p: continue - if p.order > position: - if pack.order >= position and pack.order < p.order: - pack.order += 1 - pack.notifyChange() - elif p.order < position: - if pack.order <= position and pack.order > p.order: - pack.order -= 1 - pack.notifyChange() - - p.order = position - self.db.commit() - - e = InsertEvent("pack", id, position, "collector" if not p.queue else "queue") - self.core.pullManager.addEvent(e) - - @lock - @change - def reorderFile(self, id, position): - f = self.getFileData(id) - f = f[id] - - e = RemoveEvent("file", id, "collector" if not self.getPackage(f["package"]).queue else "queue") - self.core.pullManager.addEvent(e) - - self.db.reorderLink(f, position) - - pyfiles = self.cache.values() - for pyfile in pyfiles: - if pyfile.packageid != f["package"] or pyfile.order < 0: continue - if f["order"] > position: - if pyfile.order >= position and pyfile.order < f["order"]: - pyfile.order += 1 - pyfile.notifyChange() - elif f["order"] < position: - if pyfile.order <= position and pyfile.order > f["order"]: - pyfile.order -= 1 - pyfile.notifyChange() - - if id in self.cache: - self.cache[id].order = position - - self.db.commit() - - e = InsertEvent("file", id, position, "collector" if not self.getPackage(f["package"]).queue else "queue") - self.core.pullManager.addEvent(e) - - @change - def updateFileInfo(self, data, pid): - """ updates file info (name, size, status, url)""" - ids = self.db.updateLinkInfo(data) - e = UpdateEvent("pack", pid, "collector" if not self.getPackage(pid).queue else "queue") - self.core.pullManager.addEvent(e) - - def checkPackageFinished(self, pyfile): - """ checks if package is finished and calls AddonManager """ - - ids = self.db.getUnfinished(pyfile.packageid) - if not ids or (pyfile.id in ids and len(ids) == 1): - if not pyfile.package().setFinished: - self.core.log.info(_("Package finished: %s") % pyfile.package().name) - self.core.addonManager.packageFinished(pyfile.package()) - pyfile.package().setFinished = True - - - def reCheckPackage(self, pid): - """ recheck links in package """ - data = self.db.getPackageData(pid) - - urls = [] - - for pyfile in data.itervalues(): - if pyfile["status"] not in (0, 12, 13): - urls.append((pyfile["url"], pyfile["plugin"])) - - self.core.threadManager.createInfoThread(urls, pid) - - @lock - @change - def deleteFinishedLinks(self): - """ deletes finished links and packages, return deleted packages """ - - old_packs = self.getInfoData(0) - old_packs.update(self.getInfoData(1)) - - self.db.deleteFinished() - - new_packs = self.db.getAllPackages(0) - new_packs.update(self.db.getAllPackages(1)) - #get new packages only from db - - deleted = [] - for id in old_packs.iterkeys(): - if id not in new_packs: - deleted.append(id) - self.deletePackage(int(id)) - - return deleted - - @lock - @change - def restartFailed(self): - """ restart all failed links """ - self.db.restartFailed() - -class FileMethods(object): - @style.queue - def filecount(self, queue): - """returns number of files in queue""" - self.c.execute("SELECT COUNT(*) FROM links as l INNER JOIN packages as p ON l.package=p.id WHERE p.queue=?", (queue,)) - return self.c.fetchone()[0] - - @style.queue - def queuecount(self, queue): - """ number of files in queue not finished yet""" - self.c.execute("SELECT COUNT(*) FROM links as l INNER JOIN packages as p ON l.package=p.id WHERE p.queue=? AND l.status NOT IN (0, 4)", (queue,)) - return self.c.fetchone()[0] - - @style.queue - def processcount(self, queue, fid): - """ number of files which have to be proccessed """ - self.c.execute("SELECT COUNT(*) FROM links as l INNER JOIN packages as p ON l.package=p.id WHERE p.queue=? AND l.status IN (2, 3, 5, 7, 12) AND l.id != ?", (queue, str(fid))) - return self.c.fetchone()[0] - - @style.inner - def _nextPackageOrder(self, queue=0): - self.c.execute('SELECT MAX(packageorder) FROM packages WHERE queue=?', (queue,)) - max = self.c.fetchone()[0] - if max is not None: - return max + 1 - else: - return 0 - - @style.inner - def _nextFileOrder(self, package): - self.c.execute('SELECT MAX(linkorder) FROM links WHERE package=?', (package,)) - max = self.c.fetchone()[0] - if max is not None: - return max + 1 - else: - return 0 - - @style.queue - def addLink(self, url, name, plugin, package): - order = self._nextFileOrder(package) - self.c.execute('INSERT INTO links(url, name, plugin, package, linkorder) VALUES(?,?,?,?,?)', (url, name, (plugintype, pluginname), package, order)) - return self.c.lastrowid - - @style.queue - def addLinks(self, links, package): - """ links is a list of tupels (url, plugin)""" - order = self._nextFileOrder(package) - orders = [order + x for x in range(len(links))] - links = [(x[0], x[0], (x[1], x[2]), package, o) for x, o in zip(links, orders)] - self.c.executemany('INSERT INTO links(url, name, plugin, package, linkorder) VALUES(?,?,?,?,?)', links) - - @style.queue - def addPackage(self, name, folder, queue): - order = self._nextPackageOrder(queue) - self.c.execute('INSERT INTO packages(name, folder, queue, packageorder) VALUES(?,?,?,?)', (name, folder, queue, order)) - return self.c.lastrowid - - @style.queue - def deletePackage(self, p): - - self.c.execute('DELETE FROM links WHERE package=?', (str(p.id),)) - self.c.execute('DELETE FROM packages WHERE id=?', (str(p.id),)) - self.c.execute('UPDATE packages SET packageorder=packageorder-1 WHERE packageorder > ? AND queue=?', (p.order, p.queue)) - - @style.queue - def deleteLink(self, f): - - self.c.execute('DELETE FROM links WHERE id=?', (str(f.id),)) - self.c.execute('UPDATE links SET linkorder=linkorder-1 WHERE linkorder > ? AND package=?', (f.order, str(f.packageid))) - - - @style.queue - def getAllLinks(self, q): - """return information about all links in queue q - - q0 queue - q1 collector - - format: - - { - id: {'name': name, ... 'package': id }, ... - } - - """ - self.c.execute('SELECT l.id, l.url, l.name, l.size, l.status, l.error, l.plugin, l.package, l.linkorder FROM links as l INNER JOIN packages as p ON l.package=p.id WHERE p.queue=? ORDER BY l.linkorder', (q,)) - data = {} - for r in self.c: - data[r[0]] = { - 'id': r[0], - 'url': r[1], - 'name': r[2], - 'size': r[3], - 'format_size': formatSize(r[3]), - 'status': r[4], - 'statusmsg': self.manager.statusMsg[r[4]], - 'error': r[5], - 'plugin': r[6], - 'package': r[7], - 'order': r[8], - } - - return data - - @style.queue - def getAllPackages(self, q): - """return information about packages in queue q - (only useful in get all data) - - q0 queue - q1 collector - - format: - - { - id: {'name': name ... 'links': {}}, ... - } - """ - self.c.execute('SELECT p.id, p.name, p.folder, p.site, p.password, p.queue, p.packageorder, s.sizetotal, s.sizedone, s.linksdone, s.linkstotal \ - FROM packages p JOIN pstats s ON p.id = s.id \ - WHERE p.queue=? ORDER BY p.packageorder', str(q)) - - data = {} - for r in self.c: - data[r[0]] = { - 'id': r[0], - 'name': r[1], - 'folder': r[2], - 'site': r[3], - 'password': r[4], - 'queue': r[5], - 'order': r[6], - 'sizetotal': int(r[7]), - 'sizedone': r[8] if r[8] else 0, #these can be None - 'linksdone': r[9] if r[9] else 0, - 'linkstotal': r[10], - 'links': {} - } - - return data - - @style.queue - def getLinkData(self, id): - """get link information as dict""" - self.c.execute('SELECT id, url, name, size, status, error, plugin, package, linkorder FROM links WHERE id=?', (str(id),)) - data = {} - r = self.c.fetchone() - if not r: - return None - data[r[0]] = { - 'id': r[0], - 'url': r[1], - 'name': r[2], - 'size': r[3], - 'format_size': formatSize(r[3]), - 'status': r[4], - 'statusmsg': self.manager.statusMsg[r[4]], - 'error': r[5], - 'plugin': r[6], - 'package': r[7], - 'order': r[8], - } - - return data - - @style.queue - def getPackageData(self, id): - """get data about links for a package""" - self.c.execute('SELECT id, url, name, size, status, error, plugin, package, linkorder FROM links WHERE package=? ORDER BY linkorder', (str(id),)) - - data = {} - for r in self.c: - data[r[0]] = { - 'id': r[0], - 'url': r[1], - 'name': r[2], - 'size': r[3], - 'format_size': formatSize(r[3]), - 'status': r[4], - 'statusmsg': self.manager.statusMsg[r[4]], - 'error': r[5], - 'plugin': r[6], - 'package': r[7], - 'order': r[8], - } - - return data - - - @style.async - def updateLink(self, f): - self.c.execute('UPDATE links SET url=?, name=?, size=?, status=?, error=?, package=? WHERE id=?', (f.url, f.name, f.size, f.status, f.error, str(f.packageid), str(f.id))) - - @style.queue - def updatePackage(self, p): - self.c.execute('UPDATE packages SET name=?, folder=?, site=?, password=?, queue=? WHERE id=?', (p.name, p.folder, p.site, p.password, p.queue, str(p.id))) - - @style.queue - def updateLinkInfo(self, data): - """ data is list of tupels (name, size, status, url) """ - self.c.executemany('UPDATE links SET name=?, size=?, status=? WHERE url=? AND status IN (1, 2, 3, 14)', data) - ids = [] - self.c.execute('SELECT id FROM links WHERE url IN (\'%s\')' % "','".join([x[3] for x in data])) - for r in self.c: - ids.append(int(r[0])) - return ids - - @style.queue - def reorderPackage(self, p, position, noMove=False): - if position == -1: - position = self._nextPackageOrder(p.queue) - if not noMove: - if p.order > position: - self.c.execute('UPDATE packages SET packageorder=packageorder+1 WHERE packageorder >= ? AND packageorder < ? AND queue=? AND packageorder >= 0', (position, p.order, p.queue)) - elif p.order < position: - self.c.execute('UPDATE packages SET packageorder=packageorder-1 WHERE packageorder <= ? AND packageorder > ? AND queue=? AND packageorder >= 0', (position, p.order, p.queue)) - - self.c.execute('UPDATE packages SET packageorder=? WHERE id=?', (position, str(p.id))) - - @style.queue - def reorderLink(self, f, position): - """ reorder link with f as dict for pyfile """ - if f["order"] > position: - self.c.execute('UPDATE links SET linkorder=linkorder+1 WHERE linkorder >= ? AND linkorder < ? AND package=?', (position, f["order"], f["package"])) - elif f["order"] < position: - self.c.execute('UPDATE links SET linkorder=linkorder-1 WHERE linkorder <= ? AND linkorder > ? AND package=?', (position, f["order"], f["package"])) - - self.c.execute('UPDATE links SET linkorder=? WHERE id=?', (position, f["id"])) - - @style.queue - def clearPackageOrder(self, p): - self.c.execute('UPDATE packages SET packageorder=? WHERE id=?', (-1, str(p.id))) - self.c.execute('UPDATE packages SET packageorder=packageorder-1 WHERE packageorder > ? AND queue=? AND id != ?', (p.order, p.queue, str(p.id))) - - @style.async - def restartFile(self, id): - self.c.execute('UPDATE links SET status=3, error="" WHERE id=?', (str(id),)) - - @style.async - def restartPackage(self, id): - self.c.execute('UPDATE links SET status=3 WHERE package=?', (str(id),)) - - @style.queue - def getPackage(self, id): - """return package instance from id""" - self.c.execute("SELECT name, folder, site, password, queue, packageorder FROM packages WHERE id=?", (str(id),)) - r = self.c.fetchone() - if not r: return None - return PyPackage(self.manager, id, * r) - - #-------------------------------------------------------------------------- - @style.queue - def getFile(self, id): - """return link instance from id""" - self.c.execute("SELECT url, name, size, status, error, plugin, package, linkorder FROM links WHERE id=?", (str(id),)) - r = self.c.fetchone() - if not r: return None - return PyFile(self.manager, id, * r) - - - @style.queue - def getJob(self, occ): - """return pyfile ids, which are suitable for download and dont use a occupied plugin""" - - #@TODO improve this hardcoded method - pre = "('DLC', 'LinkList', 'SerienjunkiesOrg', 'CCF', 'RSDF')" #plugins which are processed in collector - - cmd = "(" - for i, item in enumerate(occ): - if i: cmd += ", " - cmd += "'%s'" % item - - cmd += ")" - - cmd = "SELECT l.id FROM links as l INNER JOIN packages as p ON l.package=p.id WHERE ((p.queue=1 AND l.plugin NOT IN %s) OR l.plugin IN %s) AND l.status IN (2, 3, 14) ORDER BY p.packageorder ASC, l.linkorder ASC LIMIT 5" % (cmd, pre) - - self.c.execute(cmd) # very bad! - - return [x[0] for x in self.c] - - @style.queue - def getPluginJob(self, plugins): - """returns pyfile ids with suited plugins""" - cmd = "SELECT l.id FROM links as l INNER JOIN packages as p ON l.package=p.id WHERE l.plugin IN %s AND l.status IN (2, 3, 14) ORDER BY p.packageorder ASC, l.linkorder ASC LIMIT 5" % plugins - - self.c.execute(cmd) # very bad! - - return [x[0] for x in self.c] - - @style.queue - def getUnfinished(self, pid): - """return list of max length 3 ids with pyfiles in package not finished or processed""" - - self.c.execute("SELECT id FROM links WHERE package=? AND status NOT IN (0, 4, 13) LIMIT 3", (str(pid),)) - return [r[0] for r in self.c] - - @style.queue - def deleteFinished(self): - self.c.execute("DELETE FROM links WHERE status IN (0, 4)") - self.c.execute("DELETE FROM packages WHERE NOT EXISTS(SELECT 1 FROM links WHERE packages.id=links.package)") - - @style.queue - def restartFailed(self): - self.c.execute("UPDATE links SET status=3, error='' WHERE status IN (6, 8, 9)") - - @style.queue - def findDuplicates(self, id, folder, filename): - """ checks if filename exists with different id and same package """ - self.c.execute("SELECT l.plugin FROM links as l INNER JOIN packages as p ON l.package=p.id AND p.folder=? WHERE l.id!=? AND l.status=0 AND l.name=?", (folder, id, filename)) - return self.c.fetchone() - - @style.queue - def purgeLinks(self): - self.c.execute("DELETE FROM links;") - self.c.execute("DELETE FROM packages;") - -DatabaseBackend.registerSub(FileMethods) diff --git a/module/plugins/Addon.py b/module/plugins/Addon.py deleted file mode 100644 index ca36fe4ae..000000000 --- a/module/plugins/Addon.py +++ /dev/null @@ -1,185 +0,0 @@ -# -*- coding: utf-8 -*- - -from traceback import print_exc - -from pyload.plugin.Plugin import Base -from pyload.utils import has_method - - -class Expose(object): - """ used for decoration to declare rpc services """ - - def __new__(cls, f, *args, **kwargs): - addonManager.addRPC(f.__module__, f.func_name, f.func_doc) - return f - - -def threaded(fn): - - def run(*args,**kwargs): - addonManager.startThread(fn, *args, **kwargs) - - return run - - -class Addon(Base): - """ - Base class for addon plugins. - """ - __name__ = "Addon" - __type__ = "addon" - __version__ = "0.03" - - __config__ = [] #: [("name", "type", "desc", "default")] - - __description__ = """Base addon/hook plugin""" - __license__ = "GPLv3" - __authors__ = [("mkaay", "mkaay@mkaay.de"), - ("RaNaN", "RaNaN@pyload.org")] - - - #: automatically register event listeners for functions, attribute will be deleted dont use it yourself - event_map = {} - - # Deprecated alternative to event_map - #: List of events the plugin can handle, name the functions exactly like eventname. - event_list = [] #@NOTE: dont make duplicate entries in event_map - - - def __init__(self, core, manager): - Base.__init__(self, core) - - #: Provide information in dict here, usable by API `getInfo` - self.info = {} - - #: Callback of periodical job task, used by AddonManager - self.cb = None - self.interval = 60 - - #: `AddonManager` - self.manager = manager - - #register events - if self.event_map: - for event, funcs in self.event_map.iteritems(): - if type(funcs) in (list, tuple): - for f in funcs: - self.manager.addEvent(event, getattr(self,f)) - else: - self.manager.addEvent(event, getattr(self,funcs)) - - #delete for various reasons - self.event_map = None - - if self.event_list: - for f in self.event_list: - self.manager.addEvent(f, getattr(self,f)) - - self.event_list = None - - self.setup() - - # self.initPeriodical() - - - def initPeriodical(self, delay=0, threaded=False): - self.cb = self.core.scheduler.addJob(delay, self._periodical, args=[threaded], threaded=threaded) - - - def _periodical(self, threaded): - if self.interval < 0: - self.cb = None - return - - try: - self.periodical() - - except Exception, e: - self.logError(_("Error executing addon: %s") % e) - if self.core.debug: - print_exc() - - self.cb = self.core.scheduler.addJob(self.interval, self._periodical, threaded=threaded) - - - def __repr__(self): - return "<Addon %s>" % self.__name__ - - - def setup(self): - """ more init stuff if needed """ - pass - - - def deactivate(self): - """ called when addon was deactivated """ - if has_method(self.__class__, "unload"): - self.unload() - - def unload(self): # Deprecated, use method deactivate() instead - pass - - - def isActivated(self): - """ checks if addon is activated""" - return self.core.config.getPlugin(self.__name__, "activated") - - - # Event methods - overwrite these if needed - def activate(self): - """ called when addon was activated """ - if has_method(self.__class__, "coreReady"): - self.coreReady() - - def coreReady(self): # Deprecated, use method activate() instead - pass - - - def exit(self): - """ called by core.shutdown just before pyLoad exit """ - if has_method(self.__class__, "coreExiting"): - self.coreExiting() - - def coreExiting(self): # Deprecated, use method exit() instead - pass - - - def downloadPreparing(self, pyfile): - pass - - - def downloadFinished(self, pyfile): - pass - - - def downloadFailed(self, pyfile): - pass - - - def packageFinished(self, pypack): - pass - - - def beforeReconnecting(self, ip): - pass - - - def afterReconnecting(self, ip): - pass - - - def periodical(self): - pass - - - def captchaTask(self, task): - """ new captcha task for the plugin, it MUST set the handler and timeout or will be ignored """ - pass - - - def captchaCorrect(self, task): - pass - - - def captchaInvalid(self, task): - pass diff --git a/module/plugins/Captcha.py b/module/plugins/Captcha.py deleted file mode 100644 index ace488994..000000000 --- a/module/plugins/Captcha.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.Plugin import Plugin - - -class Captcha(Plugin): - __name__ = "Captcha" - __type__ = "captcha" - __version__ = "0.14" - - __description__ = """Base captcha service plugin""" - __license__ = "GPLv3" - __authors__ = [("pyLoad Team", "admin@pyload.org")] - - - KEY_PATTERN = None - - key = None #: last key detected - - - def __init__(self, plugin): - self.plugin = plugin - - - def detect_key(self, html=None): - if not html: - if hasattr(self.plugin, "html") and self.plugin.html: - html = self.plugin.html - else: - errmsg = _("%s html not found") % self.__name__ - self.plugin.error(errmsg) - raise TypeError(errmsg) - - m = re.search(self.KEY_PATTERN, html) - if m: - self.key = m.group("KEY") - self.plugin.logDebug("%s key: %s" % (self.__name__, self.key)) - return self.key - else: - self.plugin.logDebug("%s key not found" % self.__name__) - return None - - - def challenge(self, key=None): - raise NotImplementedError - - - def result(self, server, challenge): - raise NotImplementedError diff --git a/module/plugins/OCR.py b/module/plugins/OCR.py deleted file mode 100644 index f309394f5..000000000 --- a/module/plugins/OCR.py +++ /dev/null @@ -1,318 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -try: - from PIL import Image, GifImagePlugin, JpegImagePlugin, PngImagePlugin, TiffImagePlugin - -except ImportError: - import Image, GifImagePlugin, JpegImagePlugin, PngImagePlugin, TiffImagePlugin - -import logging -import os -import subprocess -#import tempfile - -from module.utils import save_join - - -class OCR(object): - __name__ = "OCR" - __type__ = "ocr" - __version__ = "0.11" - - __description__ = """OCR base plugin""" - __license__ = "GPLv3" - __authors__ = [("pyLoad Team", "admin@pyload.org")] - - - def __init__(self): - self.logger = logging.getLogger("log") - - - def load_image(self, image): - self.image = Image.open(image) - self.pixels = self.image.load() - self.result_captcha = '' - - - def unload(self): - """delete all tmp images""" - pass - - - def threshold(self, value): - self.image = self.image.point(lambda a: a * value + 10) - - - def run(self, command): - """Run a command""" - - popen = subprocess.Popen(command, bufsize=-1, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - popen.wait() - output = popen.stdout.read() + " | " + popen.stderr.read() - popen.stdout.close() - popen.stderr.close() - self.logger.debug("Tesseract ReturnCode %s Output: %s" % (popen.returncode, output)) - - - def run_tesser(self, subset=False, digits=True, lowercase=True, uppercase=True): - #tmpTif = tempfile.NamedTemporaryFile(suffix=".tif") - try: - tmpTif = open(save_join("tmp", "tmpTif_%s.tif" % self.__name__), "wb") - tmpTif.close() - - #tmpTxt = tempfile.NamedTemporaryFile(suffix=".txt") - tmpTxt = open(save_join("tmp", "tmpTxt_%s.txt" % self.__name__), "wb") - tmpTxt.close() - - except IOError, e: - self.logError(e) - return - - self.logger.debug("save tiff") - self.image.save(tmpTif.name, 'TIFF') - - if os.name == "nt": - tessparams = [os.path.join(pypath, "tesseract", "tesseract.exe")] - else: - tessparams = ["tesseract"] - - tessparams.extend([os.path.abspath(tmpTif.name), os.path.abspath(tmpTxt.name).replace(".txt", "")] ) - - if subset and (digits or lowercase or uppercase): - #tmpSub = tempfile.NamedTemporaryFile(suffix=".subset") - with open(save_join("tmp", "tmpSub_%s.subset" % self.__name__), "wb") as tmpSub: - tmpSub.write("tessedit_char_whitelist ") - - if digits: - tmpSub.write("0123456789") - if lowercase: - tmpSub.write("abcdefghijklmnopqrstuvwxyz") - if uppercase: - tmpSub.write("ABCDEFGHIJKLMNOPQRSTUVWXYZ") - - tmpSub.write("\n") - tessparams.append("nobatch") - tessparams.append(os.path.abspath(tmpSub.name)) - - self.logger.debug("run tesseract") - self.run(tessparams) - self.logger.debug("read txt") - - try: - with open(tmpTxt.name, 'r') as f: - self.result_captcha = f.read().replace("\n", "") - except Exception: - self.result_captcha = "" - - self.logger.debug(self.result_captcha) - try: - os.remove(tmpTif.name) - os.remove(tmpTxt.name) - if subset and (digits or lowercase or uppercase): - os.remove(tmpSub.name) - except Exception: - pass - - - def get_captcha(self, name): - raise NotImplementedError - - - def to_greyscale(self): - if self.image.mode != 'L': - self.image = self.image.convert('L') - - self.pixels = self.image.load() - - - def eval_black_white(self, limit): - self.pixels = self.image.load() - w, h = self.image.size - for x in xrange(w): - for y in xrange(h): - if self.pixels[x, y] > limit: - self.pixels[x, y] = 255 - else: - self.pixels[x, y] = 0 - - - def clean(self, allowed): - pixels = self.pixels - - w, h = self.image.size - - for x in xrange(w): - for y in xrange(h): - if pixels[x, y] == 255: - continue - # No point in processing white pixels since we only want to remove black pixel - count = 0 - - try: - if pixels[x - 1, y - 1] != 255: - count += 1 - if pixels[x - 1, y] != 255: - count += 1 - if pixels[x - 1, y + 1] != 255: - count += 1 - if pixels[x, y + 1] != 255: - count += 1 - if pixels[x + 1, y + 1] != 255: - count += 1 - if pixels[x + 1, y] != 255: - count += 1 - if pixels[x + 1, y - 1] != 255: - count += 1 - if pixels[x, y - 1] != 255: - count += 1 - except Exception: - pass - - # not enough neighbors are dark pixels so mark this pixel - # to be changed to white - if count < allowed: - pixels[x, y] = 1 - - # second pass: this time set all 1's to 255 (white) - for x in xrange(w): - for y in xrange(h): - if pixels[x, y] == 1: - pixels[x, y] = 255 - - self.pixels = pixels - - - def derotate_by_average(self): - """rotate by checking each angle and guess most suitable""" - - w, h = self.image.size - pixels = self.pixels - - for x in xrange(w): - for y in xrange(h): - if pixels[x, y] == 0: - pixels[x, y] = 155 - - highest = {} - counts = {} - - for angle in xrange(-45, 45): - - tmpimage = self.image.rotate(angle) - - pixels = tmpimage.load() - - w, h = self.image.size - - for x in xrange(w): - for y in xrange(h): - if pixels[x, y] == 0: - pixels[x, y] = 255 - - count = {} - - for x in xrange(w): - count[x] = 0 - for y in xrange(h): - if pixels[x, y] == 155: - count[x] += 1 - - sum = 0 - cnt = 0 - - for x in count.values(): - if x != 0: - sum += x - cnt += 1 - - avg = sum / cnt - counts[angle] = cnt - highest[angle] = 0 - for x in count.values(): - if x > highest[angle]: - highest[angle] = x - - highest[angle] = highest[angle] - avg - - hkey = 0 - hvalue = 0 - - for key, value in highest.iteritems(): - if value > hvalue: - hkey = key - hvalue = value - - self.image = self.image.rotate(hkey) - pixels = self.image.load() - - for x in xrange(w): - for y in xrange(h): - if pixels[x, y] == 0: - pixels[x, y] = 255 - - if pixels[x, y] == 155: - pixels[x, y] = 0 - - self.pixels = pixels - - - def split_captcha_letters(self): - captcha = self.image - started = False - letters = [] - width, height = captcha.size - bottomY, topY = 0, height - pixels = captcha.load() - - for x in xrange(width): - black_pixel_in_col = False - for y in xrange(height): - if pixels[x, y] != 255: - if not started: - started = True - firstX = x - lastX = x - - if y > bottomY: - bottomY = y - if y < topY: - topY = y - if x > lastX: - lastX = x - - black_pixel_in_col = True - - if black_pixel_in_col is False and started is True: - rect = (firstX, topY, lastX, bottomY) - new_captcha = captcha.crop(rect) - - w, h = new_captcha.size - if w > 5 and h > 5: - letters.append(new_captcha) - - started = False - bottomY, topY = 0, height - - return letters - - - def correct(self, values, var=None): - if var: - result = var - else: - result = self.result_captcha - - for key, item in values.iteritems(): - - if key.__class__ == str: - result = result.replace(key, item) - else: - for expr in key: - result = result.replace(expr, item) - - if var: - return result - else: - self.result_captcha = result diff --git a/module/plugins/accounts/BackinNet.py b/module/plugins/accounts/BackinNet.py deleted file mode 100644 index 46c8d7ac5..000000000 --- a/module/plugins/accounts/BackinNet.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.XFSAccount import XFSAccount - - -class BackinNet(XFSAccount): - __name__ = "BackinNet" - __type__ = "account" - __version__ = "0.01" - - __description__ = """Backin.net account plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - HOSTER_DOMAIN = "backin.net" diff --git a/module/plugins/accounts/CloudzillaTo.py b/module/plugins/accounts/CloudzillaTo.py deleted file mode 100644 index d22d5e4b3..000000000 --- a/module/plugins/accounts/CloudzillaTo.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.Account import Account - - -class CloudzillaTo(Account): - __name__ = "CloudzillaTo" - __type__ = "account" - __version__ = "0.02" - - __description__ = """Cloudzilla.to account plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - PREMIUM_PATTERN = r'<h2>account type</h2>\s*Premium Account' - - - def loadAccountInfo(self, user, req): - html = req.load("http://www.cloudzilla.to/") - - premium = True if re.search(self.PREMIUM_PATTERN, html) else False - - return {'validuntil': -1, 'trafficleft': -1, 'premium': premium} - - - def login(self, user, data, req): - html = req.load("http://www.cloudzilla.to/", - post={'lusername': user, - 'lpassword': data['password'], - 'w' : "dologin"}, - decode=True) - - if "ERROR" in html: - self.wrongPassword() diff --git a/module/plugins/accounts/DropboxCom.py b/module/plugins/accounts/DropboxCom.py deleted file mode 100644 index bcaa24b8e..000000000 --- a/module/plugins/accounts/DropboxCom.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class DropboxCom(SimpleHoster): - __name__ = "DropboxCom" - __type__ = "hoster" - __version__ = "0.04" - - __pattern__ = r'https?://(?:www\.)?dropbox\.com/.+' - - __description__ = """Dropbox.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] - - - NAME_PATTERN = r'<title>Dropbox - (?P<N>.+?)<' - SIZE_PATTERN = r' · (?P<S>[\d.,]+) (?P<U>[\w^_]+)' - - OFFLINE_PATTERN = r'<title>Dropbox - (404|Shared link error)<' - - COOKIES = [("dropbox.com", "lang", "en")] - - - def setup(self): - self.multiDL = True - self.chunkLimit = 1 - self.resumeDownload = True - - - def handleFree(self, pyfile): - self.download(pyfile.url, get={'dl': "1"}) - - -getInfo = create_getInfo(DropboxCom) diff --git a/module/plugins/accounts/ExashareCom.py b/module/plugins/accounts/ExashareCom.py deleted file mode 100644 index 431798522..000000000 --- a/module/plugins/accounts/ExashareCom.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.XFSAccount import XFSAccount - - -class ExashareCom(XFSAccount): - __name__ = "ExashareCom" - __type__ = "account" - __version__ = "0.01" - - __description__ = """Exashare.com account plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - HOSTER_DOMAIN = "exashare.com" diff --git a/module/plugins/accounts/JunkyvideoCom.py b/module/plugins/accounts/JunkyvideoCom.py deleted file mode 100644 index 8275ff176..000000000 --- a/module/plugins/accounts/JunkyvideoCom.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.XFSAccount import XFSAccount - - -class JunkyvideoCom(XFSAccount): - __name__ = "JunkyvideoCom" - __type__ = "account" - __version__ = "0.01" - - __description__ = """Junkyvideo.com account plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - HOSTER_DOMAIN = "junkyvideo.com" diff --git a/module/plugins/accounts/MultihostersCom.py b/module/plugins/accounts/MultihostersCom.py deleted file mode 100644 index e98f17b2d..000000000 --- a/module/plugins/accounts/MultihostersCom.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.accounts.ZeveraCom import ZeveraCom - - -class MultihostersCom(ZeveraCom): - __name__ = "MultihostersCom" - __type__ = "account" - __version__ = "0.03" - - __description__ = """Multihosters.com account plugin""" - __license__ = "GPLv3" - __authors__ = [("tjeh", "tjeh@gmx.net")] - - - HOSTER_DOMAIN = "multihosters.com" diff --git a/module/plugins/accounts/NoPremiumPl.py b/module/plugins/accounts/NoPremiumPl.py deleted file mode 100644 index a36b114eb..000000000 --- a/module/plugins/accounts/NoPremiumPl.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding: utf-8 -*- - -from datetime import datetime -import hashlib - -from module.plugins.Account import Account -from time import mktime -from module.common.json_layer import json_loads as loads - - -class NoPremiumPl(Account): - __name__ = "NoPremiumPl" - __version__ = "0.01" - __type__ = "account" - __description__ = "NoPremium.pl account plugin" - __license__ = "GPLv3" - __authors__ = [("goddie", "dev@nopremium.pl")] - - _api_url = "http://crypt.nopremium.pl" - - _api_query = { - "site": "nopremium", - "username": "", - "password": "", - "output": "json", - "loc": "1", - "info": "1" - } - - _req = None - _usr = None - _pwd = None - - def loadAccountInfo(self, name, req): - self._req = req - try: - result = loads(self.runAuthQuery()) - except Exception: - # todo: return or let it be thrown? - return - - premium = False - valid_untill = -1 - - if "expire" in result.keys() and result["expire"]: - premium = True - valid_untill = mktime(datetime.fromtimestamp(int(result["expire"])).timetuple()) - traffic_left = result["balance"] * 1024 - - return ({ - "validuntil": valid_untill, - "trafficleft": traffic_left, - "premium": premium - }) - - def login(self, user, data, req): - self._usr = user - self._pwd = hashlib.sha1(hashlib.md5(data["password"]).hexdigest()).hexdigest() - self._req = req - - try: - response = loads(self.runAuthQuery()) - except Exception: - self.wrongPassword() - - if "errno" in response.keys(): - self.wrongPassword() - data['usr'] = self._usr - data['pwd'] = self._pwd - - def createAuthQuery(self): - query = self._api_query - query["username"] = self._usr - query["password"] = self._pwd - - return query - - def runAuthQuery(self): - data = self._req.load(self._api_url, post=self.createAuthQuery()) - - return data
\ No newline at end of file diff --git a/module/plugins/accounts/PutdriveCom.py b/module/plugins/accounts/PutdriveCom.py deleted file mode 100644 index 4f2fadbcc..000000000 --- a/module/plugins/accounts/PutdriveCom.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.accounts.ZeveraCom import ZeveraCom - - -class PutdriveCom(ZeveraCom): - __name__ = "PutdriveCom" - __type__ = "account" - __version__ = "0.02" - - __description__ = """Putdrive.com account plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - HOSTER_DOMAIN = "putdrive.com" diff --git a/module/plugins/accounts/RapideoPl.py b/module/plugins/accounts/RapideoPl.py deleted file mode 100644 index 426c680a6..000000000 --- a/module/plugins/accounts/RapideoPl.py +++ /dev/null @@ -1,80 +0,0 @@ -# -*- coding: utf-8 -*- - -from datetime import datetime -import hashlib - -from module.plugins.Account import Account -from time import mktime -from module.common.json_layer import json_loads as loads - - -class RapideoPl(Account): - __name__ = "RapideoPl" - __version__ = "0.01" - __type__ = "account" - __description__ = "Rapideo.pl account plugin" - __license__ = "GPLv3" - __authors__ = [("goddie", "dev@rapideo.pl")] - - _api_url = "http://enc.rapideo.pl" - - _api_query = { - "site": "newrd", - "username": "", - "password": "", - "output": "json", - "loc": "1", - "info": "1" - } - - _req = None - _usr = None - _pwd = None - - def loadAccountInfo(self, name, req): - self._req = req - try: - result = loads(self.runAuthQuery()) - except Exception: - # todo: return or let it be thrown? - return - - premium = False - valid_untill = -1 - if "expire" in result.keys() and result["expire"]: - premium = True - valid_untill = mktime(datetime.fromtimestamp(int(result["expire"])).timetuple()) - - traffic_left = result["balance"] - - return ({ - "validuntil": valid_untill, - "trafficleft": traffic_left, - "premium": premium - }) - - def login(self, user, data, req): - self._usr = user - self._pwd = hashlib.md5(data["password"]).hexdigest() - self._req = req - try: - response = loads(self.runAuthQuery()) - except Exception: - self.wrongPassword() - - if "errno" in response.keys(): - self.wrongPassword() - data['usr'] = self._usr - data['pwd'] = self._pwd - - def createAuthQuery(self): - query = self._api_query - query["username"] = self._usr - query["password"] = self._pwd - - return query - - def runAuthQuery(self): - data = self._req.load(self._api_url, post=self.createAuthQuery()) - - return data
\ No newline at end of file diff --git a/module/plugins/accounts/RapiduNet.py b/module/plugins/accounts/RapiduNet.py deleted file mode 100644 index 8da698c57..000000000 --- a/module/plugins/accounts/RapiduNet.py +++ /dev/null @@ -1,66 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from time import time - -from module.plugins.Account import Account -from module.common.json_layer import json_loads - - -class RapiduNet(Account): - __name__ = "RapiduNet" - __type__ = "account" - __version__ = "0.05" - - __description__ = """Rapidu.net account plugin""" - __license__ = "GPLv3" - __authors__ = [("prOq", None), - ("Walter Purcaro", "vuolter@gmail.com")] - - - PREMIUM_PATTERN = r'>Account: <b>Premium' - - VALID_UNTIL_PATTERN = r'>Account: <b>\w+ \((\d+)' - - TRAFFIC_LEFT_PATTERN = r'class="tipsyS"><b>(.+?)<' - - - def loadAccountInfo(self, user, req): - validuntil = None - trafficleft = -1 - premium = False - - html = req.load("https://rapidu.net/", decode=True) - - if re.search(self.PREMIUM_PATTERN, html): - premium = True - - m = re.search(self.VALID_UNTIL_PATTERN, html) - if m: - validuntil = time() + (86400 * int(m.group(1))) - - m = re.search(self.TRAFFIC_LEFT_PATTERN, html) - if m: - trafficleft = self.parseTraffic(m.group(1)) - - return {'validuntil': validuntil, 'trafficleft': trafficleft, 'premium': premium} - - - def login(self, user, data, req): - req.load("https://rapidu.net/ajax.php", - get={'a': "getChangeLang"}, - post={'_go' : "", - 'lang': "en"}) - - json = json_loads(req.load("https://rapidu.net/ajax.php", - get={'a': "getUserLogin"}, - post={'_go' : "", - 'login' : user, - 'pass' : data['password'], - 'remember': "1"})) - - self.logDebug(json) - - if not json['message'] == "success": - self.wrongPassword() diff --git a/module/plugins/accounts/SmoozedCom.py b/module/plugins/accounts/SmoozedCom.py deleted file mode 100644 index e6c25752b..000000000 --- a/module/plugins/accounts/SmoozedCom.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- coding: utf-8 -*- - -import hashlib - -from beaker.crypto.pbkdf2 import PBKDF2 -from time import time - -from module.common.json_layer import json_loads -from module.plugins.Account import Account - - -class SmoozedCom(Account): - __name__ = "SmoozedCom" - __type__ = "account" - __version__ = "0.03" - - __description__ = """Smoozed.com account plugin""" - __license__ = "GPLv3" - __authors__ = [("", "")] - - - def loadAccountInfo(self, user, req): - # Get user data from premiumize.me - status = self.getAccountStatus(user, req) - - self.logDebug(status) - - if status['state'] != 'ok': - info = {'validuntil' : None, - 'trafficleft': None, - 'premium' : False} - else: - # Parse account info - info = {'validuntil' : float(status["data"]["user"]["user_premium"]), - 'trafficleft': max(0, status["data"]["traffic"][1] - status["data"]["traffic"][0]), - 'session' : status["data"]["session_key"], - 'hosters' : [hoster["name"] for hoster in status["data"]["hoster"]]} - - if info['validuntil'] < time(): - info['premium'] = False - else: - info['premium'] = True - - return info - - - def login(self, user, data, req): - # Get user data from premiumize.me - status = self.getAccountStatus(user, req) - - # Check if user and password are valid - if status['state'] != 'ok': - self.wrongPassword() - - - def getAccountStatus(self, user, req): - password = self.getAccountData(user)['password'] - salt = hashlib.sha256(password).hexdigest() - encrypted = PBKDF2(password, salt, iterations=1000).hexread(32) - - return json_loads(req.load("http://www2.smoozed.com/api/login", - get={'auth': user, 'password': encrypted})) diff --git a/module/plugins/accounts/UploadableCh.py b/module/plugins/accounts/UploadableCh.py deleted file mode 100644 index 86ae5dd17..000000000 --- a/module/plugins/accounts/UploadableCh.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.Account import Account - - -class UploadableCh(Account): - __name__ = "UploadableCh" - __type__ = "account" - __version__ = "0.03" - - __description__ = """Uploadable.ch account plugin""" - __license__ = "GPLv3" - __authors__ = [("Sasch", "gsasch@gmail.com")] - - - def loadAccountInfo(self, user, req): - html = req.load("http://www.uploadable.ch/login.php") - - premium = '<a href="/logout.php"' in html - trafficleft = -1 if premium else None - - return {'validuntil': None, 'trafficleft': trafficleft, 'premium': premium} #@TODO: validuntil - - - def login(self, user, data, req): - html = req.load("http://www.uploadable.ch/login.php", - post={'userName' : user, - 'userPassword' : data["password"], - 'autoLogin' : "1", - 'action__login': "normalLogin"}, - decode=True) - - if "Login failed" in html: - self.wrongPassword() diff --git a/module/plugins/accounts/WebshareCz.py b/module/plugins/accounts/WebshareCz.py deleted file mode 100644 index f8e3eeb73..000000000 --- a/module/plugins/accounts/WebshareCz.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from hashlib import md5, sha1 -from passlib.hash import md5_crypt -from time import mktime, strptime, time - -from module.plugins.Account import Account - - -class WebshareCz(Account): - __name__ = "WebshareCz" - __type__ = "account" - __version__ = "0.07" - - __description__ = """Webshare.cz account plugin""" - __license__ = "GPLv3" - __authors__ = [("rush", "radek.senfeld@gmail.com")] - - - VALID_UNTIL_PATTERN = r'<vip_until>(.+)</vip_until>' - - TRAFFIC_LEFT_PATTERN = r'<bytes>(.+)</bytes>' - - - def loadAccountInfo(self, user, req): - html = req.load("https://webshare.cz/api/user_data/", - post={'wst': self.infos['wst']}, - decode=True) - - self.logDebug("Response: " + html) - - expiredate = re.search(self.VALID_UNTIL_PATTERN, html).group(1) - self.logDebug("Expire date: " + expiredate) - - validuntil = mktime(strptime(expiredate, "%Y-%m-%d %H:%M:%S")) - trafficleft = self.parseTraffic(re.search(self.TRAFFIC_LEFT_PATTERN, html).group(1)) - premium = validuntil > time() - - return {'validuntil': validuntil, 'trafficleft': -1, 'premium': premium} - - - def login(self, user, data, req): - salt = req.load("https://webshare.cz/api/salt/", - post={'username_or_email': user, - 'wst' : ""}, - decode=True) - - if "<status>OK</status>" not in salt: - self.wrongPassword() - - salt = re.search('<salt>(.+)</salt>', salt).group(1) - password = sha1(md5_crypt.encrypt(data["password"], salt=salt)).hexdigest() - digest = md5(user + ":Webshare:" + password).hexdigest() - - login = req.load("https://webshare.cz/api/login/", - post={'digest' : digest, - 'keep_logged_in' : 1, - 'password' : password, - 'username_or_email': user, - 'wst' : ""}, - decode=True) - - if "<status>OK</status>" not in login: - self.wrongPassword() - - self.infos['wst'] = re.search('<token>(.+)</token>', login).group(1) diff --git a/module/plugins/addon/ClickAndLoad.py b/module/plugins/addon/ClickAndLoad.py deleted file mode 100644 index 5fe6e4bec..000000000 --- a/module/plugins/addon/ClickAndLoad.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- - -from socket import socket, error -from threading import Thread - -from pyload.plugin.Addon import Addon - - -def forward(source, destination): - string = ' ' - while string: - string = source.recv(1024) - if string: - destination.sendall(string) - else: - #source.shutdown(socket.SHUT_RD) - destination.shutdown(socket.SHUT_WR) - - -class ClickAndLoad(Addon): - __name__ = "ClickAndLoad" - __type__ = "addon" - __version__ = "0.23" - - __config__ = [("activated", "bool", "Activated" , True ), - ("port" , "int" , "Port" , 9666 ), - ("extern" , "bool", "Allow external link adding", False)] - - __description__ = """Click'N'Load hook plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.de"), - ("mkaay", "mkaay@mkaay.de"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - def setup(self): - self.interval = 300 - - - def activate(self): - self.initPeriodical() - - - def periodical(self): - webip = "0.0.0.0" if self.getConfig("extern") else "127.0.0.1" - webport = self.config['webinterface']['port'] - cnlport = self.getConfig("port")) - - try: - s = socket() - s.bind((webip, cnlport)) - s.listen(5) - - client = s.accept()[0] - server = socket() - - server.connect(("127.0.0.1", webport)) - - except error, e: - if hasattr(e, "errno"): - errno = e.errno - else: - errno = e.args[0] - - if errno == 98: - self.logWarning(_("Port %d already in use") % cnlport) - else: - self.logDebug(e) - - else: - self.core.scheduler.removeJob(self.cb) - t = Thread(target=forward, args=[client, server]) - t.setDaemon(True) - t.start() diff --git a/module/plugins/addon/ExtractArchive.py b/module/plugins/addon/ExtractArchive.py deleted file mode 100644 index 3ea8839dc..000000000 --- a/module/plugins/addon/ExtractArchive.py +++ /dev/null @@ -1,509 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import os -import sys - -from copy import copy -from traceback import print_exc - -# monkey patch bug in python 2.6 and lower -# http://bugs.python.org/issue6122 , http://bugs.python.org/issue1236 , http://bugs.python.org/issue1731717 -if sys.version_info < (2, 7) and os.name != "nt": - import errno - - from subprocess import Popen - - def _eintr_retry_call(func, *args): - while True: - try: - return func(*args) - - except OSError, e: - if e.errno == errno.EINTR: - continue - raise - - - # unsued timeout option for older python version - def wait(self, timeout=0): - """Wait for child process to terminate. Returns returncode - attribute.""" - if self.returncode is None: - try: - pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0) - except OSError, e: - if e.errno != errno.ECHILD: - raise - # This happens if SIGCLD is set to be ignored or waiting - # for child processes has otherwise been disabled for our - # process. This child is dead, we can't get the status. - sts = 0 - self._handle_exitstatus(sts) - return self.returncode - - Popen.wait = wait - -if os.name != "nt": - from grp import getgrnam - from pwd import getpwnam - -from module.plugins.Hook import Hook, threaded, Expose -from module.plugins.internal.Extractor import ArchiveError, CRCError, PasswordError -from module.plugins.internal.SimpleHoster import replace_patterns -from module.utils import fs_encode, save_join, uniqify - - -class ArchiveQueue(object): - - def __init__(self, plugin, storage): - self.plugin = plugin - self.storage = storage - - - def get(self): - try: - return [int(pid) for pid in self.plugin.getStorage("ExtractArchive:%s" % self.storage, "").decode('base64').split()] - except Exception: - return [] - - - def set(self, value): - if isinstance(value, list): - item = str(value)[1:-1].replace(' ', '').replace(',', ' ') - else: - item = str(value).strip() - return self.plugin.setStorage("ExtractArchive:%s" % self.storage, item.encode('base64')[:-1]) - - - def delete(self): - return self.plugin.delStorage("ExtractArchive:%s" % self.storage) - - - def add(self, item): - queue = self.get() - if item not in queue: - return self.set(queue + [item]) - else: - return True - - - def remove(self, item): - queue = self.get() - try: - queue.remove(item) - except ValueError: - pass - if queue == []: - return self.delete() - return self.set(queue) - - - -class ExtractArchive(Hook): - __name__ = "ExtractArchive" - __type__ = "hook" - __version__ = "1.29" - - __config__ = [("activated" , "bool" , "Activated" , True ), - ("fullpath" , "bool" , "Extract with full paths" , True ), - ("overwrite" , "bool" , "Overwrite files" , False ), - ("keepbroken" , "bool" , "Try to extract broken archives" , False ), - ("repair" , "bool" , "Repair broken archives" , True ), - ("usepasswordfile" , "bool" , "Use password file" , True ), - ("passwordfile" , "file" , "Password file" , "archive_password.txt" ), - ("delete" , "bool" , "Delete archive when successfully extracted", False ), - ("subfolder" , "bool" , "Create subfolder for each package" , False ), - ("destination" , "folder", "Extract files to folder" , "" ), - ("extensions" , "str" , "Extract the following extensions" , "7z,bz2,bzip2,gz,gzip,lha,lzh,lzma,rar,tar,taz,tbz,tbz2,tgz,xar,xz,z,zip"), - ("excludefiles" , "str" , "Don't extract the following files" , "*.nfo,*.DS_Store,index.dat,thumb.db" ), - ("recursive" , "bool" , "Extract archives in archives" , True ), - ("waitall" , "bool" , "Wait for all downloads to be finished" , False ), - ("renice" , "int" , "CPU priority" , 0 )] - - __description__ = """Extract different kind of archives""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com"), - ("Immenz" , "immenz@gmx.net" )] - - - event_list = ["allDownloadsProcessed"] - - NAME_REPLACEMENTS = [(r'\.part\d+\.rar$', ".part.rar")] - - - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass - - - def setup(self): - self.queue = ArchiveQueue(self, "Queue") - self.failed = ArchiveQueue(self, "Failed") - - self.interval = 60 - self.extracting = False - self.extractors = [] - self.passwords = [] - - - def coreReady(self): - # self.extracting = False - - for p in ("UnRar", "SevenZip", "UnZip"): - try: - module = self.core.pluginManager.loadModule("internal", p) - klass = getattr(module, p) - if klass.isUsable(): - self.extractors.append(klass) - - except OSError, e: - if e.errno == 2: - self.logInfo(_("No %s installed") % p) - else: - self.logWarning(_("Could not activate: %s") % p, e) - if self.core.debug: - print_exc() - - except Exception, e: - self.logWarning(_("Could not activate: %s") % p, e) - if self.core.debug: - print_exc() - - if self.extractors: - self.logInfo(_("Activated") + " " + "|".join("%s %s" % (Extractor.__name__,Extractor.VERSION) for Extractor in self.extractors)) - - if self.getConfig("waitall"): - self.extractPackage(*self.queue.get()) #: Resume unfinished extractions - else: - super(ExtractArchive, self).initPeriodical() - - else: - self.logInfo(_("No Extract plugins activated")) - - - def periodical(self): - if not self.extracting: - self.extractPackage(*self.queue.get()) - - - @Expose - def extractPackage(self, *ids): - """ Extract packages with given id""" - self.manager.startThread(self.extract, ids) - - - def packageFinished(self, pypack): - self.queue.add(pypack.id) - - - @threaded - def allDownloadsProcessed(self, thread): - if self.extract(self.queue.get(), thread): #@NOTE: check only if all gone fine, no failed reporting for now - self.manager.dispatchEvent("all_archives_extracted") - - self.manager.dispatchEvent("all_archives_processed") - - - def extract(self, ids, thread=None): - if not ids: - return False - - self.extracting = True - - processed = [] - extracted = [] - failed = [] - - toList = lambda string: string.replace(' ', '').replace(',', '|').replace(';', '|').split('|') - - destination = self.getConfig("destination") - subfolder = self.getConfig("subfolder") - fullpath = self.getConfig("fullpath") - overwrite = self.getConfig("overwrite") - renice = self.getConfig("renice") - recursive = self.getConfig("recursive") - delete = self.getConfig("delete") - keepbroken = self.getConfig("keepbroken") - - extensions = [x.lstrip('.').lower() for x in toList(self.getConfig("extensions"))] - excludefiles = toList(self.getConfig("excludefiles")) - - if extensions: - self.logDebug("Use for extensions: %s" % "|.".join(extensions)) - - # reload from txt file - self.reloadPasswords() - - # dl folder - dl = self.config['general']['download_folder'] - - #iterate packages -> extractors -> targets - for pid in ids: - pypack = self.core.files.getPackage(pid) - - if not pypack: - continue - - self.logInfo(_("Check package: %s") % pypack.name) - - # determine output folder - out = save_join(dl, pypack.folder, destination, "") #: force trailing slash - - if subfolder: - out = save_join(out, pypack.folder) - - if not os.path.exists(out): - os.makedirs(out) - - matched = False - success = True - files_ids = [(save_join(dl, pypack.folder, pylink['name']), pylink['id'], out) for pylink in pypack.getChildren().itervalues()] - - # check as long there are unseen files - while files_ids: - new_files_ids = [] - - if extensions: - files_ids = [(fname, fid, fout) for fname, fid, fout in files_ids \ - if filter(lambda ext: fname.lower().endswith(ext), extensions)] - - for Extractor in self.extractors: - targets = Extractor.getTargets(files_ids) - if targets: - self.logDebug("Targets for %s: %s" % (Extractor.__name__, targets)) - matched = True - - for fname, fid, fout in targets: - name = os.path.basename(fname) - - if not os.path.exists(fname): - self.logDebug(name, "File not found") - continue - - self.logInfo(name, _("Extract to: %s") % fout) - try: - archive = Extractor(self, - fname, - fout, - fullpath, - overwrite, - excludefiles, - renice, - delete, - keepbroken, - fid) - archive.init() - - new_files = self._extract(archive, fid, pypack.password, thread) - - except Exception, e: - self.logError(name, e) - success = False - continue - - files_ids.remove((fname, fid, fout)) # don't let other extractors spam log - self.logDebug("Extracted files: %s" % new_files) - self.setPermissions(new_files) - - for filename in new_files: - file = fs_encode(save_join(os.path.dirname(archive.filename), filename)) - if not os.path.exists(file): - self.logDebug("New file %s does not exists" % filename) - continue - - if recursive and os.path.isfile(file): - new_files_ids.append((filename, fid, os.path.dirname(filename))) # append as new target - - files_ids = new_files_ids # also check extracted files - - if matched: - if success: - extracted.append(pid) - self.manager.dispatchEvent("package_extracted", pypack) - else: - failed.append(pid) - self.manager.dispatchEvent("package_extract_failed", pypack) - - self.failed.add(pid) - else: - self.logInfo(_("No files found to extract")) - - if not matched or not success and subfolder: - try: - os.rmdir(out) - - except OSError: - pass - - self.queue.remove(pid) - - self.extracting = False - return True if not failed else False - - - def _extract(self, archive, fid, password, thread): - pyfile = self.core.files.getFile(fid) - name = os.path.basename(archive.filename) - - thread.addActive(pyfile) - pyfile.setStatus("processing") - - encrypted = False - try: - try: - archive.check() - - except CRCError, e: - self.logDebug(name, e) - self.logInfo(name, _("Header protected")) - - if self.getConfig("repair"): - self.logWarning(name, _("Repairing...")) - - pyfile.setCustomStatus(_("repairing")) - pyfile.setProgress(0) - - repaired = archive.repair() - - pyfile.setProgress(100) - - if not repaired and not self.getConfig("keepbroken"): - raise CRCError("Archive damaged") - - except PasswordError: - self.logInfo(name, _("Password protected")) - encrypted = True - - except ArchiveError, e: - raise ArchiveError(e) - - self.logDebug("Password: %s" % (password or "No provided")) - - pyfile.setCustomStatus(_("extracting")) - pyfile.setProgress(0) - - if not encrypted or not self.getConfig("usepasswordfile"): - archive.extract(password) - else: - for pw in filter(None, uniqify([password] + self.getPasswords(False))): - try: - self.logDebug("Try password: %s" % pw) - - ispw = archive.isPassword(pw) - if ispw or ispw is None: - archive.extract(pw) - self.addPassword(pw) - break - - except PasswordError: - self.logDebug("Password was wrong") - else: - raise PasswordError - - pyfile.setProgress(100) - pyfile.setCustomStatus(_("finalizing")) - - if self.core.debug: - self.logDebug("Would delete: %s" % ", ".join(archive.getDeleteFiles())) - - if self.getConfig("delete"): - files = archive.getDeleteFiles() - self.logInfo(_("Deleting %s files") % len(files)) - for f in files: - file = fs_encode(f) - if os.path.exists(file): - os.remove(file) - else: - self.logDebug("%s does not exists" % f) - - self.logInfo(name, _("Extracting finished")) - - extracted_files = archive.files or archive.list() - self.manager.dispatchEvent("archive_extracted", pyfile, archive.out, archive.filename, extracted_files) - - return extracted_files - - except PasswordError: - self.logError(name, _("Wrong password" if password else "No password found")) - - except CRCError, e: - self.logError(name, _("CRC mismatch"), e) - - except ArchiveError, e: - self.logError(name, _("Archive error"), e) - - except Exception, e: - self.logError(name, _("Unknown error"), e) - if self.core.debug: - print_exc() - - finally: - pyfile.finishIfDone() - - self.manager.dispatchEvent("archive_extract_failed", pyfile) - - raise Exception(_("Extract failed")) - - - @Expose - def getPasswords(self, reload=True): - """ List of saved passwords """ - if reload: - self.reloadPasswords() - - return self.passwords - - - def reloadPasswords(self): - try: - passwords = [] - - file = fs_encode(self.getConfig("passwordfile")) - with open(file) as f: - for pw in f.read().splitlines(): - passwords.append(pw) - - except IOError, e: - self.logError(e) - - else: - self.passwords = passwords - - - @Expose - def addPassword(self, password): - """ Adds a password to saved list""" - try: - self.passwords = uniqify([password] + self.passwords) - - file = fs_encode(self.getConfig("passwordfile")) - with open(file, "wb") as f: - for pw in self.passwords: - f.write(pw + '\n') - - except IOError, e: - self.logError(e) - - - def setPermissions(self, files): - for f in files: - if not os.path.exists(f): - continue - - try: - if self.config['permission']['change_file']: - if os.path.isfile(f): - os.chmod(f, int(self.config['permission']['file'], 8)) - - elif os.path.isdir(f): - os.chmod(f, int(self.config['permission']['folder'], 8)) - - if self.config['permission']['change_dl'] and os.name != "nt": - uid = getpwnam(self.config['permission']['user'])[2] - gid = getgrnam(self.config['permission']['group'])[2] - os.chown(f, uid, gid) - - except Exception, e: - self.logWarning(_("Setting User and Group failed"), e) diff --git a/module/plugins/addon/MergeFiles.py b/module/plugins/addon/MergeFiles.py deleted file mode 100644 index 42ac3ff4d..000000000 --- a/module/plugins/addon/MergeFiles.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import os -import re - -from traceback import print_exc - -from pyload.plugin.Addon import Addon, threaded -from module.utils import safe_join - - -class MergeFiles(Addon): - __name__ = "MergeFiles" - __type__ = "addon" - __version__ = "0.14" - - __config__ = [("activated", "bool", "Activated", True)] - - __description__ = """Merges parts splitted with hjsplit""" - __license__ = "GPLv3" - __authors__ = [("and9000", "me@has-no-mail.com")] - - - BUFFER_SIZE = 4096 - - - def setup(self): - pass - - - @threaded - def packageFinished(self, pack): - files = {} - fid_dict = {} - for fid, data in pack.getChildren().iteritems(): - if re.search("\.\d{3}$", data['name']): - if data['name'][:-4] not in files: - files[data['name'][:-4]] = [] - files[data['name'][:-4]].append(data['name']) - files[data['name'][:-4]].sort() - fid_dict[data['name']] = fid - - download_folder = self.config['general']['download_folder'] - - if self.config['general']['folder_per_package']: - download_folder = safe_join(download_folder, pack.folder) - - for name, file_list in files.iteritems(): - self.logInfo(_("Starting merging of"), name) - - final_file = open(safe_join(download_folder, name), "wb") - for splitted_file in file_list: - self.logDebug("Merging part", splitted_file) - - pyfile = self.core.files.getFile(fid_dict[splitted_file]) - - pyfile.setStatus("processing") - - try: - with open(save_join(download_folder, splitted_file), "rb") as s_file: - size_written = 0 - s_file_size = int(os.path.getsize(os.path.join(download_folder, splitted_file))) - - while True: - f_buffer = s_file.read(self.BUFFER_SIZE) - if f_buffer: - final_file.write(f_buffer) - size_written += self.BUFFER_SIZE - pyfile.setProgress((size_written * 100) / s_file_size) - else: - break - - self.logDebug("Finished merging part", splitted_file) - - except Exception, e: - print_exc() - - finally: - pyfile.setProgress(100) - pyfile.setStatus("finished") - pyfile.release() - - self.logInfo(_("Finished merging of"), name) diff --git a/module/plugins/addon/SkipRev.py b/module/plugins/addon/SkipRev.py deleted file mode 100644 index 0bbdec3b2..000000000 --- a/module/plugins/addon/SkipRev.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- - -from types import MethodType -from urllib import unquote -from urlparse import urlparse - -from module.PyFile import PyFile -from module.plugins.Hook import Hook -from module.plugins.Plugin import SkipDownload - - -def _setup(self): - self.pyfile.plugin._setup() - if self.pyfile.hasStatus("skipped"): - raise SkipDownload(self.pyfile.statusname or self.pyfile.pluginname) - - -class SkipRev(Hook): - __name__ = "SkipRev" - __type__ = "hook" - __version__ = "0.25" - - __config__ = [("tokeep", "int", "Number of rev files to keep for package (-1 to auto)", -1)] - - __description__ = """Skip files ending with extension rev""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass - - - def _pyname(self, pyfile): - if hasattr(pyfile.pluginmodule, "getInfo"): - return getattr(pyfile.pluginmodule, "getInfo")([pyfile.url]).next()[0] - else: - self.logWarning("Unable to grab file name") - return urlparse(unquote(pyfile.url)).path.split('/')[-1] - - - def _pyfile(self, link): - return PyFile(self.core.files, - link.fid, - link.url, - link.name, - link.size, - link.status, - link.error, - link.plugin, - link.packageID, - link.order) - - - def downloadPreparing(self, pyfile): - if pyfile.statusname is "unskipped" or not self._pyname(pyfile).endswith(".rev"): - return - - tokeep = self.getConfig("tokeep") - - if tokeep: - status_list = (1, 4, 8, 9, 14) if tokeep < 0 else (1, 3, 4, 8, 9, 14) - - queued = [True for link in self.core.api.getPackageData(pyfile.package().id).links \ - if link.name.endswith(".rev") and link.status not in status_list].count(True) - - if not queued or queued < tokeep: #: keep one rev at least in auto mode - return - - pyfile.setCustomStatus("SkipRev", "skipped") - pyfile.plugin._setup = pyfile.plugin.setup - pyfile.plugin.setup = MethodType(_setup, pyfile.plugin) #: work-around: inject status checker inside the preprocessing routine of the plugin - - - def downloadFailed(self, pyfile): - #: Check if pyfile is still "failed", - # maybe might has been restarted in meantime - if pyfile.status != 8: - return - - tokeep = self.getConfig("tokeep") - - if not tokeep: - return - - for link in self.core.api.getPackageData(pyfile.package().id).links: - if link.status is 4 and link.name.endswith(".rev"): - pylink = self._pyfile(link) - - if tokeep > -1 or pyfile.name.endswith(".rev"): - pylink.setStatus("queued") - else: - pylink.setCustomStatus("unskipped", "queued") - - self.core.files.save() - pylink.release() - return diff --git a/module/plugins/addon/UnSkipOnFail.py b/module/plugins/addon/UnSkipOnFail.py deleted file mode 100644 index 1becb937a..000000000 --- a/module/plugins/addon/UnSkipOnFail.py +++ /dev/null @@ -1,95 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.PyFile import PyFile -from module.plugins.Hook import Hook - - -class UnSkipOnFail(Hook): - __name__ = "UnSkipOnFail" - __type__ = "hook" - __version__ = "0.05" - - __config__ = [("activated", "bool", "Activated", True)] - - __description__ = """Queue skipped duplicates when download fails""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass - - - def downloadFailed(self, pyfile): - #: Check if pyfile is still "failed", - # maybe might has been restarted in meantime - if pyfile.status != 8: - return - - msg = _("Looking for skipped duplicates of: %s (pid:%s)") - self.logInfo(msg % (pyfile.name, pyfile.package().id)) - - dup = self.findDuplicate(pyfile) - if dup: - self.logInfo(_("Queue found duplicate: %s (pid:%s)") % (dup.name, dup.packageID)) - - #: Change status of "link" to "new_status". - # "link" has to be a valid FileData object, - # "new_status" has to be a valid status name - # (i.e. "queued" for this Plugin) - # It creates a temporary PyFile object using - # "link" data, changes its status, and tells - # the core.files-manager to save its data. - pylink = _pyfile(link) - - pylink.setCustomStatus("UnSkipOnFail", "queued") - - self.core.files.save() - pylink.release() - - else: - self.logInfo(_("No duplicates found")) - - - def findDuplicate(self, pyfile): - """ Search all packages for duplicate links to "pyfile". - Duplicates are links that would overwrite "pyfile". - To test on duplicity the package-folder and link-name - of twolinks are compared (link.name). - So this method returns a list of all links with equal - package-folders and filenames as "pyfile", but except - the data for "pyfile" iotselöf. - It does MOT check the link's status. - """ - queue = self.core.api.getQueue() #: get packages (w/o files, as most file data is useless here) - - for package in queue: - #: check if package-folder equals pyfile's package folder - if package.folder != pyfile.package().folder: - continue - - #: now get packaged data w/ files/links - pdata = self.core.api.getPackageData(package.pid) - for link in pdata.links: - #: check if link is "skipped" - if link.status != 4: - continue - - #: check if link name collides with pdata's name - #: AND at last check if it is not pyfile itself - if link.name == pyfile.name and link.fid != pyfile.id: - return link - - - def _pyfile(self, link): - return PyFile(self.core.files, - link.fid, - link.url, - link.name, - link.size, - link.status, - link.error, - link.plugin, - link.packageID, - link.order) diff --git a/module/plugins/addon/UpdateManager.py b/module/plugins/addon/UpdateManager.py deleted file mode 100644 index efccc73fb..000000000 --- a/module/plugins/addon/UpdateManager.py +++ /dev/null @@ -1,306 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import re -import sys - -from operator import itemgetter -from os import path, remove, stat - -from pyload.network.RequestFactory import getURL -from pyload.plugin.Addon import Expose, Addon, threaded -from pyload.utils import safe_join - - -class UpdateManager(Addon): - __name__ = "UpdateManager" - __type__ = "addon" - __version__ = "0.43" - - __config__ = [("activated" , "bool" , "Activated" , True ), - ("mode" , "pyLoad + plugins;plugins only", "Check updates for" , "pyLoad + plugins"), - ("interval" , "int" , "Check interval in hours" , 8 ), - ("autorestart" , "bool" , "Automatically restart pyLoad when required" , True ), - ("reloadplugins", "bool" , "Monitor plugins for code changes in debug mode", True ), - ("nodebugupdate", "bool" , "Don't check for updates in debug mode" , False )] - - __description__ = """Check for updates""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - # event_list = ["pluginConfigChanged"] - - SERVER_URL = "http://updatemanager.pyload.org" - VERSION = re.compile(r'__version__.*=.*("|\')([\d.]+)') - MIN_INTERVAL = 3 * 60 * 60 #: 3h minimum check interval (value is in seconds) - - - def pluginConfigChanged(self, plugin, name, value): - if name == "interval": - interval = value * 60 * 60 - if self.MIN_INTERVAL <= interval != self.interval: - self.core.scheduler.removeJob(self.cb) - self.interval = interval - self.initPeriodical() - else: - self.logDebug("Invalid interval value, kept current") - - elif name == "reloadplugins": - if self.cb2: - self.core.scheduler.removeJob(self.cb2) - if value is True and self.core.debug: - self.periodical2() - - - def activate(self): - self.pluginConfigChanged(self.__name__, "interval", self.getConfig("interval")) - x = lambda: self.pluginConfigChanged(self.__name__, "reloadplugins", self.getConfig("reloadplugins")) - self.core.scheduler.addJob(10, x, threaded=False) - - - def deactivate(self): - self.pluginConfigChanged(self.__name__, "reloadplugins", False) - - - def setup(self): - self.cb2 = None - self.interval = 0 - self.updating = False - self.info = {'pyload': False, 'version': None, 'plugins': False} - self.mtimes = {} #: store modification time for each plugin - - - def periodical2(self): - if not self.updating: - self.autoreloadPlugins() - - self.cb2 = self.core.scheduler.addJob(4, self.periodical2, threaded=False) - - - @Expose - def autoreloadPlugins(self): - """ reload and reindex all modified plugins """ - modules = filter( - lambda m: m and (m.__name__.startswith("pyload.plugin.") or - m.__name__.startswith("userplugins.")) and - m.__name__.count(".") >= 2, sys.modules.itervalues() - ) - - reloads = [] - - for m in modules: - root, type, name = m.__name__.rsplit(".", 2) - id = (type, name) - if type in self.core.pluginManager.plugins: - f = m.__file__.replace(".pyc", ".py") - if not path.isfile(f): - continue - - mtime = stat(f).st_mtime - - if id not in self.mtimes: - self.mtimes[id] = mtime - elif self.mtimes[id] < mtime: - reloads.append(id) - self.mtimes[id] = mtime - - return True if self.core.pluginManager.reloadPlugins(reloads) else False - - - def periodical(self): - if self.info['pyload'] or self.getConfig("nodebugupdate") and self.core.debug: - return - - self.updateThread() - - - def server_request(self): - try: - return getURL(self.SERVER_URL, get={'v': self.core.api.getServerVersion()}).splitlines() - except Exception: - self.logWarning(_("Unable to contact server to get updates")) - - - @threaded - def updateThread(self): - self.updating = True - - status = self.update(onlyplugin=self.getConfig("mode") == "plugins only") - - if status is 2 and self.getConfig("autorestart"): - self.core.api.restart() - else: - self.updating = False - - - @Expose - def updatePlugins(self): - """ simple wrapper for calling plugin update quickly """ - return self.update(onlyplugin=True) - - - @Expose - def update(self, onlyplugin=False): - """ check for updates """ - data = self.server_request() - - if not data: - exitcode = 0 - - elif data[0] == "None": - self.logInfo(_("No new pyLoad version available")) - updates = data[1:] - exitcode = self._updatePlugins(updates) - - elif onlyplugin: - exitcode = 0 - - else: - newversion = data[0] - self.logInfo(_("*** New pyLoad Version %s available ***") % newversion) - self.logInfo(_("*** Get it here: https://github.com/pyload/pyload/releases ***")) - exitcode = 3 - self.info['pyload'] = True - self.info['version'] = newversion - - return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required; 3 = No plugins updated, new pyLoad version available - - - def _updatePlugins(self, updates): - """ check for plugin updates """ - - if self.info['plugins']: - return False #: plugins were already updated - - exitcode = 0 - updated = [] - - url = updates[0] - schema = updates[1].split('|') - - if "BLACKLIST" in updates: - blacklist = updates[updates.index('BLACKLIST') + 1:] - updates = updates[2:updates.index('BLACKLIST')] - else: - blacklist = None - updates = updates[2:] - - upgradable = [dict(zip(schema, x.split('|'))) for x in updates] - blacklisted = [(x.split('|')[0], x.split('|')[1].rsplit('.', 1)[0]) for x in blacklist] if blacklist else [] - - if blacklist: - # Protect UpdateManager from self-removing - try: - blacklisted.remove(("hook", "UpdateManager")) - except Exception: - pass - - for t, n in blacklisted: - for idx, plugin in enumerate(upgradable): - if n == plugin['name'] and t == plugin['type']: - upgradable.pop(idx) - break - - for t, n in self.removePlugins(sorted(blacklisted)): - self.logInfo(_("Removed blacklisted plugin [%(type)s] %(name)s") % { - 'type': t, - 'name': n, - }) - - for plugin in sorted(upgradable, key=itemgetter("type", "name")): - filename = plugin['name'] - type = plugin['type'] - version = plugin['version'] - - if filename.endswith(".pyc"): - name = filename[:filename.find("_")] - else: - name = filename.replace(".py", "") - - plugins = getattr(self.core.pluginManager, "%sPlugins" % type) - - oldver = float(plugins[name]['version']) if name in plugins else None - newver = float(version) - - if not oldver: - msg = "New plugin: [%(type)s] %(name)s (v%(newver).2f)" - elif newver > oldver: - msg = "New version of plugin: [%(type)s] %(name)s (v%(oldver).2f -> v%(newver).2f)" - else: - continue - - self.logInfo(_(msg) % {'type' : type, - 'name' : name, - 'oldver': oldver, - 'newver': newver}) - try: - content = getURL(url % plugin) - m = self.VERSION.search(content) - - if m and m.group(2) == version: - with open(safe_join("userplugins", prefix, filename), "wb") as f: - f.write(content) - - updated.append((prefix, name)) - else: - raise Exception, _("Version mismatch") - - except Exception, e: - self.logError(_("Error updating plugin: %s") % filename, str(e)) - - if updated: - reloaded = self.core.pluginManager.reloadPlugins(updated) - if reloaded: - self.logInfo(_("Plugins updated and reloaded")) - exitcode = 1 - else: - self.logInfo(_("*** Plugins have been updated, but need a pyLoad restart to be reloaded ***")) - self.info['plugins'] = True - exitcode = 2 - else: - self.logInfo(_("No plugin updates available")) - - return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required - - - @Expose - def removePlugins(self, type_plugins): - """ delete plugins from disk """ - - if not type_plugins: - return - - self.logDebug("Requested deletion of plugins: %s" % type_plugins) - - removed = [] - - for type, name in type_plugins: - err = False - file = name + ".py" - - for root in ("userplugins", path.join(pypath, "pyload", "plugins")): - - filename = safe_join(root, type, file) - try: - remove(filename) - except Exception, e: - self.logDebug("Error deleting: %s" % path.basename(filename), e) - err = True - - filename += "c" - if path.isfile(filename): - try: - if type == "addon": - self.manager.deactivateAddon(name) - remove(filename) - except Exception, e: - self.logDebug("Error deleting: %s" % path.basename(filename), e) - err = True - - if not err: - id = (type, name) - removed.append(id) - - return removed #: return a list of the plugins successfully removed diff --git a/module/plugins/captcha/AdYouLike.py b/module/plugins/captcha/AdYouLike.py deleted file mode 100644 index bfb8b5ccb..000000000 --- a/module/plugins/captcha/AdYouLike.py +++ /dev/null @@ -1,107 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.Captcha import Captcha -from pyload.utils import json_loads - - -class AdYouLike(Captcha): - __name__ = "AdYouLike" - __type__ = "captcha" - __version__ = "0.02" - - __description__ = """AdYouLike captcha service plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - AYL_PATTERN = r'Adyoulike\.create\s*\((.+?)\)' - CALLBACK_PATTERN = r'(Adyoulike\.g\._jsonp_\d+)' - - - def detect_key(self, html=None): - if not html: - if hasattr(self.plugin, "html") and self.plugin.html: - html = self.plugin.html - else: - errmsg = _("AdYouLike html not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - m = re.search(self.AYL_PATTERN, html) - n = re.search(self.CALLBACK_PATTERN, html) - if m and n: - self.key = (m.group(1).strip(), n.group(1).strip()) - self.plugin.logDebug("AdYouLike ayl|callback: %s | %s" % self.key) - return self.key #: key is the tuple(ayl, callback) - else: - self.plugin.logDebug("AdYouLike ayl or callback not found") - return None - - - def challenge(self, key=None): - if not key: - if self.detect_key(): - key = self.key - else: - errmsg = _("AdYouLike key not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - ayl, callback = key - - # {"adyoulike":{"key":"P~zQ~O0zV0WTiAzC-iw0navWQpCLoYEP"}, - # "all":{"element_id":"ayl_private_cap_92300","lang":"fr","env":"prod"}} - ayl = json_loads(ayl) - - html = self.plugin.req.load("http://api-ayl.appspot.com/challenge", - get={'key' : ayl['adyoulike']['key'], - 'env' : ayl['all']['env'], - 'callback': callback}) - try: - challenge = json_loads(re.search(callback + r'\s*\((.+?)\)', html).group(1)) - except Exception: - errmsg = _("AdYouLike challenge pattern not found") - self.plugin.error(errmsg) - raise ValueError(errmsg) - - self.plugin.logDebug("AdYouLike challenge: %s" % challenge) - - return self.result(ayl, challenge) - - - def result(self, server, challenge): - # Adyoulike.g._jsonp_5579316662423138 - # ({"translations":{"fr":{"instructions_visual":"Recopiez « Soonnight » ci-dessous :"}}, - # "site_under":true,"clickable":true,"pixels":{"VIDEO_050":[],"DISPLAY":[],"VIDEO_000":[],"VIDEO_100":[], - # "VIDEO_025":[],"VIDEO_075":[]},"medium_type":"image/adyoulike", - # "iframes":{"big":"<iframe src=\"http://www.soonnight.com/campagn.html\" scrolling=\"no\" - # height=\"250\" width=\"300\" frameborder=\"0\"></iframe>"},"shares":{},"id":256, - # "token":"e6QuI4aRSnbIZJg02IsV6cp4JQ9~MjA1","formats":{"small":{"y":300,"x":0,"w":300,"h":60}, - # "big":{"y":0,"x":0,"w":300,"h":250},"hover":{"y":440,"x":0,"w":300,"h":60}}, - # "tid":"SqwuAdxT1EZoi4B5q0T63LN2AkiCJBg5"}) - - if isinstance(server, basestring): - server = json_loads(server) - - if isinstance(challenge, basestring): - challenge = json_loads(challenge) - - try: - instructions_visual = challenge['translations'][server['all']['lang']]['instructions_visual'] - result = re.search(u'«(.+?)»', instructions_visual).group(1).strip() - except Exception: - errmsg = _("AdYouLike result not found") - self.plugin.error(errmsg) - raise ValueError(errmsg) - - result = {'_ayl_captcha_engine' : "adyoulike", - '_ayl_env' : server['all']['env'], - '_ayl_tid' : challenge['tid'], - '_ayl_token_challenge': challenge['token'], - '_ayl_response' : response} - - self.plugin.logDebug("AdYouLike result: %s" % result) - - return result diff --git a/module/plugins/captcha/AdsCaptcha.py b/module/plugins/captcha/AdsCaptcha.py deleted file mode 100644 index 5c01a422e..000000000 --- a/module/plugins/captcha/AdsCaptcha.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from random import random - -from pyload.plugin.Captcha import Captcha - - -class AdsCaptcha(Captcha): - __name__ = "AdsCaptcha" - __type__ = "captcha" - __version__ = "0.06" - - __description__ = """AdsCaptcha captcha service plugin""" - __license__ = "GPLv3" - __authors__ = [("pyLoad Team", "admin@pyload.org")] - - - CAPTCHAID_PATTERN = r'api\.adscaptcha\.com/Get\.aspx\?[^"\']*CaptchaId=(\d+)' - PUBLICKEY_PATTERN = r'api\.adscaptcha\.com/Get\.aspx\?[^"\']*PublicKey=([\w-]+)' - - - def detect_key(self, html=None): - if not html: - if hasattr(self.plugin, "html") and self.plugin.html: - html = self.plugin.html - else: - errmsg = _("AdsCaptcha html not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - m = re.search(self.PUBLICKEY_PATTERN, html) - n = re.search(self.CAPTCHAID_PATTERN, html) - if m and n: - self.key = (m.group(1).strip(), n.group(1).strip()) #: key is the tuple(PublicKey, CaptchaId) - self.plugin.logDebug("AdsCaptcha key|id: %s | %s" % self.key) - return self.key - else: - self.plugin.logDebug("AdsCaptcha key or id not found") - return None - - - def challenge(self, key=None): - if not key: - if self.detect_key(): - key = self.key - else: - errmsg = _("AdsCaptcha key not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - PublicKey, CaptchaId = key - - html = self.plugin.req.load("http://api.adscaptcha.com/Get.aspx", get={'CaptchaId': CaptchaId, 'PublicKey': PublicKey}) - try: - challenge = re.search("challenge: '(.+?)',", html).group(1) - server = re.search("server: '(.+?)',", html).group(1) - except Exception: - errmsg = _("AdsCaptcha challenge pattern not found") - self.plugin.error(errmsg) - raise ValueError(errmsg) - - self.plugin.logDebug("AdsCaptcha challenge: %s" % challenge) - - return challenge, self.result(server, challenge) - - - def result(self, server, challenge): - result = self.plugin.decryptCaptcha("%sChallenge.aspx" % server, - get={'cid': challenge, 'dummy': random()}, - cookies=True, - imgtype="jpg") - - self.plugin.logDebug("AdsCaptcha result: %s" % result) - - return result diff --git a/module/plugins/captcha/ReCaptcha.py b/module/plugins/captcha/ReCaptcha.py deleted file mode 100644 index 4b900c57b..000000000 --- a/module/plugins/captcha/ReCaptcha.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.Captcha import Captcha - - -class ReCaptcha(Captcha): - __name__ = "ReCaptcha" - __type__ = "captcha" - __version__ = "0.08" - - __description__ = """ReCaptcha captcha service plugin""" - __license__ = "GPLv3" - __authors__ = [("pyLoad Team", "admin@pyload.org")] - - - KEY_PATTERN = r'recaptcha(?:/api|\.net)/(?:challenge|noscript)\?k=([\w-]+)' - KEY_AJAX_PATTERN = r'Recaptcha\.create\s*\(\s*["\']([\w-]+)' - - - def detect_key(self, html=None): - if not html: - if hasattr(self.plugin, "html") and self.plugin.html: - html = self.plugin.html - else: - errmsg = _("ReCaptcha html not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - m = re.search(self.KEY_PATTERN, html) or re.search(self.KEY_AJAX_PATTERN, html) - if m: - self.key = m.group(1).strip() - self.plugin.logDebug("ReCaptcha key: %s" % self.key) - return self.key - else: - self.plugin.logDebug("ReCaptcha key not found") - return None - - - def challenge(self, key=None): - if not key: - if self.detect_key(): - key = self.key - else: - errmsg = _("ReCaptcha key not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - html = self.plugin.req.load("http://www.google.com/recaptcha/api/challenge", get={'k': key}) - try: - challenge = re.search("challenge : '(.+?)',", html).group(1) - server = re.search("server : '(.+?)',", html).group(1) - except Exception: - errmsg = _("ReCaptcha challenge pattern not found") - self.plugin.error(errmsg) - raise ValueError(errmsg) - - self.plugin.logDebug("ReCaptcha challenge: %s" % challenge) - - return challenge, self.result(server, challenge) - - - def result(self, server, challenge): - result = self.plugin.decryptCaptcha("%simage" % server, - get={'c': challenge}, - cookies=True, - forceUser=True, - imgtype="jpg") - - self.plugin.logDebug("ReCaptcha result: %s" % result) - - return result diff --git a/module/plugins/captcha/SolveMedia.py b/module/plugins/captcha/SolveMedia.py deleted file mode 100644 index 6e2a6c362..000000000 --- a/module/plugins/captcha/SolveMedia.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.Captcha import Captcha - - -class SolveMedia(Captcha): - __name__ = "SolveMedia" - __type__ = "captcha" - __version__ = "0.06" - - __description__ = """SolveMedia captcha service plugin""" - __license__ = "GPLv3" - __authors__ = [("pyLoad Team", "admin@pyload.org")] - - - KEY_PATTERN = r'api\.solvemedia\.com/papi/challenge\.(?:no)?script\?k=(.+?)["\']' - - - def challenge(self, key=None): - if not key: - if self.detect_key(): - key = self.key - else: - errmsg = _("SolveMedia key not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - html = self.plugin.req.load("http://api.solvemedia.com/papi/challenge.noscript", get={'k': key}) - try: - challenge = re.search(r'<input type=hidden name="adcopy_challenge" id="adcopy_challenge" value="([^"]+)">', - html).group(1) - server = "http://api.solvemedia.com/papi/media" - except Exception: - errmsg = _("SolveMedia challenge pattern not found") - self.plugin.error(errmsg) - raise ValueError(errmsg) - - self.plugin.logDebug("SolveMedia challenge: %s" % challenge) - - return challenge, self.result(server, challenge) - - - def result(self, server, challenge): - result = self.plugin.decryptCaptcha(server, get={'c': challenge}, imgtype="gif") - - self.plugin.logDebug("SolveMedia result: %s" % result) - - return result diff --git a/module/plugins/container/CCF.py b/module/plugins/container/CCF.py deleted file mode 100644 index 452b9bb65..000000000 --- a/module/plugins/container/CCF.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import re - -from urllib2 import build_opener - -from MultipartPostHandler import MultipartPostHandler - -from module.plugins.Container import Container -from module.utils import fs_encode, save_join - - -class CCF(Container): - __name__ = "CCF" - __type__ = "container" - __version__ = "0.23" - - __pattern__ = r'.+\.ccf$' - - __description__ = """CCF container decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("Willnix", "Willnix@pyload.org"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - def decrypt(self, pyfile): - file = fs_encode(pyfile.url.strip()) - opener = build_opener(MultipartPostHandler) - - dlc_content = opener.open('http://service.jdownloader.net/dlcrypt/getDLC.php', - {'src' : "ccf", - 'filename': "test.ccf", - 'upload' : open(file, "rb")}).read() - - download_folder = self.config['general']['download_folder'] - dlc_file = save_join(download_folder, "tmp_%s.dlc" % pyfile.name) - - try: - dlc = re.search(r'<dlc>(.+)</dlc>', dlc_content, re.S).group(1).decode('base64') - - except AttributeError: - self.fail(_("Container is corrupted")) - - with open(dlc_file, "w") as tempdlc: - tempdlc.write(dlc) - - self.urls = [dlc_file] diff --git a/module/plugins/container/DLC.py b/module/plugins/container/DLC.py deleted file mode 100644 index b01e3098c..000000000 --- a/module/plugins/container/DLC.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import re -import xml.dom.minidom - -from Crypto.Cipher import AES - -from module.plugins.Container import Container -from module.utils import decode, fs_encode - - -class DLC(Container): - __name__ = "DLC" - __type__ = "container" - __version__ = "0.24" - - __pattern__ = r'.+\.dlc$' - - __description__ = """DLC container decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("spoob", "spoob@pyload.org"), - ("mkaay", "mkaay@mkaay.de"), - ("Schnusch", "Schnusch@users.noreply.github.com"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - KEY = "cb99b5cbc24db398" - IV = "9bc24cb995cb8db3" - API_URL = "http://service.jdownloader.org/dlcrypt/service.php?srcType=dlc&destType=pylo&data=%s" - - - def decrypt(self, pyfile): - file = fs_encode(pyfile.url.strip()) - with open(file) as dlc: - data = dlc.read().strip() - - data += '=' * (-len(data) % 4) - - dlc_key = data[-88:] - dlc_data = data[:-88].decode('base64') - dlc_content = self.load(self.API_URL % dlc_key) - - try: - rc = re.search(r'<rc>(.+)</rc>', dlc_content, re.S).group(1).decode('base64') - - except AttributeError: - self.fail(_("Container is corrupted")) - - cipher = AES.new(self.KEY, AES.MODE_CBC, self.IV).decrypt(rc) - - self.data = AES.new(cipher, AES.MODE_CBC, cipher).decrypt(dlc_data).decode('base64') - self.packages = [(entry[0] if entry[0] else pyfile.name, entry[1], entry[0] if entry[0] else pyfile.name) \ - for entry in self.getPackages()] - - - def getPackages(self): - root = xml.dom.minidom.parseString(self.data).documentElement - content = root.getElementsByTagName("content")[0] - return self.parsePackages(content) - - - def parsePackages(self, startNode): - return [(decode(node.getAttribute("name")).decode('base64'), self.parseLinks(node)) \ - for node in startNode.getElementsByTagName("package")] - - - def parseLinks(self, startNode): - return [node.getElementsByTagName("url")[0].firstChild.data.decode('base64') \ - for node in startNode.getElementsByTagName("file")] diff --git a/module/plugins/container/LinkList.py b/module/plugins/container/LinkList.py deleted file mode 100644 index ccb9b2fa3..000000000 --- a/module/plugins/container/LinkList.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: utf-8 -*- - -import codecs - -from module.plugins.Container import Container -from module.utils import fs_encode - - -class LinkList(Container): - __name__ = "LinkList" - __type__ = "container" - __version__ = "0.14" - - __pattern__ = r'.+\.txt$' - __config__ = [("flush" , "bool" , "Flush list after adding", False ), - ("encoding", "string", "File encoding" , "utf-8")] - - __description__ = """Read link lists in txt format""" - __license__ = "GPLv3" - __authors__ = [("spoob", "spoob@pyload.org"), - ("jeix", "jeix@hasnomail.com")] - - - def decrypt(self, pyfile): - try: - encoding = codecs.lookup(self.getConfig("encoding")).name - - except Exception: - encoding = "utf-8" - - file = fs_encode(pyfile.url.strip()) - txt = codecs.open(file, 'r', encoding) - curPack = "Parsed links from %s" % pyfile.name - packages = {curPack:[],} - - for link in txt.readlines(): - link = link.strip() - - if not link: - continue - - if link.startswith(";"): - continue - - if link.startswith("[") and link.endswith("]"): - # new package - curPack = link[1:-1] - packages[curPack] = [] - continue - - packages[curPack].append(link) - - txt.close() - - # empty packages fix - for key, value in packages.iteritems(): - if not value: - packages.pop(key, None) - - if self.getConfig("flush"): - try: - txt = open(file, 'wb') - txt.close() - - except IOError: - self.logWarning(_("Failed to flush list")) - - for name, links in packages.iteritems(): - self.packages.append((name, links, name)) diff --git a/module/plugins/container/RSDF.py b/module/plugins/container/RSDF.py deleted file mode 100644 index 8f9bfc0d5..000000000 --- a/module/plugins/container/RSDF.py +++ /dev/null @@ -1,52 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import binascii -import re - -from Crypto.Cipher import AES - -from module.plugins.Container import Container -from module.utils import fs_encode - - -class RSDF(Container): - __name__ = "RSDF" - __type__ = "container" - __version__ = "0.27" - - __pattern__ = r'.+\.rsdf$' - - __description__ = """RSDF container decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("spoob", "spoob@pyload.org"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - KEY = "8C35192D964DC3182C6F84F3252239EB4A320D2500000000" - IV = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - - - def decrypt(self, pyfile): - KEY = binascii.unhexlify(self.KEY) - IV = AES.new(Key, AES.MODE_ECB).encrypt(binascii.unhexlify(self.IV)) - - cipher = AES.new(KEY, AES.MODE_CFB, IV) - - try: - file = fs_encode(pyfile.url.strip()) - with open(file, 'r') as rsdf: - data = rsdf.read() - - except IOError, e: - self.fail(e) - - if re.search(r"<title>404 - Not Found</title>", data): - return - - for link in binascii.unhexlify(''.join(data.split())).splitlines(): - if link: - link = cipher.decrypt(link.decode('base64')).replace('CCF: ', '') - self.urls.append(link) diff --git a/module/plugins/crypter/BitshareCom.py b/module/plugins/crypter/BitshareCom.py deleted file mode 100644 index 2960243fc..000000000 --- a/module/plugins/crypter/BitshareCom.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleCrypter import SimpleCrypter - - -class BitshareCom(SimpleCrypter): - __name__ = "BitshareCom" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?bitshare\.com/\?d=\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Bitshare.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - LINK_PATTERN = r'<a href="(http://bitshare\.com/files/.+)">.+</a></td>' - NAME_PATTERN = r'View public folder "(?P<N>.+)"</h1>' - - -getInfo = create_getInfo(BitshareComFolder) diff --git a/module/plugins/crypter/C1NeonCom.py b/module/plugins/crypter/C1NeonCom.py deleted file mode 100644 index eaccb471f..000000000 --- a/module/plugins/crypter/C1NeonCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class C1NeonCom(DeadCrypter): - __name__ = "C1NeonCom" - __type__ = "crypter" - __version__ = "0.05" - - __pattern__ = r'http://(?:www\.)?c1neon\.com/.+' - __config__ = [] - - __description__ = """C1neon.com decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("godofdream", "soilfiction@gmail.com")] - - -getInfo = create_getInfo(C1NeonCom) diff --git a/module/plugins/crypter/CloudzillaToFolder.py b/module/plugins/crypter/CloudzillaToFolder.py deleted file mode 100644 index 76019d928..000000000 --- a/module/plugins/crypter/CloudzillaToFolder.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urlparse import urljoin - -from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo - - -class CloudzillaToFolder(SimpleHoster): - __name__ = "CloudzillaToFolder" - __type__ = "crypter" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?cloudzilla\.to/share/folder/(?P<ID>[\w^_]+)' - - __description__ = """Cloudzilla.to folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - INFO_PATTERN = r'<span class="name" title="(?P<N>.+?)"' - OFFLINE_PATTERN = r'>File not found...<' - - LINK_PATTERN = r'<a href="(.+?)" class="item_href">' - - PASSWORD_PATTERN = r'<div id="pwd_protected">' - - - def checkErrors(self): - m = re.search(self.PASSWORD_PATTERN, self.html) - if m: - self.html = self.load(self.pyfile.url, get={'key': self.getPassword()}) - - if re.search(self.PASSWORD_PATTERN, self.html): - self.retry(reason="Wrong password") - - -getInfo = create_getInfo(CloudzillaToFolder) diff --git a/module/plugins/crypter/CrockoCom.py b/module/plugins/crypter/CrockoCom.py deleted file mode 100644 index 9fad661d2..000000000 --- a/module/plugins/crypter/CrockoCom.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleCrypter import SimpleCrypter - - -class CrockoCom(SimpleCrypter): - __name__ = "CrockoCom" - __type__ = "crypter" - __version__ = "0.01" - - __pattern__ = r'http://(?:www\.)?crocko\.com/f/.+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Crocko.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - LINK_PATTERN = r'<td class="last"><a href="([^"]+)">download</a>' - - -getInfo = create_getInfo(CrockoComFolder) diff --git a/module/plugins/crypter/CryptItCom.py b/module/plugins/crypter/CryptItCom.py deleted file mode 100644 index cb3347f55..000000000 --- a/module/plugins/crypter/CryptItCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class CryptItCom(DeadCrypter): - __name__ = "CryptItCom" - __type__ = "crypter" - __version__ = "0.11" - - __pattern__ = r'http://(?:www\.)?crypt-it\.com/(s|e|d|c)/\w+' - __config__ = [] - - __description__ = """Crypt-it.com decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("jeix", "jeix@hasnomail.de")] - - -getInfo = create_getInfo(CryptItCom) diff --git a/module/plugins/crypter/DataHu.py b/module/plugins/crypter/DataHu.py deleted file mode 100644 index e8b3acbb7..000000000 --- a/module/plugins/crypter/DataHu.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.SimpleCrypter import SimpleCrypter - - -class DataHu(SimpleCrypter): - __name__ = "DataHu" - __type__ = "crypter" - __version__ = "0.06" - - __pattern__ = r'http://(?:www\.)?data\.hu/dir/\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Data.hu folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("crash", ""), - ("stickell", "l.stickell@yahoo.it")] - - - LINK_PATTERN = r'<a href=\'(http://data\.hu/get/.+)\' target=\'_blank\'>\1</a>' - NAME_PATTERN = ur'<title>(?P<N>.+) Let\xf6lt\xe9se</title>' - - - def prepare(self): - super(DataHu, self).prepare() - - if u'K\xe9rlek add meg a jelsz\xf3t' in self.html: # Password protected - password = self.getPassword() - if not password: - self.fail(_("Password required")) - - self.logDebug("The folder is password protected', 'Using password: " + password) - - self.html = self.load(self.pyfile.url, post={'mappa_pass': password}, decode=True) - - if u'Hib\xe1s jelsz\xf3' in self.html: # Wrong password - self.fail(_("Wrong password")) - - -getInfo = create_getInfo(DataHuFolder) diff --git a/module/plugins/crypter/DdlstorageCom.py b/module/plugins/crypter/DdlstorageCom.py deleted file mode 100644 index 1d87e975b..000000000 --- a/module/plugins/crypter/DdlstorageCom.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class DdlstorageCom(DeadCrypter): - __name__ = "DdlstorageCom" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'https?://(?:www\.)?ddlstorage\.com/folder/\w+' - __config__ = [] - - __description__ = """DDLStorage.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("godofdream", "soilfiction@gmail.com"), - ("stickell", "l.stickell@yahoo.it")] - - -getInfo = create_getInfo(DdlstorageCom) diff --git a/module/plugins/crypter/DepositfilesCom.py b/module/plugins/crypter/DepositfilesCom.py deleted file mode 100644 index ba578a4ed..000000000 --- a/module/plugins/crypter/DepositfilesCom.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleCrypter import SimpleCrypter - - -class DepositfilesCom(SimpleCrypter): - __name__ = "DepositfilesCom" - __type__ = "crypter" - __version__ = "0.01" - - __pattern__ = r'http://(?:www\.)?depositfiles\.com/folders/\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Depositfiles.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - LINK_PATTERN = r'<div class="progressName"[^>]*>\s*<a href="([^"]+)" title="[^"]*" target="_blank">' - - -getInfo = create_getInfo(DepositfilesComFolder) diff --git a/module/plugins/crypter/Dereferer.py b/module/plugins/crypter/Dereferer.py deleted file mode 100644 index d52bb1094..000000000 --- a/module/plugins/crypter/Dereferer.py +++ /dev/null @@ -1,17 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.Crypter import Crypter - - -class Dereferer(SimpleDereferer): - __name__ = "Dereferer" - __type__ = "crypter" - __version__ = "0.11" - - __pattern__ = r'https?://([^/]+)/.*?(?P<LINK>(ht|f)tps?(://|%3A%2F%2F).+)' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Crypter for dereferers""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/module/plugins/crypter/DevhostStFolder.py b/module/plugins/crypter/DevhostStFolder.py deleted file mode 100644 index 2fbc90ba8..000000000 --- a/module/plugins/crypter/DevhostStFolder.py +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# http://d-h.st/users/shine/?fld_id=37263#files - -import re - -from urlparse import urljoin - -from module.plugins.internal.SimpleCrypter import SimpleCrypter - - -class DevhostStFolder(SimpleCrypter): - __name__ = "DevhostStFolder" - __type__ = "crypter" - __version__ = "0.04" - - __pattern__ = r'http://(?:www\.)?d-h\.st/users/(?P<USER>\w+)(/\?fld_id=(?P<ID>\d+))?' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """d-h.st folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - LINK_PATTERN = r'(?:/> |;">)<a href="(.+?)"(?!>Back to \w+<)' - OFFLINE_PATTERN = r'"/cHP">test\.png<' - - - def getFileInfo(self): - if re.search(self.OFFLINE_PATTERN, self.html): - self.offline() - - try: - id = re.match(self.__pattern__, self.pyfile.url).group('ID') - if id == "0": - raise - - p = r'href="(.+?)">Back to \w+<' - m = re.search(p, self.html) - html = self.load(urljoin("http://d-h.st", m.group(1)), - cookies=False) - - p = '\?fld_id=%s.*?">(.+?)<' % id - m = re.search(p, html) - name = folder = m.group(1) - - except Exception, e: - self.logDebug(e) - name = folder = re.match(self.__pattern__, self.pyfile.url).group('USER') - - return {'name': name, 'folder': folder} - - -getInfo = create_getInfo(DevhostStFolder) diff --git a/module/plugins/crypter/DlProtectCom.py b/module/plugins/crypter/DlProtectCom.py deleted file mode 100644 index 1cfe7639a..000000000 --- a/module/plugins/crypter/DlProtectCom.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from base64 import urlsafe_b64encode -from time import time - -from module.plugins.internal.SimpleCrypter import SimpleCrypter - - -class DlProtectCom(SimpleCrypter): - __name__ = "DlProtectCom" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'https?://(?:www\.)?dl-protect\.com/((en|fr)/)?\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Dl-protect.com decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - COOKIES = [("dl-protect.com", "l", "en")] - - OFFLINE_PATTERN = r'Unfortunately, the link you are looking for is not found' - - - def getLinks(self): - # Direct link with redirect - if not re.match(r"https?://(?:www\.)?dl-protect\.com/.+", self.req.http.lastEffectiveURL): - return [self.req.http.lastEffectiveURL] - - post_req = {'key' : re.search(r'name="key" value="(.+?)"', self.html).group(1), - 'submitform': ""} - - if "Please click on continue to see the content" in self.html: - post_req['submitform'] = "Continue" - self.wait(2) - - else: - mstime = int(round(time() * 1000)) - b64time = "_" + urlsafe_b64encode(str(mstime)).replace("=", "%3D") - - post_req.update({'i' : b64time, - 'submitform': "Decrypt+link"}) - - if "Password :" in self.html: - post_req['pwd'] = self.getPassword() - - if "Security Code" in self.html: - captcha_id = re.search(r'/captcha\.php\?uid=(.+?)"', self.html).group(1) - captcha_url = "http://www.dl-protect.com/captcha.php?uid=" + captcha_id - captcha_code = self.decryptCaptcha(captcha_url, imgtype="gif") - - post_req['secure'] = captcha_code - - self.html = self.load(self.pyfile.url, post=post_req) - - for errmsg in ("The password is incorrect", "The security code is incorrect"): - if errmsg in self.html: - self.fail(_(errmsg[1:])) - - return re.findall(r'<a href="([^/].+?)" target="_blank">', self.html) - - -getInfo = create_getInfo(DlProtectCom) diff --git a/module/plugins/crypter/DontKnowMe.py b/module/plugins/crypter/DontKnowMe.py deleted file mode 100644 index 7a4b85b2d..000000000 --- a/module/plugins/crypter/DontKnowMe.py +++ /dev/null @@ -1,17 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.Crypter import Crypter - - -class DontKnowMe(SimpleDereferer): - __name__ = "DontKnowMe" - __type__ = "crypter" - __version__ = "0.11" - - __pattern__ = r'http://(?:www\.)?dontknow\.me/at/\?(?P<LINK>.+)' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """DontKnow.me decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("selaux", "")] diff --git a/module/plugins/crypter/DuploadOrg.py b/module/plugins/crypter/DuploadOrg.py deleted file mode 100644 index 70745b550..000000000 --- a/module/plugins/crypter/DuploadOrg.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class DuploadOrg(DeadCrypter): - __name__ = "DuploadOrg" - __type__ = "crypter" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?dupload\.org/folder/\d+' - __config__ = [] - - __description__ = """Dupload.org folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - -getInfo = create_getInfo(DuploadOrg) diff --git a/module/plugins/crypter/EasybytezCom.py b/module/plugins/crypter/EasybytezCom.py deleted file mode 100644 index d9685e2f1..000000000 --- a/module/plugins/crypter/EasybytezCom.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.XFSCrypter import XFSCrypter - - -class EasybytezCom(XFSCrypter): - __name__ = "EasybytezCom" - __type__ = "crypter" - __version__ = "0.10" - - __pattern__ = r'http://(?:www\.)?easybytez\.com/users/\d+/\d+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Easybytez.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - LOGIN_ACCOUNT = True - - -getInfo = create_getInfo(EasybytezComFolder) diff --git a/module/plugins/crypter/FilebeerInfo.py b/module/plugins/crypter/FilebeerInfo.py deleted file mode 100644 index 4e8ab1259..000000000 --- a/module/plugins/crypter/FilebeerInfo.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class FilebeerInfo(DeadCrypter): - __name__ = "FilebeerInfo" - __type__ = "crypter" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?filebeer\.info/\d*~f\w+' - __config__ = [] - - __description__ = """Filebeer.info folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(FilebeerInfo) diff --git a/module/plugins/crypter/FilecloudIo.py b/module/plugins/crypter/FilecloudIo.py deleted file mode 100644 index d0ca619de..000000000 --- a/module/plugins/crypter/FilecloudIo.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleCrypter import SimpleCrypter - - -class FilecloudIo(SimpleCrypter): - __name__ = "FilecloudIo" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'https?://(?:www\.)?(filecloud\.io|ifile\.it)/_\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Filecloud.io folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - LINK_PATTERN = r'href="(http://filecloud\.io/\w+)" title' - NAME_PATTERN = r'>(?P<N>.+?) - filecloud\.io<' - - -getInfo = create_getInfo(FilecloudIoFolder) diff --git a/module/plugins/crypter/FilecryptCc.py b/module/plugins/crypter/FilecryptCc.py deleted file mode 100644 index 938ceafa9..000000000 --- a/module/plugins/crypter/FilecryptCc.py +++ /dev/null @@ -1,182 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# http://filecrypt.cc/Container/64E039F859.html - -import binascii -import re - -from Crypto.Cipher import AES -from urlparse import urljoin - -from pyload.plugin.Crypter import Crypter -from module.plugins.internal.CaptchaService import ReCaptcha - - -class FilecryptCc(Crypter): - __name__ = "FilecryptCc" - __type__ = "crypter" - __version__ = "0.11" - - __pattern__ = r'https?://(?:www\.)?filecrypt\.cc/Container/\w+' - - __description__ = """Filecrypt.cc decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] - - - # URL_REPLACEMENTS = [(r'.html$', ""), (r'$', ".html")] #@TODO: Extend SimpleCrypter - - DLC_LINK_PATTERN = r'<button class="dlcdownload" type="button" title="Download \*.dlc" onclick="DownloadDLC\(\'(.+)\'\);"><i></i><span>dlc<' - WEBLINK_PATTERN = r"openLink.?'([\w_-]*)'," - - CAPTCHA_PATTERN = r'<img id="nc" src="(.+?)"' - CIRCLE_CAPTCHA_PATTERN = r'<input type="image" src="(.+?)"' - - MIRROR_PAGE_PATTERN = r'"[\w]*" href="(http://filecrypt.cc/Container/\w+\.html\?mirror=\d+)">' - - - def setup(self): - self.links = [] - - - def decrypt(self, pyfile): - self.html = self.load(pyfile.url, cookies=True) - - if "content notfound" in self.html: #@NOTE: "content notfound" is NOT a typo - self.offline() - - self.handlePasswordProtection() - self.handleCaptcha() - self.handleMirrorPages() - - for handle in (self.handleCNL, self.handleWeblinks, self.handleDlcContainer): - handle() - if self.links: - self.packages = [(pyfile.package().name, self.links, pyfile.package().name)] - return - - - def handleMirrorPages(self): - if "mirror=" not in self.siteWithLinks: - return - - mirror = re.findall(self.MIRROR_PAGE_PATTERN, self.siteWithLinks) - - self.logInfo(_("Found %d mirrors") % len(mirror)) - - for i in mirror[1:]: - self.siteWithLinks = self.siteWithLinks + self.load(i, cookies=True).decode("utf-8", "replace") - - - def handlePasswordProtection(self): - if '<input type="text" name="password"' not in self.html: - return - - self.logInfo(_("Folder is password protected")) - - password = self.getPassword() - - if not password: - self.fail(_("Please enter the password in package section and try again")) - - self.html = self.load(self.pyfile.url, post={"password": password}, cookies=True) - - - def handleCaptcha(self): - m = re.search(self.CAPTCHA_PATTERN, self.html) - m2 = re.search(self.CIRCLE_CAPTCHA_PATTERN, self.html) - - if m: #: normal captcha - self.logDebug("Captcha-URL: %s" % m.group(1)) - - captcha_code = self.decryptCaptcha(urljoin("http://filecrypt.cc", m.group(1)), - forceUser=True, - imgtype="gif") - - self.siteWithLinks = self.load(self.pyfile.url, - post={'recaptcha_response_field': captcha_code}, - cookies=True, - decode=True) - elif m2: #: circle captcha - self.logDebug("Captcha-URL: %s" % m2.group(1)) - - captcha_code = self.decryptCaptcha(urljoin("http://filecrypt.cc", m2.group(1)), - forceUser=True, - imgtype="gif", - result_type='positional') - - self.siteWithLinks = self.load(self.pyfile.url, - post={'button.x': captcha_code[0], 'button.y': captcha_code[1]}, - cookies=True, - decode=True) - - else: - recaptcha = ReCaptcha(self) - captcha_key = recaptcha.detect_key() - - if captcha_key: - response, challenge = recaptcha.challenge(captcha_key) - self.siteWithLinks = self.load(self.pyfile.url, - post={'g-recaptcha-response': response}, - decode=True) - else: - self.logInfo(_("No captcha found")) - self.siteWithLinks = self.html - - if "recaptcha_image" in self.siteWithLinks or "data-sitekey" in self.siteWithLinks: - self.invalidCaptcha() - self.retry() - - - def handleDlcContainer(self): - dlc = re.findall(self.DLC_LINK_PATTERN, self.siteWithLinks) - - if not dlc: - return - - for i in dlc: - self.links.append("http://filecrypt.cc/DLC/%s.dlc" % i) - - - def handleWeblinks(self): - try: - weblinks = re.findall(self.WEBLINK_PATTERN, self.siteWithLinks) - - for link in weblinks: - res = self.load("http://filecrypt.cc/Link/%s.html" % link, cookies=True) - link2 = re.search('<iframe noresize src="(.*)"></iframe>', res) - res2 = self.load(link2.group(1), just_header=True, cookies=True) - self.links.append(res2['location']) - - except Exception, e: - self.logDebug("Error decrypting weblinks: %s" % e) - - - def handleCNL(self): - try: - vjk = re.findall('<input type="hidden" name="jk" value="function f\(\){ return \'(.*)\';}">', self.siteWithLinks) - vcrypted = re.findall('<input type="hidden" name="crypted" value="(.*)">', self.siteWithLinks) - - for i in xrange(len(vcrypted)): - self.links.extend(self._getLinks(vcrypted[i], vjk[i])) - - except Exception, e: - self.logDebug("Error decrypting CNL: %s" % e) - - - def _getLinks(self, crypted, jk): - # Get key - key = binascii.unhexlify(str(jk)) - - # Decrypt - Key = key - IV = key - obj = AES.new(Key, AES.MODE_CBC, IV) - text = obj.decrypt(crypted.decode('base64')) - - # Extract links - text = text.replace("\x00", "").replace("\r", "") - links = filter(bool, text.split('\n')) - - return links diff --git a/module/plugins/crypter/FilefactoryCom.py b/module/plugins/crypter/FilefactoryCom.py deleted file mode 100644 index c6bdb81eb..000000000 --- a/module/plugins/crypter/FilefactoryCom.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleCrypter import SimpleCrypter - - -class FilefactoryCom(SimpleCrypter): - __name__ = "FilefactoryCom" - __type__ = "crypter" - __version__ = "0.32" - - __pattern__ = r'https?://(?:www\.)?filefactory\.com/(?:f|folder)/\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Filefactory.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - COOKIES = [("filefactory.com", "locale", "en_US.utf8")] - - LINK_PATTERN = r'<td>\s*<a href="(.+?)"' - NAME_PATTERN = r'<h1>Files in <span>(?P<N>.+?)<' - PAGES_PATTERN = r'data-paginator-totalPages="(\d+)' - - - def loadPage(self, page_n): - return self.load(self.pyfile.url, get={'page': page_n, 'show': 100}) - - -getInfo = create_getInfo(FilefactoryComFolder) diff --git a/module/plugins/crypter/FilerNet.py b/module/plugins/crypter/FilerNet.py deleted file mode 100644 index 054c8d3a7..000000000 --- a/module/plugins/crypter/FilerNet.py +++ /dev/null @@ -1,27 +0,0 @@ -import re - -from module.plugins.internal.SimpleCrypter import SimpleCrypter - - -class FilerNet(SimpleCrypter): - __name__ = "FilerNet" - __type__ = "crypter" - __version__ = "0.42" - - __pattern__ = r'https?://filer\.net/folder/\w{16}' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Filer.net decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("nath_schwarz", "nathan.notwhite@gmail.com"), - ("stickell", "l.stickell@yahoo.it")] - - - LINK_PATTERN = r'href="(/get/\w{16})">(?!<)' - - NAME_PATTERN = r'<h3>(?P<N>.+?) - <small' - OFFLINE_PATTERN = r'Nicht gefunden' - - -getInfo = create_getInfo(FilerNetFolder) diff --git a/module/plugins/crypter/FilesonicCom.py b/module/plugins/crypter/FilesonicCom.py deleted file mode 100644 index b1722c1bb..000000000 --- a/module/plugins/crypter/FilesonicCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class FilesonicCom(DeadCrypter): - __name__ = "FilesonicCom" - __type__ = "crypter" - __version__ = "0.12" - - __pattern__ = r'http://(?:www\.)?filesonic\.com/folder/\w+' - - __description__ = """Filesonic.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(FilesonicCom) diff --git a/module/plugins/crypter/FilestubeCom.py b/module/plugins/crypter/FilestubeCom.py deleted file mode 100644 index befe6f9a7..000000000 --- a/module/plugins/crypter/FilestubeCom.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleCrypter import SimpleCrypter - - -class FilestubeCom(SimpleCrypter): - __name__ = "FilestubeCom" - __type__ = "crypter" - __version__ = "0.05" - - __pattern__ = r'http://(?:www\.)?filestube\.(?:com|to)/\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Filestube.com decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - LINK_PATTERN = r'<a class=\"file-link-main(?: noref)?\" [^>]* href=\"(http://[^\"]+)' - NAME_PATTERN = r'<h1\s*> (?P<N>.+) download\s*</h1>' - - -getInfo = create_getInfo(FilestubeCom) diff --git a/module/plugins/crypter/FiletramCom.py b/module/plugins/crypter/FiletramCom.py deleted file mode 100644 index 6c3c071ec..000000000 --- a/module/plugins/crypter/FiletramCom.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleCrypter import SimpleCrypter - - -class FiletramCom(SimpleCrypter): - __name__ = "FiletramCom" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?filetram\.com/[^/]+/.+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Filetram.com decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("igel", "igelkun@myopera.com"), - ("stickell", "l.stickell@yahoo.it")] - - - LINK_PATTERN = r'\s+(http://.+)' - NAME_PATTERN = r'<title>(?P<N>.+?) - Free Download' - - -getInfo = create_getInfo(FiletramCom) diff --git a/module/plugins/crypter/FiredriveCom.py b/module/plugins/crypter/FiredriveCom.py deleted file mode 100644 index bf315ad16..000000000 --- a/module/plugins/crypter/FiredriveCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class FiredriveCom(DeadCrypter): - __name__ = "FiredriveCom" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'https?://(?:www\.)?(firedrive|putlocker)\.com/share/.+' - __config__ = [] - - __description__ = """Firedrive.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - -getInfo = create_getInfo(FiredriveCom) diff --git a/module/plugins/crypter/FreakhareCom.py b/module/plugins/crypter/FreakhareCom.py deleted file mode 100644 index c5fd2ee29..000000000 --- a/module/plugins/crypter/FreakhareCom.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleCrypter import SimpleCrypter - - -class FreakhareCom(SimpleCrypter): - __name__ = "FreakhareCom" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?freakshare\.com/folder/.+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Freakhare.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - LINK_PATTERN = r'<a href="(http://freakshare\.com/files/[^"]+)" target="_blank">' - NAME_PATTERN = r'Folder:</b> (?P<N>.+)' - PAGES_PATTERN = r'Pages: +(\d+)' - - - def loadPage(self, page_n): - if not hasattr(self, 'f_id') and not hasattr(self, 'f_md5'): - m = re.search(r'http://freakshare.com/\?x=folder&f_id=(\d+)&f_md5=(\w+)', self.html) - if m: - self.f_id = m.group(1) - self.f_md5 = m.group(2) - return self.load('http://freakshare.com/', get={'x': 'folder', - 'f_id': self.f_id, - 'f_md5': self.f_md5, - 'entrys': '20', - 'page': page_n - 1, - 'order': ''}, decode=True) - - -getInfo = create_getInfo(FreakhareComFolder) diff --git a/module/plugins/crypter/FreetexthostCom.py b/module/plugins/crypter/FreetexthostCom.py deleted file mode 100644 index 4634455b6..000000000 --- a/module/plugins/crypter/FreetexthostCom.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleCrypter import SimpleCrypter - - -class FreetexthostCom(SimpleCrypter): - __name__ = "FreetexthostCom" - __type__ = "crypter" - __version__ = "0.01" - - __pattern__ = r'http://(?:www\.)?freetexthost\.com/\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Freetexthost.com decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - def getLinks(self): - m = re.search(r'<div id="contentsinner">\s*(.+)<div class="viewcount">', self.html, re.S) - if m is None: - self.error(_("Unable to extract links")) - links = m.group(1) - return links.strip().split("<br />\r\n") - - -getInfo = create_getInfo(FreetexthostCom) diff --git a/module/plugins/crypter/FshareVn.py b/module/plugins/crypter/FshareVn.py deleted file mode 100644 index e85085cf1..000000000 --- a/module/plugins/crypter/FshareVn.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.SimpleCrypter import SimpleCrypter - - -class FshareVn(SimpleCrypter): - __name__ = "FshareVn" - __type__ = "crypter" - __version__ = "0.01" - - __pattern__ = r'http://(?:www\.)?fshare\.vn/folder/.+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Fshare.vn folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - LINK_PATTERN = r'<li class="w_80pc"><a href="([^"]+)" target="_blank">' - - -getInfo = create_getInfo(FshareVnFolder) diff --git a/module/plugins/crypter/Go4UpCom.py b/module/plugins/crypter/Go4UpCom.py deleted file mode 100644 index ffd945737..000000000 --- a/module/plugins/crypter/Go4UpCom.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urlparse import urljoin - -from pyload.plugin.internal.SimpleCrypter import SimpleCrypter, create_getInfo - - -class Go4UpCom(SimpleCrypter): - __name__ = "Go4UpCom" - __type__ = "crypter" - __version__ = "0.11" - - __pattern__ = r'http://go4up\.com/(dl/\w{12}|rd/\w{12}/\d+)' - - __description__ = """Go4Up.com decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("rlindner81", "rlindner81@gmail.com"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - LINK_PATTERN = r'(http://go4up\.com/rd/.+?)<' - - NAME_PATTERN = r'<title>Download (.+?)<' - - OFFLINE_PATTERN = r'>\s*(404 Page Not Found|File not Found|Mirror does not exist)' - - - def getLinks(self - links = [] - - m = re.search(r'(/download/gethosts/.+?)"') - if m: - self.html = self.load(urljoin("http://go4up.com/", m.group(1))) - pages = [self.load(url) for url in re.findall(self.LINK_PATTERN, self.html)] - else: - pages = [self.html] - - for html in pages: - try: - links.append(re.search(r'<b><a href="(.+?)"', html).group(1)) - except Exception: - continue - - return links - - -getInfo = create_getInfo(Go4UpCom) diff --git a/module/plugins/crypter/HotfileCom.py b/module/plugins/crypter/HotfileCom.py deleted file mode 100644 index 72eec8f93..000000000 --- a/module/plugins/crypter/HotfileCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class HotfileCom(DeadCrypter): - __name__ = "HotfileCom" - __type__ = "crypter" - __version__ = "0.30" - - __pattern__ = r'https?://(?:www\.)?hotfile\.com/list/\w+/\w+' - __config__ = [] - - __description__ = """Hotfile.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org")] - - -getInfo = create_getInfo(HotfileCom) diff --git a/module/plugins/crypter/ILoadTo.py b/module/plugins/crypter/ILoadTo.py deleted file mode 100644 index d3e50630c..000000000 --- a/module/plugins/crypter/ILoadTo.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class ILoadTo(DeadCrypter): - __name__ = "ILoadTo" - __type__ = "crypter" - __version__ = "0.11" - - __pattern__ = r'http://(?:www\.)?iload\.to/go/\d+-[\w.-]+/' - __config__ = [] - - __description__ = """Iload.to decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("hzpz", "")] - - -getInfo = create_getInfo(ILoadTo) diff --git a/module/plugins/crypter/ImgurComAlbum.py b/module/plugins/crypter/ImgurComAlbum.py deleted file mode 100644 index 6c074f5f1..000000000 --- a/module/plugins/crypter/ImgurComAlbum.py +++ /dev/null @@ -1,30 +0,0 @@ -import re - -from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo -from module.utils import uniqify - - -class ImgurComAlbum(SimpleCrypter): - __name__ = "ImgurComAlbum" - __type__ = "crypter" - __version__ = "0.51" - - __pattern__ = r'https?://(?:www\.|m\.)?imgur\.com/(a|gallery|)/?\w{5,7}' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Imgur.com decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("nath_schwarz", "nathan.notwhite@gmail.com")] - - - NAME_PATTERN = r'(?P<N>.+?) - Imgur' - LINK_PATTERN = r'i\.imgur\.com/\w{7}s?\.(?:jpeg|jpg|png|gif|apng)' - - - def getLinks(self): - f = lambda url: "http://" + re.sub(r'(\w{7})s\.', r'\1.', url) - return uniqify(map(f, re.findall(self.LINK_PATTERN, self.html))) - - -getInfo = create_getInfo(ImgurComAlbum) diff --git a/module/plugins/crypter/LinkSaveIn.py b/module/plugins/crypter/LinkSaveIn.py deleted file mode 100644 index e96d0438e..000000000 --- a/module/plugins/crypter/LinkSaveIn.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleDereferer import SimpleDereferer - - -class LinkSaveIn(SimpleDereferer): - __name__ = "LinkSaveIn" - __type__ = "crypter" - __version__ = "2.03" - - __pattern__ = r'https?://(?:www\.)?linksave\.in/\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """LinkSave.in decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - COOKIES = [("linksave.in", "Linksave_Language", "english")] - - OFFLINE_PATTERN = r'>(Error )?404 -' diff --git a/module/plugins/crypter/LofCc.py b/module/plugins/crypter/LofCc.py deleted file mode 100644 index e18349877..000000000 --- a/module/plugins/crypter/LofCc.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class LofCc(DeadCrypter): - __name__ = "LofCc" - __type__ = "crypter" - __version__ = "0.21" - - __pattern__ = r'http://(?:www\.)?lof\.cc/(.+)' - __config__ = [] - - __description__ = """Lof.cc decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("mkaay", "mkaay@mkaay.de")] - - -getInfo = create_getInfo(LofCc) diff --git a/module/plugins/crypter/MBLinkInfo.py b/module/plugins/crypter/MBLinkInfo.py deleted file mode 100644 index 7f1561756..000000000 --- a/module/plugins/crypter/MBLinkInfo.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class MBLinkInfo(DeadCrypter): - __name__ = "MBLinkInfo" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?mblink\.info/?\?id=(\d+)' - __config__ = [] - - __description__ = """MBLink.info decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("Gummibaer", "Gummibaer@wiki-bierkiste.de"), - ("stickell", "l.stickell@yahoo.it")] - - -getInfo = create_getInfo(MBLinkInfo) diff --git a/module/plugins/crypter/MegaCoNzFolder.py b/module/plugins/crypter/MegaCoNzFolder.py deleted file mode 100644 index 4bef61f67..000000000 --- a/module/plugins/crypter/MegaCoNzFolder.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.Crypter import Crypter - - -class MegaCoNzFolder(Crypter): - __name__ = "MegaCoNzFolder" - __type__ = "crypter" - __version__ = "0.04" - - __pattern__ = r'(?:https?://(?:www\.)?mega\.co\.nz/|mega:|chrome:.+?)#F!(?P<ID>[\w^_]+)!(?P<KEY>[\w,\\-]+)' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Mega.co.nz folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - def setup(self): - self.req.setOption("timeout", 300) - - - def decrypt(self, pyfile): - url = "https://mega.co.nz/#F!%s!%s" % re.match(self.__pattern__, pyfile.url).groups() - self.html = self.load("http://rapidgen.org/linkfinder", post={'linklisturl': url}) - self.urls = re.findall(r'(https://mega.co.nz/#N!.+?)<', self.html) - - if not self.urls: #@TODO: Remove in 0.4.10 - self.fail(_("No link grabbed")) diff --git a/module/plugins/crypter/MegaRapidCz.py b/module/plugins/crypter/MegaRapidCz.py deleted file mode 100644 index 86235444b..000000000 --- a/module/plugins/crypter/MegaRapidCz.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo - - -class MegaRapidCz(SimpleCrypter): - __name__ = "MegaRapidCz" - __type__ = "crypter" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?(share|mega)rapid\.cz/slozka/\d+/\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Share-Rapid.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - LINK_PATTERN = r'<td class="soubor"[^>]*><a href="([^"]+)">' - - -getInfo = create_getInfo(MegaRapidCzFolder) diff --git a/module/plugins/crypter/MegauploadCom.py b/module/plugins/crypter/MegauploadCom.py deleted file mode 100644 index 6981cebc8..000000000 --- a/module/plugins/crypter/MegauploadCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class MegauploadCom(DeadCrypter): - __name__ = "MegauploadCom" - __type__ = "crypter" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?megaupload\.com/(\?f|xml/folderfiles\.php\?.*&?folderid)=\w+' - - __description__ = """Megaupload.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(MegauploadCom) diff --git a/module/plugins/crypter/Movie2KTo.py b/module/plugins/crypter/Movie2KTo.py deleted file mode 100644 index 92bc128c7..000000000 --- a/module/plugins/crypter/Movie2KTo.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class Movie2KTo(DeadCrypter): - __name__ = "Movie2KTo" - __type__ = "crypter" - __version__ = "0.51" - - __pattern__ = r'http://(?:www\.)?movie2k\.to/(.+)\.html' - __config__ = [] - - __description__ = """Movie2k.to decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("4Christopher", "4Christopher@gmx.de")] - - -getInfo = create_getInfo(Movie2KTo) diff --git a/module/plugins/crypter/MultiUpOrg.py b/module/plugins/crypter/MultiUpOrg.py deleted file mode 100644 index 7955fca6c..000000000 --- a/module/plugins/crypter/MultiUpOrg.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- - -import re -from urlparse import urljoin - -from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo - - -class MultiUpOrg(SimpleCrypter): - __name__ = "MultiUpOrg" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?multiup\.org/(en|fr)/(?P<TYPE>project|download|miror)/\w+(/\w+)?' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """MultiUp.org decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - NAME_PATTERN = r'<title>.*(?:Project|Projet|ownload|élécharger) (?P<N>.+?) (\(|- )' - - - def getLinks(self): - m_type = re.match(self.__pattern__, self.pyfile.url).group('TYPE') - - if m_type == "project": - pattern = r'\n(http://www\.multiup\.org/(?:en|fr)/download/.*)' - else: - pattern = r'style="width:97%;text-align:left".*\n.*href="(.*)"' - if m_type == "download": - dl_pattern = r'href="(.*)">.*\n.*<h5>DOWNLOAD</h5>' - miror_page = urljoin("http://www.multiup.org", re.search(dl_pattern, self.html).group(1)) - self.html = self.load(miror_page) - - return re.findall(pattern, self.html) - - -getInfo = create_getInfo(MultiUpOrg) diff --git a/module/plugins/crypter/MultiuploadCom.py b/module/plugins/crypter/MultiuploadCom.py deleted file mode 100644 index 98708bd95..000000000 --- a/module/plugins/crypter/MultiuploadCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class MultiuploadCom(DeadCrypter): - __name__ = "MultiuploadCom" - __type__ = "crypter" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?multiupload\.(com|nl)/\w+' - - __description__ = """MultiUpload.com decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(MultiuploadCom) diff --git a/module/plugins/crypter/NetfolderIn.py b/module/plugins/crypter/NetfolderIn.py deleted file mode 100644 index 62dc5c914..000000000 --- a/module/plugins/crypter/NetfolderIn.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo - - -class NetfolderIn(SimpleCrypter): - __name__ = "NetfolderIn" - __type__ = "crypter" - __version__ = "0.72" - - __pattern__ = r'http://(?:www\.)?netfolder\.in/(folder\.php\?folder_id=)?(?P<ID>\w+)(?(1)|/\w+)' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """NetFolder.in decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("fragonib", "fragonib[AT]yahoo[DOT]es")] - - - NAME_PATTERN = r'<div class="Text">Inhalt des Ordners <span.*>(?P<N>.+)</span></div>' - - - def prepare(self): - super(NetfolderIn, self).prepare() - - # Check for password protection - if self.isPasswordProtected(): - self.html = self.submitPassword() - if not self.html: - self.fail(_("Incorrect password, please set right password on Add package form and retry")) - - - def isPasswordProtected(self): - if '<input type="password" name="password"' in self.html: - self.logDebug("Links are password protected") - return True - return False - - - def submitPassword(self): - # Gather data - try: - m = re.match(self.__pattern__, self.pyfile.url) - id = m.group('ID') - except AttributeError: - self.logDebug("Unable to get package id from url [%s]" % self.pyfile.url) - return - url = "http://netfolder.in/folder.php?folder_id=" + id - password = self.getPassword() - - # Submit package password - post = {'password': password, 'save': 'Absenden'} - self.logDebug("Submitting password [%s] for protected links with id [%s]" % (password, id)) - html = self.load(url, {}, post) - - # Check for invalid password - if '<div class="InPage_Error">' in html: - self.logDebug("Incorrect password, please set right password on Edit package form and retry") - return None - - return html - - - def getLinks(self): - links = re.search(r'name="list" value="(.*?)"', self.html).group(1).split(",") - self.logDebug("Package has %d links" % len(links)) - return links - - -getInfo = create_getInfo(NetfolderIn) diff --git a/module/plugins/crypter/NosvideoCom.py b/module/plugins/crypter/NosvideoCom.py deleted file mode 100644 index 1e280abd2..000000000 --- a/module/plugins/crypter/NosvideoCom.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo - - -class NosvideoCom(SimpleCrypter): - __name__ = "NosvideoCom" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?nosvideo\.com/\?v=\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Nosvideo.com decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("igel", "igelkun@myopera.com")] - - - LINK_PATTERN = r'href="(http://(?:w{3}\.)?nosupload\.com/\?d=\w+)"' - NAME_PATTERN = r'<[tT]itle>Watch (?P<N>.+?)<' - - -getInfo = create_getInfo(NosvideoCom) diff --git a/module/plugins/crypter/OronCom.py b/module/plugins/crypter/OronCom.py deleted file mode 100644 index 42483c497..000000000 --- a/module/plugins/crypter/OronCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class OronCom(DeadCrypter): - __name__ = "OronCom" - __type__ = "crypter" - __version__ = "0.11" - - __pattern__ = r'http://(?:www\.)?oron\.com/folder/\w+' - __config__ = [] - - __description__ = """Oron.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("DHMH", "webmaster@pcProfil.de")] - - -getInfo = create_getInfo(OronCom) diff --git a/module/plugins/crypter/PastebinCom.py b/module/plugins/crypter/PastebinCom.py deleted file mode 100644 index b3d5a4bea..000000000 --- a/module/plugins/crypter/PastebinCom.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo - - -class PastebinCom(SimpleCrypter): - __name__ = "PastebinCom" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?pastebin\.com/\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Pastebin.com decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - LINK_PATTERN = r'<div class="de\d+">(https?://[^ <]+)(?:[^<]*)</div>' - NAME_PATTERN = r'<div class="paste_box_line1" title="(?P<N>[^"]+)">' - - -getInfo = create_getInfo(PastebinCom) diff --git a/module/plugins/crypter/RSLayerCom.py b/module/plugins/crypter/RSLayerCom.py deleted file mode 100644 index ebd3c509c..000000000 --- a/module/plugins/crypter/RSLayerCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class RSLayerCom(DeadCrypter): - __name__ = "RSLayerCom" - __type__ = "crypter" - __version__ = "0.21" - - __pattern__ = r'http://(?:www\.)?rs-layer\.com/directory-' - __config__ = [] - - __description__ = """RS-Layer.com decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("hzpz", "")] - - -getInfo = create_getInfo(RSLayerCom) diff --git a/module/plugins/crypter/RelinkUs.py b/module/plugins/crypter/RelinkUs.py deleted file mode 100644 index b361f87d8..000000000 --- a/module/plugins/crypter/RelinkUs.py +++ /dev/null @@ -1,293 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import binascii -import re -import os - -from Crypto.Cipher import AES -from pyload.plugin.Crypter import Crypter -from module.utils import safe_join - - -class RelinkUs(Crypter): - __name__ = "RelinkUs" - __type__ = "crypter" - __version__ = "3.12" - - __pattern__ = r'http://(?:www\.)?relink\.us/(f/|((view|go)\.php\?id=))(?P<ID>.+)' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Relink.us decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("fragonib", "fragonib[AT]yahoo[DOT]es"), - ("AndroKev", "neureither.kevin@gmail.com")] - - - PREFERRED_LINK_SOURCES = ["cnl2", "dlc", "web"] - - OFFLINE_TOKEN = r'<title>Tattooside' - - PASSWORD_TOKEN = r'container_password.php' - PASSWORD_ERROR_ROKEN = r'You have entered an incorrect password' - PASSWORD_SUBMIT_URL = r'http://www.relink.us/container_password.php' - - CAPTCHA_TOKEN = r'container_captcha.php' - CAPTCHA_ERROR_ROKEN = r'You have solved the captcha wrong' - CAPTCHA_IMG_URL = r'http://www.relink.us/core/captcha/circlecaptcha.php' - CAPTCHA_SUBMIT_URL = r'http://www.relink.us/container_captcha.php' - - FILE_TITLE_REGEX = r'<th>Title</th><td>(.*)</td></tr>' - FILE_NOTITLE = r'No title' - - CNL2_FORM_REGEX = r'<form id="cnl_form-(.*?)</form>' - CNL2_FORMINPUT_REGEX = r'<input.*?name="%s".*?value="(.*?)"' - CNL2_JK_KEY = "jk" - CNL2_CRYPTED_KEY = "crypted" - - DLC_LINK_REGEX = r'<a href=".*?" class="dlc_button" target="_blank">' - DLC_DOWNLOAD_URL = r'http://www.relink.us/download.php' - - WEB_FORWARD_REGEX = r'getFile\(\'(.+)\'\)' - WEB_FORWARD_URL = r'http://www.relink.us/frame.php' - WEB_LINK_REGEX = r'<iframe name="Container" height="100%" frameborder="no" width="100%" src="(.+)"></iframe>' - - - def setup(self): - self.fileid = None - self.package = None - self.captcha = False - - - def decrypt(self, pyfile): - # Init - self.initPackage(pyfile) - - # Request package - self.requestPackage() - - # Check for online - if not self.isOnline(): - self.offline() - - # Check for protection - if self.isPasswordProtected(): - self.unlockPasswordProtection() - self.handleErrors() - - if self.isCaptchaProtected(): - self.captcha = True - self.unlockCaptchaProtection() - self.handleErrors() - - # Get package name and folder - (package_name, folder_name) = self.getPackageInfo() - - # Extract package links - package_links = [] - for sources in self.PREFERRED_LINK_SOURCES: - package_links.extend(self.handleLinkSource(sources)) - if package_links: # use only first source which provides links - break - package_links = set(package_links) - - # Pack - if package_links: - self.packages = [(package_name, package_links, folder_name)] - - - def initPackage(self, pyfile): - self.fileid = re.match(self.__pattern__, pyfile.url).group('ID') - self.package = pyfile.package() - - - def requestPackage(self): - self.html = self.load(self.pyfile.url, decode=True) - - - def isOnline(self): - if self.OFFLINE_TOKEN in self.html: - self.logDebug("File not found") - return False - return True - - - def isPasswordProtected(self): - if self.PASSWORD_TOKEN in self.html: - self.logDebug("Links are password protected") - return True - - - def isCaptchaProtected(self): - if self.CAPTCHA_TOKEN in self.html: - self.logDebug("Links are captcha protected") - return True - return False - - - def unlockPasswordProtection(self): - password = self.getPassword() - - self.logDebug("Submitting password [%s] for protected links" % password) - - if password: - passwd_url = self.PASSWORD_SUBMIT_URL + "?id=%s" % self.fileid - passwd_data = {'id': self.fileid, 'password': password, 'pw': 'submit'} - self.html = self.load(passwd_url, post=passwd_data, decode=True) - - - def unlockCaptchaProtection(self): - self.logDebug("Request user positional captcha resolving") - captcha_img_url = self.CAPTCHA_IMG_URL + "?id=%s" % self.fileid - coords = self.decryptCaptcha(captcha_img_url, forceUser=True, imgtype="png", result_type='positional') - self.logDebug("Captcha resolved, coords [%s]" % str(coords)) - captcha_post_url = self.CAPTCHA_SUBMIT_URL + "?id=%s" % self.fileid - captcha_post_data = {'button.x': coords[0], 'button.y': coords[1], 'captcha': 'submit'} - self.html = self.load(captcha_post_url, post=captcha_post_data, decode=True) - - - def getPackageInfo(self): - name = folder = None - - # Try to get info from web - m = re.search(self.FILE_TITLE_REGEX, self.html) - if m is not None: - title = m.group(1).strip() - if not self.FILE_NOTITLE in title: - name = folder = title - self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder)) - - # Fallback to defaults - if not name or not folder: - name = self.package.name - folder = self.package.folder - self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder)) - - # Return package info - return name, folder - - - def handleErrors(self): - if self.PASSWORD_ERROR_ROKEN in self.html: - msg = "Incorrect password, please set right password on 'Edit package' form and retry" - self.logDebug(msg) - self.fail(_(msg)) - - if self.captcha: - if self.CAPTCHA_ERROR_ROKEN in self.html: - self.invalidCaptcha() - self.retry() - else: - self.correctCaptcha() - - - def handleLinkSource(self, source): - if source == 'cnl2': - return self.handleCNL2Links() - elif source == 'dlc': - return self.handleDLCLinks() - elif source == 'web': - return self.handleWEBLinks() - else: - self.error(_('Unknown source type "%s"') % source) - - - def handleCNL2Links(self): - self.logDebug("Search for CNL2 links") - package_links = [] - m = re.search(self.CNL2_FORM_REGEX, self.html, re.S) - if m is not None: - cnl2_form = m.group(1) - try: - (vcrypted, vjk) = self._getCipherParams(cnl2_form) - for (crypted, jk) in zip(vcrypted, vjk): - package_links.extend(self._getLinks(crypted, jk)) - except Exception: - self.logDebug("Unable to decrypt CNL2 links") - return package_links - - - def handleDLCLinks(self): - self.logDebug("Search for DLC links") - package_links = [] - m = re.search(self.DLC_LINK_REGEX, self.html) - if m is not None: - container_url = self.DLC_DOWNLOAD_URL + "?id=%s&dlc=1" % self.fileid - self.logDebug("Downloading DLC container link [%s]" % container_url) - try: - dlc = self.load(container_url) - dlc_filename = self.fileid + ".dlc" - dlc_filepath = save_join(self.config['general']['download_folder'], dlc_filename) - with open(dlc_filepath, "wb") as f: - f.write(dlc) - package_links.append(dlc_filepath) - - except Exception: - self.fail(_("Unable to download DLC container")) - - return package_links - - - def handleWEBLinks(self): - self.logDebug("Search for WEB links") - - package_links = [] - params = re.findall(self.WEB_FORWARD_REGEX, self.html) - - self.logDebug("Decrypting %d Web links" % len(params)) - - for index, param in enumerate(params): - try: - url = self.WEB_FORWARD_URL + "?%s" % param - - self.logDebug("Decrypting Web link %d, %s" % (index + 1, url)) - - res = self.load(url, decode=True) - link = re.search(self.WEB_LINK_REGEX, res).group(1) - - package_links.append(link) - - except Exception, detail: - self.logDebug("Error decrypting Web link %s, %s" % (index, detail)) - - self.setWait(4) - self.wait() - - return package_links - - - def _getCipherParams(self, cnl2_form): - # Get jk - jk_re = self.CNL2_FORMINPUT_REGEX % self.CNL2_JK_KEY - vjk = re.findall(jk_re, cnl2_form, re.I) - - # Get crypted - crypted_re = self.CNL2_FORMINPUT_REGEX % RelinkUs.CNL2_CRYPTED_KEY - vcrypted = re.findall(crypted_re, cnl2_form, re.I) - - # Log and return - self.logDebug("Detected %d crypted blocks" % len(vcrypted)) - return vcrypted, vjk - - - def _getLinks(self, crypted, jk): - # Get key - jreturn = self.js.eval("%s f()" % jk) - self.logDebug("JsEngine returns value [%s]" % jreturn) - key = binascii.unhexlify(jreturn) - - # Decrypt - Key = key - IV = key - obj = AES.new(Key, AES.MODE_CBC, IV) - text = obj.decrypt(crypted.decode('base64')) - - # Extract links - text = text.replace("\x00", "").replace("\r", "") - links = filter(bool, text.split('\n')) - - # Log and return - self.logDebug("Package has %d links" % len(links)) - return links diff --git a/module/plugins/crypter/SecuredIn.py b/module/plugins/crypter/SecuredIn.py deleted file mode 100644 index 9aee9e52e..000000000 --- a/module/plugins/crypter/SecuredIn.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class SecuredIn(DeadCrypter): - __name__ = "SecuredIn" - __type__ = "crypter" - __version__ = "0.21" - - __pattern__ = r'http://(?:www\.)?secured\.in/download-[\d]+-\w{8}\.html' - __config__ = [] - - __description__ = """Secured.in decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("mkaay", "mkaay@mkaay.de")] - - -getInfo = create_getInfo(SecuredIn) diff --git a/module/plugins/crypter/SharingmatrixCom.py b/module/plugins/crypter/SharingmatrixCom.py deleted file mode 100644 index be23ada49..000000000 --- a/module/plugins/crypter/SharingmatrixCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class SharingmatrixCom(DeadCrypter): - __name__ = "SharingmatrixCom" - __type__ = "crypter" - __version__ = "0.01" - - __pattern__ = r'http://(?:www\.)?sharingmatrix\.com/folder/\w+' - - __description__ = """Sharingmatrix.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(SharingmatrixCom) diff --git a/module/plugins/crypter/SpeedLoadOrg.py b/module/plugins/crypter/SpeedLoadOrg.py deleted file mode 100644 index 190ec66eb..000000000 --- a/module/plugins/crypter/SpeedLoadOrg.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class SpeedLoadOrg(DeadCrypter): - __name__ = "SpeedLoadOrg" - __type__ = "crypter" - __version__ = "0.30" - - __pattern__ = r'http://(?:www\.)?speedload\.org/(\d+~f$|folder/\d+/)' - __config__ = [] - - __description__ = """Speedload decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - -getInfo = create_getInfo(SpeedLoadOrg) diff --git a/module/plugins/crypter/StealthTo.py b/module/plugins/crypter/StealthTo.py deleted file mode 100644 index 8513fb3f8..000000000 --- a/module/plugins/crypter/StealthTo.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class StealthTo(DeadCrypter): - __name__ = "StealthTo" - __type__ = "crypter" - __version__ = "0.20" - - __pattern__ = r'http://(?:www\.)?stealth\.to/folder/.+' - __config__ = [] - - __description__ = """Stealth.to decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("spoob", "spoob@pyload.org")] - - -getInfo = create_getInfo(StealthTo) diff --git a/module/plugins/crypter/TnyCz.py b/module/plugins/crypter/TnyCz.py deleted file mode 100644 index d36128550..000000000 --- a/module/plugins/crypter/TnyCz.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo - -import re - - -class TnyCz(SimpleCrypter): - __name__ = "TnyCz" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?tny\.cz/\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Tny.cz decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - NAME_PATTERN = r'<title>(?P<N>.+) - .+</title>' - - - def getLinks(self): - m = re.search(r'<a id=\'save_paste\' href="(.+save\.php\?hash=.+)">', self.html) - return re.findall(".+", self.load(m.group(1), decode=True)) if m else None - - -getInfo = create_getInfo(TnyCz) diff --git a/module/plugins/crypter/TrailerzoneInfo.py b/module/plugins/crypter/TrailerzoneInfo.py deleted file mode 100644 index ca14e6df5..000000000 --- a/module/plugins/crypter/TrailerzoneInfo.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class TrailerzoneInfo(DeadCrypter): - __name__ = "TrailerzoneInfo" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?trailerzone\.info/.+' - __config__ = [] - - __description__ = """TrailerZone.info decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("godofdream", "soilfiction@gmail.com")] - - -getInfo = create_getInfo(TrailerzoneInfo) diff --git a/module/plugins/crypter/TurbobitNet.py b/module/plugins/crypter/TurbobitNet.py deleted file mode 100644 index 67f7c74d4..000000000 --- a/module/plugins/crypter/TurbobitNet.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo -from pyload.utils import json_loads - - -class TurbobitNet(SimpleCrypter): - __name__ = "TurbobitNet" - __type__ = "crypter" - __version__ = "0.05" - - __pattern__ = r'http://(?:www\.)?turbobit\.net/download/folder/(?P<ID>\w+)' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Turbobit.net folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - NAME_PATTERN = r'src=\'/js/lib/grid/icon/folder.png\'> <span>(?P<N>.+?)</span>' - - - def _getLinks(self, id, page=1): - gridFile = self.load("http://turbobit.net/downloadfolder/gridFile", - get={"rootId": id, "rows": 200, "page": page}, decode=True) - grid = json_loads(gridFile) - - if grid['rows']: - for i in grid['rows']: - yield i['id'] - for id in self._getLinks(id, page + 1): - yield id - else: - return - - - def getLinks(self): - id = re.match(self.__pattern__, self.pyfile.url).group('ID') - fixurl = lambda id: "http://turbobit.net/%s.html" % id - return map(fixurl, self._getLinks(id)) - - -getInfo = create_getInfo(TurbobitNetFolder) diff --git a/module/plugins/crypter/TusfilesNet.py b/module/plugins/crypter/TusfilesNet.py deleted file mode 100644 index 94b6bbb5d..000000000 --- a/module/plugins/crypter/TusfilesNet.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: utf-8 -*- - -import math -import re -from urlparse import urljoin - -from module.plugins.internal.XFSCrypter import XFSCrypter, create_getInfo - - -class TusfilesNet(XFSCrypter): - __name__ = "TusfilesNet" - __type__ = "crypter" - __version__ = "0.08" - - __pattern__ = r'https?://(?:www\.)?tusfiles\.net/go/(?P<ID>\w+)' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Tusfiles.net folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com"), - ("stickell", "l.stickell@yahoo.it")] - - - PAGES_PATTERN = r'>\((\d+) \w+\)<' - - URL_REPLACEMENTS = [(__pattern__ + ".*", r'https://www.tusfiles.net/go/\g<ID>/')] - - - def loadPage(self, page_n): - return self.load(urljoin(self.pyfile.url, str(page_n)), decode=True) - - - def handlePages(self, pyfile): - pages = re.search(self.PAGES_PATTERN, self.html) - if pages: - pages = int(math.ceil(int(pages.group('pages')) / 25.0)) - else: - return - - for p in xrange(2, pages + 1): - self.html = self.loadPage(p) - self.links += self.getLinks() - - -getInfo = create_getInfo(TusfilesNetFolder) diff --git a/module/plugins/crypter/UploadableCh.py b/module/plugins/crypter/UploadableCh.py deleted file mode 100644 index 8e4ff71c0..000000000 --- a/module/plugins/crypter/UploadableCh.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo - - -class UploadableCh(SimpleCrypter): - __name__ = "UploadableCh" - __type__ = "crypter" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?uploadable\.ch/list/\w+' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Uploadable.ch folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("guidobelix", "guidobelix@hotmail.it"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - LINK_PATTERN = r'"(.+?)" class="icon_zipfile">' - NAME_PATTERN = r'<div class="folder"><span> </span>(?P<N>.+?)</div>' - OFFLINE_PATTERN = r'We are sorry... The URL you entered cannot be found on the server.' - TEMP_OFFLINE_PATTERN = r'<div class="icon_err">' - - -getInfo = create_getInfo(UploadableChFolder) diff --git a/module/plugins/crypter/UploadedTo.py b/module/plugins/crypter/UploadedTo.py deleted file mode 100644 index f6bc861de..000000000 --- a/module/plugins/crypter/UploadedTo.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urlparse import urljoin - -from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo - - -class UploadedTo(SimpleCrypter): - __name__ = "UploadedTo" - __type__ = "crypter" - __version__ = "0.42" - - __pattern__ = r'http://(?:www\.)?(uploaded|ul)\.(to|net)/(f|folder|list)/(?P<ID>\w+)' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """UploadedTo decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - PLAIN_PATTERN = r'<small class="date"><a href="([\w/]+)" onclick=' - NAME_PATTERN = r'<title>(?P<N>.+?)<' - - - def getLinks(self): - m = re.search(self.PLAIN_PATTERN, self.html) - if m is None: - self.error(_("PLAIN_PATTERN not found")) - - plain_link = urljoin("http://uploaded.net/", m.group(1)) - return self.load(plain_link).split('\n')[:-1] - - -getInfo = create_getInfo(UploadedToFolder) diff --git a/module/plugins/crypter/WiiReloadedOrg.py b/module/plugins/crypter/WiiReloadedOrg.py deleted file mode 100644 index 7b4270e65..000000000 --- a/module/plugins/crypter/WiiReloadedOrg.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class WiiReloadedOrg(DeadCrypter): - __name__ = "WiiReloadedOrg" - __type__ = "crypter" - __version__ = "0.11" - - __pattern__ = r'http://(?:www\.)?wii-reloaded\.org/protect/get\.php\?i=.+' - __config__ = [] - - __description__ = """Wii-Reloaded.org decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("hzpz", "")] - - -getInfo = create_getInfo(WiiReloadedOrg) diff --git a/module/plugins/crypter/WuploadCom.py b/module/plugins/crypter/WuploadCom.py deleted file mode 100644 index 0a098a40c..000000000 --- a/module/plugins/crypter/WuploadCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadCrypter import DeadCrypter, create_getInfo - - -class WuploadCom(DeadCrypter): - __name__ = "WuploadCom" - __type__ = "crypter" - __version__ = "0.01" - - __pattern__ = r'http://(?:www\.)?wupload\.com/folder/\w+' - - __description__ = """Wupload.com folder decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(WuploadCom) diff --git a/module/plugins/crypter/XFileSharingPro.py b/module/plugins/crypter/XFileSharingPro.py deleted file mode 100644 index a965f0c48..000000000 --- a/module/plugins/crypter/XFileSharingPro.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.XFSCrypter import XFSCrypter, create_getInfo - - -class XFileSharingPro(XFSCrypter): - __name__ = "XFileSharingPro" - __type__ = "crypter" - __version__ = "0.04" - - __pattern__ = r'^unmatchable$' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """XFileSharingPro dummy folder decrypter plugin for hook""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - def _log(self, type, args): - msg = " | ".join(str(a).strip() for a in args if a) - logger = getattr(self.log, type) - logger("%s: %s: %s" % (self.__name__, self.HOSTER_NAME, msg or _("%s MARK" % type.upper()))) - - - def init(self): - super(XFileSharingPro, self).init() - - self.__pattern__ = self.core.pluginManager.crypterPlugins[self.__name__]['pattern'] - - self.HOSTER_DOMAIN = re.match(self.__pattern__, self.pyfile.url).group("DOMAIN").lower() - self.HOSTER_NAME = "".join(part.capitalize() for part in re.split(r'(\.|\d+)', self.HOSTER_DOMAIN) if part != '.') - - if self.HOSTER_NAME[0].isdigit(): - self.HOSTER_NAME = 'X' + self.HOSTER_NAME - - account = self.core.accountManager.getAccountPlugin(self.HOSTER_NAME) - - if account and account.canUse(): - self.account = account - - elif self.account: - self.account.HOSTER_DOMAIN = self.HOSTER_DOMAIN - - else: - return - - self.user, data = self.account.selectAccount() - self.req = self.account.getAccountRequest(self.user) - self.premium = self.account.isPremium(self.user) - - -getInfo = create_getInfo(XFileSharingProFolder) diff --git a/module/plugins/hooks/AlldebridCom.py b/module/plugins/hooks/AlldebridCom.py deleted file mode 100644 index fd89571eb..000000000 --- a/module/plugins/hooks/AlldebridCom.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.MultiHook import MultiHook - - -class AlldebridCom(MultiHook): - __name__ = "AlldebridCom" - __type__ = "hook" - __version__ = "0.16" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 ), - ("ssl" , "bool" , "Use HTTPS" , True )] - - __description__ = """Alldebrid.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("Andy Voigt", "spamsales@online.de")] - - - def getHosters(self): - https = "https" if self.getConfig("ssl") else "http" - html = self.getURL(https + "://www.alldebrid.com/api.php", get={'action': "get_host"}).replace("\"", "").strip() - - return [x.strip() for x in html.split(",") if x.strip()] diff --git a/module/plugins/hooks/AndroidPhoneNotify.py b/module/plugins/hooks/AndroidPhoneNotify.py deleted file mode 100644 index a3b24a255..000000000 --- a/module/plugins/hooks/AndroidPhoneNotify.py +++ /dev/null @@ -1,80 +0,0 @@ -# -*- coding: utf-8 -*- - -from time import time - -from module.network.RequestFactory import getURL -from module.plugins.Hook import Hook - - -class AndroidPhoneNotify(Hook): - __name__ = "AndroidPhoneNotify" - __type__ = "hook" - __version__ = "0.05" - - __config__ = [("apikey" , "str" , "API key" , "" ), - ("notifycaptcha" , "bool", "Notify captcha request" , True ), - ("notifypackage" , "bool", "Notify package finished" , True ), - ("notifyprocessed", "bool", "Notify processed packages status" , True ), - ("timeout" , "int" , "Timeout between captchas in seconds" , 5 ), - ("force" , "bool", "Send notifications if client is connected", False)] - - __description__ = """Send push notifications to your Android Phone using notifymyandroid.com""" - __license__ = "GPLv3" - __authors__ = [("Steven Kosyra", "steven.kosyra@gmail.com"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - event_list = ["allDownloadsProcessed"] - - - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass - - - def setup(self): - self.info = {} #@TODO: Remove in 0.4.10 - self.last_notify = 0 - - - def newCaptchaTask(self, task): - if not self.getConfig("notifycaptcha"): - return False - - if time() - self.last_notify < self.getConf("timeout"): - return False - - self.notify(_("Captcha"), _("New request waiting user input")) - - - def packageFinished(self, pypack): - if self.getConfig("notifypackage"): - self.notify(_("Package finished"), pypack.name) - - - def allDownloadsProcessed(self): - if not self.getConfig("notifyprocessed"): - return False - - if any(True for pdata in self.core.api.getQueue() if pdata.linksdone < pdata.linkstotal): - self.notify(_("Package failed"), _("One or more packages was not completed successfully")) - else: - self.notify(_("All packages finished")) - - - def notify(self, event, msg=""): - apikey = self.getConfig("apikey") - - if not apikey: - return False - - if self.core.isClientConnected() and not self.getConfig("force"): - return False - - getURL("http://www.notifymyandroid.com/publicapi/notify", - get={'apikey' : apikey, - 'application': "pyLoad", - 'event' : event, - 'description': msg}) - - self.last_notify = time() diff --git a/module/plugins/hooks/BypassCaptcha.py b/module/plugins/hooks/BypassCaptcha.py deleted file mode 100644 index bd19fe953..000000000 --- a/module/plugins/hooks/BypassCaptcha.py +++ /dev/null @@ -1,135 +0,0 @@ -# -*- coding: utf-8 -*- - -from pycurl import FORM_FILE, LOW_SPEED_TIME - -from module.network.HTTPRequest import BadHeader -from module.network.RequestFactory import getURL, getRequest -from module.plugins.Addon import Addon, threaded - - -class BypassCaptchaException(Exception): - - def __init__(self, err): - self.err = err - - - def getCode(self): - return self.err - - - def __str__(self): - return "<BypassCaptchaException %s>" % self.err - - - def __repr__(self): - return "<BypassCaptchaException %s>" % self.err - - -class BypassCaptcha(Addon): - __name__ = "BypassCaptcha" - __type__ = "hook" - __version__ = "0.06" - - __config__ = [("force", "bool", "Force BC even if client is connected", False), - ("passkey", "password", "Passkey", "")] - - __description__ = """Send captchas to BypassCaptcha.com""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("Godofdream", "soilfcition@gmail.com"), - ("zoidberg", "zoidberg@mujmail.cz")] - - - PYLOAD_KEY = "4f771155b640970d5607f919a615bdefc67e7d32" - - SUBMIT_URL = "http://bypasscaptcha.com/upload.php" - RESPOND_URL = "http://bypasscaptcha.com/check_value.php" - GETCREDITS_URL = "http://bypasscaptcha.com/ex_left.php" - - - def getCredits(self): - res = getURL(self.GETCREDITS_URL, post={"key": self.getConfig("passkey")}) - - data = dict(x.split(' ', 1) for x in res.splitlines()) - return int(data['Left']) - - - def submit(self, captcha, captchaType="file", match=None): - req = getRequest() - - #raise timeout threshold - req.c.setopt(LOW_SPEED_TIME, 80) - - try: - res = req.load(self.SUBMIT_URL, - post={'vendor_key': self.PYLOAD_KEY, - 'key': self.getConfig("passkey"), - 'gen_task_id': "1", - 'file': (FORM_FILE, captcha)}, - multipart=True) - finally: - req.close() - - data = dict(x.split(' ', 1) for x in res.splitlines()) - if not data or "Value" not in data: - raise BypassCaptchaException(res) - - result = data['Value'] - ticket = data['TaskId'] - self.logDebug("Result %s : %s" % (ticket, result)) - - return ticket, result - - - def respond(self, ticket, success): - try: - res = getURL(self.RESPOND_URL, post={"task_id": ticket, "key": self.getConfig("passkey"), - "cv": 1 if success else 0}) - except BadHeader, e: - self.logError(_("Could not send response"), e) - - - def captchaTask(self, task): - if "service" in task.data: - return False - - if not task.isTextual(): - return False - - if not self.getConfig("passkey"): - return False - - if self.core.isClientConnected() and not self.getConfig("force"): - return False - - if self.getCredits() > 0: - task.handler.append(self) - task.data['service'] = self.__name__ - task.setWaiting(100) - self._processCaptcha(task) - - else: - self.logInfo(_("Your %s account has not enough credits") % self.__name__) - - - def captchaCorrect(self, task): - if task.data['service'] == self.__name__ and "ticket" in task.data: - self.respond(task.data['ticket'], True) - - - def captchaInvalid(self, task): - if task.data['service'] == self.__name__ and "ticket" in task.data: - self.respond(task.data['ticket'], False) - - - @threaded - def _processCaptcha(self, task): - c = task.captchaFile - try: - ticket, result = self.submit(c) - except BypassCaptchaException, e: - task.error = e.getCode() - return - - task.data['ticket'] = ticket - task.setResult(result) diff --git a/module/plugins/hooks/Captcha9Kw.py b/module/plugins/hooks/Captcha9Kw.py deleted file mode 100644 index 04caff345..000000000 --- a/module/plugins/hooks/Captcha9Kw.py +++ /dev/null @@ -1,251 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import re - -from base64 import b64encode -from time import sleep - -from pyload.network.HTTPRequest import BadHeader -from pyload.network.RequestFactory import getURL - -from module.plugins.Hook import Hook, threaded - - -class Captcha9kw(Hook): - __name__ = "Captcha9Kw" - __type__ = "hook" - __version__ = "0.28" - - __config__ = [("ssl" , "bool" , "Use HTTPS" , True ), - ("force" , "bool" , "Force captcha resolving even if client is connected" , True ), - ("confirm" , "bool" , "Confirm Captcha (cost +6 credits)" , False ), - ("captchaperhour", "int" , "Captcha per hour" , "9999" ), - ("captchapermin" , "int" , "Captcha per minute" , "9999" ), - ("prio" , "int" , "Priority (max 10)(cost +0 -> +10 credits)" , "0" ), - ("queue" , "int" , "Max. Queue (max 999)" , "50" ), - ("hoster_options", "string" , "Hoster options (format: pluginname:prio=1:selfsolfe=1:confirm=1:timeout=900|...)", "ShareonlineBiz:prio=0:timeout=999 | UploadedTo:prio=0:timeout=999"), - ("selfsolve" , "bool" , "Selfsolve (manually solve your captcha in your 9kw client if active)" , "0" ), - ("passkey" , "password", "API key" , "" ), - ("timeout" , "int" , "Timeout in seconds (min 60, max 3999)" , "900" )] - - __description__ = """Send captchas to 9kw.eu""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - API_URL = "http://www.9kw.eu/index.cgi" - - - def activate(self): - if self.getConfig("ssl"): - self.API_URL = self.API_URL.replace("http://", "https://") - - - def getCredits(self): - res = getURL(self.API_URL, - get={'apikey': self.getConfig("passkey"), - 'pyload': "1", - 'source': "pyload", - 'action': "usercaptchaguthaben"}) - - if res.isdigit(): - self.logInfo(_("%s credits left") % res) - credits = self.info['credits'] = int(res) - return credits - else: - self.logError(res) - return 0 - - - @threaded - def _processCaptcha(self, task): - try: - with open(task.captchaFile, 'rb') as f: - data = f.read() - - except IOError, e: - self.logError(e) - return - - pluginname = re.search(r'_([^_]*)_\d+.\w+', task.captchaFile).group(1) - option = {'min' : 2, - 'max' : 50, - 'phrase' : 0, - 'numeric' : 0, - 'case_sensitive': 0, - 'math' : 0, - 'prio' : min(max(self.getConfig("prio"), 0), 10), - 'confirm' : self.getConfig("confirm"), - 'timeout' : min(max(self.getConfig("timeout"), 300), 3999), - 'selfsolve' : self.getConfig("selfsolve"), - 'cph' : self.getConfig("captchaperhour"), - 'cpm' : self.getConfig("captchapermin")} - - for opt in str(self.getConfig("hoster_options").split('|')): - - details = map(str.strip, opt.split(':')) - - if not details or details[0].lower() != pluginname.lower(): - continue - - for d in details: - hosteroption = d.split("=") - - if len(hosteroption) < 2 or not hosteroption[1].isdigit(): - continue - - o = hosteroption[0].lower() - if o in option: - option[o] = hosteroption[1] - - break - - post_data = {'apikey' : self.getConfig("passkey"), - 'prio' : option['prio'], - 'confirm' : option['confirm'], - 'maxtimeout' : option['timeout'], - 'selfsolve' : option['selfsolve'], - 'captchaperhour': option['cph'], - 'captchapermin' : option['cpm'], - 'case-sensitive': option['case_sensitive'], - 'min_len' : option['min'], - 'max_len' : option['max'], - 'phrase' : option['phrase'], - 'numeric' : option['numeric'], - 'math' : option['math'], - 'oldsource' : pluginname, - 'pyload' : "1", - 'source' : "pyload", - 'base64' : "1", - 'mouse' : 1 if task.isPositional() else 0, - 'file-upload-01': b64encode(data), - 'action' : "usercaptchaupload"} - - for _i in xrange(5): - try: - res = getURL(self.API_URL, post=post_data) - except BadHeader, e: - sleep(3) - else: - if res and res.isdigit(): - break - else: - self.logError(_("Bad upload: %s") % res) - return - - self.logDebug(_("NewCaptchaID ticket: %s") % res, task.captchaFile) - - task.data["ticket"] = res - - for _i in xrange(int(self.getConfig("timeout") / 5)): - result = getURL(self.API_URL, - get={'apikey': self.getConfig("passkey"), - 'id' : res, - 'pyload': "1", - 'info' : "1", - 'source': "pyload", - 'action': "usercaptchacorrectdata"}) - - if not result or result == "NO DATA": - sleep(5) - else: - break - else: - self.logDebug("Could not send request: %s" % res) - result = None - - self.logInfo(_("Captcha result for ticket %s: %s") % (res, result)) - - task.setResult(result) - - - def captchaTask(self, task): - if not task.isTextual() and not task.isPositional(): - return - - if not self.getConfig("passkey"): - return - - if self.core.isClientConnected() and not self.getConfig("force"): - return - - credits = self.getCredits() - - if not credits: - self.logError(_("Your captcha 9kw.eu account has not enough credits")) - return - - queue = min(self.getConfig("queue"), 999) - timeout = min(max(self.getConfig("timeout"), 300), 3999) - pluginname = re.search(r'_([^_]*)_\d+.\w+', task.captchaFile).group(1) - - for _i in xrange(5): - servercheck = getURL("http://www.9kw.eu/grafik/servercheck.txt") - if queue < re.search(r'queue=(\d+)', servercheck).group(1): - break - - sleep(10) - else: - self.fail(_("Too many captchas in queue")) - - for opt in str(self.getConfig("hoster_options").split('|')): - details = map(str.strip, opt.split(':')) - - if not details or details[0].lower() != pluginname.lower(): - continue - - for d in details: - hosteroption = d.split("=") - - if len(hosteroption) > 1 \ - and hosteroption[0].lower() == 'timeout' \ - and hosteroption[1].isdigit(): - timeout = int(hosteroption[1]) - - break - - task.handler.append(self) - - task.setWaiting(timeout) - - self._processCaptcha(task) - - - def _captchaResponse(self, task, correct): - type = "correct" if correct else "refund" - - if 'ticket' not in task.data: - self.logDebug("No CaptchaID for %s request (task: %s)" % (type, task)) - return - - passkey = self.getConfig("passkey") - - for _i in xrange(3): - res = getURL(self.API_URL, - get={'action' : "usercaptchacorrectback", - 'apikey' : passkey, - 'api_key': passkey, - 'correct': "1" if correct else "2", - 'pyload' : "1", - 'source' : "pyload", - 'id' : task.data["ticket"]}) - - self.logDebug("Request %s: %s" % (type, res)) - - if res == "OK": - break - - sleep(5) - else: - self.logDebug("Could not send %s request: %s" % (type, res)) - - - def captchaCorrect(self, task): - self._captchaResponse(task, True) - - - def captchaInvalid(self, task): - self._captchaResponse(task, False) diff --git a/module/plugins/hooks/CaptchaBrotherhood.py b/module/plugins/hooks/CaptchaBrotherhood.py deleted file mode 100644 index ba9d3eb8e..000000000 --- a/module/plugins/hooks/CaptchaBrotherhood.py +++ /dev/null @@ -1,167 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import StringIO -import pycurl - -try: - from PIL import Image -except ImportError: - import Image - -from time import sleep -from urllib import urlencode - -from pyload.network.RequestFactory import getURL, getRequest -from module.plugins.Hook import Hook, threaded - - -class CaptchaBrotherhoodException(Exception): - - def __init__(self, err): - self.err = err - - - def getCode(self): - return self.err - - - def __str__(self): - return "<CaptchaBrotherhoodException %s>" % self.err - - - def __repr__(self): - return "<CaptchaBrotherhoodException %s>" % self.err - - -class CaptchaBrotherhood(Addon): - __name__ = "CaptchaBrotherhood" - __type__ = "hook" - __version__ = "0.08" - - __config__ = [("username", "str", "Username", ""), - ("force", "bool", "Force CT even if client is connected", False), - ("passkey", "password", "Password", "")] - - __description__ = """Send captchas to CaptchaBrotherhood.com""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("zoidberg", "zoidberg@mujmail.cz")] - - - API_URL = "http://www.captchabrotherhood.com/" - - - def getCredits(self): - res = getURL(self.API_URL + "askCredits.aspx", - get={"username": self.getConfig("username"), "password": self.getConfig("passkey")}) - if not res.startswith("OK"): - raise CaptchaBrotherhoodException(res) - else: - credits = int(res[3:]) - self.logInfo(_("%d credits left") % credits) - self.info['credits'] = credits - return credits - - - def submit(self, captcha, captchaType="file", match=None): - try: - img = Image.open(captcha) - output = StringIO.StringIO() - self.logDebug("CAPTCHA IMAGE", img, img.format, img.mode) - if img.format in ("GIF", "JPEG"): - img.save(output, img.format) - else: - if img.mode != "RGB": - img = img.convert("RGB") - img.save(output, "JPEG") - data = output.getvalue() - output.close() - except Exception, e: - raise CaptchaBrotherhoodException("Reading or converting captcha image failed: %s" % e) - - req = getRequest() - - url = "%ssendNewCaptcha.aspx?%s" % (self.API_URL, - urlencode({'username' : self.getConfig("username"), - 'password' : self.getConfig("passkey"), - 'captchaSource': "pyLoad", - 'timeout' : "80"})) - - req.c.setopt(pycurl.URL, url) - req.c.setopt(pycurl.POST, 1) - req.c.setopt(pycurl.POSTFIELDS, data) - req.c.setopt(pycurl.HTTPHEADER, ["Content-Type: text/html"]) - - try: - req.c.perform() - res = req.getResponse() - except Exception, e: - raise CaptchaBrotherhoodException("Submit captcha image failed") - - req.close() - - if not res.startswith("OK"): - raise CaptchaBrotherhoodException(res[1]) - - ticket = res[3:] - - for _i in xrange(15): - sleep(5) - res = self.api_response("askCaptchaResult", ticket) - if res.startswith("OK-answered"): - return ticket, res[12:] - - raise CaptchaBrotherhoodException("No solution received in time") - - - def api_response(self, api, ticket): - res = getURL("%s%s.aspx" % (self.API_URL, api), - get={"username": self.getConfig("username"), - "password": self.getConfig("passkey"), - "captchaID": ticket}) - if not res.startswith("OK"): - raise CaptchaBrotherhoodException("Unknown response: %s" % res) - - return res - - - def captchaTask(self, task): - if "service" in task.data: - return False - - if not task.isTextual(): - return False - - if not self.getConfig("username") or not self.getConfig("passkey"): - return False - - if self.core.isClientConnected() and not self.getConfig("force"): - return False - - if self.getCredits() > 10: - task.handler.append(self) - task.data['service'] = self.__name__ - task.setWaiting(100) - self._processCaptcha(task) - else: - self.logInfo(_("Your CaptchaBrotherhood Account has not enough credits")) - - - def captchaInvalid(self, task): - if task.data['service'] == self.__name__ and "ticket" in task.data: - res = self.api_response("complainCaptcha", task.data['ticket']) - - - @threaded - def _processCaptcha(self, task): - c = task.captchaFile - try: - ticket, result = self.submit(c) - except CaptchaBrotherhoodException, e: - task.error = e.getCode() - return - - task.data['ticket'] = ticket - task.setResult(result) diff --git a/module/plugins/hooks/ClickAndLoad.py b/module/plugins/hooks/ClickAndLoad.py deleted file mode 100644 index 8b53872e4..000000000 --- a/module/plugins/hooks/ClickAndLoad.py +++ /dev/null @@ -1,124 +0,0 @@ -# -*- coding: utf-8 -*- - -import socket - -from threading import Lock - -from module.plugins.Hook import Hook, threaded - - -def forward(source, destination): - try: - bufsize = 1024 - bufdata = source.recv(bufsize) - while bufdata: - destination.sendall(bufdata) - bufdata = source.recv(bufsize) - finally: - destination.shutdown(socket.SHUT_WR) - - -#: create_connection wrapper for python 2.5 socket module -def create_connection(address, timeout=object(), source_address=None): - if hasattr(socket, 'create_connection'): - if type(timeout) == object: - timeout = socket._GLOBAL_DEFAULT_TIMEOUT - - return socket.create_connection(address, timeout, source_address) - - else: - host, port = address - err = None - for res in getaddrinfo(host, port, 0, SOCK_STREAM): - af, socktype, proto, canonname, sa = res - sock = None - try: - sock = socket(af, socktype, proto) - if type(timeout) != object: - sock.settimeout(timeout) - if source_address: - sock.bind(source_address) - sock.connect(sa) - return sock - - except socket.error, _: - err = _ - if sock is not None: - sock.close() - - if err is not None: - raise err - else: - raise socket.error("getaddrinfo returns an empty list") - - -class ClickAndLoad(Hook): - __name__ = "ClickAndLoad" - __type__ = "hook" - __version__ = "0.35" - - __config__ = [("activated", "bool", "Activated" , True), - ("port" , "int" , "Port" , 9666), - ("extern" , "bool", "Listen on the public network interface", True)] - - __description__ = """Click'N'Load hook plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.de"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass - - - def coreReady(self): - if not self.config['webinterface']['activated']: - return - - ip = socket.gethostbyname(socket.gethostname()) if self.getConfig("extern") else "127.0.0.1" - webport = int(self.config['webinterface']['port']) - cnlport = self.getConfig('port') - - self.proxy(ip, webport, cnlport) - - - @threaded - def proxy(self, ip, webport, cnlport): - self.manager.startThread(self._server, ip, webport, cnlport) - lock = Lock() - lock.acquire() - lock.acquire() - - - def _server(self, ip, webport, cnlport, thread): - try: - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind((ip, cnlport)) - server_socket.listen(5) - - while True: - client_socket = server_socket.accept()[0] - dock_socket = create_connection(("127.0.0.1", webport)) - - self.manager.startThread(forward, dock_socket, client_socket) - self.manager.startThread(forward, client_socket, dock_socket) - - except socket.error, e: - self.logDebug(e) - self._server(ip, webport, cnlport, thread) - - except Exception, e: - self.logError(e) - - try: - client_socket.close() - dock_socket.close() - except Exception: - pass - - try: - server_socket.close() - except Exception: - pass diff --git a/module/plugins/hooks/DeathByCaptcha.py b/module/plugins/hooks/DeathByCaptcha.py deleted file mode 100644 index 8786df12f..000000000 --- a/module/plugins/hooks/DeathByCaptcha.py +++ /dev/null @@ -1,214 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import re - -from base64 import b64encode -from pycurl import FORM_FILE, HTTPHEADER -from time import sleep - -from pyload.utils import json_loads -from pyload.network.HTTPRequest import BadHeader -from pyload.network.RequestFactory import getRequest -from module.plugins.Hook import Hook, threaded - - -class DeathByCaptchaException(Exception): - DBC_ERRORS = {'not-logged-in': 'Access denied, check your credentials', - 'invalid-credentials': 'Access denied, check your credentials', - 'banned': 'Access denied, account is suspended', - 'insufficient-funds': 'Insufficient account balance to decrypt CAPTCHA', - 'invalid-captcha': 'CAPTCHA is not a valid image', - 'service-overload': 'CAPTCHA was rejected due to service overload, try again later', - 'invalid-request': 'Invalid request', - 'timed-out': 'No CAPTCHA solution received in time'} - - - def __init__(self, err): - self.err = err - - - def getCode(self): - return self.err - - - def getDesc(self): - if self.err in self.DBC_ERRORS.keys(): - return self.DBC_ERRORS[self.err] - else: - return self.err - - - def __str__(self): - return "<DeathByCaptchaException %s>" % self.err - - - def __repr__(self): - return "<DeathByCaptchaException %s>" % self.err - - -class DeathByCaptcha(Addon): - __name__ = "DeathByCaptcha" - __type__ = "hook" - __version__ = "0.06" - - __config__ = [("username", "str", "Username", ""), - ("passkey", "password", "Password", ""), - ("force", "bool", "Force DBC even if client is connected", False)] - - __description__ = """Send captchas to DeathByCaptcha.com""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("zoidberg", "zoidberg@mujmail.cz")] - - - API_URL = "http://api.dbcapi.me/api/" - - - def api_response(self, api="captcha", post=False, multipart=False): - req = getRequest() - req.c.setopt(HTTPHEADER, ["Accept: application/json", "User-Agent: pyLoad %s" % self.core.version]) - - if post: - if not isinstance(post, dict): - post = {} - post.update({"username": self.getConfig("username"), - "password": self.getConfig("passkey")}) - - res = None - try: - json = req.load("%s%s" % (self.API_URL, api), - post=post, - multipart=multipart) - self.logDebug(json) - res = json_loads(json) - - if "error" in res: - raise DeathByCaptchaException(res['error']) - elif "status" not in res: - raise DeathByCaptchaException(str(res)) - - except BadHeader, e: - if 403 == e.code: - raise DeathByCaptchaException('not-logged-in') - elif 413 == e.code: - raise DeathByCaptchaException('invalid-captcha') - elif 503 == e.code: - raise DeathByCaptchaException('service-overload') - elif e.code in (400, 405): - raise DeathByCaptchaException('invalid-request') - else: - raise - - finally: - req.close() - - return res - - - def getCredits(self): - res = self.api_response("user", True) - - if 'is_banned' in res and res['is_banned']: - raise DeathByCaptchaException('banned') - elif 'balance' in res and 'rate' in res: - self.info.update(res) - else: - raise DeathByCaptchaException(res) - - - def getStatus(self): - res = self.api_response("status", False) - - if 'is_service_overloaded' in res and res['is_service_overloaded']: - raise DeathByCaptchaException('service-overload') - - - def submit(self, captcha, captchaType="file", match=None): - #@NOTE: Workaround multipart-post bug in HTTPRequest.py - if re.match("^\w*$", self.getConfig("passkey")): - multipart = True - data = (FORM_FILE, captcha) - else: - multipart = False - with open(captcha, 'rb') as f: - data = f.read() - data = "base64:" + b64encode(data) - - res = self.api_response("captcha", {"captchafile": data}, multipart) - - if "captcha" not in res: - raise DeathByCaptchaException(res) - ticket = res['captcha'] - - for _i in xrange(24): - sleep(5) - res = self.api_response("captcha/%d" % ticket, False) - if res['text'] and res['is_correct']: - break - else: - raise DeathByCaptchaException('timed-out') - - result = res['text'] - self.logDebug("Result %s : %s" % (ticket, result)) - - return ticket, result - - - def captchaTask(self, task): - if "service" in task.data: - return False - - if not task.isTextual(): - return False - - if not self.getConfig("username") or not self.getConfig("passkey"): - return False - - if self.core.isClientConnected() and not self.getConfig("force"): - return False - - try: - self.getStatus() - self.getCredits() - except DeathByCaptchaException, e: - self.logError(e.getDesc()) - return False - - balance, rate = self.info['balance'], self.info['rate'] - self.logInfo(_("Account balance"), - _("US$%.3f (%d captchas left at %.2f cents each)") % (balance / 100, - balance // rate, rate)) - - if balance > rate: - task.handler.append(self) - task.data['service'] = self.__name__ - task.setWaiting(180) - self._processCaptcha(task) - - - def captchaInvalid(self, task): - if task.data['service'] == self.__name__ and "ticket" in task.data: - try: - res = self.api_response("captcha/%d/report" % task.data['ticket'], True) - - except DeathByCaptchaException, e: - self.logError(e.getDesc()) - - except Exception, e: - self.logError(e) - - - @threaded - def _processCaptcha(self, task): - c = task.captchaFile - try: - ticket, result = self.submit(c) - except DeathByCaptchaException, e: - task.error = e.getCode() - self.logError(e.getDesc()) - return - - task.data['ticket'] = ticket - task.setResult(result) diff --git a/module/plugins/hooks/DebridItaliaCom.py b/module/plugins/hooks/DebridItaliaCom.py deleted file mode 100644 index 719f3dd3a..000000000 --- a/module/plugins/hooks/DebridItaliaCom.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.MultiHook import MultiHook - - -class DebridItaliaCom(MultiHook): - __name__ = "DebridItaliaCom" - __type__ = "hook" - __version__ = "0.12" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Debriditalia.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - def getHosters(self): - return self.getURL("http://debriditalia.com/api.php", get={'hosts': ""}).replace('"', '').split(',') diff --git a/module/plugins/hooks/EasybytezCom.py b/module/plugins/hooks/EasybytezCom.py deleted file mode 100644 index 85c616054..000000000 --- a/module/plugins/hooks/EasybytezCom.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.MultiHook import MultiHook - - -class EasybytezCom(MultiHook): - __name__ = "EasybytezCom" - __type__ = "hook" - __version__ = "0.07" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """EasyBytez.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - def getHosters(self): - user, data = self.account.selectAccount() - - req = self.account.getAccountRequest(user) - html = req.load("http://www.easybytez.com") - - return re.search(r'</textarea>\s*Supported sites:(.*)', html).group(1).split(',') diff --git a/module/plugins/hooks/ExpertDecoders.py b/module/plugins/hooks/ExpertDecoders.py deleted file mode 100644 index 04f6d0795..000000000 --- a/module/plugins/hooks/ExpertDecoders.py +++ /dev/null @@ -1,96 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -from base64 import b64encode -from pycurl import LOW_SPEED_TIME -from uuid import uuid4 - -from module.network.HTTPRequest import BadHeader -from module.network.RequestFactory import getURL, getRequest -from module.plugins.Hook import Hook, threaded - - -class ExpertDecoders(Addon): - __name__ = "ExpertDecoders" - __type__ = "hook" - __version__ = "0.04" - - __config__ = [("force", "bool", "Force CT even if client is connected", False), - ("passkey", "password", "Access key", "")] - - __description__ = """Send captchas to expertdecoders.com""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("zoidberg", "zoidberg@mujmail.cz")] - - - API_URL = "http://www.fasttypers.org/imagepost.ashx" - - - def getCredits(self): - res = getURL(self.API_URL, post={"key": self.getConfig("passkey"), "action": "balance"}) - - if res.isdigit(): - self.logInfo(_("%s credits left") % res) - self.info['credits'] = credits = int(res) - return credits - else: - self.logError(res) - return 0 - - - @threaded - def _processCaptcha(self, task): - task.data['ticket'] = ticket = uuid4() - result = None - - with open(task.captchaFile, 'rb') as f: - data = f.read() - - req = getRequest() - #raise timeout threshold - req.c.setopt(LOW_SPEED_TIME, 80) - - try: - result = req.load(self.API_URL, - post={'action' : "upload", - 'key' : self.getConfig("passkey"), - 'file' : b64encode(data), - 'gen_task_id': ticket}) - finally: - req.close() - - self.logDebug("Result %s : %s" % (ticket, result)) - task.setResult(result) - - - def captchaTask(self, task): - if not task.isTextual(): - return False - - if not self.getConfig("passkey"): - return False - - if self.core.isClientConnected() and not self.getConfig("force"): - return False - - if self.getCredits() > 0: - task.handler.append(self) - task.setWaiting(100) - self._processCaptcha(task) - - else: - self.logInfo(_("Your ExpertDecoders Account has not enough credits")) - - - def captchaInvalid(self, task): - if "ticket" in task.data: - - try: - res = getURL(self.API_URL, - post={'action': "refund", 'key': self.getConfig("passkey"), 'gen_task_id': task.data['ticket']}) - self.logInfo(_("Request refund"), res) - - except BadHeader, e: - self.logError(_("Could not send refund request"), e) diff --git a/module/plugins/hooks/FastixRu.py b/module/plugins/hooks/FastixRu.py deleted file mode 100644 index 5f339c4c0..000000000 --- a/module/plugins/hooks/FastixRu.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.utils import json_loads -from module.plugins.internal.MultiHook import MultiHook - - -class FastixRu(MultiHook): - __name__ = "FastixRu" - __type__ = "hook" - __version__ = "0.05" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Fastix.ru hook plugin""" - __license__ = "GPLv3" - __authors__ = [("Massimo Rosamilia", "max@spiritix.eu")] - - - def getHosters(self): - html = self.getURL("http://fastix.ru/api_v2", - get={'apikey': "5182964c3f8f9a7f0b00000a_kelmFB4n1IrnCDYuIFn2y", - 'sub' : "allowed_sources"}) - host_list = json_loads(html) - host_list = host_list['allow'] - return host_list diff --git a/module/plugins/hooks/FreeWayMe.py b/module/plugins/hooks/FreeWayMe.py deleted file mode 100644 index 6fec037d8..000000000 --- a/module/plugins/hooks/FreeWayMe.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.MultiHook import MultiHook - - -class FreeWayMe(MultiHook): - __name__ = "FreeWayMe" - __type__ = "hook" - __version__ = "0.14" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """FreeWay.me hook plugin""" - __license__ = "GPLv3" - __authors__ = [("Nicolas Giese", "james@free-way.me")] - - - def getHosters(self): - hostis = self.getURL("https://www.free-way.me/ajax/jd.php", get={'id': 3}).replace("\"", "").strip() - self.logDebug("Hosters", hostis) - return [x.strip() for x in hostis.split(",") if x.strip()] diff --git a/module/plugins/hooks/ImageTyperz.py b/module/plugins/hooks/ImageTyperz.py deleted file mode 100644 index 8bf326f4d..000000000 --- a/module/plugins/hooks/ImageTyperz.py +++ /dev/null @@ -1,153 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import re - -from base64 import b64encode -from pycurl import FORM_FILE, LOW_SPEED_TIME - -from module.network.RequestFactory import getURL, getRequest -from module.plugins.Hook import Hook, threaded - - -class ImageTyperzException(Exception): - - def __init__(self, err): - self.err = err - - - def getCode(self): - return self.err - - - def __str__(self): - return "<ImageTyperzException %s>" % self.err - - - def __repr__(self): - return "<ImageTyperzException %s>" % self.err - - -class ImageTyperz(Addon): - __name__ = "ImageTyperz" - __type__ = "hook" - __version__ = "0.06" - - __config__ = [("username", "str", "Username", ""), - ("passkey", "password", "Password", ""), - ("force", "bool", "Force IT even if client is connected", False)] - - __description__ = """Send captchas to ImageTyperz.com""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("zoidberg", "zoidberg@mujmail.cz")] - - - SUBMIT_URL = "http://captchatypers.com/Forms/UploadFileAndGetTextNEW.ashx" - RESPOND_URL = "http://captchatypers.com/Forms/SetBadImage.ashx" - GETCREDITS_URL = "http://captchatypers.com/Forms/RequestBalance.ashx" - - - def getCredits(self): - res = getURL(self.GETCREDITS_URL, - post={'action': "REQUESTBALANCE", - 'username': self.getConfig("username"), - 'password': self.getConfig("passkey")}) - - if res.startswith('ERROR'): - raise ImageTyperzException(res) - - try: - balance = float(res) - except Exception: - raise ImageTyperzException("Invalid response") - - self.logInfo(_("Account balance: $%s left") % res) - return balance - - - def submit(self, captcha, captchaType="file", match=None): - req = getRequest() - #raise timeout threshold - req.c.setopt(LOW_SPEED_TIME, 80) - - try: - #@NOTE: Workaround multipart-post bug in HTTPRequest.py - if re.match("^\w*$", self.getConfig("passkey")): - multipart = True - data = (FORM_FILE, captcha) - else: - multipart = False - with open(captcha, 'rb') as f: - data = f.read() - data = b64encode(data) - - res = req.load(self.SUBMIT_URL, - post={'action': "UPLOADCAPTCHA", - 'username': self.getConfig("username"), - 'password': self.getConfig("passkey"), "file": data}, - multipart=multipart) - finally: - req.close() - - if res.startswith("ERROR"): - raise ImageTyperzException(res) - else: - data = res.split('|') - if len(data) == 2: - ticket, result = data - else: - raise ImageTyperzException("Unknown response: %s" % res) - - return ticket, result - - - def captchaTask(self, task): - if "service" in task.data: - return False - - if not task.isTextual(): - return False - - if not self.getConfig("username") or not self.getConfig("passkey"): - return False - - if self.core.isClientConnected() and not self.getConfig("force"): - return False - - if self.getCredits() > 0: - task.handler.append(self) - task.data['service'] = self.__name__ - task.setWaiting(100) - self._processCaptcha(task) - - else: - self.logInfo(_("Your %s account has not enough credits") % self.__name__) - - - def captchaInvalid(self, task): - if task.data['service'] == self.__name__ and "ticket" in task.data: - res = getURL(self.RESPOND_URL, - post={'action': "SETBADIMAGE", - 'username': self.getConfig("username"), - 'password': self.getConfig("passkey"), - 'imageid': task.data['ticket']}) - - if res == "SUCCESS": - self.logInfo(_("Bad captcha solution received, requested refund")) - else: - self.logError(_("Bad captcha solution received, refund request failed"), res) - - - @threaded - def _processCaptcha(self, task): - c = task.captchaFile - try: - ticket, result = self.submit(c) - except ImageTyperzException, e: - task.error = e.getCode() - return - - task.data['ticket'] = ticket - task.setResult(result) diff --git a/module/plugins/hooks/JustPremium.py b/module/plugins/hooks/JustPremium.py deleted file mode 100644 index b70d8dd2c..000000000 --- a/module/plugins/hooks/JustPremium.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.Hook import Hook - - -class JustPremium(Hook): - __name__ = "JustPremium" - __type__ = "hook" - __version__ = "0.21" - - __config__ = [("excluded", "str", "Exclude hosters (comma separated)", "")] - - __description__ = """Remove all not premium links from urls added""" - __license__ = "GPLv3" - __authors__ = [("mazleu", "mazleica@gmail.com"), - ("Walter Purcaro", "vuolter@gmail.com"), - ("immenz", "immenz@gmx.net")] - - - event_list = ["linksAdded"] - - - def linksAdded(self, links, pid): - hosterdict = self.core.pluginManager.hosterPlugins - linkdict = self.core.api.checkURLs(links) - - premiumplugins = set(account.type for account in self.core.api.getAccounts(False) \ - if account.valid and account.premium) - multihosters = set(hoster for hoster in self.core.pluginManager.hosterPlugins \ - if 'new_name' in hosterdict[hoster] \ - and hosterdict[hoster]['new_name'] in premiumplugins) - - #: Found at least one hoster with account or multihoster - if not any(True for pluginname in linkdict if pluginname in premiumplugins | multihosters): - return - - excluded = map(lambda domain: "".join(part.capitalize() for part in re.split(r'(\.|\d+)', domain) if part != '.'), - self.getConfig('excluded').replace(' ', '').replace(',', '|').replace(';', '|').split('|')) - - for pluginname in set(linkdict.keys()) - (premiumplugins | multihosters).union(excluded): - self.logInfo(_("Remove links of plugin: %s") % pluginname) - for link in linkdict[pluginname]: - self.logDebug("Remove link: %s" % link) - links.remove(link) diff --git a/module/plugins/hooks/LinkdecrypterCom.py b/module/plugins/hooks/LinkdecrypterCom.py deleted file mode 100644 index f85a598bc..000000000 --- a/module/plugins/hooks/LinkdecrypterCom.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.MultiHook import MultiHook - - -class LinkdecrypterCom(MultiHook): - __name__ = "LinkdecrypterCom" - __type__ = "hook" - __version__ = "1.02" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Linkdecrypter.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - def getCrypters(self): - return re.search(r'>Supported\(\d+\)</b>: <i>(.[\w.\-, ]+)', - self.getURL("http://linkdecrypter.com/").replace("(g)", "")).group(1).split(', ') diff --git a/module/plugins/hooks/LinksnappyCom.py b/module/plugins/hooks/LinksnappyCom.py deleted file mode 100644 index 7e607a3d3..000000000 --- a/module/plugins/hooks/LinksnappyCom.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.utils import json_loads -from module.plugins.internal.MultiHook import MultiHook - - -class LinksnappyCom(MultiHook): - __name__ = "LinksnappyCom" - __type__ = "hook" - __version__ = "0.04" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Linksnappy.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - def getHosters(self): - json_data = self.getURL("http://gen.linksnappy.com/lseAPI.php", get={'act': "FILEHOSTS"}) - json_data = json_loads(json_data) - - return json_data['return'].keys() diff --git a/module/plugins/hooks/MegaDebridEu.py b/module/plugins/hooks/MegaDebridEu.py deleted file mode 100644 index 0711b3546..000000000 --- a/module/plugins/hooks/MegaDebridEu.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.utils import json_loads -from module.plugins.internal.MultiHook import MultiHook - - -class MegaDebridEu(MultiHook): - __name__ = "MegaDebridEu" - __type__ = "hook" - __version__ = "0.05" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Mega-debrid.eu hook plugin""" - __license__ = "GPLv3" - __authors__ = [("D.Ducatel", "dducatel@je-geek.fr")] - - - def getHosters(self): - reponse = self.getURL("http://www.mega-debrid.eu/api.php", get={'action': "getHosters"}) - json_data = json_loads(reponse) - - if json_data['response_code'] == "ok": - host_list = [element[0] for element in json_data['hosters']] - else: - self.logError(_("Unable to retrieve hoster list")) - host_list = list() - - return host_list diff --git a/module/plugins/hooks/MultihostersCom.py b/module/plugins/hooks/MultihostersCom.py deleted file mode 100644 index bf88cfae7..000000000 --- a/module/plugins/hooks/MultihostersCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.hooks.ZeveraCom import ZeveraCom - - -class MultihostersCom(ZeveraCom): - __name__ = "MultihostersCom" - __type__ = "hook" - __version__ = "0.02" - - __config__ = [("mode" , "all;listed;unlisted", "Use for plugins (if supported)" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed", "bool" , "Revert to standard download if download fails", False), - ("interval" , "int" , "Reload interval in hours (0 to disable)" , 12 )] - - __description__ = """Multihosters.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("tjeh", "tjeh@gmx.net")] diff --git a/module/plugins/hooks/MultishareCz.py b/module/plugins/hooks/MultishareCz.py deleted file mode 100644 index d02f4f8e3..000000000 --- a/module/plugins/hooks/MultishareCz.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.MultiHook import MultiHook - - -class MultishareCz(MultiHook): - __name__ = "MultishareCz" - __type__ = "hook" - __version__ = "0.07" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """MultiShare.cz hook plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - HOSTER_PATTERN = r'<img class="logo-shareserveru"[^>]*?alt="([^"]+)"></td>\s*<td class="stav">[^>]*?alt="OK"' - - - def getHosters(self): - html = self.getURL("http://www.multishare.cz/monitoring/") - return re.findall(self.HOSTER_PATTERN, html) diff --git a/module/plugins/hooks/MyfastfileCom.py b/module/plugins/hooks/MyfastfileCom.py deleted file mode 100644 index a1b5aaba0..000000000 --- a/module/plugins/hooks/MyfastfileCom.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.MultiHook import MultiHook -from pyload.utils import json_loads - - -class MyfastfileCom(MultiHook): - __name__ = "MyfastfileCom" - __type__ = "hook" - __version__ = "0.05" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Myfastfile.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - def getHosters(self): - json_data = self.getURL("http://myfastfile.com/api.php", get={'hosts': ""}, decode=True) - self.logDebug("JSON data", json_data) - json_data = json_loads(json_data) - - return json_data['hosts'] diff --git a/module/plugins/hooks/NoPremiumPl.py b/module/plugins/hooks/NoPremiumPl.py deleted file mode 100644 index 1727bec70..000000000 --- a/module/plugins/hooks/NoPremiumPl.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.common.json_layer import json_loads -from module.plugins.internal.MultiHook import MultiHook - - -class NoPremiumPl(MultiHook): - __name__ = "NoPremiumPl" - __type__ = "hook" - __version__ = "0.03" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """NoPremium.pl hook plugin""" - __license__ = "GPLv3" - __authors__ = [("goddie", "dev@nopremium.pl")] - - - def getHosters(self): - hostings = json_loads(self.getURL("https://www.nopremium.pl/clipboard.php?json=3").strip()) - hostings_domains = [domain for row in hostings for domain in row["domains"] if row["sdownload"] == "0"] - - self.logDebug(hostings_domains) - - return hostings_domains diff --git a/module/plugins/hooks/OverLoadMe.py b/module/plugins/hooks/OverLoadMe.py deleted file mode 100644 index b15ce2766..000000000 --- a/module/plugins/hooks/OverLoadMe.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.MultiHook import MultiHook - - -class OverLoadMe(MultiHook): - __name__ = "OverLoadMe" - __type__ = "hook" - __version__ = "0.04" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 ), - ("ssl" , "bool" , "Use HTTPS" , True )] - - __description__ = """Over-Load.me hook plugin""" - __license__ = "GPLv3" - __authors__ = [("marley", "marley@over-load.me")] - - - def getHosters(self): - https = "https" if self.getConfig("ssl") else "http" - html = self.getURL(https + "://api.over-load.me/hoster.php", - get={'auth': "0001-cb1f24dadb3aa487bda5afd3b76298935329be7700cd7-5329be77-00cf-1ca0135f"}).replace("\"", "").strip() - self.logDebug("Hosterlist", html) - - return [x.strip() for x in html.split(",") if x.strip()] diff --git a/module/plugins/hooks/PremiumTo.py b/module/plugins/hooks/PremiumTo.py deleted file mode 100644 index b629b111e..000000000 --- a/module/plugins/hooks/PremiumTo.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.MultiHook import MultiHook - - -class PremiumTo(MultiHook): - __name__ = "PremiumTo" - __type__ = "hook" - __version__ = "0.08" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Premium.to hook plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("zoidberg", "zoidberg@mujmail.cz"), - ("stickell", "l.stickell@yahoo.it")] - - - def getHosters(self): - html = self.getURL("http://premium.to/api/hosters.php", - get={'username': self.account.username, 'password': self.account.password}) - return [x.strip() for x in html.replace("\"", "").split(";")] diff --git a/module/plugins/hooks/PremiumizeMe.py b/module/plugins/hooks/PremiumizeMe.py deleted file mode 100644 index 18b6187c4..000000000 --- a/module/plugins/hooks/PremiumizeMe.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.utils import json_loads -from module.plugins.internal.MultiHook import MultiHook - - -class PremiumizeMe(MultiHook): - __name__ = "PremiumizeMe" - __type__ = "hook" - __version__ = "0.17" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Premiumize.me hook plugin""" - __license__ = "GPLv3" - __authors__ = [("Florian Franzen", "FlorianFranzen@gmail.com")] - - - def getHosters(self): - # Get account data - user, data = self.account.selectAccount() - - # Get supported hosters list from premiumize.me using the - # json API v1 (see https://secure.premiumize.me/?show=api) - answer = self.getURL("https://api.premiumize.me/pm-api/v1.php", - get={'method': "hosterlist", 'params[login]': user, 'params[pass]': data['password']}) - data = json_loads(answer) - - # If account is not valid thera are no hosters available - if data['status'] != 200: - return [] - - # Extract hosters from json file - return data['result']['hosterlist'] diff --git a/module/plugins/hooks/PutdriveCom.py b/module/plugins/hooks/PutdriveCom.py deleted file mode 100644 index f665dabee..000000000 --- a/module/plugins/hooks/PutdriveCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.hooks.ZeveraCom import ZeveraCom - - -class PutdriveCom(ZeveraCom): - __name__ = "PutdriveCom" - __type__ = "hook" - __version__ = "0.01" - - __config__ = [("mode" , "all;listed;unlisted", "Use for plugins (if supported)" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed", "bool" , "Revert to standard download if download fails", False), - ("interval" , "int" , "Reload interval in hours (0 to disable)" , 12 )] - - __description__ = """Putdrive.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] diff --git a/module/plugins/hooks/RPNetBiz.py b/module/plugins/hooks/RPNetBiz.py deleted file mode 100644 index 2277b10ab..000000000 --- a/module/plugins/hooks/RPNetBiz.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.utils import json_loads -from module.plugins.internal.MultiHook import MultiHook - - -class RPNetBiz(MultiHook): - __name__ = "RPNetBiz" - __type__ = "hook" - __version__ = "0.14" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """RPNet.biz hook plugin""" - __license__ = "GPLv3" - __authors__ = [("Dman", "dmanugm@gmail.com")] - - - def getHosters(self): - # Get account data - user, data = self.account.selectAccount() - - res = self.getURL("https://premium.rpnet.biz/client_api.php", - get={'username': user, 'password': data['password'], 'action': "showHosterList"}) - hoster_list = json_loads(res) - - # If account is not valid thera are no hosters available - if 'error' in hoster_list: - return [] - - # Extract hosters from json file - return hoster_list['hosters'] diff --git a/module/plugins/hooks/RapideoPl.py b/module/plugins/hooks/RapideoPl.py deleted file mode 100644 index b605eca17..000000000 --- a/module/plugins/hooks/RapideoPl.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.common.json_layer import json_loads -from module.plugins.internal.MultiHook import MultiHook - - -class RapideoPl(MultiHook): - __name__ = "RapideoPl" - __type__ = "hook" - __version__ = "0.03" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Rapideo.pl hook plugin""" - __license__ = "GPLv3" - __authors__ = [("goddie", "dev@rapideo.pl")] - - - def getHosters(self): - hostings = json_loads(self.getURL("https://www.rapideo.pl/clipboard.php?json=3").strip()) - hostings_domains = [domain for row in hostings for domain in row["domains"] if row["sdownload"] == "0"] - - self.logDebug(hostings_domains) - - return hostings_domains diff --git a/module/plugins/hooks/RealdebridCom.py b/module/plugins/hooks/RealdebridCom.py deleted file mode 100644 index d9c9407dd..000000000 --- a/module/plugins/hooks/RealdebridCom.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.MultiHook import MultiHook - - -class RealdebridCom(MultiHook): - __name__ = "RealdebridCom" - __type__ = "hook" - __version__ = "0.46" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 ), - ("ssl" , "bool" , "Use HTTPS" , True )] - - __description__ = """Real-Debrid.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("Devirex Hazzard", "naibaf_11@yahoo.de")] - - - def getHosters(self): - https = "https" if self.getConfig("ssl") else "http" - html = self.getURL(https + "://real-debrid.com/api/hosters.php").replace("\"", "").strip() - - return [x.strip() for x in html.split(",") if x.strip()] diff --git a/module/plugins/hooks/RehostTo.py b/module/plugins/hooks/RehostTo.py deleted file mode 100644 index 845601c3f..000000000 --- a/module/plugins/hooks/RehostTo.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.MultiHook import MultiHook - - -class RehostTo(MultiHook): - __name__ = "RehostTo" - __type__ = "hook" - __version__ = "0.50" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Rehost.to hook plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org")] - - - def getHosters(self): - user, data = self.account.selectAccount() - html = self.getURL("http://rehost.to/api.php", - get={'cmd' : "get_supported_och_dl", - 'long_ses': self.account.getAccountInfo(user)['session']}) - return [x.strip() for x in html.replace("\"", "").split(",")] diff --git a/module/plugins/hooks/SimplyPremiumCom.py b/module/plugins/hooks/SimplyPremiumCom.py deleted file mode 100644 index e51cbd1bc..000000000 --- a/module/plugins/hooks/SimplyPremiumCom.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.utils import json_loads -from module.plugins.internal.MultiHook import MultiHook - - -class SimplyPremiumCom(MultiHook): - __name__ = "SimplyPremiumCom" - __type__ = "hook" - __version__ = "0.05" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Simply-Premium.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("EvolutionClip", "evolutionclip@live.de")] - - - def getHosters(self): - json_data = self.getURL("http://www.simply-premium.com/api/hosts.php", get={'format': "json", 'online': 1}) - json_data = json_loads(json_data) - - host_list = [element['regex'] for element in json_data['result']] - - return host_list diff --git a/module/plugins/hooks/SimplydebridCom.py b/module/plugins/hooks/SimplydebridCom.py deleted file mode 100644 index 4d27f5ae4..000000000 --- a/module/plugins/hooks/SimplydebridCom.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.MultiHook import MultiHook - - -class SimplydebridCom(MultiHook): - __name__ = "SimplydebridCom" - __type__ = "hook" - __version__ = "0.04" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Simply-Debrid.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("Kagenoshin", "kagenoshin@gmx.ch")] - - - def getHosters(self): - html = self.getURL("http://simply-debrid.com/api.php", get={'list': 1}) - return [x.strip() for x in html.rstrip(';').replace("\"", "").split(";")] diff --git a/module/plugins/hooks/SmoozedCom.py b/module/plugins/hooks/SmoozedCom.py deleted file mode 100644 index 9ba2daac9..000000000 --- a/module/plugins/hooks/SmoozedCom.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.MultiHook import MultiHook - - -class SmoozedCom(MultiHook): - __name__ = "SmoozedCom" - __type__ = "hook" - __version__ = "0.03" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Smoozed.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("", "")] - - - def getHosters(self): - user, data = self.account.selectAccount() - return self.account.getAccountInfo(user)["hosters"] diff --git a/module/plugins/hooks/UnrestrictLi.py b/module/plugins/hooks/UnrestrictLi.py deleted file mode 100644 index b4c547883..000000000 --- a/module/plugins/hooks/UnrestrictLi.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.utils import json_loads -from module.plugins.internal.MultiHook import MultiHook - - -class UnrestrictLi(MultiHook): - __name__ = "UnrestrictLi" - __type__ = "hook" - __version__ = "0.05" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 ), - ("history" , "bool" , "Delete History" , False)] - - __description__ = """Unrestrict.li hook plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - def getHosters(self): - json_data = self.getURL("http://unrestrict.li/api/jdownloader/hosts.php", get={'format': "json"}) - json_data = json_loads(json_data) - - return [element['host'] for element in json_data['result']] diff --git a/module/plugins/hooks/WindowsPhoneNotify.py b/module/plugins/hooks/WindowsPhoneNotify.py deleted file mode 100644 index e0dd75f92..000000000 --- a/module/plugins/hooks/WindowsPhoneNotify.py +++ /dev/null @@ -1,96 +0,0 @@ -# -*- coding: utf-8 -*- - -import httplib - -from time import time - -from module.plugins.Hook import Hook - - -class WindowsPhoneNotify(Hook): - __name__ = "WindowsPhoneNotify" - __type__ = "hook" - __version__ = "0.07" - - __config__ = [("id" , "str" , "Push ID" , "" ), - ("url" , "str" , "Push url" , "" ), - ("notifycaptcha" , "bool", "Notify captcha request" , True ), - ("notifypackage" , "bool", "Notify package finished" , True ), - ("notifyprocessed", "bool", "Notify processed packages status" , True ), - ("timeout" , "int" , "Timeout between captchas in seconds" , 5 ), - ("force" , "bool", "Send notifications if client is connected", False)] - - __description__ = """Send push notifications to Windows Phone""" - __license__ = "GPLv3" - __authors__ = [("Andy Voigt", "phone-support@hotmail.de"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - event_list = ["allDownloadsProcessed"] - - - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass - - - def setup(self): - self.info = {} #@TODO: Remove in 0.4.10 - self.last_notify = 0 - - - def newCaptchaTask(self, task): - if not self.getConfig("notifycaptcha"): - return False - - if time() - self.last_notify < self.getConf("timeout"): - return False - - self.notify(_("Captcha"), _("New request waiting user input")) - - - def packageFinished(self, pypack): - if self.getConfig("notifypackage"): - self.notify(_("Package finished"), pypack.name) - - - def allDownloadsProcessed(self): - if not self.getConfig("notifyprocessed"): - return False - - if any(True for pdata in self.core.api.getQueue() if pdata.linksdone < pdata.linkstotal): - self.notify(_("Package failed"), _("One or more packages was not completed successfully")) - else: - self.notify(_("All packages finished")) - - - def getXmlData(self, msg): - return ("<?xml version='1.0' encoding='utf-8'?> <wp:Notification xmlns:wp='WPNotification'> " - "<wp:Toast> <wp:Text1>pyLoad</wp:Text1> <wp:Text2>%s</wp:Text2> " - "</wp:Toast> </wp:Notification>" % msg) - - - def notify(self, event, msg=""): - id = self.getConfig("id") - url = self.getConfig("url") - - if not id or not url: - return False - - if self.core.isClientConnected() and not self.getConfig("force"): - return False - - request = self.getXmlData("%s: %s" % (event, msg) if msg else event) - webservice = httplib.HTTP(url) - - webservice.putrequest("POST", id) - webservice.putheader("Host", url) - webservice.putheader("Content-type", "text/xml") - webservice.putheader("X-NotificationClass", "2") - webservice.putheader("X-WindowsPhone-Target", "toast") - webservice.putheader("Content-length", "%d" % len(request)) - webservice.endheaders() - webservice.send(request) - webservice.close() - - self.last_notify = time() diff --git a/module/plugins/hooks/XFileSharingPro.py b/module/plugins/hooks/XFileSharingPro.py deleted file mode 100644 index 78e14c179..000000000 --- a/module/plugins/hooks/XFileSharingPro.py +++ /dev/null @@ -1,110 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.Addon import Addon - - -class XFileSharingPro(Addon): - __name__ = "XFileSharingPro" - __type__ = "hook" - __version__ = "0.31" - - __config__ = [("activated" , "bool", "Activated" , True ), - ("use_hoster_list" , "bool", "Load listed hosters only" , False), - ("use_crypter_list", "bool", "Load listed crypters only" , False), - ("use_builtin_list", "bool", "Load built-in plugin list" , True ), - ("hoster_list" , "str" , "Hoster list (comma separated)" , "" ), - ("crypter_list" , "str" , "Crypter list (comma separated)", "" )] - - __description__ = """Load XFileSharingPro based hosters and crypter which don't need a own plugin to run""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - # event_list = ["pluginConfigChanged"] - regexp = {'hoster' : (r'https?://(?:www\.)?(?P<DOMAIN>[\w.^_]+(?:\.[a-zA-Z]{2,})(?:\:\d+)?)/(?:embed-)?\w{12}(?:\W|$)', - r'https?://(?:[^/]+\.)?(?P<DOMAIN>%s)/(?:embed-)?\w+'), - 'crypter': (r'https?://(?:www\.)?(?P<DOMAIN>[\w.^_]+(?:\.[a-zA-Z]{2,})(?:\:\d+)?)/(?:user|folder)s?/\w+', - r'https?://(?:[^/]+\.)?(?P<DOMAIN>%s)/(?:user|folder)s?/\w+')} - - HOSTER_BUILTIN = [#WORKING HOSTERS: - "180upload.com", "backin.net", "eyesfile.ca", "file4safe.com", "fileband.com", "filedwon.com", - "fileparadox.in", "filevice.com", "hostingbulk.com", "junkyvideo.com", "linestorage.com", "ravishare.com", - "ryushare.com", "salefiles.com", "sendmyway.com", "sharesix.com", "thefile.me", "verzend.be", "xvidstage.com", - #NOT TESTED: - "101shared.com", "4upfiles.com", "filemaze.ws", "filenuke.com", "linkzhost.com", "mightyupload.com", - "rockdizfile.com", "sharebeast.com", "sharerepo.com", "shareswift.com", "uploadbaz.com", "uploadc.com", - "vidbull.com", "zalaa.com", "zomgupload.com", - #NOT WORKING: - "amonshare.com", "banicrazy.info", "boosterking.com", "host4desi.com", "laoupload.com", "rd-fs.com"] - CRYPTER_BUILTIN = ["junocloud.me", "rapidfileshare.net"] - - - # def pluginConfigChanged(self.__name__, plugin, name, value): - # self.loadPattern() - - - def activate(self): - self.loadPattern() - - - def loadPattern(self): - use_builtin_list = self.getConfig('use_builtin_list') - - for type in ("hoster", "crypter"): - every_plugin = not self.getConfig("use_%s_list" % type) - - if every_plugin: - self.logInfo(_("Handling any %s I can!") % type) - pattern = self.regexp[type][0] - else: - plugins = self.getConfig('%s_list' % type) - plugin_set = set(plugins.replace(' ', '').replace('\\', '').replace('|', ',').replace(';', ',').lower().split(',')) - - if use_builtin_list: - plugin_set |= set(x.lower() for x in getattr(self, "%s_BUILTIN" % type.upper())) - - plugin_set -= set(('', u'')) - - if not plugin_set: - self.logInfo(_("No %s to handle") % type) - self._unload(type) - return - - match_list = '|'.join(sorted(plugin_set)) - - len_match_list = len(plugin_set) - self.logInfo(_("Handling %d %s%s: %s") % (len_match_list, - type, - "" if len_match_list == 1 else "s", - match_list.replace('|', ', '))) - - pattern = self.regexp[type][1] % match_list.replace('.', '\.') - - dict = self.core.pluginManager.plugins[type]["XFileSharingPro"] - dict['pattern'] = pattern - dict['re'] = re.compile(pattern) - - self.logDebug("Loaded %s pattern: %s" % (type, pattern)) - - - def _unload(self, type): - dict = self.core.pluginManager.plugins[type]["XFileSharingPro"] - dict['pattern'] = r'^unmatchable$' - dict['re'] = re.compile(dict['pattern']) - - - def deactivate(self): - # self.unloadHoster("BasePlugin") - for type in ("hoster", "crypter"): - self._unload(type, "XFileSharingPro") - - - # def downloadFailed(self, pyfile): - # if pyfile.pluginname == "BasePlugin" \ - # and pyfile.hasStatus("failed") \ - # and not self.getConfig("use_hoster_list") \ - # and self.unloadHoster("BasePlugin"): - # self.logDebug("Unloaded XFileSharingPro from BasePlugin") - # pyfile.setStatus("queued") diff --git a/module/plugins/hooks/ZeveraCom.py b/module/plugins/hooks/ZeveraCom.py deleted file mode 100644 index 215ec3673..000000000 --- a/module/plugins/hooks/ZeveraCom.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.MultiHook import MultiHook - - -class ZeveraCom(MultiHook): - __name__ = "ZeveraCom" - __type__ = "hook" - __version__ = "0.05" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Zevera.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - def getHosters(self): - html = self.account.api_response(pyreq.getHTTPRequest(timeout=120), cmd="gethosters") - return [x.strip() for x in html.split(",")] diff --git a/module/plugins/hoster/AlldebridCom.py b/module/plugins/hoster/AlldebridCom.py deleted file mode 100644 index 427eb42f0..000000000 --- a/module/plugins/hoster/AlldebridCom.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from random import randrange -from urllib import unquote - -from module.common.json_layer import json_loads -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo -from module.utils import parseFileSize - - -class AlldebridCom(MultiHoster): - __name__ = "AlldebridCom" - __type__ = "hoster" - __version__ = "0.44" - - __pattern__ = r'https?://(?:www\.|s\d+\.)?alldebrid\.com/dl/[\w^_]+' - - __description__ = """Alldebrid.com multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Andy Voigt", "spamsales@online.de")] - - - def getFilename(self, url): - try: - name = unquote(url.rsplit("/", 1)[1]) - except IndexError: - name = "Unknown_Filename..." - - if name.endswith("..."): # incomplete filename, append random stuff - name += "%s.tmp" % randrange(100, 999) - - return name - - - def setup(self): - self.chunkLimit = 16 - - - def handlePremium(self, pyfile): - password = self.getPassword() - - data = json_loads(self.load("http://www.alldebrid.com/service.php", - get={'link': pyfile.url, 'json': "true", 'pw': password})) - - self.logDebug("Json data", data) - - if data['error']: - if data['error'] == "This link isn't available on the hoster website.": - self.offline() - else: - self.logWarning(data['error']) - self.tempOffline() - else: - if pyfile.name and not pyfile.name.endswith('.tmp'): - pyfile.name = data['filename'] - pyfile.size = parseFileSize(data['filesize']) - self.link = data['link'] - - if self.getConfig("ssl"): - self.link = self.link.replace("http://", "https://") - else: - self.link = self.link.replace("https://", "http://") - - if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown"): - #only use when name wasnt already set - pyfile.name = self.getFilename(self.link) - - - def checkFile(self): - if self.checkDownload({'error': "<title>An error occured while processing your request</title>"}) == "error": - self.retry(wait_time=60, reason=_("An error occured while generating link")) - - return super(AlldebridCom, self).checkFile() - - -getInfo = create_getInfo(AlldebridCom) diff --git a/module/plugins/hoster/AndroidfilehostCom.py b/module/plugins/hoster/AndroidfilehostCom.py deleted file mode 100644 index b6e43d632..000000000 --- a/module/plugins/hoster/AndroidfilehostCom.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -* -# -# Test links: -# https://www.androidfilehost.com/?fid=95916177934518197 - -import re - -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class AndroidfilehostCom(SimpleHoster): - __name__ = "AndroidfilehostCom" - __type__ = "hoster" - __version__ = "0.01" - - __pattern__ = r'https?://(?:www\.)?androidfilehost\.com/\?fid=\d+' - - __description__ = """Androidfilehost.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] - - - NAME_PATTERN = r'<br />(?P<N>.*?)</h1>' - SIZE_PATTERN = r'<h4>size</h4>\s*<p>(?P<S>[\d.,]+)(?P<U>[\w^_]+)</p>' - HASHSUM_PATTERN = r'<h4>(?P<T>.*?)</h4>\s*<p><code>(?P<H>.*?)</code></p>' - - OFFLINE_PATTERN = r'404 not found' - - WAIT_PATTERN = r'users must wait <strong>(\d+) secs' - - - def setup(self): - self.multiDL = True - self.resumeDownload = True - self.chunkLimit = 1 - - - def handleFree(self, pyfile): - wait = re.search(self.WAIT_PATTERN, self.html) - self.logDebug("Waiting time: %s seconds" % wait.group(1)) - - fid = re.search(r'id="fid" value="(\d+)" />', self.html).group(1) - self.logDebug("fid: %s" % fid) - - html = self.load("https://www.androidfilehost.com/libs/otf/mirrors.otf.php", - post={'submit': 'submit', - 'action': 'getdownloadmirrors', - 'fid' : fid}, - decode=True) - - self.link = re.findall('"url":"(.*?)"', html)[0].replace("\\", "") - mirror_host = self.link.split("/")[2] - - self.logDebug("Mirror Host: %s" % mirror_host) - - html = self.load("https://www.androidfilehost.com/libs/otf/stats.otf.php", - get={'fid' : fid, - 'w' : 'download', - 'mirror': mirror_host}, - decode=True) - - -getInfo = create_getInfo(AndroidfilehostCom) diff --git a/module/plugins/hoster/BasketbuildCom.py b/module/plugins/hoster/BasketbuildCom.py deleted file mode 100644 index db482c7c5..000000000 --- a/module/plugins/hoster/BasketbuildCom.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: utf-8 -* -# -# Test links: -# https://s.basketbuild.com/filedl/devs?dev=pacman&dl=pacman/falcon/RC-3/pac_falcon-RC-3-20141103.zip -# https://s.basketbuild.com/filedl/gapps?dl=gapps-gb-20110828-signed.zip - -import re - -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class BasketbuildCom(SimpleHoster): - __name__ = "BasketbuildCom" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'https?://(?:www\.)?(?:\w\.)?basketbuild\.com/filedl/.+' - - __description__ = """basketbuild.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] - - - NAME_PATTERN = r'File Name:</strong> (?P<N>.+?)<br/>' - SIZE_PATTERN = r'File Size:</strong> (?P<S>[\d.,]+) (?P<U>[\w^_]+)' - OFFLINE_PATTERN = r'404 - Page Not Found' - - - def setup(self): - self.multiDL = True - self.resumeDownload = True - self.chunkLimit = 1 - - - def handleFree(self, pyfile): - try: - link1 = re.search(r'href="(.+dlgate/.+)"', self.html).group(1) - self.html = self.load(link1) - - except AttributeError: - self.error(_("Hop #1 not found")) - - else: - self.logDebug("Next hop: %s" % link1) - - try: - wait = re.search(r'var sec = (\d+)', self.html).group(1) - self.logDebug("Wait %s seconds" % wait) - self.wait(wait) - - except AttributeError: - self.logDebug("No wait time found") - - try: - self.link = re.search(r'id="dlLink">\s*<a href="(.+?)"', self.html).group(1) - - except AttributeError: - self.error(_("DL-Link not found")) - - -getInfo = create_getInfo(BasketbuildCom) diff --git a/module/plugins/hoster/BayfilesCom.py b/module/plugins/hoster/BayfilesCom.py deleted file mode 100644 index 0929ece01..000000000 --- a/module/plugins/hoster/BayfilesCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo - - -class BayfilesCom(DeadHoster): - __name__ = "BayfilesCom" - __type__ = "hoster" - __version__ = "0.09" - - __pattern__ = r'https?://(?:www\.)?bayfiles\.(com|net)/file/(?P<ID>\w+/\w+/[^/]+)' - - __description__ = """Bayfiles.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - -getInfo = create_getInfo(BayfilesCom) diff --git a/module/plugins/hoster/BezvadataCz.py b/module/plugins/hoster/BezvadataCz.py deleted file mode 100644 index 86ef46cc3..000000000 --- a/module/plugins/hoster/BezvadataCz.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class BezvadataCz(SimpleHoster): - __name__ = "BezvadataCz" - __type__ = "hoster" - __version__ = "0.26" - - __pattern__ = r'http://(?:www\.)?bezvadata\.cz/stahnout/.+' - - __description__ = """BezvaData.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<p><b>Soubor: (?P<N>[^<]+)</b></p>' - SIZE_PATTERN = r'<li><strong>Velikost:</strong> (?P<S>[^<]+)</li>' - OFFLINE_PATTERN = r'<title>BezvaData \| Soubor nenalezen</title>' - - - def setup(self): - self.resumeDownload = True - self.multiDL = True - - - def handleFree(self, pyfile): - #download button - m = re.search(r'<a class="stahnoutSoubor".*?href="(.*?)"', self.html) - if m is None: - self.error(_("Page 1 URL not found")) - url = "http://bezvadata.cz%s" % m.group(1) - - #captcha form - self.html = self.load(url) - self.checkErrors() - for _i in xrange(5): - action, inputs = self.parseHtmlForm('frm-stahnoutFreeForm') - if not inputs: - self.error(_("FreeForm")) - - m = re.search(r'<img src="data:image/png;base64,(.*?)"', self.html) - if m is None: - self.error(_("Wrong captcha image")) - - #captcha image is contained in html page as base64encoded data but decryptCaptcha() expects image url - self.load, proper_load = self.loadcaptcha, self.load - try: - inputs['captcha'] = self.decryptCaptcha(m.group(1), imgtype='png') - finally: - self.load = proper_load - - if '<img src="data:image/png;base64' in self.html: - self.invalidCaptcha() - else: - self.correctCaptcha() - break - else: - self.fail(_("No valid captcha code entered")) - - #download url - self.html = self.load("http://bezvadata.cz%s" % action, post=inputs) - self.checkErrors() - m = re.search(r'<a class="stahnoutSoubor2" href="(.*?)">', self.html) - if m is None: - self.error(_("Page 2 URL not found")) - url = "http://bezvadata.cz%s" % m.group(1) - self.logDebug("DL URL %s" % url) - - #countdown - m = re.search(r'id="countdown">(\d\d):(\d\d)<', self.html) - wait_time = (int(m.group(1)) * 60 + int(m.group(2))) if m else 120 - self.wait(wait_time, False) - - self.download(url) - - - def checkErrors(self): - if 'images/button-download-disable.png' in self.html: - self.longWait(5 * 60, 24) #: parallel dl limit - elif '<div class="infobox' in self.html: - self.tempOffline() - - self.info.pop('error', None) - - - def loadcaptcha(self, data, *args, **kwargs): - return data.decode('base64') - - -getInfo = create_getInfo(BezvadataCz) diff --git a/module/plugins/hoster/BillionuploadsCom.py b/module/plugins/hoster/BillionuploadsCom.py deleted file mode 100644 index fb79fe29a..000000000 --- a/module/plugins/hoster/BillionuploadsCom.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class BillionuploadsCom(XFSHoster): - __name__ = "BillionuploadsCom" - __type__ = "hoster" - __version__ = "0.04" - - __pattern__ = r'http://(?:www\.)?billionuploads\.com/\w{12}' - - __description__ = """Billionuploads.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<td class="dofir" title="(?P<N>.+?)"' - SIZE_PATTERN = r'<td class="dofir">(?P<S>[\d.,]+) (?P<U>[\w^_]+)' - - -getInfo = create_getInfo(BillionuploadsCom) diff --git a/module/plugins/hoster/BitshareCom.py b/module/plugins/hoster/BitshareCom.py deleted file mode 100644 index feb2b682c..000000000 --- a/module/plugins/hoster/BitshareCom.py +++ /dev/null @@ -1,158 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import re - -from pyload.plugin.internal.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class BitshareCom(SimpleHoster): - __name__ = "BitshareCom" - __type__ = "hoster" - __version__ = "0.53" - - __pattern__ = r'http://(?:www\.)?bitshare\.com/(files/)?(?(1)|\?f=)(?P<ID>\w+)(?(1)/(?P<NAME>.+?)\.html)' - - __description__ = """Bitshare.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Paul King", ""), - ("fragonib", "fragonib[AT]yahoo[DOT]es")] - - - COOKIES = [("bitshare.com", "language_selection", "EN")] - - INFO_PATTERN = r'Downloading (?P<N>.+) - (?P<S>[\d.,]+) (?P<U>[\w^_]+)</h1>' - OFFLINE_PATTERN = r'[Ff]ile (not available|was deleted|was not found)' - - AJAXID_PATTERN = r'var ajaxdl = "(.*?)";' - TRAFFIC_USED_UP = r'Your Traffic is used up for today' - - - def setup(self): - self.multiDL = self.premium - self.chunkLimit = 1 - - - def process(self, pyfile): - if self.premium: - self.account.relogin(self.user) - - # File id - m = re.match(self.__pattern__, pyfile.url) - self.file_id = max(m.group('ID1'), m.group('ID2')) - self.logDebug("File id is [%s]" % self.file_id) - - # Load main page - self.html = self.load(pyfile.url, ref=False, decode=True) - - # Check offline - if re.search(self.OFFLINE_PATTERN, self.html): - self.offline() - - # Check Traffic used up - if re.search(self.TRAFFIC_USED_UP, self.html): - self.logInfo(_("Your Traffic is used up for today")) - self.wait(30 * 60, True) - self.retry() - - # File name - m = re.match(self.__pattern__, pyfile.url) - name1 = m.group('NAME') if m else None - - m = re.search(self.INFO_PATTERN, self.html) - name2 = m.group('N') if m else None - - pyfile.name = max(name1, name2) - - # Ajax file id - self.ajaxid = re.search(self.AJAXID_PATTERN, self.html).group(1) - self.logDebug("File ajax id is [%s]" % self.ajaxid) - - # This may either download our file or forward us to an error page - self.download(self.getDownloadUrl()) - - if self.checkDownload({"error": ">Error occured<"}): - self.retry(5, 5 * 60, "Bitshare host : Error occured") - - - def getDownloadUrl(self): - # Return location if direct download is active - if self.premium: - header = self.load(self.pyfile.url, cookies=True, just_header=True) - if 'location' in header: - return header['location'] - - # Get download info - self.logDebug("Getting download info") - res = self.load("http://bitshare.com/files-ajax/" + self.file_id + "/request.html", - post={"request": "generateID", "ajaxid": self.ajaxid}) - - self.handleErrors(res, ':') - - parts = res.split(":") - filetype = parts[0] - wait = int(parts[1]) - captcha = int(parts[2]) - - self.logDebug("Download info [type: '%s', waiting: %d, captcha: %d]" % (filetype, wait, captcha)) - - # Waiting - if wait > 0: - self.logDebug("Waiting %d seconds." % wait) - if wait < 120: - self.wait(wait, False) - else: - self.wait(wait - 55, True) - self.retry() - - # Resolve captcha - if captcha == 1: - self.logDebug("File is captcha protected") - recaptcha = ReCaptcha(self) - - # Try up to 3 times - for i in xrange(3): - response, challenge = recaptcha.challenge() - res = self.load("http://bitshare.com/files-ajax/" + self.file_id + "/request.html", - post={"request" : "validateCaptcha", - "ajaxid" : self.ajaxid, - "recaptcha_challenge_field": challenge, - "recaptcha_response_field" : response}) - if self.handleCaptchaErrors(res): - break - - # Get download URL - self.logDebug("Getting download url") - res = self.load("http://bitshare.com/files-ajax/" + self.file_id + "/request.html", - post={"request": "getDownloadURL", "ajaxid": self.ajaxid}) - - self.handleErrors(res, '#') - - url = res.split("#")[-1] - - return url - - - def handleErrors(self, res, separator): - self.logDebug("Checking response [%s]" % res) - if "ERROR:Session timed out" in res: - self.retry() - elif "ERROR" in res: - msg = res.split(separator)[-1] - self.fail(msg) - - - def handleCaptchaErrors(self, res): - self.logDebug("Result of captcha resolving [%s]" % res) - if "SUCCESS" in res: - self.correctCaptcha() - return True - elif "ERROR:SESSION ERROR" in res: - self.retry() - - self.invalidCaptcha() - - -getInfo = create_getInfo(BitshareCom) diff --git a/module/plugins/hoster/BoltsharingCom.py b/module/plugins/hoster/BoltsharingCom.py deleted file mode 100644 index 93f6d619a..000000000 --- a/module/plugins/hoster/BoltsharingCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class BoltsharingCom(DeadHoster): - __name__ = "BoltsharingCom" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?boltsharing\.com/\w{12}' - - __description__ = """Boltsharing.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(BoltsharingCom) diff --git a/module/plugins/hoster/CatShareNet.py b/module/plugins/hoster/CatShareNet.py deleted file mode 100644 index d61856b7c..000000000 --- a/module/plugins/hoster/CatShareNet.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class CatShareNet(SimpleHoster): - __name__ = "CatShareNet" - __type__ = "hoster" - __version__ = "0.11" - - __pattern__ = r'http://(?:www\.)?catshare\.net/\w{16}' - - __description__ = """CatShare.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("z00nx", "z00nx0@gmail.com"), - ("prOq", ""), - ("Walter Purcaro", "vuolter@gmail.com")] - - - TEXT_ENCODING = True - - INFO_PATTERN = r'<title>(?P<N>.+) \((?P<S>[\d.,]+) (?P<U>[\w^_]+)\)<' - OFFLINE_PATTERN = ur'Podany plik zostaÅ usuniÄty\s*</div>' - - IP_BLOCKED_PATTERN = ur'>Nasz serwis wykryÅ ÅŒe Twój adres IP nie pochodzi z Polski.<' - WAIT_PATTERN = r'var\scount\s=\s(\d+);' - - LINK_FREE_PATTERN = LINK_PREMIUM_PATTERN = r'<form action="(.+?)" method="GET">' - - - def setup(self): - self.multiDL = self.premium - self.resumeDownload = True - - - def getFileInfo(self): - m = re.search(self.IP_BLOCKED_PATTERN, self.html) - if m: - self.fail(_("Only connections from Polish IP address are allowed")) - return super(CatShareNet, self).getFileInfo() - - - def handleFree(self, pyfile): - recaptcha = ReCaptcha(self) - - response, challenge = recaptcha.challenge() - self.html = self.load(pyfile.url, - post={'recaptcha_challenge_field': challenge, - 'recaptcha_response_field' : response}) - - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.invalidCaptcha() - self.retry(reason=_("Wrong captcha entered")) - - self.link = m.group(1) - - -getInfo = create_getInfo(CatShareNet) diff --git a/module/plugins/hoster/CloudzerNet.py b/module/plugins/hoster/CloudzerNet.py deleted file mode 100644 index cb764e335..000000000 --- a/module/plugins/hoster/CloudzerNet.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class CloudzerNet(DeadHoster): - __name__ = "CloudzerNet" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'https?://(?:www\.)?(cloudzer\.net/file/|clz\.to/(file/)?)\w+' - - __description__ = """Cloudzer.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("gs", "I-_-I-_-I@web.de"), - ("z00nx", "z00nx0@gmail.com"), - ("stickell", "l.stickell@yahoo.it")] - - -getInfo = create_getInfo(CloudzerNet) diff --git a/module/plugins/hoster/CloudzillaTo.py b/module/plugins/hoster/CloudzillaTo.py deleted file mode 100644 index ee966c280..000000000 --- a/module/plugins/hoster/CloudzillaTo.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class CloudzillaTo(SimpleHoster): - __name__ = "CloudzillaTo" - __type__ = "hoster" - __version__ = "0.06" - - __pattern__ = r'http://(?:www\.)?cloudzilla\.to/share/file/(?P<ID>[\w^_]+)' - - __description__ = """Cloudzilla.to hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - INFO_PATTERN = r'title="(?P<N>.+?)">\1</span> <span class="size">\((?P<S>[\d.]+) (?P<U>[\w^_]+)' - OFFLINE_PATTERN = r'>File not found...<' - - PASSWORD_PATTERN = r'<div id="pwd_protected">' - - - def checkErrors(self): - m = re.search(self.PASSWORD_PATTERN, self.html) - if m: - self.html = self.load(self.pyfile.url, get={'key': self.getPassword()}) - - if re.search(self.PASSWORD_PATTERN, self.html): - self.retry(reason="Wrong password") - - - def handleFree(self, pyfile): - self.html = self.load("http://www.cloudzilla.to/generateticket/", - post={'file_id': self.info['pattern']['ID'], 'key': self.getPassword()}) - - ticket = dict(re.findall(r'<(.+?)>([^<>]+?)</', self.html)) - - self.logDebug(ticket) - - if 'error' in ticket: - if "File is password protected" in ticket['error']: - self.retry(reason="Wrong password") - else: - self.fail(ticket['error']) - - if 'wait' in ticket: - self.wait(ticket['wait'], int(ticket['wait']) > 5) - - self.link = "http://%(server)s/download/%(file_id)s/%(ticket_id)s" % {'server' : ticket['server'], - 'file_id' : self.info['pattern']['ID'], - 'ticket_id': ticket['ticket_id']} - - - def handlePremium(self, pyfile): - return self.handleFree(pyfile) - - -getInfo = create_getInfo(CloudzillaTo) diff --git a/module/plugins/hoster/CramitIn.py b/module/plugins/hoster/CramitIn.py deleted file mode 100644 index 8e239cdc5..000000000 --- a/module/plugins/hoster/CramitIn.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class CramitIn(XFSHoster): - __name__ = "CramitIn" - __type__ = "hoster" - __version__ = "0.07" - - __pattern__ = r'http://(?:www\.)?cramit\.in/\w{12}' - - __description__ = """Cramit.in hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - INFO_PATTERN = r'<span class=t2>\s*(?P<N>.*?)</span>.*?<small>\s*\((?P<S>.*?)\)' - - LINK_PATTERN = r'href="(http://cramit\.in/file_download/.*?)"' - - -getInfo = create_getInfo(CramitIn) diff --git a/module/plugins/hoster/CrockoCom.py b/module/plugins/hoster/CrockoCom.py deleted file mode 100644 index a2abc2b7b..000000000 --- a/module/plugins/hoster/CrockoCom.py +++ /dev/null @@ -1,66 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class CrockoCom(SimpleHoster): - __name__ = "CrockoCom" - __type__ = "hoster" - __version__ = "0.19" - - __pattern__ = r'http://(?:www\.)?(crocko|easy-share)\.com/\w+' - - __description__ = """Crocko hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<span class="fz24">Download:\s*<strong>(?P<N>.*)' - SIZE_PATTERN = r'<span class="tip1"><span class="inner">(?P<S>[^<]+)</span></span>' - OFFLINE_PATTERN = r'<h1>Sorry,<br />the page you\'re looking for <br />isn\'t here.</h1>|File not found' - - CAPTCHA_PATTERN = re.compile(r"u='(/file_contents/captcha/\w+)';\s*w='(\d+)';") - - FORM_PATTERN = r'<form method="post" action="([^"]+)">(.*?)</form>' - FORM_INPUT_PATTERN = r'<input[^>]* name="?([^" ]+)"? value="?([^" ]+)"?[^>]*>' - - NAME_REPLACEMENTS = [(r'<[^>]*>', '')] - - - def handleFree(self, pyfile): - if "You need Premium membership to download this file." in self.html: - self.fail(_("You need Premium membership to download this file")) - - for _i in xrange(5): - m = re.search(self.CAPTCHA_PATTERN, self.html) - if m: - url, wait_time = 'http://crocko.com' + m.group(1), int(m.group(2)) - self.wait(wait_time) - self.html = self.load(url) - else: - break - - m = re.search(self.FORM_PATTERN, self.html, re.S) - if m is None: - self.error(_("FORM_PATTERN not found")) - - action, form = m.groups() - inputs = dict(re.findall(self.FORM_INPUT_PATTERN, form)) - recaptcha = ReCaptcha(self) - - for _i in xrange(5): - inputs['recaptcha_response_field'], inputs['recaptcha_challenge_field'] = recaptcha.challenge() - self.download(action, post=inputs) - - if self.checkDownload({"captcha": recaptcha.KEY_AJAX_PATTERN}): - self.invalidCaptcha() - else: - break - else: - self.fail(_("No valid captcha solution received")) - - -getInfo = create_getInfo(CrockoCom) diff --git a/module/plugins/hoster/CyberlockerCh.py b/module/plugins/hoster/CyberlockerCh.py deleted file mode 100644 index 1c6a04caf..000000000 --- a/module/plugins/hoster/CyberlockerCh.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class CyberlockerCh(DeadHoster): - __name__ = "CyberlockerCh" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?cyberlocker\.ch/\w+' - - __description__ = """Cyberlocker.ch hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - -getInfo = create_getInfo(CyberlockerCh) diff --git a/module/plugins/hoster/CzshareCom.py b/module/plugins/hoster/CzshareCom.py deleted file mode 100644 index 419e43a7a..000000000 --- a/module/plugins/hoster/CzshareCom.py +++ /dev/null @@ -1,161 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# http://czshare.com/5278880/random.bin - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo -from pyload.utils import parseFileSize - - -class CzshareCom(SimpleHoster): - __name__ = "CzshareCom" - __type__ = "hoster" - __version__ = "0.98" - - __pattern__ = r'http://(?:www\.)?(czshare|sdilej)\.(com|cz)/(\d+/|download\.php\?).+' - - __description__ = """CZshare.com hoster plugin, now Sdilej.cz""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<div class="tab" id="parameters">\s*<p>\s*Cel. n.zev: <a href=[^>]*>(?P<N>[^<]+)</a>' - SIZE_PATTERN = r'<div class="tab" id="category">(?:\s*<p>[^\n]*</p>)*\s*Velikost:\s*(?P<S>[\d .,]+)(?P<U>[\w^_]+)\s*</div>' - OFFLINE_PATTERN = r'<div class="header clearfix">\s*<h2 class="red">' - - SIZE_REPLACEMENTS = [(' ', '')] - URL_REPLACEMENTS = [(r'http://[^/]*/download.php\?.*?id=(\w+).*', r'http://sdilej.cz/\1/x/')] - - CHECK_TRAFFIC = True - - FREE_URL_PATTERN = r'<a href="([^"]+)" class="page-download">[^>]*alt="([^"]+)" /></a>' - FREE_FORM_PATTERN = r'<form action="download\.php" method="post">\s*<img src="captcha\.php" id="captcha" />(.*?)</form>' - PREMIUM_FORM_PATTERN = r'<form action="/profi_down\.php" method="post">(.*?)</form>' - FORM_INPUT_PATTERN = r'<input[^>]* name="([^"]+)" value="([^"]+)"[^>]*/>' - MULTIDL_PATTERN = r'<p><font color=\'red\'>Z[^<]*PROFI.</font></p>' - USER_CREDIT_PATTERN = r'<div class="credit">\s*kredit: <strong>([\d .,]+)(\w+)</strong>\s*</div><!-- .credit -->' - - - def checkTrafficLeft(self): - # check if user logged in - m = re.search(self.USER_CREDIT_PATTERN, self.html) - if m is None: - self.account.relogin(self.user) - self.html = self.load(self.pyfile.url, cookies=True, decode=True) - m = re.search(self.USER_CREDIT_PATTERN, self.html) - if m is None: - return False - - # check user credit - try: - credit = parseFileSize(m.group(1).replace(' ', ''), m.group(2)) - self.logInfo(_("Premium download for %i KiB of Credit") % (self.pyfile.size / 1024)) - self.logInfo(_("User %s has %i KiB left") % (self.user, credit / 1024)) - if credit < self.pyfile.size: - self.logInfo(_("Not enough credit to download file: %s") % self.pyfile.name) - return False - except Exception, e: - # let's continue and see what happens... - self.logError(e) - - return True - - - def handlePremium(self, pyfile): - # parse download link - try: - form = re.search(self.PREMIUM_FORM_PATTERN, self.html, re.S).group(1) - inputs = dict(re.findall(self.FORM_INPUT_PATTERN, form)) - except Exception, e: - self.logError(e) - self.resetAccount() - - # download the file, destination is determined by pyLoad - self.download("http://sdilej.cz/profi_down.php", post=inputs, disposition=True) - - - def handleFree(self, pyfile): - # get free url - m = re.search(self.FREE_URL_PATTERN, self.html) - if m is None: - self.error(_("FREE_URL_PATTERN not found")) - - parsed_url = "http://sdilej.cz" + m.group(1) - - self.logDebug("PARSED_URL:" + parsed_url) - - # get download ticket and parse html - self.html = self.load(parsed_url, cookies=True, decode=True) - if re.search(self.MULTIDL_PATTERN, self.html): - self.longWait(5 * 60, 12) - - try: - form = re.search(self.FREE_FORM_PATTERN, self.html, re.S).group(1) - inputs = dict(re.findall(self.FORM_INPUT_PATTERN, form)) - pyfile.size = int(inputs['size']) - - except Exception, e: - self.logError(e) - self.error(_("Form")) - - # get and decrypt captcha - captcha_url = 'http://sdilej.cz/captcha.php' - for _i in xrange(5): - inputs['captchastring2'] = self.decryptCaptcha(captcha_url) - self.html = self.load(parsed_url, cookies=True, post=inputs, decode=True) - - if u"<li>ZadanÃœ ovÄÅovacà kód nesouhlasÃ!</li>" in self.html: - self.invalidCaptcha() - - elif re.search(self.MULTIDL_PATTERN, self.html): - self.longWait(5 * 60, 12) - - else: - self.correctCaptcha() - break - else: - self.fail(_("No valid captcha code entered")) - - m = re.search("countdown_number = (\d+);", self.html) - self.setWait(int(m.group(1)) if m else 50) - - # download the file, destination is determined by pyLoad - self.logDebug("WAIT URL", self.req.lastEffectiveURL) - - m = re.search("free_wait.php\?server=(.*?)&(.*)", self.req.lastEffectiveURL) - if m is None: - self.error(_("Download URL not found")) - - self.link = "http://%s/download.php?%s" % (m.group(1), m.group(2)) - - self.wait() - - - def checkFile(self): - # check download - check = self.checkDownload({ - "temp offline" : re.compile(r"^Soubor je do.*asn.* nedostupn.*$"), - "credit" : re.compile(r"^Nem.*te dostate.*n.* kredit.$"), - "multi-dl" : re.compile(self.MULTIDL_PATTERN), - "captcha" : "<li>ZadanÃœ ovÄÅovacà kód nesouhlasÃ!</li>" - }) - - if check == "temp offline": - self.fail(_("File not available - try later")) - - elif check == "credit": - self.resetAccount() - - elif check == "multi-dl": - self.longWait(5 * 60, 12) - - elif check == "captcha": - self.invalidCaptcha() - self.retry() - - return super(CzshareCom, self).checkFile() - - -getInfo = create_getInfo(CzshareCom) diff --git a/module/plugins/hoster/DataHu.py b/module/plugins/hoster/DataHu.py deleted file mode 100644 index f24b5cdba..000000000 --- a/module/plugins/hoster/DataHu.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# http://data.hu/get/6381232/random.bin - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class DataHu(SimpleHoster): - __name__ = "DataHu" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?data\.hu/get/\w+' - - __description__ = """Data.hu hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("crash", ""), - ("stickell", "l.stickell@yahoo.it")] - - - INFO_PATTERN = ur'<title>(?P<N>.*) \((?P<S>[^)]+)\) let\xf6lt\xe9se</title>' - OFFLINE_PATTERN = ur'Az adott f\xe1jl nem l\xe9tezik' - LINK_FREE_PATTERN = r'<div class="download_box_button"><a href="([^"]+)">' - - - def setup(self): - self.resumeDownload = True - self.multiDL = self.premium - - -getInfo = create_getInfo(DataHu) diff --git a/module/plugins/hoster/DataportCz.py b/module/plugins/hoster/DataportCz.py deleted file mode 100644 index 592bece93..000000000 --- a/module/plugins/hoster/DataportCz.py +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class DataportCz(SimpleHoster): - __name__ = "DataportCz" - __type__ = "hoster" - __version__ = "0.41" - - __pattern__ = r'http://(?:www\.)?dataport\.cz/file/(.+)' - - __description__ = """Dataport.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<span itemprop="name">(?P<N>[^<]+)</span>' - SIZE_PATTERN = r'<td class="fil">Velikost</td>\s*<td>(?P<S>[^<]+)</td>' - OFFLINE_PATTERN = r'<h2>Soubor nebyl nalezen</h2>' - - CAPTCHA_PATTERN = r'<section id="captcha_bg">\s*<img src="(.*?)"' - FREE_SLOTS_PATTERN = ur'PoÄet volnÃœch slotů: <span class="darkblue">(\d+)</span><br />' - - - def handleFree(self, pyfile): - captchas = {"1": "jkeG", "2": "hMJQ", "3": "vmEK", "4": "ePQM", "5": "blBd"} - - for _i in xrange(60): - action, inputs = self.parseHtmlForm('free_download_form') - self.logDebug(action, inputs) - if not action or not inputs: - self.error(_("free_download_form")) - - if "captchaId" in inputs and inputs['captchaId'] in captchas: - inputs['captchaCode'] = captchas[inputs['captchaId']] - else: - self.error(_("captcha")) - - self.html = self.download("http://www.dataport.cz%s" % action, post=inputs) - - check = self.checkDownload({"captcha": 'alert("\u0160patn\u011b opsan\u00fd k\u00f3d z obr\u00e1zu");', - "slot" : 'alert("Je n\u00e1m l\u00edto, ale moment\u00e1ln\u011b nejsou'}) - if check == "captcha": - self.error(_("invalid captcha")) - - elif check == "slot": - self.logDebug("No free slots - wait 60s and retry") - self.wait(60, False) - self.html = self.load(pyfile.url, decode=True) - continue - - else: - break - - -getInfo = create_getInfo(DataportCz) diff --git a/module/plugins/hoster/DateiTo.py b/module/plugins/hoster/DateiTo.py deleted file mode 100644 index 66102939a..000000000 --- a/module/plugins/hoster/DateiTo.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class DateiTo(SimpleHoster): - __name__ = "DateiTo" - __type__ = "hoster" - __version__ = "0.07" - - __pattern__ = r'http://(?:www\.)?datei\.to/datei/(?P<ID>\w+)\.html' - - __description__ = """Datei.to hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'Dateiname:</td>\s*<td colspan="2"><strong>(?P<N>.*?)</' - SIZE_PATTERN = r'Dateigröße:</td>\s*<td colspan="2">(?P<S>.*?)</' - OFFLINE_PATTERN = r'>Datei wurde nicht gefunden<|>Bitte wÀhle deine Datei aus... <' - - WAIT_PATTERN = r'countdown\({seconds: (\d+)' - MULTIDL_PATTERN = r'>Du lÀdst bereits eine Datei herunter<' - - DATA_PATTERN = r'url: "(.*?)", data: "(.*?)",' - - - def handleFree(self, pyfile): - url = 'http://datei.to/ajax/download.php' - data = {'P': 'I', 'ID': self.info['pattern']['ID']} - recaptcha = ReCaptcha(self) - - for _i in xrange(10): - self.logDebug("URL", url, "POST", data) - self.html = self.load(url, post=data) - self.checkErrors() - - if url.endswith('download.php') and 'P' in data: - if data['P'] == 'I': - self.doWait() - - elif data['P'] == 'IV': - break - - m = re.search(self.DATA_PATTERN, self.html) - if m is None: - self.error(_("data")) - url = 'http://datei.to/' + m.group(1) - data = dict(x.split('=') for x in m.group(2).split('&')) - - if url.endswith('recaptcha.php'): - data['recaptcha_response_field'], data['recaptcha_challenge_field'] = recaptcha.challenge() - else: - self.fail(_("Too bad...")) - - self.download(self.html) - - - def checkErrors(self): - m = re.search(self.MULTIDL_PATTERN, self.html) - if m: - m = re.search(self.WAIT_PATTERN, self.html) - wait_time = int(m.group(1)) if m else 30 - - errmsg = self.info['error'] = _("Parallel downloads") - self.retry(wait_time=wait_time, reason=errmsg) - - self.info.pop('error', None) - - - def doWait(self): - m = re.search(self.WAIT_PATTERN, self.html) - wait_time = int(m.group(1)) if m else 30 - - self.load('http://datei.to/ajax/download.php', post={'P': 'Ads'}) - self.wait(wait_time, False) - - -getInfo = create_getInfo(DateiTo) diff --git a/module/plugins/hoster/DdlstorageCom.py b/module/plugins/hoster/DdlstorageCom.py deleted file mode 100644 index 32a5a8bb7..000000000 --- a/module/plugins/hoster/DdlstorageCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class DdlstorageCom(DeadHoster): - __name__ = "DdlstorageCom" - __type__ = "hoster" - __version__ = "1.02" - - __pattern__ = r'https?://(?:www\.)?ddlstorage\.com/\w+' - - __description__ = """DDLStorage.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("stickell", "l.stickell@yahoo.it")] - - -getInfo = create_getInfo(DdlstorageCom) diff --git a/module/plugins/hoster/DebridItaliaCom.py b/module/plugins/hoster/DebridItaliaCom.py deleted file mode 100644 index 8cda56c0c..000000000 --- a/module/plugins/hoster/DebridItaliaCom.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo - - -class DebridItaliaCom(MultiHoster): - __name__ = "DebridItaliaCom" - __type__ = "hoster" - __version__ = "0.17" - - __pattern__ = r'https?://(?:www\.|s\d+\.)?debriditalia\.com/dl/\d+' - - __description__ = """Debriditalia.com multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - URL_REPLACEMENTS = [("https://", "http://")] - - - def handlePremium(self, pyfile): - self.html = self.load("http://www.debriditalia.com/api.php", - get={'generate': "on", 'link': pyfile.url, 'p': self.getPassword()}) - - if "ERROR:" not in self.html: - self.link = self.html.strip() - else: - self.info['error'] = re.search(r'ERROR:(.*)', self.html).group(1).strip() - - self.html = self.load("http://debriditalia.com/linkgen2.php", - post={'xjxfun' : "convertiLink", - 'xjxargs[]': "S<![CDATA[%s]]>" % pyfile.url, - 'xjxargs[]': "S%s" % self.getPassword()}) - try: - self.link = re.search(r'<a href="(.+?)"', self.html).group(1) - except AttributeError: - pass - - -getInfo = create_getInfo(DebridItaliaCom) diff --git a/module/plugins/hoster/DepositfilesCom.py b/module/plugins/hoster/DepositfilesCom.py deleted file mode 100644 index c9e2040f8..000000000 --- a/module/plugins/hoster/DepositfilesCom.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urllib import unquote - -from pyload.plugin.internal.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class DepositfilesCom(SimpleHoster): - __name__ = "DepositfilesCom" - __type__ = "hoster" - __version__ = "0.53" - - __pattern__ = r'https?://(?:www\.)?(depositfiles\.com|dfiles\.(eu|ru))(/\w{1,3})?/files/(?P<ID>\w+)' - - __description__ = """Depositfiles.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("spoob", "spoob@pyload.org"), - ("zoidberg", "zoidberg@mujmail.cz"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - NAME_PATTERN = r'<script type="text/javascript">eval\( unescape\(\'(?P<N>.*?)\'' - SIZE_PATTERN = r': <b>(?P<S>[\d.,]+) (?P<U>[\w^_]+)</b>' - OFFLINE_PATTERN = r'<span class="html_download_api-not_exists"></span>' - - NAME_REPLACEMENTS = [(r'\%u([0-9A-Fa-f]{4})', lambda m: unichr(int(m.group(1), 16))), - (r'.*<b title="(?P<N>[^"]+).*', "\g<N>")] - URL_REPLACEMENTS = [(__pattern__ + ".*", "https://dfiles.eu/files/\g<ID>")] - - COOKIES = [("dfiles.eu", "lang_current", "en")] - - LINK_FREE_PATTERN = r'<form id="downloader_file_form" action="(http://.+?\.(dfiles\.eu|depositfiles\.com)/.+?)" method="post"' - LINK_PREMIUM_PATTERN = r'class="repeat"><a href="(.+?)"' - LINK_MIRROR_PATTERN = r'class="repeat_mirror"><a href="(.+?)"' - - - def handleFree(self, pyfile): - if re.search(r'File is checked, please try again in a minute.', self.html) is not None: - self.logInfo(_("The file is being checked. Waiting 1 minute")) - self.retry(wait_time=60) - - wait = re.search(r'html_download_api-limit_interval\">(\d+)</span>', self.html) - if wait: - wait_time = int(wait.group(1)) - self.logInfo(_("Traffic used up. Waiting %d seconds") % wait_time) - self.wait(wait_time, True) - self.retry() - - wait = re.search(r'>Try in (\d+) minutes or use GOLD account', self.html) - if wait: - wait_time = int(wait.group(1)) - self.logInfo(_("All free slots occupied. Waiting %d minutes") % wait_time) - self.setWait(wait_time * 60, False) - - wait = re.search(r'Please wait (\d+) sec', self.html) - if wait: - self.setWait(int(wait.group(1))) - - m = re.search(r"var fid = '(\w+)';", self.html) - if m is None: - self.retry(wait_time=5) - params = {'fid': m.group(1)} - self.logDebug("FID: %s" % params['fid']) - - self.wait() - recaptcha = ReCaptcha(self) - captcha_key = recaptcha.detect_key() - if captcha_key is None: - self.error(_("ReCaptcha key not found")) - - for _i in xrange(5): - self.html = self.load("https://dfiles.eu/get_file.php", get=params) - - if '<input type=button value="Continue" onclick="check_recaptcha' in self.html: - if 'response' in params: - self.invalidCaptcha() - params['response'], params['challenge'] = recaptcha.challenge(captcha_key) - self.logDebug(params) - continue - - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m: - if 'response' in params: - self.correctCaptcha() - - self.link = unquote(m.group(1)) - break - else: - self.error(_("Download link")) - else: - self.fail(_("No valid captcha response received")) - - - def handlePremium(self, pyfile): - if '<span class="html_download_api-gold_traffic_limit">' in self.html: - self.logWarning(_("Download limit reached")) - self.retry(25, 60 * 60, "Download limit reached") - elif 'onClick="show_gold_offer' in self.html: - self.account.relogin(self.user) - self.retry() - else: - link = re.search(self.LINK_PREMIUM_PATTERN, self.html) - mirror = re.search(self.LINK_MIRROR_PATTERN, self.html) - - if link: - self.link = link.group(1) - - elif mirror: - self.link = mirror.group(1) - - -getInfo = create_getInfo(DepositfilesCom) diff --git a/module/plugins/hoster/DevhostSt.py b/module/plugins/hoster/DevhostSt.py deleted file mode 100644 index 2365baa5f..000000000 --- a/module/plugins/hoster/DevhostSt.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# http://d-h.st/mM8 - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class DevhostSt(SimpleHoster): - __name__ = "DevhostSt" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'http://(?:www\.)?d-h\.st/(?!users/)\w{3}' - - __description__ = """d-h.st hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] - - - NAME_PATTERN = r'<span title="(?P<N>.*?)"' - SIZE_PATTERN = r'</span> \((?P<S>[\d.,]+) (?P<U>[\w^_]+)\)<br' - HASHSUM_PATTERN = r'>(?P<T>.*?) Sum</span>: (?P<H>.*?)<br' - - OFFLINE_PATTERN = r'>File Not Found' - LINK_FREE_PATTERN = r'var product_download_url= \'(.+?)\'' - - - def setup(self): - self.multiDL = True - self.chunkLimit = 1 - - -getInfo = create_getInfo(DevhostSt) diff --git a/module/plugins/hoster/DlFreeFr.py b/module/plugins/hoster/DlFreeFr.py deleted file mode 100644 index 541989120..000000000 --- a/module/plugins/hoster/DlFreeFr.py +++ /dev/null @@ -1,140 +0,0 @@ -# -*- coding: utf-8 -*- - -import pycurl -import re - -from pyload.network.Browser import Browser -from pyload.network.CookieJar import CookieJar -from pyload.plugin.internal.captcha import AdYouLike -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo, replace_patterns -from pyload.utils import json_loads - - -class CustomBrowser(Browser): - - def __init__(self, bucket=None, options={}): - Browser.__init__(self, bucket, options) - - - def load(self, *args, **kwargs): - post = kwargs.get("post") - - if post is None and len(args) > 2: - post = args[2] - - if post: - self.http.c.setopt(pycurl.FOLLOWLOCATION, 0) - self.http.c.setopt(pycurl.POST, 1) - self.http.c.setopt(pycurl.CUSTOMREQUEST, "POST") - else: - self.http.c.setopt(pycurl.FOLLOWLOCATION, 1) - self.http.c.setopt(pycurl.POST, 0) - self.http.c.setopt(pycurl.CUSTOMREQUEST, "GET") - - return Browser.load(self, *args, **kwargs) - - -class DlFreeFr(SimpleHoster): - __name__ = "DlFreeFr" - __type__ = "hoster" - __version__ = "0.28" - - __pattern__ = r'http://(?:www\.)?dl\.free\.fr/(\w+|getfile\.pl\?file=/\w+)' - - __description__ = """Dl.free.fr hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("the-razer", "daniel_ AT gmx DOT net"), - ("zoidberg", "zoidberg@mujmail.cz"), - ("Toilal", "toilal.dev@gmail.com")] - - - NAME_PATTERN = r'Fichier:</td>\s*<td[^>]*>(?P<N>[^>]*)</td>' - SIZE_PATTERN = r'Taille:</td>\s*<td[^>]*>(?P<S>[\d.,]+\w)o' - OFFLINE_PATTERN = r'Erreur 404 - Document non trouv|Fichier inexistant|Le fichier demandé n\'a pas été trouvé' - - - def setup(self): - self.resumeDownload = True - self.multiDL = True - self.limitDL = 5 - self.chunkLimit = 1 - - - def init(self): - factory = self.core.requestFactory - self.req = CustomBrowser(factory.bucket, factory.getOptions()) - - - def process(self, pyfile): - pyfile.url = replace_patterns(pyfile.url, self.URL_REPLACEMENTS) - valid_url = pyfile.url - headers = self.load(valid_url, just_header=True) - - if headers.get('code') == 302: - valid_url = headers.get('location') - headers = self.load(valid_url, just_header=True) - - if headers.get('code') == 200: - content_type = headers.get('content-type') - if content_type and content_type.startswith("text/html"): - # Undirect acces to requested file, with a web page providing it (captcha) - self.html = self.load(valid_url) - self.handleFree(pyfile) - else: - # Direct access to requested file for users using free.fr as Internet Service Provider. - self.link = valid_url - - elif headers.get('code') == 404: - self.offline() - - else: - self.fail(_("Invalid return code: ") + str(headers.get('code'))) - - - def handleFree(self, pyfile): - action, inputs = self.parseHtmlForm('action="getfile.pl"') - - adyoulike = AdYouLike(self) - response, challenge = adyoulike.challenge() - inputs.update(response) - - self.load("http://dl.free.fr/getfile.pl", post=inputs) - headers = self.getLastHeaders() - if headers.get("code") == 302 and "set-cookie" in headers and "location" in headers: - m = re.search("(.*?)=(.*?); path=(.*?); domain=(.*?)", headers.get("set-cookie")) - cj = CookieJar(__name__) - if m: - cj.setCookie(m.group(4), m.group(1), m.group(2), m.group(3)) - else: - self.fail(_("Cookie error")) - - self.link = headers.get("location") - - self.req.setCookieJar(cj) - else: - self.fail(_("Invalid response")) - - - def getLastHeaders(self): - #parse header - header = {"code": self.req.code} - for line in self.req.http.header.splitlines(): - line = line.strip() - if not line or ":" not in line: - continue - - key, none, value = line.partition(":") - key = key.lower().strip() - value = value.strip() - - if key in header: - if type(header[key]) == list: - header[key].append(value) - else: - header[key] = [header[key], value] - else: - header[key] = value - return header - - -getInfo = create_getInfo(DlFreeFr) diff --git a/module/plugins/hoster/DodanePl.py b/module/plugins/hoster/DodanePl.py deleted file mode 100644 index 65d8452fa..000000000 --- a/module/plugins/hoster/DodanePl.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo - - -class DodanePl(DeadHoster): - __name__ = "DodanePl" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?dodane\.pl/file/\d+' - - __description__ = """Dodane.pl hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("z00nx", "z00nx0@gmail.com")] - - -getInfo = create_getInfo(DodanePl) diff --git a/module/plugins/hoster/DuploadOrg.py b/module/plugins/hoster/DuploadOrg.py deleted file mode 100644 index 6dd25407e..000000000 --- a/module/plugins/hoster/DuploadOrg.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class DuploadOrg(DeadHoster): - __name__ = "DuploadOrg" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?dupload\.org/\w{12}' - - __description__ = """Dupload.grg hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - -getInfo = create_getInfo(DuploadOrg) diff --git a/module/plugins/hoster/EasybytezCom.py b/module/plugins/hoster/EasybytezCom.py deleted file mode 100644 index 6ca45f545..000000000 --- a/module/plugins/hoster/EasybytezCom.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class EasybytezCom(XFSHoster): - __name__ = "EasybytezCom" - __type__ = "hoster" - __version__ = "0.23" - - __pattern__ = r'http://(?:www\.)?easybytez\.com/\w{12}' - - __description__ = """Easybytez.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("stickell", "l.stickell@yahoo.it")] - - - OFFLINE_PATTERN = r'>File not available' - - LINK_PATTERN = r'(http://(\w+\.(easybytez|easyload|ezbytez|zingload)\.(com|to)|\d+\.\d+\.\d+\.\d+)/files/\d+/\w+/.+?)["\'<]' - - -getInfo = create_getInfo(EasybytezCom) diff --git a/module/plugins/hoster/EdiskCz.py b/module/plugins/hoster/EdiskCz.py deleted file mode 100644 index 76e55ae3c..000000000 --- a/module/plugins/hoster/EdiskCz.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class EdiskCz(SimpleHoster): - __name__ = "EdiskCz" - __type__ = "hoster" - __version__ = "0.23" - - __pattern__ = r'http://(?:www\.)?edisk\.(cz|sk|eu)/(stahni|sk/stahni|en/download)/.+' - - __description__ = """Edisk.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - INFO_PATTERN = r'<span class="fl" title="(?P<N>[^"]+)">\s*.*?\((?P<S>[\d.,]+) (?P<U>[\w^_]+)\)</h1></span>' - OFFLINE_PATTERN = r'<h3>This file does not exist due to one of the following:</h3><ul><li>' - - ACTION_PATTERN = r'/en/download/(\d+/.*\.html)' - LINK_FREE_PATTERN = r'http://.*edisk\.cz.*\.html' - - - def setup(self): - self.multiDL = False - - - def process(self, pyfile): - url = re.sub("/(stahni|sk/stahni)/", "/en/download/", pyfile.url) - - self.logDebug("URL:" + url) - - m = re.search(self.ACTION_PATTERN, url) - if m is None: - self.error(_("ACTION_PATTERN not found")) - action = m.group(1) - - self.html = self.load(url, decode=True) - self.getFileInfo() - - self.html = self.load(re.sub("/en/download/", "/en/download-slow/", url)) - - url = self.load(re.sub("/en/download/", "/x-download/", url), post={ - "action": action - }) - - if not re.match(self.LINK_FREE_PATTERN, url): - self.fail(_("Unexpected server response")) - - self.download(url) - - -getInfo = create_getInfo(EdiskCz) diff --git a/module/plugins/hoster/EgoFilesCom.py b/module/plugins/hoster/EgoFilesCom.py deleted file mode 100644 index ad5ad0796..000000000 --- a/module/plugins/hoster/EgoFilesCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class EgoFilesCom(DeadHoster): - __name__ = "EgoFilesCom" - __type__ = "hoster" - __version__ = "0.16" - - __pattern__ = r'https?://(?:www\.)?egofiles\.com/\w+' - - __description__ = """Egofiles.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - -getInfo = create_getInfo(EgoFilesCom) diff --git a/module/plugins/hoster/EnteruploadCom.py b/module/plugins/hoster/EnteruploadCom.py deleted file mode 100644 index 0be9b8d76..000000000 --- a/module/plugins/hoster/EnteruploadCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class EnteruploadCom(DeadHoster): - __name__ = "EnteruploadCom" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?enterupload\.com/\w+' - - __description__ = """EnterUpload.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(EnteruploadCom) diff --git a/module/plugins/hoster/EpicShareNet.py b/module/plugins/hoster/EpicShareNet.py deleted file mode 100644 index 061782468..000000000 --- a/module/plugins/hoster/EpicShareNet.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class EpicShareNet(DeadHoster): - __name__ = "EpicShareNet" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'https?://(?:www\.)?epicshare\.net/\w{12}' - - __description__ = """EpicShare.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("t4skforce", "t4skforce1337[AT]gmail[DOT]com")] - - -getInfo = create_getInfo(EpicShareNet) diff --git a/module/plugins/hoster/EuroshareEu.py b/module/plugins/hoster/EuroshareEu.py deleted file mode 100644 index 41cc37087..000000000 --- a/module/plugins/hoster/EuroshareEu.py +++ /dev/null @@ -1,67 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class EuroshareEu(SimpleHoster): - __name__ = "EuroshareEu" - __type__ = "hoster" - __version__ = "0.27" - - __pattern__ = r'http://(?:www\.)?euroshare\.(eu|sk|cz|hu|pl)/file/.+' - - __description__ = """Euroshare.eu hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - INFO_PATTERN = r'<span style="float: left;"><strong>(?P<N>.+?)</strong> \((?P<S>.+?)\)</span>' - OFFLINE_PATTERN = ur'<h2>S.bor sa nena.iel</h2>|PoÅŸadovaná stránka neexistuje!' - - LINK_FREE_PATTERN = r'<a href="(/file/\d+/[^/]*/download/)"><div class="downloadButton"' - - ERR_PARDL_PATTERN = r'<h2>Prebieha s.ahovanie</h2>|<p>Naraz je z jednej IP adresy mo.n. s.ahova. iba jeden s.bor' - ERR_NOT_LOGGED_IN_PATTERN = r'href="/customer-zone/login/"' - - URL_REPLACEMENTS = [(r"(http://[^/]*\.)(sk|cz|hu|pl)/", r"\1eu/")] - - - def handlePremium(self, pyfile): - if self.ERR_NOT_LOGGED_IN_PATTERN in self.html: - self.account.relogin(self.user) - self.retry(reason=_("User not logged in")) - - self.download(pyfile.url.rstrip('/') + "/download/") - - check = self.checkDownload({"login": re.compile(self.ERR_NOT_LOGGED_IN_PATTERN), - "json" : re.compile(r'\{"status":"error".*?"message":"(.*?)"')}) - - if check == "login" or (check == "json" and self.lastCheck.group(1) == "Access token expired"): - self.account.relogin(self.user) - self.retry(reason=_("Access token expired")) - - elif check == "json": - self.fail(self.lastCheck.group(1)) - - - def handleFree(self, pyfile): - if re.search(self.ERR_PARDL_PATTERN, self.html) is not None: - self.longWait(5 * 60, 12) - - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("LINK_FREE_PATTERN not found")) - - self.link = "http://euroshare.eu%s" % m.group(1) - - - def checkFile(self): - if self.checkDownload({"multi-dl": re.compile(self.ERR_PARDL_PATTERN)}) - self.longWait(5 * 60, 12) - - return super(EuroshareEu, self).checkFile() - - -getInfo = create_getInfo(EuroshareEu) diff --git a/module/plugins/hoster/ExashareCom.py b/module/plugins/hoster/ExashareCom.py deleted file mode 100644 index 536c09b6d..000000000 --- a/module/plugins/hoster/ExashareCom.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo - - -class ExashareCom(XFSHoster): - __name__ = "ExashareCom" - __type__ = "hoster" - __version__ = "0.01" - - __pattern__ = r'http://(?:www\.)?exashare\.com/\w{12}' - - __description__ = """Exashare.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - INFO_PATTERN = r'>(?P<NAME>.+?)<small>\( (?P<S>[\d.,]+) (?P<U>[\w^_]+)' - LINK_FREE_PATTERN = r'file: "(.+?)"' - - - def setup(self): - self.multiDL = True - self.chunkLimit = 1 - self.resumeDownload = self.premium - - - def handleFree(self, pyfile): - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("Free download link not found")) - else: - self.link = m.group(1) - - -getInfo = create_getInfo(ExashareCom) diff --git a/module/plugins/hoster/ExtabitCom.py b/module/plugins/hoster/ExtabitCom.py deleted file mode 100644 index f9f76b28b..000000000 --- a/module/plugins/hoster/ExtabitCom.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.utils import json_loads - -from module.plugins.internal.CaptchaService import ReCaptcha -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, secondsToMidnight - - -class ExtabitCom(SimpleHoster): - __name__ = "ExtabitCom" - __type__ = "hoster" - __version__ = "0.65" - - __pattern__ = r'http://(?:www\.)?extabit\.com/(file|go|fid)/(?P<ID>\w+)' - - __description__ = """Extabit.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<th>File:</th>\s*<td class="col-fileinfo">\s*<div title="(?P<N>[^"]+)">' - SIZE_PATTERN = r'<th>Size:</th>\s*<td class="col-fileinfo">(?P<S>[^<]+)</td>' - OFFLINE_PATTERN = r'>File not found<' - TEMP_OFFLINE_PATTERN = r'>(File is temporary unavailable|No download mirror)<' - - LINK_FREE_PATTERN = r'[\'"](http://guest\d+\.extabit\.com/\w+/.*?)[\'"]' - - - def handleFree(self, pyfile): - if r">Only premium users can download this file" in self.html: - self.fail(_("Only premium users can download this file")) - - m = re.search(r"Next free download from your ip will be available in <b>(\d+)\s*minutes", self.html) - if m: - self.wait(int(m.group(1)) * 60, True) - elif "The daily downloads limit from your IP is exceeded" in self.html: - self.logWarning(_("You have reached your daily downloads limit for today")) - self.wait(secondsToMidnight(gmt=2), True) - - self.logDebug("URL: " + self.req.http.lastEffectiveURL) - m = re.match(self.__pattern__, self.req.http.lastEffectiveURL) - fileID = m.group('ID') if m else self.info['pattern']['ID'] - - m = re.search(r'recaptcha/api/challenge\?k=(\w+)', self.html) - if m: - recaptcha = ReCaptcha(self) - captcha_key = m.group(1) - - for _i in xrange(5): - get_data = {"type": "recaptcha"} - get_data['capture'], get_data['challenge'] = recaptcha.challenge(captcha_key) - res = json_loads(self.load("http://extabit.com/file/%s/" % fileID, get=get_data)) - if "ok" in res: - self.correctCaptcha() - break - else: - self.invalidCaptcha() - else: - self.fail(_("Invalid captcha")) - else: - self.error(_("Captcha")) - - if not "href" in res: - self.error(_("Bad JSON response")) - - self.html = self.load("http://extabit.com/file/%s%s" % (fileID, res['href'])) - - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("LINK_FREE_PATTERN not found")) - - url = m.group(1) - self.download(url) - - -getInfo = create_getInfo(ExtabitCom) diff --git a/module/plugins/hoster/FastixRu.py b/module/plugins/hoster/FastixRu.py deleted file mode 100644 index 8f1b9e694..000000000 --- a/module/plugins/hoster/FastixRu.py +++ /dev/null @@ -1,66 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from random import randrange -from urllib import unquote - -from pyload.utils import json_loads -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo - - -class FastixRu(MultiHoster): - __name__ = "FastixRu" - __type__ = "hoster" - __version__ = "0.09" - - __pattern__ = r'http://(?:www\.)?fastix\.(ru|it)/file/\w{24}' - - __description__ = """Fastix multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Massimo Rosamilia", "max@spiritix.eu")] - - - def getFilename(self, url): - try: - name = unquote(url.rsplit("/", 1)[1]) - except IndexError: - name = "Unknown_Filename..." - if name.endswith("..."): # incomplete filename, append random stuff - name += "%s.tmp" % randrange(100, 999) - return name - - - def setup(self): - self.chunkLimit = 3 - - - def handlePremium(self, pyfile): - api_key = self.account.getAccountData(self.user) - api_key = api_key['api'] - - self.html = self.load("http://fastix.ru/api_v2/", - get={'apikey': api_key, 'sub': "getdirectlink", 'link': pyfile.url}) - - data = json_loads(self.html) - - self.logDebug("Json data", data) - - if "error\":true" in self.html: - self.offline() - else: - self.link = data['downloadlink'] - - if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown"): - #only use when name wasnt already set - pyfile.name = self.getFilename(self.link) - - - def checkFile(self): - if self.checkDownload({"error": "<title>An error occurred while processing your request</title>"}): - self.retry(wait_time=60, reason=_("An error occurred while generating link")) - - return super(FastixRu, self).checkFile() - - -getInfo = create_getInfo(FastixRu) diff --git a/module/plugins/hoster/FastshareCz.py b/module/plugins/hoster/FastshareCz.py deleted file mode 100644 index 6fe871ad4..000000000 --- a/module/plugins/hoster/FastshareCz.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urlparse import urljoin - -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class FastshareCz(SimpleHoster): - __name__ = "FastshareCz" - __type__ = "hoster" - __version__ = "0.27" - - __pattern__ = r'http://(?:www\.)?fastshare\.cz/\d+/.+' - - __description__ = """FastShare.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - URL_REPLACEMENTS = [("#.*", "")] - - COOKIES = [("fastshare.cz", "lang", "en")] - - INFO_PATTERN = r'<h1 class="dwp">(?P<N>[^<]+)</h1>\s*<div class="fileinfo">\s*Size\s*: (?P<S>\d+) (?P<U>[\w^_]+),' - OFFLINE_PATTERN = r'>(The file has been deleted|Requested page not found)' - - LINK_FREE_PATTERN = r'action=(/free/.*?)>\s*<img src="([^"]*)"><br' - LINK_PREMIUM_PATTERN = r'(http://data\d+\.fastshare\.cz/download\.php\?id=\d+&)' - - SLOT_ERROR = "> 100% of FREE slots are full" - CREDIT_ERROR = " credit for " - - - def checkErrors(self): - if self.SLOT_ERROR in self.html: - errmsg = self.info['error'] = _("No free slots") - self.retry(12, 60, errmsg) - - if self.CREDIT_ERROR in self.html: - errmsg = self.info['error'] = _("Not enough traffic left") - self.logWarning(errmsg) - self.resetAccount() - - self.info.pop('error', None) - - - def handleFree(self, pyfile): - m = re.search(self.FREE_URL_PATTERN, self.html) - if m: - action, captcha_src = m.groups() - else: - self.error(_("FREE_URL_PATTERN not found")) - - baseurl = "http://www.fastshare.cz" - captcha = self.decryptCaptcha(urljoin(baseurl, captcha_src)) - self.download(urljoin(baseurl, action), post={'code': captcha, 'btn.x': 77, 'btn.y': 18}) - - - def checkFile(self): - check = self.checkDownload({ - 'paralell-dl' : re.compile(r"<title>FastShare.cz</title>|<script>alert\('Pres FREE muzete stahovat jen jeden soubor najednou.'\)"), - 'wrong captcha': re.compile(r'Download for FREE'), - 'credit' : re.compile(self.CREDIT_ERROR) - }) - - if check == "paralell-dl": - self.retry(6, 10 * 60, _("Paralell download")) - - elif check == "wrong captcha": - self.retry(max_tries=5, reason=_("Wrong captcha")) - - elif check == "credit": - self.resetAccount() - - return super(FastshareCz, self).checkFile() - - -getInfo = create_getInfo(FastshareCz) diff --git a/module/plugins/hoster/FileApeCom.py b/module/plugins/hoster/FileApeCom.py deleted file mode 100644 index 212e3ba9c..000000000 --- a/module/plugins/hoster/FileApeCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class FileApeCom(DeadHoster): - __name__ = "FileApeCom" - __type__ = "hoster" - __version__ = "0.12" - - __pattern__ = r'http://(?:www\.)?fileape\.com/(index\.php\?act=download\&id=|dl/)\w+' - - __description__ = """FileApe.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("espes", "")] - - -getInfo = create_getInfo(FileApeCom) diff --git a/module/plugins/hoster/FileSharkPl.py b/module/plugins/hoster/FileSharkPl.py deleted file mode 100644 index 29c95ee8f..000000000 --- a/module/plugins/hoster/FileSharkPl.py +++ /dev/null @@ -1,133 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urlparse import urljoin - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class FileSharkPl(SimpleHoster): - __name__ = "FileSharkPl" - __type__ = "hoster" - __version__ = "0.07" - - __pattern__ = r'http://(?:www\.)?fileshark\.pl/pobierz/\d+/\w+' - - __description__ = """FileShark.pl hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("prOq", ""), - ("Walter Purcaro", "vuolter@gmail.com")] - - - NAME_PATTERN = r'<h2 class="name-file">(?P<N>.+)</h2>' - SIZE_PATTERN = r'<p class="size-file">(.*?)<strong>(?P<S>\d+\.?\d*)\s(?P<U>\w+)</strong></p>' - - OFFLINE_PATTERN = '(P|p)lik zosta. (usuni.ty|przeniesiony)' - - LINK_FREE_PATTERN = r'<a href="(.*?)" class="btn-upload-free">' - LINK_PREMIUM_PATTERN = r'<a href="(.*?)" class="btn-upload-premium">' - - WAIT_PATTERN = r'var timeToDownload = (\d+);' - ERROR_PATTERN = r'<p class="lead text-center alert alert-warning">(.*?)</p>' - IP_ERROR_PATTERN = r'Strona jest dost.pna wy..cznie dla u.ytkownik.w znajduj.cych si. na terenie Polski' - SLOT_ERROR_PATTERN = r'Osi.gni.to maksymaln. liczb. .ci.ganych jednocze.nie plik.w\.' - - CAPTCHA_PATTERN = '<img src="data:image/jpeg;base64,(.*?)" title="captcha"' - TOKEN_PATTERN = r'name="form\[_token\]" value="(.*?)" />' - - - def setup(self): - self.resumeDownload = True - - if self.premium: - self.multiDL = True - self.limitDL = 20 - else: - self.multiDL = False - - - def checkErrors(self): - # check if file is now available for download (-> file name can be found in html body) - m = re.search(self.WAIT_PATTERN, self.html) - if m: - errmsg = self.info['error'] = _("Another download already run") - self.retry(15, int(m.group(1)), errmsg) - - m = re.search(self.ERROR_PATTERN, self.html) - if m: - alert = m.group(1) - - if re.match(self.IP_ERROR_PATTERN, alert): - self.fail(_("Only connections from Polish IP are allowed")) - - elif re.match(self.SLOT_ERROR_PATTERN, alert): - errmsg = self.info['error'] = _("No free download slots available") - self.logWarning(errmsg) - self.retry(10, 30 * 60, _("Still no free download slots available")) - - else: - self.info['error'] = alert - self.retry(10, 10 * 60, _("Try again later")) - - self.info.pop('error', None) - - - def handleFree(self, pyfile): - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("Download url not found")) - - link = urljoin("http://fileshark.pl", m.group(1)) - - m = re.search(self.WAIT_PATTERN, self.html) - if m: - seconds = int(m.group(1)) - self.logDebug("Wait %s seconds" % seconds) - self.wait(seconds) - - action, inputs = self.parseHtmlForm('action=""') - - m = re.search(self.TOKEN_PATTERN, self.html) - if m is None: - self.retry(reason=_("Captcha form not found")) - - inputs['form[_token]'] = m.group(1) - - m = re.search(self.CAPTCHA_PATTERN, self.html) - if m is None: - self.retry(reason=_("Captcha image not found")) - - tmp_load = self.load - self.load = self._decode64 #: work-around: injects decode64 inside decryptCaptcha - - inputs['form[captcha]'] = self.decryptCaptcha(m.group(1), imgtype='jpeg') - inputs['form[start]'] = "" - - self.load = tmp_load - - self.download(link, post=inputs, cookies=True, disposition=True) - - - def checkFile(self): - check = self.checkDownload({'wrong_captcha': re.compile(r'<label for="form_captcha" generated="true" class="error">(.*?)</label>'), - 'wait_pattern' : re.compile(self.SECONDS_PATTERN), - 'DL-found' : re.compile('<a href="(.*)">')}) - if check == "DL-found": - self.correctCaptcha() - - elif check == "wrong_captcha": - self.invalidCaptcha() - self.retry(10, 1, _("Wrong captcha solution")) - - elif check == "wait_pattern": - self.retry() - - return super(FileSharkPl, self).checkFile() - - - def _decode64(self, data, *args, **kwargs): - return data.decode('base64') - - -getInfo = create_getInfo(FileSharkPl) diff --git a/module/plugins/hoster/FileStoreTo.py b/module/plugins/hoster/FileStoreTo.py deleted file mode 100644 index 8a5171219..000000000 --- a/module/plugins/hoster/FileStoreTo.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class FileStoreTo(SimpleHoster): - __name__ = "FileStoreTo" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'http://(?:www\.)?filestore\.to/\?d=(?P<ID>\w+)' - - __description__ = """FileStore.to hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com"), - ("stickell", "l.stickell@yahoo.it")] - - - INFO_PATTERN = r'File: <span.*?>(?P<N>.+?)<.*>Size: (?P<S>[\d.,]+) (?P<U>[\w^_]+)' - OFFLINE_PATTERN = r'>Download-Datei wurde nicht gefunden<' - TEMP_OFFLINE_PATTERN = r'>Der Download ist nicht bereit !<' - - - def setup(self): - self.resumeDownload = True - self.multiDL = True - - - def handleFree(self, pyfile): - self.wait(10) - self.link = self.load("http://filestore.to/ajax/download.php", - get={'D': re.search(r'"D=(\w+)', self.html).group(1)}) - - -getInfo = create_getInfo(FileStoreTo) diff --git a/module/plugins/hoster/FilebeerInfo.py b/module/plugins/hoster/FilebeerInfo.py deleted file mode 100644 index 51a0137a0..000000000 --- a/module/plugins/hoster/FilebeerInfo.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class FilebeerInfo(DeadHoster): - __name__ = "FilebeerInfo" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?filebeer\.info/(?!\d*~f)(?P<ID>\w+)' - - __description__ = """Filebeer.info plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(FilebeerInfo) diff --git a/module/plugins/hoster/FilecloudIo.py b/module/plugins/hoster/FilecloudIo.py deleted file mode 100644 index 6fb153658..000000000 --- a/module/plugins/hoster/FilecloudIo.py +++ /dev/null @@ -1,126 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.utils import json_loads -from pyload.plugin.internal.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class FilecloudIo(SimpleHoster): - __name__ = "FilecloudIo" - __type__ = "hoster" - __version__ = "0.08" - - __pattern__ = r'http://(?:www\.)?(?:filecloud\.io|ifile\.it|mihd\.net)/(?P<ID>\w+)' - - __description__ = """Filecloud.io hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("stickell", "l.stickell@yahoo.it")] - - - LOGIN_ACCOUNT = True - - NAME_PATTERN = r'id="aliasSpan">(?P<N>.*?) <' - SIZE_PATTERN = r'{var __ab1 = (?P<S>\d+);}' - OFFLINE_PATTERN = r'l10n\.(FILES__DOESNT_EXIST|REMOVED)' - TEMP_OFFLINE_PATTERN = r'l10n\.FILES__WARNING' - - UKEY_PATTERN = r'\'ukey\'\s*:\'(\w+)' - AB1_PATTERN = r'if\( __ab1 == \'(\w+)\' \)' - - ERROR_MSG_PATTERN = r'var __error_msg\s*=\s*l10n\.(.*?);' - - RECAPTCHA_PATTERN = r'var __recaptcha_public\s*=\s*\'(.+?)\';' - - LINK_FREE_PATTERN = r'"(http://s\d+\.filecloud\.io/%s/\d+/.*?)"' - - - def setup(self): - self.resumeDownload = True - self.multiDL = True - self.chunkLimit = 1 - - - def handleFree(self, pyfile): - data = {"ukey": self.info['pattern']['ID']} - - m = re.search(self.AB1_PATTERN, self.html) - if m is None: - self.error(_("__AB1")) - data['__ab1'] = m.group(1) - - recaptcha = ReCaptcha(self) - - m = re.search(self.RECAPTCHA_PATTERN, self.html) - captcha_key = m.group(1) if m else recaptcha.detect_key() - - if captcha_key is None: - self.error(_("ReCaptcha key not found")) - - response, challenge = recaptcha.challenge(captcha_key) - self.account.form_data = {"recaptcha_challenge_field": challenge, - "recaptcha_response_field" : response} - self.account.relogin(self.user) - self.retry(2) - - json_url = "http://filecloud.io/download-request.json" - res = self.load(json_url, post=data) - self.logDebug(res) - res = json_loads(res) - - if "error" in res and res['error']: - self.fail(res) - - self.logDebug(res) - if res['captcha']: - data['ctype'] = "recaptcha" - - for _i in xrange(5): - data['recaptcha_response'], data['recaptcha_challenge'] = recaptcha.challenge(captcha_key) - - json_url = "http://filecloud.io/download-request.json" - res = self.load(json_url, post=data) - self.logDebug(res) - res = json_loads(res) - - if "retry" in res and res['retry']: - self.invalidCaptcha() - else: - self.correctCaptcha() - break - else: - self.fail(_("Incorrect captcha")) - - if res['dl']: - self.html = self.load('http://filecloud.io/download.html') - - m = re.search(self.LINK_FREE_PATTERN % self.info['pattern']['ID'], self.html) - if m is None: - self.error(_("LINK_FREE_PATTERN not found")) - - if "size" in self.info and self.info['size']: - self.check_data = {"size": int(self.info['size'])} - - download_url = m.group(1) - self.download(download_url) - else: - self.fail(_("Unexpected server response")) - - - def handlePremium(self, pyfile): - akey = self.account.getAccountData(self.user)['akey'] - ukey = self.info['pattern']['ID'] - self.logDebug("Akey: %s | Ukey: %s" % (akey, ukey)) - rep = self.load("http://api.filecloud.io/api-fetch_download_url.api", - post={"akey": akey, "ukey": ukey}) - self.logDebug("FetchDownloadUrl: " + rep) - rep = json_loads(rep) - if rep['status'] == 'ok': - self.link = rep['download_url'] - else: - self.fail(rep['message']) - - -getInfo = create_getInfo(FilecloudIo) diff --git a/module/plugins/hoster/FileomCom.py b/module/plugins/hoster/FileomCom.py deleted file mode 100644 index 23f059546..000000000 --- a/module/plugins/hoster/FileomCom.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# http://fileom.com/gycaytyzdw3g/random.bin.html - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class FileomCom(XFSHoster): - __name__ = "FileomCom" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'https?://(?:www\.)?fileom\.com/\w{12}' - - __description__ = """Fileom.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - NAME_PATTERN = r'Filename: <span>(?P<N>.+?)<' - SIZE_PATTERN = r'File Size: <span class="size">(?P<S>[\d.,]+) (?P<U>[\w^_]+)' - - LINK_PATTERN = r'var url2 = \'(.+?)\';' - - - def setup(self): - self.multiDL = True - self.chunkLimit = 1 - self.resumeDownload = self.premium - - -getInfo = create_getInfo(FileomCom) diff --git a/module/plugins/hoster/FilepostCom.py b/module/plugins/hoster/FilepostCom.py deleted file mode 100644 index 89f7fe9a4..000000000 --- a/module/plugins/hoster/FilepostCom.py +++ /dev/null @@ -1,133 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from time import time - -from pyload.utils import json_loads -from pyload.plugin.internal.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class FilepostCom(SimpleHoster): - __name__ = "FilepostCom" - __type__ = "hoster" - __version__ = "0.33" - - __pattern__ = r'https?://(?:www\.)?(?:filepost\.com/files|fp\.io)/(?P<ID>[^/]+)' - - __description__ = """Filepost.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - INFO_PATTERN = r'<input type="text" id="url" value=\'<a href[^>]*>(?P<N>[^>]+?) - (?P<S>[\d.,]+) (?P<U>[\w^_]+)</a>\' class="inp_text"/>' - OFFLINE_PATTERN = r'class="error_msg_title"> Invalid or Deleted File. </div>|<div class="file_info file_info_deleted">' - - PREMIUM_ONLY_PATTERN = r'members only. Please upgrade to premium|a premium membership is required to download this file' - RECAPTCHA_PATTERN = r'Captcha.init\({\s*key:\s*\'(.+?)\'' - FLP_TOKEN_PATTERN = r'set_store_options\({token: \'(.+?)\'' - - - def handleFree(self, pyfile): - m = re.search(self.FLP_TOKEN_PATTERN, self.html) - if m is None: - self.error(_("Token")) - flp_token = m.group(1) - - m = re.search(self.RECAPTCHA_PATTERN, self.html) - if m is None: - self.error(_("Captcha key")) - captcha_key = m.group(1) - - # Get wait time - get_dict = {'SID': self.req.cj.getCookie('SID'), 'JsHttpRequest': str(int(time() * 10000)) + '-xml'} - post_dict = {'action': 'set_download', 'token': flp_token, 'code': self.info['pattern']['ID']} - wait_time = int(self.getJsonResponse(get_dict, post_dict, 'wait_time')) - - if wait_time > 0: - self.wait(wait_time) - - post_dict = {"token": flp_token, "code": self.info['pattern']['ID'], "file_pass": ''} - - if 'var is_pass_exists = true;' in self.html: - # Solve password - password = self.getPassword() - - if password: - self.logInfo(_("Password protected link, trying ") + file_pass) - - get_dict['JsHttpRequest'] = str(int(time() * 10000)) + '-xml' - post_dict['file_pass'] = file_pass - - self.link = self.getJsonResponse(get_dict, post_dict, 'link') - - if not self.link: - self.fail(_("Incorrect password")) - else: - self.fail(_("No password found")) - - else: - # Solve recaptcha - recaptcha = ReCaptcha(self) - - for i in xrange(5): - get_dict['JsHttpRequest'] = str(int(time() * 10000)) + '-xml' - if i: - post_dict['recaptcha_response_field'], post_dict['recaptcha_challenge_field'] = recaptcha.challenge( - captcha_key) - self.logDebug(u"RECAPTCHA: %s : %s : %s" % ( - captcha_key, post_dict['recaptcha_challenge_field'], post_dict['recaptcha_response_field'])) - - download_url = self.getJsonResponse(get_dict, post_dict, 'link') - if download_url: - if i: - self.correctCaptcha() - break - elif i: - self.invalidCaptcha() - - else: - self.fail(_("Invalid captcha")) - - # Download - self.download(download_url) - - - def getJsonResponse(self, get_dict, post_dict, field): - res = json_loads(self.load('https://filepost.com/files/get/', get=get_dict, post=post_dict)) - - self.logDebug(res) - - if not 'js' in res: - self.error(_("JSON %s 1") % field) - - # i changed js_answer to res['js'] since js_answer is nowhere set. - # i don't know the JSON-HTTP specs in detail, but the previous author - # accessed res['js']['error'] as well as js_answer['error']. - # see the two lines commented out with "# ~?". - if 'error' in res['js']: - - if res['js']['error'] == 'download_delay': - self.retry(wait_time=res['js']['params']['next_download']) - # ~? self.retry(wait_time=js_answer['params']['next_download']) - - elif 'Wrong file password' in res['js']['error'] \ - or 'You entered a wrong CAPTCHA code' in res['js']['error'] \ - or 'CAPTCHA Code nicht korrekt' in res['js']['error']: - return None - - elif 'CAPTCHA' in res['js']['error']: - self.logDebug("Error response is unknown, but mentions CAPTCHA") - return None - - else: - self.fail(res['js']['error']) - - if not 'answer' in res['js'] or not field in res['js']['answer']: - self.error(_("JSON %s 2") % field) - - return res['js']['answer'][field] - - -getInfo = create_getInfo(FilepostCom) diff --git a/module/plugins/hoster/FilepupNet.py b/module/plugins/hoster/FilepupNet.py deleted file mode 100644 index 6ac9994cc..000000000 --- a/module/plugins/hoster/FilepupNet.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# http://www.filepup.net/files/k5w4ZVoF1410184283.html -# http://www.filepup.net/files/R4GBq9XH1410186553.html - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class FilepupNet(SimpleHoster): - __name__ = "FilepupNet" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?filepup\.net/files/\w+' - - __description__ = """Filepup.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - NAME_PATTERN = r'>(?P<N>.+?)</h1>' - SIZE_PATTERN = r'class="fa fa-archive"></i> \((?P<S>[\d.,]+) (?P<U>[\w^_]+)' - - OFFLINE_PATTERN = r'>This file has been deleted' - - LINK_FREE_PATTERN = r'(http://www\.filepup\.net/get/.+?)\'' - - - def setup(self): - self.multiDL = False - self.chunkLimit = 1 - - - def handleFree(self, pyfile): - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("Download link not found")) - - dl_link = m.group(1) - self.download(dl_link, post={'task': "download"}) - - -getInfo = create_getInfo(FilepupNet) diff --git a/module/plugins/hoster/FilerNet.py b/module/plugins/hoster/FilerNet.py deleted file mode 100644 index 85ff7da33..000000000 --- a/module/plugins/hoster/FilerNet.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# http://filer.net/get/ivgf5ztw53et3ogd -# http://filer.net/get/hgo14gzcng3scbvv - -import pycurl -import re - -from urlparse import urljoin - -from pyload.plugin.internal.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class FilerNet(SimpleHoster): - __name__ = "FilerNet" - __type__ = "hoster" - __version__ = "0.16" - - __pattern__ = r'https?://(?:www\.)?filer\.net/get/\w+' - - __description__ = """Filer.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - INFO_PATTERN = r'<h1 class="page-header">Free Download (?P<N>\S+) <small>(?P<S>[\w.]+) (?P<U>[\w^_]+)</small></h1>' - OFFLINE_PATTERN = r'Nicht gefunden' - - LINK_FREE_PATTERN = LINK_PREMIUM_PATTERN = r'href="([^"]+)">Get download</a>' - - - def checkErrors(self): - # Wait between downloads - m = re.search(r'musst du <span id="time">(\d+)</span> Sekunden warten', self.html) - if m: - errmsg = self.info['error'] = _("Wait between free downloads") - self.retry(wait_time=int(m.group(1)), reason=errmsg) - - self.info.pop('error', None) - - - def handleFree(self, pyfile): - inputs = self.parseHtmlForm(input_names={'token': re.compile(r'.+')})[1] - if 'token' not in inputs: - self.error(_("Unable to detect token")) - - self.html = self.load(pyfile.url, post={'token': inputs['token']}, decode=True) - - inputs = self.parseHtmlForm(input_names={'hash': re.compile(r'.+')})[1] - if 'hash' not in inputs: - self.error(_("Unable to detect hash")) - - recaptcha = ReCaptcha(self) - response, challenge = recaptcha.challenge() - - #@NOTE: Work-around for v0.4.9 just_header issue - #@TODO: Check for v0.4.10 - self.req.http.c.setopt(pycurl.FOLLOWLOCATION, 0) - self.load(pyfile.url, post={'recaptcha_challenge_field': challenge, - 'recaptcha_response_field' : response, - 'hash' : inputs['hash']}) - self.req.http.c.setopt(pycurl.FOLLOWLOCATION, 1) - - if 'location' in self.req.http.header.lower(): - self.link = re.search(r'location: (\S+)', self.req.http.header, re.I).group(1) - self.correctCaptcha() - else: - self.invalidCaptcha() - - -getInfo = create_getInfo(FilerNet) diff --git a/module/plugins/hoster/FilerioCom.py b/module/plugins/hoster/FilerioCom.py deleted file mode 100644 index 12b7e7705..000000000 --- a/module/plugins/hoster/FilerioCom.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class FilerioCom(XFSHoster): - __name__ = "FilerioCom" - __type__ = "hoster" - __version__ = "0.07" - - __pattern__ = r'http://(?:www\.)?(filerio\.(in|com)|filekeen\.com)/\w{12}' - - __description__ = """FileRio.in hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - URL_REPLACEMENTS = [(r'filekeen\.com', "filerio.in")] - - OFFLINE_PATTERN = r'>"File Not Found|File has been removed' - - -getInfo = create_getInfo(FilerioCom) diff --git a/module/plugins/hoster/FileserveCom.py b/module/plugins/hoster/FileserveCom.py deleted file mode 100644 index cc977ac25..000000000 --- a/module/plugins/hoster/FileserveCom.py +++ /dev/null @@ -1,216 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.common.json_layer import json_loads -from module.network.RequestFactory import getURL -from module.plugins.Hoster import Hoster -from module.plugins.Plugin import chunks -from module.plugins.internal.CaptchaService import ReCaptcha -from module.plugins.internal.SimpleHoster import secondsToMidnight -from module.utils import parseFileSize - - -def checkFile(plugin, urls): - html = getURL(plugin.URLS[1], post={"urls": "\n".join(urls)}, decode=True) - - file_info = [] - for li in re.finditer(plugin.LINKCHECK_TR, html, re.S): - try: - cols = re.findall(plugin.LINKCHECK_TD, li.group(1)) - if cols: - file_info.append(( - cols[1] if cols[1] != '--' else cols[0], - parseFileSize(cols[2]) if cols[2] != '--' else 0, - 2 if cols[3].startswith('Available') else 1, - cols[0])) - except Exception, e: - continue - - return file_info - - -class FileserveCom(Hoster): - __name__ = "FileserveCom" - __type__ = "hoster" - __version__ = "0.54" - - __pattern__ = r'http://(?:www\.)?fileserve\.com/file/(?P<ID>[^/]+)' - - __description__ = """Fileserve.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("jeix", "jeix@hasnomail.de"), - ("mkaay", "mkaay@mkaay.de"), - ("Paul King", ""), - ("zoidberg", "zoidberg@mujmail.cz")] - - - URLS = ["http://www.fileserve.com/file/", "http://www.fileserve.com/link-checker.php", - "http://www.fileserve.com/checkReCaptcha.php"] - LINKCHECK_TR = r'<tr>\s*(<td>http://www\.fileserve\.com/file/.*?)</tr>' - LINKCHECK_TD = r'<td>(?:<[^>]*>| )*([^<]*)' - - CAPTCHA_KEY_PATTERN = r'var reCAPTCHA_publickey=\'(.+?)\'' - LONG_WAIT_PATTERN = r'<li class="title">You need to wait (\d+) (\w+) to start another download\.</li>' - LINK_EXPIRED_PATTERN = r'Your download link has expired' - DAILY_LIMIT_PATTERN = r'Your daily download limit has been reached' - NOT_LOGGED_IN_PATTERN = r'<form (name="loginDialogBoxForm"|id="login_form")|<li><a href="/login\.php">Login</a></li>' - - - def setup(self): - self.resumeDownload = self.multiDL = self.premium - self.file_id = re.match(self.__pattern__, self.pyfile.url).group('ID') - self.url = "%s%s" % (self.URLS[0], self.file_id) - - self.logDebug("File ID: %s URL: %s" % (self.file_id, self.url)) - - - def process(self, pyfile): - pyfile.name, pyfile.size, status, self.url = checkFile(self, [self.url])[0] - if status != 2: - self.offline() - self.logDebug("File Name: %s Size: %d" % (pyfile.name, pyfile.size)) - - if self.premium: - self.handlePremium() - else: - self.handleFree() - - - def handleFree(self): - self.html = self.load(self.url) - action = self.load(self.url, post={"checkDownload": "check"}, decode=True) - action = json_loads(action) - self.logDebug(action) - - if "fail" in action: - if action['fail'] == "timeLimit": - self.html = self.load(self.url, post={"checkDownload": "showError", "errorType": "timeLimit"}, - decode=True) - - self.doLongWait(re.search(self.LONG_WAIT_PATTERN, self.html)) - - elif action['fail'] == "parallelDownload": - self.logWarning(_("Parallel download error, now waiting 60s")) - self.retry(wait_time=60, reason=_("parallelDownload")) - - else: - self.fail(_("Download check returned: %s") % action['fail']) - - elif "success" in action: - if action['success'] == "showCaptcha": - self.doCaptcha() - self.doTimmer() - elif action['success'] == "showTimmer": - self.doTimmer() - - else: - self.error(_("Unknown server response")) - - # show download link - res = self.load(self.url, post={"downloadLink": "show"}, decode=True) - self.logDebug("Show downloadLink response: %s" % res) - if "fail" in res: - self.error(_("Couldn't retrieve download url")) - - # this may either download our file or forward us to an error page - self.download(self.url, post={"download": "normal"}) - self.logDebug(self.req.http.lastEffectiveURL) - - check = self.checkDownload({"expired": self.LINK_EXPIRED_PATTERN, - "wait" : re.compile(self.LONG_WAIT_PATTERN), - "limit" : self.DAILY_LIMIT_PATTERN}) - - if check == "expired": - self.logDebug("Download link was expired") - self.retry() - - elif check == "wait": - self.doLongWait(self.lastCheck) - - elif check == "limit": - self.logWarning(_("Download limited reached for today")) - self.setWait(secondsToMidnight(gmt=2), True) - self.wait() - self.retry() - - self.thread.m.reconnecting.wait(3) # Ease issue with later downloads appearing to be in parallel - - - def doTimmer(self): - res = self.load(self.url, post={"downloadLink": "wait"}, decode=True) - self.logDebug("Wait response: %s" % res[:80]) - - if "fail" in res: - self.fail(_("Failed getting wait time")) - - if self.__name__ == "FilejungleCom": - m = re.search(r'"waitTime":(\d+)', res) - if m is None: - self.fail(_("Cannot get wait time")) - wait_time = int(m.group(1)) - else: - wait_time = int(res) + 3 - - self.setWait(wait_time) - self.wait() - - - def doCaptcha(self): - captcha_key = re.search(self.CAPTCHA_KEY_PATTERN, self.html).group(1) - recaptcha = ReCaptcha(self) - - for _i in xrange(5): - response, challenge = recaptcha.challenge(captcha_key) - res = json_loads(self.load(self.URLS[2], - post={'recaptcha_challenge_field' : challenge, - 'recaptcha_response_field' : response, - 'recaptcha_shortencode_field': self.file_id})) - if not res['success']: - self.invalidCaptcha() - else: - self.correctCaptcha() - break - else: - self.fail(_("Invalid captcha")) - - - def doLongWait(self, m): - wait_time = (int(m.group(1)) * {'seconds': 1, 'minutes': 60, 'hours': 3600}[m.group(2)]) if m else 12 * 60 - self.setWait(wait_time, True) - self.wait() - self.retry() - - - def handlePremium(self): - premium_url = None - if self.__name__ == "FileserveCom": - #try api download - res = self.load("http://app.fileserve.com/api/download/premium/", - post={"username": self.user, - "password": self.account.getAccountData(self.user)['password'], - "shorten": self.file_id}, - decode=True) - if res: - res = json_loads(res) - if res['error_code'] == "302": - premium_url = res['next'] - elif res['error_code'] in ["305", "500"]: - self.tempOffline() - elif res['error_code'] in ["403", "605"]: - self.resetAccount() - elif res['error_code'] in ["606", "607", "608"]: - self.offline() - else: - self.logError(res['error_code'], res['error_message']) - - self.download(premium_url or self.pyfile.url) - - if not premium_url and self.checkDownload({"login": re.compile(self.NOT_LOGGED_IN_PATTERN)}): - self.account.relogin(self.user) - self.retry(reason=_("Not logged in")) - - -def getInfo(urls): - for chunk in chunks(urls, 100): - yield checkFile(FileserveCom, chunk) diff --git a/module/plugins/hoster/FileshareInUa.py b/module/plugins/hoster/FileshareInUa.py deleted file mode 100644 index 5f5089e54..000000000 --- a/module/plugins/hoster/FileshareInUa.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class FileshareInUa(DeadHoster): - __name__ = "FileshareInUa" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'https?://(?:www\.)?fileshare\.in\.ua/\w{7}' - - __description__ = """Fileshare.in.ua hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("fwannmacher", "felipe@warhammerproject.com")] - - -getInfo = create_getInfo(FileshareInUa) diff --git a/module/plugins/hoster/FilesonicCom.py b/module/plugins/hoster/FilesonicCom.py deleted file mode 100644 index c2b87d4d7..000000000 --- a/module/plugins/hoster/FilesonicCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class FilesonicCom(DeadHoster): - __name__ = "FilesonicCom" - __type__ = "hoster" - __version__ = "0.35" - - __pattern__ = r'http://(?:www\.)?filesonic\.com/file/\w+' - - __description__ = """Filesonic.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("jeix", "jeix@hasnomail.de"), - ("paulking", "")] - - -getInfo = create_getInfo(FilesonicCom) diff --git a/module/plugins/hoster/FilezyNet.py b/module/plugins/hoster/FilezyNet.py deleted file mode 100644 index 1fcc9363d..000000000 --- a/module/plugins/hoster/FilezyNet.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class FilezyNet(DeadHoster): - __name__ = "FilezyNet" - __type__ = "hoster" - __version__ = "0.20" - - __pattern__ = r'http://(?:www\.)?filezy\.net/\w{12}' - - __description__ = """Filezy.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [] - - -getInfo = create_getInfo(FilezyNet) diff --git a/module/plugins/hoster/FiredriveCom.py b/module/plugins/hoster/FiredriveCom.py deleted file mode 100644 index 3395fc261..000000000 --- a/module/plugins/hoster/FiredriveCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class FiredriveCom(DeadHoster): - __name__ = "FiredriveCom" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'https?://(?:www\.)?(firedrive|putlocker)\.com/(mobile/)?(file|embed)/(?P<ID>\w+)' - - __description__ = """Firedrive.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - -getInfo = create_getInfo(FiredriveCom) diff --git a/module/plugins/hoster/FourSharedCom.py b/module/plugins/hoster/FourSharedCom.py deleted file mode 100644 index 8d13ea0b7..000000000 --- a/module/plugins/hoster/FourSharedCom.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class FourSharedCom(SimpleHoster): - __name__ = "FourSharedCom" - __type__ = "hoster" - __version__ = "0.31" - - __pattern__ = r'https?://(?:www\.)?4shared(\-china)?\.com/(account/)?(download|get|file|document|photo|video|audio|mp3|office|rar|zip|archive|music)/.+' - - __description__ = """4Shared.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("jeix", "jeix@hasnomail.de"), - ("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<meta name="title" content="(?P<N>.+?)"' - SIZE_PATTERN = r'<span title="Size: (?P<S>[\d.,]+) (?P<U>[\w^_]+)">' - OFFLINE_PATTERN = r'The file link that you requested is not valid\.|This file was deleted.' - - NAME_REPLACEMENTS = [(r"&#(\d+).", lambda m: unichr(int(m.group(1))))] - SIZE_REPLACEMENTS = [(",", "")] - - DIRECT_LINK = False - LOGIN_ACCOUNT = True - - LINK_FREE_PATTERN = r'name="d3link" value="(.*?)"' - LINK_BTN_PATTERN = r'id="btnLink" href="(.*?)"' - - ID_PATTERN = r'name="d3fid" value="(.*?)"' - - - def handleFree(self, pyfile): - m = re.search(self.LINK_BTN_PATTERN, self.html) - if m: - link = m.group(1) - else: - link = re.sub(r'/(download|get|file|document|photo|video|audio)/', r'/get/', pyfile.url) - - self.html = self.load(link) - - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("Download link")) - - self.link = m.group(1) - - try: - m = re.search(self.ID_PATTERN, self.html) - res = self.load('http://www.4shared.com/web/d2/getFreeDownloadLimitInfo?fileId=%s' % m.group(1)) - self.logDebug(res) - except Exception: - pass - - self.wait(20) - - -getInfo = create_getInfo(FourSharedCom) diff --git a/module/plugins/hoster/FreakshareCom.py b/module/plugins/hoster/FreakshareCom.py deleted file mode 100644 index 9a11f933d..000000000 --- a/module/plugins/hoster/FreakshareCom.py +++ /dev/null @@ -1,180 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.Hoster import Hoster -from module.plugins.internal.CaptchaService import ReCaptcha -from module.plugins.internal.SimpleHoster import secondsToMidnight - - -class FreakshareCom(Hoster): - __name__ = "FreakshareCom" - __type__ = "hoster" - __version__ = "0.40" - - __pattern__ = r'http://(?:www\.)?freakshare\.(net|com)/files/\S*?/' - - __description__ = """Freakshare.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("sitacuisses", "sitacuisses@yahoo.de"), - ("spoob", "spoob@pyload.org"), - ("mkaay", "mkaay@mkaay.de"), - ("Toilal", "toilal.dev@gmail.com")] - - - def setup(self): - self.multiDL = False - self.req_opts = [] - - - def process(self, pyfile): - self.pyfile = pyfile - - pyfile.url = pyfile.url.replace("freakshare.net/", "freakshare.com/") - - if self.account: - self.html = self.load(pyfile.url, cookies=False) - pyfile.name = self.get_file_name() - self.download(pyfile.url) - - else: - self.prepare() - self.get_file_url() - - self.download(pyfile.url, post=self.req_opts) - - check = self.checkDownload({"bad" : "bad try", - "paralell" : "> Sorry, you cant download more then 1 files at time. <", - "empty" : "Warning: Unknown: Filename cannot be empty", - "wrong_captcha" : "Wrong Captcha!", - "downloadserver": "No Downloadserver. Please try again later!"}) - - if check == "bad": - self.fail(_("Bad Try")) - - elif check == "paralell": - self.setWait(300, True) - self.wait() - self.retry() - - elif check == "empty": - self.fail(_("File not downloadable")) - - elif check == "wrong_captcha": - self.invalidCaptcha() - self.retry() - - elif check == "downloadserver": - self.retry(5, 15 * 60, _("No Download server")) - - - def prepare(self): - pyfile = self.pyfile - - self.download_html() - - if not self.file_exists(): - self.offline() - - self.setWait(self.get_waiting_time()) - - pyfile.name = self.get_file_name() - pyfile.size = self.get_file_size() - - self.wait() - - return True - - - def download_html(self): - self.load("http://freakshare.com/index.php", {"language": "EN"}) # Set english language in server session - self.html = self.load(self.pyfile.url) - - - def get_file_url(self): - """ returns the absolute downloadable filepath - """ - if not self.html: - self.download_html() - if not self.wantReconnect: - self.req_opts = self.get_download_options() # get the Post options for the Request - #file_url = self.pyfile.url - #return file_url - else: - self.offline() - - - def get_file_name(self): - if not self.html: - self.download_html() - if not self.wantReconnect: - file_name = re.search(r"<h1\sclass=\"box_heading\"\sstyle=\"text-align:center;\">([^ ]+)", self.html) - if file_name is not None: - file_name = file_name.group(1) - else: - file_name = self.pyfile.url - return file_name - else: - return self.pyfile.url - - - def get_file_size(self): - size = 0 - if not self.html: - self.download_html() - if not self.wantReconnect: - file_size_check = re.search( - r"<h1\sclass=\"box_heading\"\sstyle=\"text-align:center;\">[^ ]+ - ([^ ]+) (\w\w)yte", self.html) - if file_size_check is not None: - units = float(file_size_check.group(1).replace(",", "")) - pow = {'KB': 1, 'MB': 2, 'GB': 3}[file_size_check.group(2)] - size = int(units * 1024 ** pow) - - return size - - - def get_waiting_time(self): - if not self.html: - self.download_html() - - if "Your Traffic is used up for today" in self.html: - self.wantReconnect = True - return secondsToMidnight(gmt=2) - - timestring = re.search('\s*var\s(?:downloadWait|time)\s=\s(\d*)[\d.]*;', self.html) - if timestring: - return int(timestring.group(1)) - else: - return 60 - - - def file_exists(self): - """ returns True or False - """ - if not self.html: - self.download_html() - if re.search(r"This file does not exist!", self.html) is not None: - return False - else: - return True - - - def get_download_options(self): - re_envelope = re.search(r".*?value=\"Free\sDownload\".*?\n*?(.*?<.*?>\n*)*?\n*\s*?</form>", - self.html).group(0) # get the whole request - to_sort = re.findall(r"<input\stype=\"hidden\"\svalue=\"(.*?)\"\sname=\"(.*?)\"\s\/>", re_envelope) - request_options = dict((n, v) for (v, n) in to_sort) - - herewego = self.load(self.pyfile.url, None, request_options) # the actual download-Page - - to_sort = re.findall(r"<input\stype=\".*?\"\svalue=\"(\S*?)\".*?name=\"(\S*?)\"\s.*?\/>", herewego) - request_options = dict((n, v) for (v, n) in to_sort) - - challenge = re.search(r"http://api\.recaptcha\.net/challenge\?k=(\w+)", herewego) - - if challenge: - re_captcha = ReCaptcha(self) - (request_options['recaptcha_challenge_field'], - request_options['recaptcha_response_field']) = re_captcha.challenge(challenge.group(1)) - - return request_options diff --git a/module/plugins/hoster/FreeWayMe.py b/module/plugins/hoster/FreeWayMe.py deleted file mode 100644 index 76ffca505..000000000 --- a/module/plugins/hoster/FreeWayMe.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo - - -class FreeWayMe(MultiHoster): - __name__ = "FreeWayMe" - __type__ = "hoster" - __version__ = "0.16" - - __pattern__ = r'https://(?:www\.)?free-way\.me/.+' - - __description__ = """FreeWayMe multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Nicolas Giese", "james@free-way.me")] - - - def setup(self): - self.resumeDownload = False - self.multiDL = self.premium - self.chunkLimit = 1 - - - def handlePremium(self, pyfile): - user, data = self.account.selectAccount() - - for _i in xrange(5): - # try it five times - header = self.load("https://www.free-way.me/load.php", - get={'multiget': 7, - 'url' : pyfile.url, - 'user' : user, - 'pw' : self.account.getAccountData(user)['password'], - 'json' : ""}, - just_header=True) - - if 'location' in header: - headers = self.load(header['location'], just_header=True) - if headers['code'] == 500: - # error on 2nd stage - self.logError(_("Error [stage2]")) - else: - # seems to work.. - self.download(header['location']) - break - else: - # error page first stage - self.logError(_("Error [stage1]")) - - #@TODO: handle errors - - -getInfo = create_getInfo(FreeWayMe) diff --git a/module/plugins/hoster/FreevideoCz.py b/module/plugins/hoster/FreevideoCz.py deleted file mode 100644 index 86c30e64c..000000000 --- a/module/plugins/hoster/FreevideoCz.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class FreevideoCz(DeadHoster): - __name__ = "FreevideoCz" - __type__ = "hoster" - __version__ = "0.30" - - __pattern__ = r'http://(?:www\.)?freevideo\.cz/vase-videa/.+' - - __description__ = """Freevideo.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(FreevideoCz)
\ No newline at end of file diff --git a/module/plugins/hoster/GigapetaCom.py b/module/plugins/hoster/GigapetaCom.py deleted file mode 100644 index d12084d42..000000000 --- a/module/plugins/hoster/GigapetaCom.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from random import randint - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class GigapetaCom(SimpleHoster): - __name__ = "GigapetaCom" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?gigapeta\.com/dl/\w+' - - __description__ = """GigaPeta.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<img src=".*" alt="file" />-->\s*(?P<N>.*?)\s*</td>' - SIZE_PATTERN = r'<th>\s*Size\s*</th>\s*<td>\s*(?P<S>.*?)\s*</td>' - OFFLINE_PATTERN = r'<div id="page_error">' - - COOKIES = [("gigapeta.com", "lang", "us")] - - - def handleFree(self, pyfile): - captcha_key = str(randint(1, 100000000)) - captcha_url = "http://gigapeta.com/img/captcha.gif?x=%s" % captcha_key - - for _i in xrange(5): - self.checkErrors() - - captcha = self.decryptCaptcha(captcha_url) - self.html = self.load(pyfile.url, - post={'captcha_key': captcha_key, - 'captcha' : captcha, - 'download' : "Download"}, - follow_location=False) - - m = re.search(r'Location\s*:\s*(.+)', self.req.http.header, re.I) - if m: - download_url = m.group(1) - break - elif "Entered figures don`t coincide with the picture" in self.html: - self.invalidCaptcha() - else: - self.fail(_("No valid captcha code entered")) - - self.download(download_url) - - - def checkErrors(self): - if "All threads for IP" in self.html: - self.logDebug("Your IP is already downloading a file") - self.wait(5 * 60, True) - self.retry() - - self.info.pop('error', None) - - -getInfo = create_getInfo(GigapetaCom) diff --git a/module/plugins/hoster/GooIm.py b/module/plugins/hoster/GooIm.py deleted file mode 100644 index 331d63a99..000000000 --- a/module/plugins/hoster/GooIm.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# https://goo.im/devs/liquidsmooth/3.x/codina/Nightly/LS-KK-v3.2-2014-08-01-codina.zip - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class GooIm(SimpleHoster): - __name__ = "GooIm" - __type__ = "hoster" - __version__ = "0.04" - - __pattern__ = r'https?://(?:www\.)?goo\.im/.+' - - __description__ = """Goo.im hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] - - - NAME_PATTERN = r'You will be redirected to .*(?P<N>[^/ ]+) in' - OFFLINE_PATTERN = r'The file you requested was not found' - - - def setup(self): - self.resumeDownload = True - self.multiDL = True - - - def handleFree(self, pyfile): - self.wait(10) - self.download(pyfile.url, cookies=True) - - -getInfo = create_getInfo(GooIm) diff --git a/module/plugins/hoster/GoogledriveCom.py b/module/plugins/hoster/GoogledriveCom.py deleted file mode 100644 index 0c8ca9c52..000000000 --- a/module/plugins/hoster/GoogledriveCom.py +++ /dev/null @@ -1,65 +0,0 @@ -# -*- coding: utf-8 -* -# -# Test links: -# https://drive.google.com/file/d/0B6RNTe4ygItBQm15RnJiTmMyckU/view?pli=1 - -import re - -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo -from module.utils import html_unescape - - -class GoogledriveCom(SimpleHoster): - __name__ = "GoogledriveCom" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'https?://(?:www\.)?drive\.google\.com/file/.+' - - __description__ = """Drive.google.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] - - - DISPOSITION = False - - NAME_PATTERN = r'"og:title" content="(?P<N>.*?)">' - OFFLINE_PATTERN = r'align="center"><p class="errorMessage"' - - - def setup(self): - self.multiDL = True - self.resumeDownload = True - self.chunkLimit = 1 - - - def handleFree(self, pyfile): - try: - link1 = re.search(r'"(https://docs.google.com/uc\?id.*?export=download)",', - self.html.decode('unicode-escape')).group(1) - - except AttributeError: - self.error(_("Hop #1 not found")) - - else: - self.logDebug("Next hop: %s" % link1) - - self.html = self.load(link1).decode('unicode-escape') - - try: - link2 = html_unescape(re.search(r'href="(/uc\?export=download.*?)">', - self.html).group(1)) - - except AttributeError: - self.error(_("Hop #2 not found")) - - else: - self.logDebug("Next hop: %s" % link2) - - link3 = self.load("https://docs.google.com" + link2, just_header=True) - self.logDebug("DL-Link: %s" % link3['location']) - - self.link = link3['location'] - - -getInfo = create_getInfo(GoogledriveCom) diff --git a/module/plugins/hoster/HellshareCz.py b/module/plugins/hoster/HellshareCz.py deleted file mode 100644 index 8a00e01b0..000000000 --- a/module/plugins/hoster/HellshareCz.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- - -from urlparse import urljoin - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class HellshareCz(SimpleHoster): - __name__ = "HellshareCz" - __type__ = "hoster" - __version__ = "0.85" - - __pattern__ = r'http://(?:www\.)?hellshare\.(?:cz|com|sk|hu|pl)/[^?]*/\d+' - - __description__ = """Hellshare.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - CHECK_TRAFFIC = True - LOGIN_ACCOUNT = True - - NAME_PATTERN = r'<h1 id="filename"[^>]*>(?P<N>[^<]+)</h1>' - SIZE_PATTERN = r'<strong id="FileSize_master">(?P<S>[\d.,]+) (?P<U>[\w^_]+)</strong>' - OFFLINE_PATTERN = r'<h1>File not found.</h1>' - - LINK_FREE_PATTERN = LINK_PREMIUM_PATTERN = r'<a href="([^?]+/(\d+)/\?do=(fileDownloadButton|relatedFileDownloadButton-\2)-showDownloadWindow)"' - - - def setup(self): - self.resumeDownload = self.multiDL = bool(self.account) - self.chunkLimit = 1 - - -getInfo = create_getInfo(HellshareCz) diff --git a/module/plugins/hoster/HellspyCz.py b/module/plugins/hoster/HellspyCz.py deleted file mode 100644 index 0d33b35b9..000000000 --- a/module/plugins/hoster/HellspyCz.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class HellspyCz(DeadHoster): - __name__ = "HellspyCz" - __type__ = "hoster" - __version__ = "0.28" - - __pattern__ = r'http://(?:www\.)?(?:hellspy\.(?:cz|com|sk|hu|pl)|sciagaj\.pl)(/\S+/\d+)' - - __description__ = """HellSpy.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(HellspyCz) diff --git a/module/plugins/hoster/HotfileCom.py b/module/plugins/hoster/HotfileCom.py deleted file mode 100644 index b64bb5fd7..000000000 --- a/module/plugins/hoster/HotfileCom.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class HotfileCom(DeadHoster): - __name__ = "HotfileCom" - __type__ = "hoster" - __version__ = "0.37" - - __pattern__ = r'https?://(?:www\.)?hotfile\.com/dl/\d+/\w+' - - __description__ = """Hotfile.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("sitacuisses", "sitacuisses@yhoo.de"), - ("spoob", "spoob@pyload.org"), - ("mkaay", "mkaay@mkaay.de"), - ("JoKoT3", "jokot3@gmail.com")] - - -getInfo = create_getInfo(HotfileCom) diff --git a/module/plugins/hoster/HugefilesNet.py b/module/plugins/hoster/HugefilesNet.py deleted file mode 100644 index f5085c8c3..000000000 --- a/module/plugins/hoster/HugefilesNet.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class HugefilesNet(XFSHoster): - __name__ = "HugefilesNet" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'http://(?:www\.)?hugefiles\.net/\w{12}' - - __description__ = """Hugefiles.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - SIZE_PATTERN = r'File Size:</span>\s*<span[^>]*>(?P<S>[^<]+)</span></div>' - - FORM_INPUTS_MAP = {'ctype': re.compile(r'\d+')} - - -getInfo = create_getInfo(HugefilesNet) diff --git a/module/plugins/hoster/HundredEightyUploadCom.py b/module/plugins/hoster/HundredEightyUploadCom.py deleted file mode 100644 index 2edb6310d..000000000 --- a/module/plugins/hoster/HundredEightyUploadCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class HundredEightyUploadCom(XFSHoster): - __name__ = "HundredEightyUploadCom" - __type__ = "hoster" - __version__ = "0.04" - - __pattern__ = r'http://(?:www\.)?180upload\.com/\w{12}' - - __description__ = """180upload.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - -getInfo = create_getInfo(HundredEightyUploadCom) diff --git a/module/plugins/hoster/IFileWs.py b/module/plugins/hoster/IFileWs.py deleted file mode 100644 index 59d9c7f40..000000000 --- a/module/plugins/hoster/IFileWs.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class IFileWs(DeadHoster): - __name__ = "IFileWs" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?ifile\.ws/\w{12}' - - __description__ = """Ifile.ws hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("z00nx", "z00nx0@gmail.com")] - - -getInfo = create_getInfo(IFileWs) diff --git a/module/plugins/hoster/IcyFilesCom.py b/module/plugins/hoster/IcyFilesCom.py deleted file mode 100644 index 201626fa5..000000000 --- a/module/plugins/hoster/IcyFilesCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class IcyFilesCom(DeadHoster): - __name__ = "IcyFilesCom" - __type__ = "hoster" - __version__ = "0.06" - - __pattern__ = r'http://(?:www\.)?icyfiles\.com/(.+)' - - __description__ = """IcyFiles.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("godofdream", "soilfiction@gmail.com")] - - -getInfo = create_getInfo(IcyFilesCom) diff --git a/module/plugins/hoster/IfileIt.py b/module/plugins/hoster/IfileIt.py deleted file mode 100644 index 056b05a65..000000000 --- a/module/plugins/hoster/IfileIt.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo - - -class IfileIt(DeadHoster): - __name__ = "IfileIt" - __type__ = "hoster" - __version__ = "0.29" - - __pattern__ = r'^unmatchable$' - - __description__ = """Ifile.it""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(IfileIt) diff --git a/module/plugins/hoster/IfolderRu.py b/module/plugins/hoster/IfolderRu.py deleted file mode 100644 index 33da64ba2..000000000 --- a/module/plugins/hoster/IfolderRu.py +++ /dev/null @@ -1,76 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class IfolderRu(SimpleHoster): - __name__ = "IfolderRu" - __type__ = "hoster" - __version__ = "0.39" - - __pattern__ = r'http://(?:www\.)?(?:ifolder\.ru|rusfolder\.(?:com|net|ru))/(?:files/)?(?P<ID>\d+)' - - __description__ = """Ifolder.ru hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - SIZE_REPLACEMENTS = [(u'Ðб', 'KB'), (u'Ðб', 'MB'), (u'Ðб', 'GB')] - - NAME_PATTERN = ur'(?:<div><span>)?ÐазваМОе:(?:</span>)? <b>(?P<N>[^<]+)</b><(?:/div|br)>' - SIZE_PATTERN = ur'(?:<div><span>)?РазЌеÑ:(?:</span>)? <b>(?P<S>[^<]+)</b><(?:/div|br)>' - OFFLINE_PATTERN = ur'<p>Ѐайл ÐœÐŸÐŒÐµÑ <b>[^<]*</b> (Ме МайЎеМ|ÑЎалеМ) !!!</p>' - - SESSION_ID_PATTERN = r'<a href=(http://ints\.(?:rusfolder\.com|ifolder\.ru)/ints/sponsor/\?bi=\d*&session=([^&]+)&u=[^>]+)>' - INTS_SESSION_PATTERN = r'\(\'ints_session\'\);\s*if\(tag\)\{tag\.value = "([^"]+)";\}' - HIDDEN_INPUT_PATTERN = r'var v = .*?name=\'(.+?)\' value=\'1\'' - - LINK_FREE_PATTERN = r'<a id="download_file_href" href="([^"]+)"' - - WRONG_CAPTCHA_PATTERN = ur'<font color=Red>МевеÑÐœÑй кПЎ,<br>ввеЎОÑе еÑе Ñаз</font><br>' - - - def setup(self): - self.resumeDownload = self.multiDL = bool(self.account) - self.chunkLimit = 1 - - - def handleFree(self, pyfile): - self.html = self.load("http://rusfolder.com/%s" % self.info['pattern']['ID'], cookies=True, decode=True) - self.getFileInfo() - - url = re.search(r"location\.href = '(http://ints\..*?=)'", self.html).group(1) - self.html = self.load(url, cookies=True, decode=True) - - url, session_id = re.search(self.SESSION_ID_PATTERN, self.html).groups() - self.html = self.load(url, cookies=True, decode=True) - - url = "http://ints.rusfolder.com/ints/frame/?session=%s" % session_id - self.html = self.load(url, cookies=True) - - self.wait(31, False) - - captcha_url = "http://ints.rusfolder.com/random/images/?session=%s" % session_id - for _i in xrange(5): - self.html = self.load(url, cookies=True) - action, inputs = self.parseHtmlForm('ID="Form1"') - inputs['ints_session'] = re.search(self.INTS_SESSION_PATTERN, self.html).group(1) - inputs[re.search(self.HIDDEN_INPUT_PATTERN, self.html).group(1)] = '1' - inputs['confirmed_number'] = self.decryptCaptcha(captcha_url, cookies=True) - inputs['action'] = '1' - self.logDebug(inputs) - - self.html = self.load(url, decode=True, cookies=True, post=inputs) - if self.WRONG_CAPTCHA_PATTERN in self.html: - self.invalidCaptcha() - else: - break - else: - self.fail(_("Invalid captcha")) - - self.link = re.search(self.LINK_PATTERN, self.html).group(1) - - -getInfo = create_getInfo(IfolderRu) diff --git a/module/plugins/hoster/JumbofilesCom.py b/module/plugins/hoster/JumbofilesCom.py deleted file mode 100644 index 2331179bc..000000000 --- a/module/plugins/hoster/JumbofilesCom.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class JumbofilesCom(SimpleHoster): - __name__ = "JumbofilesCom" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?jumbofiles\.com/(?P<ID>\w{12})' - - __description__ = """JumboFiles.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("godofdream", "soilfiction@gmail.com")] - - - INFO_PATTERN = r'<TR><TD>(?P<N>[^<]+?)\s*<small>\((?P<S>[\d.,]+)\s*(?P<U>[\w^_]+)' - OFFLINE_PATTERN = r'Not Found or Deleted / Disabled due to inactivity or DMCA' - LINK_FREE_PATTERN = r'<meta http-equiv="refresh" content="10;url=(.+)">' - - - def setup(self): - self.resumeDownload = True - self.multiDL = True - - - def handleFree(self, pyfile): - post_data = {"id": self.info['pattern']['ID'], "op": "download3", "rand": ""} - html = self.load(self.pyfile.url, post=post_data, decode=True) - self.link = re.search(self.LINK_FREE_PATTERN, html).group(1) - - -getInfo = create_getInfo(JumbofilesCom) diff --git a/module/plugins/hoster/JunocloudMe.py b/module/plugins/hoster/JunocloudMe.py deleted file mode 100644 index ad37b01e4..000000000 --- a/module/plugins/hoster/JunocloudMe.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class JunocloudMe(XFSHoster): - __name__ = "JunocloudMe" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'http://(?:\w+\.)?junocloud\.me/\w{12}' - - __description__ = """Junocloud.me hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("guidobelix", "guidobelix@hotmail.it")] - - - URL_REPLACEMENTS = [(r'//(www\.)?junocloud', "//dl3.junocloud")] - - OFFLINE_PATTERN = r'>No such file with this filename<' - TEMP_OFFLINE_PATTERN = r'The page may have been renamed, removed or be temporarily unavailable.<' - - -getInfo = create_getInfo(JunocloudMe) diff --git a/module/plugins/hoster/Keep2ShareCc.py b/module/plugins/hoster/Keep2ShareCc.py deleted file mode 100644 index 3ed11aa13..000000000 --- a/module/plugins/hoster/Keep2ShareCc.py +++ /dev/null @@ -1,112 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urlparse import urljoin - -from module.plugins.internal.CaptchaService import ReCaptcha -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class Keep2ShareCc(SimpleHoster): - __name__ = "Keep2ShareCc" - __type__ = "hoster" - __version__ = "0.21" - - __pattern__ = r'https?://(?:www\.)?(keep2share|k2s|keep2s)\.cc/file/(?P<ID>\w+)' - - __description__ = """Keep2Share.cc hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - URL_REPLACEMENTS = [(__pattern__ + ".*", "http://k2s.cc/file/\g<ID>")] - - NAME_PATTERN = r'File: <span>(?P<N>.+)</span>' - SIZE_PATTERN = r'Size: (?P<S>[^<]+)</div>' - - OFFLINE_PATTERN = r'File not found or deleted|Sorry, this file is blocked or deleted|Error 404' - TEMP_OFFLINE_PATTERN = r'Downloading blocked due to' - - LINK_FREE_PATTERN = r'"([^"]+url.html?file=.+?)"|window\.location\.href = \'(.+?)\';' - LINK_PREMIUM_PATTERN = r'window\.location\.href = \'(.+?)\';' - - CAPTCHA_PATTERN = r'src="(/file/captcha\.html.+?)"' - - WAIT_PATTERN = r'Please wait ([\d:]+) to download this file' - TEMP_ERROR_PATTERN = r'>\s*(Download count files exceed|Traffic limit exceed|Free account does not allow to download more than one file at the same time)' - ERROR_PATTERN = r'>\s*(Free user can\'t download large files|You no can access to this file|This download available only for premium users|This is private file)' - - - def checkErrors(self): - m = re.search(self.TEMP_ERROR_PATTERN, self.html) - if m: - self.info['error'] = m.group(1) - self.wantReconnect = True - self.retry(wait_time=30 * 60, reason=m.group(0)) - - m = re.search(self.ERROR_PATTERN, self.html) - if m: - errmsg = self.info['error'] = m.group(1) - self.error(errmsg) - - m = re.search(self.WAIT_PATTERN, self.html) - if m: - self.logDebug("Hoster told us to wait for %s" % m.group(1)) - - # string to time convert courtesy of https://stackoverflow.com/questions/10663720 - ftr = [3600, 60, 1] - wait_time = sum(a * b for a, b in zip(ftr, map(int, m.group(1).split(':')))) - - self.wantReconnect = True - self.retry(wait_time=wait_time, reason="Please wait to download this file") - - self.info.pop('error', None) - - - def handleFree(self, pyfile): - self.fid = re.search(r'<input type="hidden" name="slow_id" value="([^"]+)">', self.html).group(1) - self.html = self.load(pyfile.url, post={'yt0': '', 'slow_id': self.fid}) - - self.checkErrors() - - m = re.search(self.LINK_FREE_PATTERN, self.html) - - if m is None: - self.handleCaptcha() - - self.wait(30) - - self.html = self.load(pyfile.url) - - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("Free download link not found")) - - self.link = m.group(1) - def handleCaptcha(self): - recaptcha = ReCaptcha(self) - post_data = {'free' : 1, - 'freeDownloadRequest': 1, - 'uniqueId' : self.fid, - 'yt0' : ''} - - m = re.search(self.CAPTCHA_PATTERN, self.html) - if m: - captcha_url = urljoin("http://k2s.cc/", m.group(1)) - post_data['CaptchaForm[code]'] = self.decryptCaptcha(captcha_url) - else: - response, challenge = recaptcha.challenge() - post_data.update({'recaptcha_challenge_field': challenge, - 'recaptcha_response_field' : response}) - - self.html = self.load(self.pyfile.url, post=post_data) - - if 'verification code is incorrect' not in self.html: - self.correctCaptcha() - else: - self.invalidCaptcha() - - -getInfo = create_getInfo(Keep2ShareCc) diff --git a/module/plugins/hoster/KickloadCom.py b/module/plugins/hoster/KickloadCom.py deleted file mode 100644 index 1f0c41f3d..000000000 --- a/module/plugins/hoster/KickloadCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class KickloadCom(DeadHoster): - __name__ = "KickloadCom" - __type__ = "hoster" - __version__ = "0.21" - - __pattern__ = r'http://(?:www\.)?kickload\.com/get/.+' - - __description__ = """Kickload.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("mkaay", "mkaay@mkaay.de")] - - -getInfo = create_getInfo(KickloadCom) diff --git a/module/plugins/hoster/KingfilesNet.py b/module/plugins/hoster/KingfilesNet.py deleted file mode 100644 index 73fa494b0..000000000 --- a/module/plugins/hoster/KingfilesNet.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.captcha import SolveMedia -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class KingfilesNet(SimpleHoster): - __name__ = "KingfilesNet" - __type__ = "hoster" - __version__ = "0.07" - - __pattern__ = r'http://(?:www\.)?kingfiles\.net/(?P<ID>\w{12})' - - __description__ = """Kingfiles.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - NAME_PATTERN = r'name="fname" value="(?P<N>.+?)">' - SIZE_PATTERN = r'>Size: .+?">(?P<S>[\d.,]+) (?P<U>[\w^_]+)' - - OFFLINE_PATTERN = r'>(File Not Found</b><br><br>|File Not Found</h2>)' - - RAND_ID_PATTERN = r'type=\"hidden\" name=\"rand\" value=\"(.+)\">' - - LINK_FREE_PATTERN = r'var download_url = \'(.+)\';' - - - def setup(self): - self.resumeDownload = True - self.multiDL = True - - - def handleFree(self, pyfile): - # Click the free user button - post_data = {'op' : "download1", - 'usr_login' : "", - 'id' : self.info['pattern']['ID'], - 'fname' : pyfile.name, - 'referer' : "", - 'method_free': "+"} - - self.html = self.load(pyfile.url, post=post_data, cookies=True, decode=True) - - solvemedia = SolveMedia(self) - response, challenge = solvemedia.challenge() - - # Make the downloadlink appear and load the file - m = re.search(self.RAND_ID_PATTERN, self.html) - if m is None: - self.error(_("Random key not found")) - - rand = m.group(1) - self.logDebug("rand = ", rand) - - post_data = {'op' : "download2", - 'id' : self.info['pattern']['ID'], - 'rand' : rand, - 'referer' : pyfile.url, - 'method_free' : "+", - 'method_premium' : "", - 'adcopy_response' : response, - 'adcopy_challenge': challenge, - 'down_direct' : "1"} - - self.html = self.load(pyfile.url, post=post_data, cookies=True, decode=True) - - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("Download url not found")) - - self.link = m.group(1) - - -getInfo = create_getInfo(KingfilesNet) diff --git a/module/plugins/hoster/LemUploadsCom.py b/module/plugins/hoster/LemUploadsCom.py deleted file mode 100644 index 822670348..000000000 --- a/module/plugins/hoster/LemUploadsCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class LemUploadsCom(DeadHoster): - __name__ = "LemUploadsCom" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'https?://(?:www\.)?lemuploads\.com/\w{12}' - - __description__ = """LemUploads.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("t4skforce", "t4skforce1337[AT]gmail[DOT]com")] - - -getInfo = create_getInfo(LemUploadsCom) diff --git a/module/plugins/hoster/LetitbitNet.py b/module/plugins/hoster/LetitbitNet.py deleted file mode 100644 index 2c725427d..000000000 --- a/module/plugins/hoster/LetitbitNet.py +++ /dev/null @@ -1,155 +0,0 @@ -# -*- coding: utf-8 -*- -# -# API Documentation: -# http://api.letitbit.net/reg/static/api.pdf -# -# Test links: -# http://letitbit.net/download/07874.0b5709a7d3beee2408bb1f2eefce/random.bin.html - -import re - -from urlparse import urljoin - -from module.common.json_layer import json_loads, json_dumps -from module.network.RequestFactory import getURL -from module.plugins.internal.CaptchaService import ReCaptcha -from module.plugins.internal.SimpleHoster import SimpleHoster, secondsToMidnight - - -def api_response(url): - json_data = ["yw7XQy2v9", ["download/info", {"link": url}]] - api_rep = getURL("http://api.letitbit.net/json", - post={'r': json_dumps(json_data)}) - return json_loads(api_rep) - - -def getInfo(urls): - for url in urls: - api_rep = api_response(url) - if api_rep['status'] == 'OK': - info = api_rep['data'][0] - yield (info['name'], info['size'], 2, url) - else: - yield (url, 0, 1, url) - - -class LetitbitNet(SimpleHoster): - __name__ = "LetitbitNet" - __type__ = "hoster" - __version__ = "0.30" - - __pattern__ = r'https?://(?:www\.)?(letitbit|shareflare)\.net/download/.+' - - __description__ = """Letitbit.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("z00nx", "z00nx0@gmail.com")] - - - URL_REPLACEMENTS = [(r"(?<=http://)([^/]+)", "letitbit.net")] - - SECONDS_PATTERN = r'seconds\s*=\s*(\d+);' - CAPTCHA_CONTROL_FIELD = r'recaptcha_control_field\s=\s\'(.+?)\'' - - - def setup(self): - self.resumeDownload = True - - - def getFileInfo(self): - api_rep = api_response(self.pyfile.url) - if api_rep['status'] == 'OK': - self.api_data = api_rep['data'][0] - self.pyfile.name = self.api_data['name'] - self.pyfile.size = self.api_data['size'] - else: - self.offline() - - - def handleFree(self, pyfile): - action, inputs = self.parseHtmlForm('id="ifree_form"') - if not action: - self.error(_("ifree_form")) - - pyfile.size = float(inputs['sssize']) - self.logDebug(action, inputs) - inputs['desc'] = "" - - self.html = self.load(urljoin("http://letitbit.net/", action), post=inputs, cookies=True) - - m = re.search(self.SECONDS_PATTERN, self.html) - seconds = int(m.group(1)) if m else 60 - - self.logDebug("Seconds found", seconds) - - m = re.search(self.CAPTCHA_CONTROL_FIELD, self.html) - recaptcha_control_field = m.group(1) - - self.logDebug("ReCaptcha control field found", recaptcha_control_field) - - self.wait(seconds) - - res = self.load("http://letitbit.net/ajax/download3.php", post=" ", cookies=True) - if res != '1': - self.error(_("Unknown response - ajax_check_url")) - - self.logDebug(res) - - recaptcha = ReCaptcha(self) - response, challenge = recaptcha.challenge() - - post_data = {"recaptcha_challenge_field": challenge, - "recaptcha_response_field": response, - "recaptcha_control_field": recaptcha_control_field} - - self.logDebug("Post data to send", post_data) - - res = self.load("http://letitbit.net/ajax/check_recaptcha.php", post=post_data, cookies=True) - - self.logDebug(res) - - if not res: - self.invalidCaptcha() - - if res == "error_free_download_blocked": - self.logWarning(_("Daily limit reached")) - self.wait(secondsToMidnight(gmt=2), True) - - if res == "error_wrong_captcha": - self.invalidCaptcha() - self.retry() - - elif res.startswith('['): - urls = json_loads(res) - - elif res.startswith('http://'): - urls = [res] - - else: - self.error(_("Unknown response - captcha check")) - - self.correctCaptcha() - - for download_url in urls: - try: - self.download(download_url) - break - except Exception, e: - self.logError(e) - else: - self.fail(_("Download did not finish correctly")) - - - def handlePremium(self, pyfile): - api_key = self.user - premium_key = self.account.getAccountData(self.user)['password'] - - json_data = [api_key, ["download/direct_links", {"pass": premium_key, "link": pyfile.url}]] - api_rep = self.load('http://api.letitbit.net/json', post={'r': json_dumps(json_data)}) - self.logDebug("API Data: " + api_rep) - api_rep = json_loads(api_rep) - - if api_rep['status'] == 'FAIL': - self.fail(api_rep['data']) - - self.link = api_rep['data'][0][0] diff --git a/module/plugins/hoster/LinksnappyCom.py b/module/plugins/hoster/LinksnappyCom.py deleted file mode 100644 index 5b0fab43a..000000000 --- a/module/plugins/hoster/LinksnappyCom.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urlparse import urlsplit - -from module.common.json_layer import json_loads, json_dumps -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo - - -class LinksnappyCom(MultiHoster): - __name__ = "LinksnappyCom" - __type__ = "hoster" - __version__ = "0.08" - - __pattern__ = r'https?://(?:[^/]+\.)?linksnappy\.com' - - __description__ = """Linksnappy.com multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - SINGLE_CHUNK_HOSTERS = ["easybytez.com"] - - - def handlePremium(self, pyfile): - host = self._get_host(pyfile.url) - json_params = json_dumps({'link' : pyfile.url, - 'type' : host, - 'username': self.user, - 'password': self.account.getAccountData(self.user)['password']}) - - r = self.load("http://gen.linksnappy.com/genAPI.php", - post={'genLinks': json_params}) - - self.logDebug("JSON data: " + r) - - j = json_loads(r)['links'][0] - - if j['error']: - self.error(_("Error converting the link")) - - pyfile.name = j['filename'] - self.link = j['generated'] - - if host in self.SINGLE_CHUNK_HOSTERS: - self.chunkLimit = 1 - else: - self.setup() - - - @staticmethod - def _get_host(url): - host = urlsplit(url).netloc - return re.search(r'[\w-]+\.\w+$', host).group(0) - - -getInfo = create_getInfo(LinksnappyCom) diff --git a/module/plugins/hoster/LoadTo.py b/module/plugins/hoster/LoadTo.py deleted file mode 100644 index 0f344a88b..000000000 --- a/module/plugins/hoster/LoadTo.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# http://www.load.to/JWydcofUY6/random.bin -# http://www.load.to/oeSmrfkXE/random100.bin - -import re - -from pyload.plugin.internal.captcha import SolveMedia -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class LoadTo(SimpleHoster): - __name__ = "LoadTo" - __type__ = "hoster" - __version__ = "0.22" - - __pattern__ = r'http://(?:www\.)?load\.to/\w+' - - __description__ = """Load.to hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("halfman", "Pulpan3@gmail.com"), - ("stickell", "l.stickell@yahoo.it")] - - - NAME_PATTERN = r'<h1>(?P<N>.+)</h1>' - SIZE_PATTERN = r'Size: (?P<S>[\d.,]+) (?P<U>[\w^_]+)' - OFFLINE_PATTERN = r'>Can\'t find file' - - LINK_FREE_PATTERN = r'<form method="post" action="(.+?)"' - WAIT_PATTERN = r'type="submit" value="Download \((\d+)\)"' - - URL_REPLACEMENTS = [(r'(\w)$', r'\1/')] - - - def setup(self): - self.multiDL = True - self.chunkLimit = 1 - - - def handleFree(self, pyfile): - # Search for Download URL - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("LINK_FREE_PATTERN not found")) - - download_url = m.group(1) - - # Set Timer - may be obsolete - m = re.search(self.WAIT_PATTERN, self.html) - if m: - self.wait(m.group(1)) - - # Load.to is using solvemedia captchas since ~july 2014: - solvemedia = SolveMedia(self) - captcha_key = solvemedia.detect_key() - - if captcha_key is None: - self.download(download_url) - else: - response, challenge = solvemedia.challenge(captcha_key) - self.download(download_url, - post={'adcopy_challenge': challenge, - 'adcopy_response' : response, - 'returnUrl' : pyfile.url}) - - -getInfo = create_getInfo(LoadTo) diff --git a/module/plugins/hoster/LomafileCom.py b/module/plugins/hoster/LomafileCom.py deleted file mode 100644 index 475cdacaa..000000000 --- a/module/plugins/hoster/LomafileCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo - - -class LomafileCom(DeadHoster): - __name__ = "LomafileCom" - __type__ = "hoster" - __version__ = "0.52" - - __pattern__ = r'http://lomafile\.com/\w{12}' - - __description__ = """Lomafile.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("nath_schwarz", "nathan.notwhite@gmail.com"), - ("guidobelix", "guidobelix@hotmail.it")] - - -getInfo = create_getInfo(LomafileCom) diff --git a/module/plugins/hoster/LuckyShareNet.py b/module/plugins/hoster/LuckyShareNet.py deleted file mode 100644 index 33f8ab393..000000000 --- a/module/plugins/hoster/LuckyShareNet.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from bottle import json_loads - -from pyload.plugin.internal.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class LuckyShareNet(SimpleHoster): - __name__ = "LuckyShareNet" - __type__ = "hoster" - __version__ = "0.06" - - __pattern__ = r'https?://(?:www\.)?luckyshare\.net/(?P<ID>\d{10,})' - - __description__ = """LuckyShare.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - INFO_PATTERN = r'<h1 class=\'file_name\'>(?P<N>\S+)</h1>\s*<span class=\'file_size\'>Filesize: (?P<S>[\d.,]+)(?P<U>[\w^_]+)</span>' - OFFLINE_PATTERN = r'There is no such file available' - - - def parseJson(self, rep): - if 'AJAX Error' in rep: - html = self.load(self.pyfile.url, decode=True) - m = re.search(r"waitingtime = (\d+);", html) - if m: - seconds = int(m.group(1)) - self.logDebug("You have to wait %d seconds between free downloads" % seconds) - self.retry(wait_time=seconds) - else: - self.error(_("Unable to detect wait time between free downloads")) - elif 'Hash expired' in rep: - self.retry(reason=_("Hash expired")) - return json_loads(rep) - - - # TODO: There should be a filesize limit for free downloads - # TODO: Some files could not be downloaded in free mode - def handleFree(self, pyfile): - rep = self.load(r"http://luckyshare.net/download/request/type/time/file/" + self.info['pattern']['ID'], decode=True) - - self.logDebug("JSON: " + rep) - - json = self.parseJson(rep) - self.wait(json['time']) - - recaptcha = ReCaptcha(self) - - for _i in xrange(5): - response, challenge = recaptcha.challenge() - rep = self.load(r"http://luckyshare.net/download/verify/challenge/%s/response/%s/hash/%s" % - (challenge, response, json['hash']), decode=True) - self.logDebug("JSON: " + rep) - if 'link' in rep: - json.update(self.parseJson(rep)) - self.correctCaptcha() - break - elif 'Verification failed' in rep: - self.invalidCaptcha() - else: - self.error(_("Unable to get downlaod link")) - - if not json['link']: - self.fail(_("No Download url retrieved/all captcha attempts failed")) - - self.download(json['link']) - - -getInfo = create_getInfo(LuckyShareNet) diff --git a/module/plugins/hoster/MegaCoNz.py b/module/plugins/hoster/MegaCoNz.py deleted file mode 100644 index 4ad20b265..000000000 --- a/module/plugins/hoster/MegaCoNz.py +++ /dev/null @@ -1,217 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import random -import re - -from array import array -from base64 import standard_b64decode - -from Crypto.Cipher import AES -from Crypto.Util import Counter -# from pycurl import SSL_CIPHER_LIST - -from module.common.json_layer import json_loads, json_dumps -from module.plugins.Hoster import Hoster -from module.utils import decode, fs_decode, fs_encode - - -############################ General errors ################################### -# EINTERNAL (-1): An internal error has occurred. Please submit a bug report, detailing the exact circumstances in which this error occurred -# EARGS (-2): You have passed invalid arguments to this command -# EAGAIN (-3): (always at the request level) A temporary congestion or server malfunction prevented your request from being processed. No data was altered. Retry. Retries must be spaced with exponential backoff -# ERATELIMIT (-4): You have exceeded your command weight per time quota. Please wait a few seconds, then try again (this should never happen in sane real-life applications) -# -############################ Upload errors #################################### -# EFAILED (-5): The upload failed. Please restart it from scratch -# ETOOMANY (-6): Too many concurrent IP addresses are accessing this upload target URL -# ERANGE (-7): The upload file packet is out of range or not starting and ending on a chunk boundary -# EEXPIRED (-8): The upload target URL you are trying to access has expired. Please request a fresh one -# -############################ Stream/System errors ############################# -# ENOENT (-9): Object (typically, node or user) not found -# ECIRCULAR (-10): Circular linkage attempted -# EACCESS (-11): Access violation (e.g., trying to write to a read-only share) -# EEXIST (-12): Trying to create an object that already exists -# EINCOMPLETE (-13): Trying to access an incomplete resource -# EKEY (-14): A decryption operation failed (never returned by the API) -# ESID (-15): Invalid or expired user session, please relogin -# EBLOCKED (-16): User blocked -# EOVERQUOTA (-17): Request over quota -# ETEMPUNAVAIL (-18): Resource temporarily not available, please try again later -# ETOOMANYCONNECTIONS (-19): Too many connections on this resource -# EWRITE (-20): Write failed -# EREAD (-21): Read failed -# EAPPKEY (-22): Invalid application key; request not processed - - -class MegaCoNz(Hoster): - __name__ = "MegaCoNz" - __type__ = "hoster" - __version__ = "0.26" - - __pattern__ = r'(?:https?://(?:www\.)?mega\.co\.nz/|mega:|chrome:.+?)#(?P<TYPE>N|)!(?P<ID>[\w^_]+)!(?P<KEY>[\w,\\-]+)' - - __description__ = """Mega.co.nz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "ranan@pyload.org"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - API_URL = "https://eu.api.mega.co.nz/cs" - FILE_SUFFIX = ".crypted" - - - def b64_decode(self, data): - data = data.replace("-", "+").replace("_", "/") - return standard_b64decode(data + '=' * (-len(data) % 4)) - - - def getCipherKey(self, key): - """ Construct the cipher key from the given data """ - a = array("I", self.b64_decode(key)) - - k = array("I", (a[0] ^ a[4], a[1] ^ a[5], a[2] ^ a[6], a[3] ^ a[7])) - iv = a[4:6] + array("I", (0, 0)) - meta_mac = a[6:8] - - return k, iv, meta_mac - - - def api_response(self, **kwargs): - """ Dispatch a call to the api, see https://mega.co.nz/#developers """ - - # generate a session id, no idea where to obtain elsewhere - uid = random.randint(10 << 9, 10 ** 10) - - res = self.load(self.API_URL, get={'id': uid}, post=json_dumps([kwargs])) - self.logDebug("Api Response: " + res) - return json_loads(res) - - - def decryptAttr(self, data, key): - k, iv, meta_mac = self.getCipherKey(key) - cbc = AES.new(k, AES.MODE_CBC, "\0" * 16) - attr = decode(cbc.decrypt(self.b64_decode(data))) - - self.logDebug("Decrypted Attr: %s" % attr) - if not attr.startswith("MEGA"): - self.fail(_("Decryption failed")) - - # Data is padded, 0-bytes must be stripped - return json_loads(re.search(r'{.+?}', attr).group(0)) - - - def decryptFile(self, key): - """ Decrypts the file at lastDownload` """ - - # upper 64 bit of counter start - n = self.b64_decode(key)[16:24] - - # convert counter to long and shift bytes - k, iv, meta_mac = self.getCipherKey(key) - ctr = Counter.new(128, initial_value=long(n.encode("hex"), 16) << 64) - cipher = AES.new(k, AES.MODE_CTR, counter=ctr) - - self.pyfile.setStatus("decrypting") - self.pyfile.setProgress(0) - - file_crypted = fs_encode(self.lastDownload) - file_decrypted = file_crypted.rsplit(self.FILE_SUFFIX)[0] - - try: - f = open(file_crypted, "rb") - df = open(file_decrypted, "wb") - - except IOError, e: - self.fail(e) - - chunk_size = 2 ** 15 # buffer size, 32k - # file_mac = [0, 0, 0, 0] # calculate CBC-MAC for checksum - - chunks = os.path.getsize(file_crypted) / chunk_size + 1 - for i in xrange(chunks): - buf = f.read(chunk_size) - if not buf: - break - - chunk = cipher.decrypt(buf) - df.write(chunk) - - self.pyfile.setProgress(int((100.0 / chunks) * i)) - - # chunk_mac = [iv[0], iv[1], iv[0], iv[1]] - # for i in xrange(0, chunk_size, 16): - # block = chunk[i:i+16] - # if len(block) % 16: - # block += '=' * (16 - (len(block) % 16)) - # block = array("I", block) - - # chunk_mac = [chunk_mac[0] ^ a_[0], chunk_mac[1] ^ block[1], chunk_mac[2] ^ block[2], chunk_mac[3] ^ block[3]] - # chunk_mac = aes_cbc_encrypt_a32(chunk_mac, k) - - # file_mac = [file_mac[0] ^ chunk_mac[0], file_mac[1] ^ chunk_mac[1], file_mac[2] ^ chunk_mac[2], file_mac[3] ^ chunk_mac[3]] - # file_mac = aes_cbc_encrypt_a32(file_mac, k) - - self.pyfile.setProgress(100) - - f.close() - df.close() - - # if file_mac[0] ^ file_mac[1], file_mac[2] ^ file_mac[3] != meta_mac: - # os.remove(file_decrypted) - # self.fail(_("Checksum mismatch")) - - os.remove(file_crypted) - self.lastDownload = fs_decode(file_decrypted) - - - def checkError(self, code): - ecode = abs(code) - - if ecode in (9, 16, 21): - self.offline() - - elif ecode in (3, 13, 17, 18, 19): - self.tempOffline() - - elif ecode in (1, 4, 6, 10, 15, 21): - self.retry(5, 30, _("Error code: [%s]") % -ecode) - - else: - self.fail(_("Error code: [%s]") % -ecode) - - - def process(self, pyfile): - pattern = re.match(self.__pattern__, pyfile.url).groupdict() - id = pattern['ID'] - key = pattern['KEY'] - public = pattern['TYPE'] == '' - - self.logDebug("ID: %s" % id, "Key: %s" % key, "Type: %s" % ("public" if public else "node")) - - # g is for requesting a download url - # this is similar to the calls in the mega js app, documentation is very bad - if public: - mega = self.api_response(a="g", g=1, p=id, ssl=1)[0] - else: - mega = self.api_response(a="g", g=1, n=id, ssl=1)[0] - - if isinstance(mega, int): - self.checkError(mega) - elif "e" in mega: - self.checkError(mega['e']) - - attr = self.decryptAttr(mega['at'], key) - - pyfile.name = attr['n'] + self.FILE_SUFFIX - pyfile.size = mega['s'] - - # self.req.http.c.setopt(SSL_CIPHER_LIST, "RC4-MD5:DEFAULT") - - self.download(mega['g']) - - self.decryptFile(key) - - # Everything is finished and final name can be set - pyfile.name = attr['n'] diff --git a/module/plugins/hoster/MegaDebridEu.py b/module/plugins/hoster/MegaDebridEu.py deleted file mode 100644 index b42362800..000000000 --- a/module/plugins/hoster/MegaDebridEu.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urllib import unquote_plus - -from module.common.json_layer import json_loads -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo - - -class MegaDebridEu(MultiHoster): - __name__ = "MegaDebridEu" - __type__ = "hoster" - __version__ = "0.46" - - __pattern__ = r'http://((?:www\d+\.|s\d+\.)?mega-debrid\.eu|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/download/file/[\w^_]+' - - __description__ = """mega-debrid.eu multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("D.Ducatel", "dducatel@je-geek.fr")] - - - API_URL = "https://www.mega-debrid.eu/api.php" - - - def getFilename(self, url): - try: - return unquote_plus(url.rsplit("/", 1)[1]) - except IndexError: - return "" - - - def handlePremium(self, pyfile): - if not self.api_load(): - self.exitOnFail("Unable to connect to Mega-debrid.eu") - - self.link = self.debridLink(pyfile.url) - - filename = self.getFilename(self.link) - if filename: - pyfile.name = filename - - - def api_load(self): - """ - Connexion to the mega-debrid API - Return True if succeed - """ - user, data = self.account.selectAccount() - jsonResponse = self.load(self.API_URL, - get={'action': 'connectUser', 'login': user, 'password': data['password']}) - res = json_loads(jsonResponse) - - if res['response_code'] == "ok": - self.token = res['token'] - return True - else: - return False - - - def debridLink(self, linkToDebrid): - """ - Debrid a link - Return The debrided link if succeed or original link if fail - """ - jsonResponse = self.load(self.API_URL, get={'action': 'getLink', 'token': self.token}, - post={"link": linkToDebrid}) - res = json_loads(jsonResponse) - - if res['response_code'] == "ok": - debridedLink = res['debridLink'][1:-1] - return debridedLink - else: - self.exitOnFail("Unable to debrid %s" % linkToDebrid) - - - def exitOnFail(self, msg): - """ - exit the plugin on fail case - And display the reason of this failure - """ - if self.getConfig("unloadFailing"): - self.logError(_(msg)) - self.resetAccount() - else: - self.fail(_(msg)) - - -getInfo = create_getInfo(MegaDebridEu) diff --git a/module/plugins/hoster/MegaFilesSe.py b/module/plugins/hoster/MegaFilesSe.py deleted file mode 100644 index 4120e17d6..000000000 --- a/module/plugins/hoster/MegaFilesSe.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class MegaFilesSe(DeadHoster): - __name__ = "MegaFilesSe" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?megafiles\.se/\w{12}' - - __description__ = """MegaFiles.se hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("t4skforce", "t4skforce1337[AT]gmail[DOT]com")] - - -getInfo = create_getInfo(MegaFilesSe) diff --git a/module/plugins/hoster/MegaRapidCz.py b/module/plugins/hoster/MegaRapidCz.py deleted file mode 100644 index 7d8a25c03..000000000 --- a/module/plugins/hoster/MegaRapidCz.py +++ /dev/null @@ -1,65 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pycurl import HTTPHEADER - -from module.network.HTTPRequest import BadHeader -from module.network.RequestFactory import getRequest -from module.plugins.internal.SimpleHoster import SimpleHoster, parseFileInfo - - -def getInfo(urls): - h = getRequest() - h.c.setopt(HTTPHEADER, - ["Accept: text/html", - "User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0"]) - - for url in urls: - html = h.load(url, decode=True) - yield parseFileInfo(MegaRapidCz, url, html) - - -class MegaRapidCz(SimpleHoster): - __name__ = "MegaRapidCz" - __type__ = "hoster" - __version__ = "0.56" - - __pattern__ = r'http://(?:www\.)?(share|mega)rapid\.cz/soubor/\d+/.+' - - __description__ = """MegaRapid.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("MikyWoW", "mikywow@seznam.cz"), - ("zoidberg", "zoidberg@mujmail.cz"), - ("stickell", "l.stickell@yahoo.it"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - NAME_PATTERN = r'<h1[^>]*><span[^>]*>(?:<a[^>]*>)?(?P<N>[^<]+)' - SIZE_PATTERN = r'<td class="i">Velikost:</td>\s*<td class="h"><strong>\s*(?P<S>[\d.,]+) (?P<U>[\w^_]+)</strong></td>' - OFFLINE_PATTERN = ur'Nastala chyba 404|Soubor byl smazán' - - CHECK_TRAFFIC = True - - LINK_PREMIUM_PATTERN = r'<a href="([^"]+)" title="Stahnout">([^<]+)</a>' - - ERR_LOGIN_PATTERN = ur'<div class="error_div"><strong>Stahovánà je pÅÃstupné pouze pÅihlášenÃœm uÅŸivatelům' - ERR_CREDIT_PATTERN = ur'<div class="error_div"><strong>Stahovánà zdarma je moÅŸné jen pÅes náš' - - - def setup(self): - self.chunkLimit = 1 - - - def handlePremium(self, pyfile): - m = re.search(self.LINK_PREMIUM_PATTERN, self.html) - if m: - self.link = m.group(1) - else: - if re.search(self.ERR_LOGIN_PATTERN, self.html): - self.relogin(self.user) - self.retry(wait_time=60, reason=_("User login failed")) - elif re.search(self.ERR_CREDIT_PATTERN, self.html): - self.fail(_("Not enough credit left")) - else: - self.fail(_("Download link not found")) diff --git a/module/plugins/hoster/MegareleaseOrg.py b/module/plugins/hoster/MegareleaseOrg.py deleted file mode 100644 index 6eacbd6e0..000000000 --- a/module/plugins/hoster/MegareleaseOrg.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class MegareleaseOrg(DeadHoster): - __name__ = "MegareleaseOrg" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'https?://(?:www\.)?megarelease\.org/\w{12}' - - __description__ = """Megarelease.org hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("derek3x", "derek3x@vmail.me"), - ("stickell", "l.stickell@yahoo.it")] - - -getInfo = create_getInfo(MegareleaseOrg) diff --git a/module/plugins/hoster/MegasharesCom.py b/module/plugins/hoster/MegasharesCom.py deleted file mode 100644 index 84777adeb..000000000 --- a/module/plugins/hoster/MegasharesCom.py +++ /dev/null @@ -1,113 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from time import time - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class MegasharesCom(SimpleHoster): - __name__ = "MegasharesCom" - __type__ = "hoster" - __version__ = "0.28" - - __pattern__ = r'http://(?:www\.)?(d\d{2}\.)?megashares\.com/((index\.php)?\?d\d{2}=|dl/)\w+' - - __description__ = """Megashares.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - NAME_PATTERN = r'<h1 class="black xxl"[^>]*title="(?P<N>[^"]+)">' - SIZE_PATTERN = r'<strong><span class="black">Filesize:</span></strong> (?P<S>[\d.,]+) (?P<U>[\w^_]+)' - OFFLINE_PATTERN = r'<dd class="red">(Invalid Link Request|Link has been deleted|Invalid link)' - - LINK_PATTERN = r'<div id="show_download_button_%d"[^>]*>\s*<a href="([^"]+)">' - - PASSPORT_LEFT_PATTERN = r'Your Download Passport is: <[^>]*>(\w+).*?You have.*?<[^>]*>.*?([\d.]+) (\w+)' - PASSPORT_RENEW_PATTERN = r'(\d+):<strong>(\d+)</strong>:<strong>(\d+)</strong>' - REACTIVATE_NUM_PATTERN = r'<input[^>]*id="random_num" value="(\d+)" />' - REACTIVATE_PASSPORT_PATTERN = r'<input[^>]*id="passport_num" value="(\w+)" />' - REQUEST_URI_PATTERN = r'var request_uri = "([^"]+)";' - NO_SLOTS_PATTERN = r'<dd class="red">All download slots for this link are currently filled' - - - def setup(self): - self.resumeDownload = True - self.multiDL = self.premium - - - def handlePremium(self, pyfile): - self.handleDownload(True) - - - def handleFree(self, pyfile): - if self.NO_SLOTS_PATTERN in self.html: - self.retry(wait_time=5 * 60) - - m = re.search(self.REACTIVATE_PASSPORT_PATTERN, self.html) - if m: - passport_num = m.group(1) - request_uri = re.search(self.REQUEST_URI_PATTERN, self.html).group(1) - - for _i in xrange(5): - random_num = re.search(self.REACTIVATE_NUM_PATTERN, self.html).group(1) - - verifyinput = self.decryptCaptcha("http://d01.megashares.com/index.php", - get={'secgfx': "gfx", 'random_num': random_num}) - - self.logInfo(_("Reactivating passport %s: %s %s") % (passport_num, random_num, verifyinput)) - - res = self.load("http://d01.megashares.com%s" % request_uri, - get={'rs' : "check_passport_renewal", - 'rsargs[]': verifyinput, - 'rsargs[]': random_num, - 'rsargs[]': passport_num, - 'rsargs[]': "replace_sec_pprenewal", - 'rsrnd[]' : str(int(time() * 1000))}) - - if 'Thank you for reactivating your passport.' in res: - self.correctCaptcha() - self.retry() - else: - self.invalidCaptcha() - else: - self.fail(_("Failed to reactivate passport")) - - m = re.search(self.PASSPORT_RENEW_PATTERN, self.html) - if m: - time = [int(x) for x in m.groups()] - renew = time[0] + (time[1] * 60) + (time[2] * 60) - self.logDebug("Waiting %d seconds for a new passport" % renew) - self.retry(wait_time=renew, reason=_("Passport renewal")) - - # Check traffic left on passport - m = re.search(self.PASSPORT_LEFT_PATTERN, self.html, re.M | re.S) - if m is None: - self.fail(_("Passport not found")) - - self.logInfo(_("Download passport: %s") % m.group(1)) - data_left = float(m.group(2)) * 1024 ** {'B': 0, 'KB': 1, 'MB': 2, 'GB': 3}[m.group(3)] - self.logInfo(_("Data left: %s %s (%d MB needed)") % (m.group(2), m.group(3), self.pyfile.size / 1048576)) - - if not data_left: - self.retry(wait_time=600, reason=_("Passport renewal")) - - self.handleDownload(False) - - - def handleDownload(self, premium=False): - # Find download link; - m = re.search(self.LINK_PATTERN % (1 if premium else 2), self.html) - msg = _('%s download URL' % ('Premium' if premium else 'Free')) - if m is None: - self.error(msg) - - download_url = m.group(1) - self.logDebug("%s: %s" % (msg, download_url)) - self.download(download_url) - - -getInfo = create_getInfo(MegasharesCom) diff --git a/module/plugins/hoster/MegauploadCom.py b/module/plugins/hoster/MegauploadCom.py deleted file mode 100644 index 7896dabfb..000000000 --- a/module/plugins/hoster/MegauploadCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class MegauploadCom(DeadHoster): - __name__ = "MegauploadCom" - __type__ = "hoster" - __version__ = "0.31" - - __pattern__ = r'http://(?:www\.)?megaupload\.com/\?.*&?(d|v)=\w+' - - __description__ = """Megaupload.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("spoob", "spoob@pyload.org")] - - -getInfo = create_getInfo(MegauploadCom) diff --git a/module/plugins/hoster/MegavideoCom.py b/module/plugins/hoster/MegavideoCom.py deleted file mode 100644 index 02054fecb..000000000 --- a/module/plugins/hoster/MegavideoCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class MegavideoCom(DeadHoster): - __name__ = "MegavideoCom" - __type__ = "hoster" - __version__ = "0.21" - - __pattern__ = r'http://(?:www\.)?megavideo\.com/\?.*&?(d|v)=\w+' - - __description__ = """Megavideo.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("jeix", "jeix@hasnomail.de"), - ("mkaay", "mkaay@mkaay.de")] - - -getInfo = create_getInfo(MegavideoCom) diff --git a/module/plugins/hoster/MovReelCom.py b/module/plugins/hoster/MovReelCom.py deleted file mode 100644 index 3e18a8960..000000000 --- a/module/plugins/hoster/MovReelCom.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class MovReelCom(XFSHoster): - __name__ = "MovReelCom" - __type__ = "hoster" - __version__ = "1.24" - - __pattern__ = r'http://(?:www\.)?movreel\.com/\w{12}' - - __description__ = """MovReel.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("JorisV83", "jorisv83-pyload@yahoo.com")] - - - LINK_PATTERN = r'<a href="([^"]+)">Download Link' - - -getInfo = create_getInfo(MovReelCom) diff --git a/module/plugins/hoster/MultihostersCom.py b/module/plugins/hoster/MultihostersCom.py deleted file mode 100644 index bcd7c6237..000000000 --- a/module/plugins/hoster/MultihostersCom.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.hoster.ZeveraCom import ZeveraCom - - -class MultihostersCom(ZeveraCom): - __name__ = "MultihostersCom" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'https?://(?:www\.)multihosters\.com/(getFiles\.ashx|Members/download\.ashx)\?.*ourl=.+' - - __description__ = """Multihosters.com multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("tjeh", "tjeh@gmx.net")] diff --git a/module/plugins/hoster/MultishareCz.py b/module/plugins/hoster/MultishareCz.py deleted file mode 100644 index ca626a833..000000000 --- a/module/plugins/hoster/MultishareCz.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from random import random - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class MultishareCz(SimpleHoster): - __name__ = "MultishareCz" - __type__ = "hoster" - __version__ = "0.40" - - __pattern__ = r'http://(?:www\.)?multishare\.cz/stahnout/(?P<ID>\d+)' - - __description__ = """MultiShare.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - SIZE_REPLACEMENTS = [(' ', '')] - - CHECK_TRAFFIC = True - MULTI_HOSTER = True - - INFO_PATTERN = ur'(?:<li>Název|Soubor): <strong>(?P<N>[^<]+)</strong><(?:/li><li|br)>Velikost: <strong>(?P<S>[^<]+)</strong>' - OFFLINE_PATTERN = ur'<h1>Stáhnout soubor</h1><p><strong>PoÅŸadovanÃœ soubor neexistuje.</strong></p>' - - - def handleFree(self, pyfile): - self.download("http://www.multishare.cz/html/download_free.php", get={'ID': self.info['pattern']['ID']}) - - - def handlePremium(self, pyfile): - self.download("http://www.multishare.cz/html/download_premium.php", get={'ID': self.info['pattern']['ID']}) - - - def handleMulti(self, pyfile): - self.html = self.load('http://www.multishare.cz/html/mms_ajax.php', post={"link": pyfile.url}, decode=True) - - self.checkInfo() - - if not self.checkTrafficLeft(): - self.fail(_("Not enough credit left to download file")) - - self.download("http://dl%d.mms.multishare.cz/html/mms_process.php" % round(random() * 10000 * random()), - get={'u_ID' : self.acc_info['u_ID'], - 'u_hash': self.acc_info['u_hash'], - 'link' : pyfile.url}, - disposition=True) - - -getInfo = create_getInfo(MultishareCz) diff --git a/module/plugins/hoster/MyfastfileCom.py b/module/plugins/hoster/MyfastfileCom.py deleted file mode 100644 index 3862bfe32..000000000 --- a/module/plugins/hoster/MyfastfileCom.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.common.json_layer import json_loads -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo - - -class MyfastfileCom(MultiHoster): - __name__ = "MyfastfileCom" - __type__ = "hoster" - __version__ = "0.08" - - __pattern__ = r'http://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/dl/' - - __description__ = """Myfastfile.com multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - - def setup(self): - self.chunkLimit = -1 - - - def handlePremium(self, pyfile): - self.html = self.load('http://myfastfile.com/api.php', - get={'user': self.user, 'pass': self.account.getAccountData(self.user)['password'], - 'link': pyfile.url}) - self.logDebug("JSON data: " + self.html) - - self.html = json_loads(self.html) - if self.html['status'] != 'ok': - self.fail(_("Unable to unrestrict link")) - - self.link = self.html['link'] - - -getInfo = create_getInfo(MyfastfileCom) diff --git a/module/plugins/hoster/MystoreTo.py b/module/plugins/hoster/MystoreTo.py deleted file mode 100644 index 3bb424d4d..000000000 --- a/module/plugins/hoster/MystoreTo.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test link: -# http://mystore.to/dl/mxcA50jKfP - -import re - -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class MystoreTo(SimpleHoster): - __name__ = "MystoreTo" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'https?://(?:www\.)?mystore\.to/dl/.+' - - __description__ = """Mystore.to hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "")] - - - NAME_PATTERN = r'<h1>(?P<N>.+?)<' - SIZE_PATTERN = r'FILESIZE: (?P<S>[\d\.,]+) (?P<U>[\w^_]+)' - OFFLINE_PATTERN = r'>file not found<' - - - def setup(self): - self.chunkLimit = 1 - self.resumeDownload = True - self.multiDL = True - - - def handleFree(self, pyfile): - try: - fid = re.search(r'wert="(.+?)"', self.html).group(1) - - except AttributeError: - self.error(_("File-ID not found")) - - self.link = self.load("http://mystore.to/api/download", - post={'FID': fid}) - - -getInfo = create_getInfo(MystoreTo) diff --git a/module/plugins/hoster/NahrajCz.py b/module/plugins/hoster/NahrajCz.py deleted file mode 100644 index 5c5c71ae6..000000000 --- a/module/plugins/hoster/NahrajCz.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class NahrajCz(DeadHoster): - __name__ = "NahrajCz" - __type__ = "hoster" - __version__ = "0.21" - - __pattern__ = r'http://(?:www\.)?nahraj\.cz/content/download/.+' - - __description__ = """Nahraj.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(NahrajCz) diff --git a/module/plugins/hoster/NarodRu.py b/module/plugins/hoster/NarodRu.py deleted file mode 100644 index 1738d9724..000000000 --- a/module/plugins/hoster/NarodRu.py +++ /dev/null @@ -1,66 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from random import random - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class NarodRu(SimpleHoster): - __name__ = "NarodRu" - __type__ = "hoster" - __version__ = "0.12" - - __pattern__ = r'http://(?:www\.)?narod(\.yandex)?\.ru/(disk|start/\d+\.\w+-narod\.yandex\.ru)/(?P<ID>\d+)/.+' - - __description__ = """Narod.ru hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<dt class="name">(?:<[^<]*>)*(?P<N>[^<]+)</dt>' - SIZE_PATTERN = r'<dd class="size">(?P<S>\d[^<]*)</dd>' - OFFLINE_PATTERN = r'<title>404</title>|Ѐайл ÑЎалеМ Ñ ÑеÑвОÑа|ÐакПМÑОлÑÑ ÑÑПк Ñ
ÑÐ°ÐœÐµÐœÐžÑ Ñайла\.' - - SIZE_REPLACEMENTS = [(u'ÐÐ', 'KB'), (u'ÐÐ', 'MB'), (u'ÐÐ', 'GB')] - URL_REPLACEMENTS = [("narod.yandex.ru/", "narod.ru/"), - (r"/start/\d+\.\w+-narod\.yandex\.ru/(\d{6,15})/\w+/(\w+)", r"/disk/\1/\2")] - - CAPTCHA_PATTERN = r'<number url="(.*?)">(\w+)</number>' - LINK_FREE_PATTERN = r'<a class="h-link" rel="yandex_bar" href="(.+?)">' - - - def handleFree(self, pyfile): - for _i in xrange(5): - self.html = self.load('http://narod.ru/disk/getcapchaxml/?rnd=%d' % int(random() * 777)) - - m = re.search(self.CAPTCHA_PATTERN, self.html) - if m is None: - self.error(_("Captcha")) - - post_data = {"action": "sendcapcha"} - captcha_url, post_data['key'] = m.groups() - post_data['rep'] = self.decryptCaptcha(captcha_url) - - self.html = self.load(pyfile.url, post=post_data, decode=True) - - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m: - url = 'http://narod.ru' + m.group(1) - self.correctCaptcha() - break - - elif u'<b class="error-msg"><strong>ÐÑОблОÑÑ?</strong>' in self.html: - self.invalidCaptcha() - - else: - self.error(_("Download link")) - - else: - self.fail(_("No valid captcha code entered")) - - self.download(url) - - -getInfo = create_getInfo(NarodRu) diff --git a/module/plugins/hoster/NitroflareCom.py b/module/plugins/hoster/NitroflareCom.py deleted file mode 100644 index 5bbef64de..000000000 --- a/module/plugins/hoster/NitroflareCom.py +++ /dev/null @@ -1,107 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Note: -# Right now premium support is not added -# Thus, any file that require premium support -# cannot be downloaded. Only the file that is free to -# download can be downloaded. - -import re - -from module.common.json_layer import json_loads -from module.plugins.internal.CaptchaService import ReCaptcha -from module.plugins.internal.SimpleHoster import SimpleHoster - - -class NitroflareCom(SimpleHoster): - __name__ = "NitroflareCom" - __type__ = "hoster" - __version__ = "0.08" - - __pattern__ = r'https?://(?:www\.)?nitroflare\.com/view/(?P<ID>[\w^_]+)' - - __description__ = """Nitroflare.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("sahil", "sahilshekhawat01@gmail.com"), - ("Walter Purcaro", "vuolter@gmail.com"), - ("Stickell", "l.stickell@yahoo.it")] - - # URL_REPLACEMENTS = [("http://", "https://")] - - INFO_PATTERN = r'title="(?P<N>.+?)".+>(?P<S>[\d.,]+) (?P<U>[\w^_]+)' - OFFLINE_PATTERN = r'>File doesn\'t exist' - - LINK_FREE_PATTERN = r'(https?://[\w\-]+\.nitroflare\.com/.+?)"' - - RECAPTCHA_KEY = "6Lenx_USAAAAAF5L1pmTWvWcH73dipAEzNnmNLgy" - - PREMIUM_ONLY_PATTERN = r'This file is available with Premium only' - WAIT_PATTERN = r'You have to wait .+' - ERROR_PATTERN = r'downloading is not possible' - - - def checkErrors(self): - if not self.html: - return - - if not self.premium and re.search(self.PREMIUM_ONLY_PATTERN, self.html): - self.fail(_("Link require a premium account to be handled")) - - elif hasattr(self, 'WAIT_PATTERN'): - m = re.search(self.WAIT_PATTERN, self.html) - if m: - wait_time = sum(int(v) * {"hr": 3600, "hour": 3600, "min": 60, "sec": 1}[u.lower()] for v, u in - re.findall(r'(\d+)\s*(hr|hour|min|sec)', m.group(0), re.I)) - self.wait(wait_time, wait_time > 300) - return - - elif hasattr(self, 'ERROR_PATTERN'): - m = re.search(self.ERROR_PATTERN, self.html) - if m: - errmsg = self.info['error'] = m.group(1) - self.error(errmsg) - - self.info.pop('error', None) - - - def handleFree(self, pyfile): - # used here to load the cookies which will be required later - self.load(pyfile.url, post={'goToFreePage': ""}) - - self.load("https://www.nitroflare.com/ajax/setCookie.php", post={'fileId': self.info['pattern']['ID']}) - self.html = self.load("https://www.nitroflare.com/ajax/freeDownload.php", - post={'method': "startTimer", 'fileId': self.info['pattern']['ID']}) - - self.checkErrors() - - try: - js_file = self.load("http://nitroflare.com/js/downloadFree.js?v=1.0.1") - var_time = re.search("var time = (\\d+);", js_file) - wait_time = int(var_time.groups()[0]) - - except Exception: - wait_time = 60 - - self.wait(wait_time) - - recaptcha = ReCaptcha(self) - response, challenge = recaptcha.challenge(self.RECAPTCHA_KEY) - - self.html = self.load("https://www.nitroflare.com/ajax/freeDownload.php", - post={'method' : "fetchDownload", - 'recaptcha_challenge_field': challenge, - 'recaptcha_response_field' : response}) - - if "The captcha wasn't entered correctly" in self.html: - self.logWarning("The captcha wasn't entered correctly") - return - - if "You have to fill the captcha" in self.html: - self.logWarning("Captcha unfilled") - return - - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m: - self.link = m.group(1) - else: - self.logError("Unable to detect direct link") diff --git a/module/plugins/hoster/NoPremiumPl.py b/module/plugins/hoster/NoPremiumPl.py deleted file mode 100644 index 43ae8b3cc..000000000 --- a/module/plugins/hoster/NoPremiumPl.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.common.json_layer import json_loads -from module.plugins.internal.MultiHoster import MultiHoster - - -class NoPremiumPl(MultiHoster): - __name__ = "NoPremiumPl" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'https?://direct\.nopremium\.pl.+' - - __description__ = """NoPremium.pl multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("goddie", "dev@nopremium.pl")] - - - API_URL = "http://crypt.nopremium.pl" - - API_QUERY = {'site' : "nopremium", - 'output' : "json", - 'username': "", - 'password': "", - 'url' : ""} - - ERROR_CODES = {0 : "[%s] Incorrect login credentials", - 1 : "[%s] Not enough transfer to download - top-up your account", - 2 : "[%s] Incorrect / dead link", - 3 : "[%s] Error connecting to hosting, try again later", - 9 : "[%s] Premium account has expired", - 15: "[%s] Hosting no longer supported", - 80: "[%s] Too many incorrect login attempts, account blocked for 24h"} - - - def prepare(self): - super(NoPremiumPl, self).prepare() - - data = self.account.getAccountData(self.user) - - self.usr = data['usr'] - self.pwd = data['pwd'] - - - def runFileQuery(self, url, mode=None): - query = self.API_QUERY.copy() - - query["username"] = self.usr - query["password"] = self.pwd - query["url"] = url - - if mode == "fileinfo": - query['check'] = 2 - query['loc'] = 1 - - self.logDebug(query) - - return self.load(self.API_URL, post=query) - - - def handleFree(self, pyfile): - try: - data = self.runFileQuery(pyfile.url, 'fileinfo') - - except Exception: - self.logDebug("runFileQuery error") - self.tempOffline() - - try: - parsed = json_loads(data) - - except Exception: - self.logDebug("loads error") - self.tempOffline() - - self.logDebug(parsed) - - if "errno" in parsed.keys(): - if parsed["errno"] in self.ERROR_CODES: - # error code in known - self.fail(self.ERROR_CODES[parsed["errno"]] % self.__name__) - else: - # error code isn't yet added to plugin - self.fail( - parsed["errstring"] - or _("Unknown error (code: %s)") % parsed["errno"] - ) - - if "sdownload" in parsed: - if parsed["sdownload"] == "1": - self.fail( - _("Download from %s is possible only using NoPremium.pl website \ - directly") % parsed["hosting"]) - - pyfile.name = parsed["filename"] - pyfile.size = parsed["filesize"] - - try: - self.link = self.runFileQuery(pyfile.url, 'filedownload') - - except Exception: - self.logDebug("runFileQuery error #2") - self.tempOffline() diff --git a/module/plugins/hoster/NosuploadCom.py b/module/plugins/hoster/NosuploadCom.py deleted file mode 100644 index 842481a60..000000000 --- a/module/plugins/hoster/NosuploadCom.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class NosuploadCom(XFSHoster): - __name__ = "NosuploadCom" - __type__ = "hoster" - __version__ = "0.31" - - __pattern__ = r'http://(?:www\.)?nosupload\.com/\?d=\w{12}' - - __description__ = """Nosupload.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("igel", "igelkun@myopera.com")] - - - SIZE_PATTERN = r'<p><strong>Size:</strong> (?P<S>[\d.,]+) (?P<U>[\w^_]+)</p>' - LINK_PATTERN = r'<a class="select" href="(http://.+?)">Download</a>' - - WAIT_PATTERN = r'Please wait.*?>(\d+)</span>' - - - def getDownloadLink(self): - # stage1: press the "Free Download" button - data = self.getPostParameters() - self.html = self.load(self.pyfile.url, post=data, ref=True, decode=True) - - # stage2: wait some time and press the "Download File" button - data = self.getPostParameters() - wait_time = re.search(self.WAIT_PATTERN, self.html, re.M | re.S).group(1) - self.logDebug("Hoster told us to wait %s seconds" % wait_time) - self.wait(wait_time) - self.html = self.load(self.pyfile.url, post=data, ref=True, decode=True) - - # stage3: get the download link - return re.search(self.LINK_PATTERN, self.html, re.S).group(1) - - -getInfo = create_getInfo(NosuploadCom) diff --git a/module/plugins/hoster/NovafileCom.py b/module/plugins/hoster/NovafileCom.py deleted file mode 100644 index f73570ec2..000000000 --- a/module/plugins/hoster/NovafileCom.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# http://novafile.com/vfun4z6o2cit -# http://novafile.com/s6zrr5wemuz4 - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class NovafileCom(XFSHoster): - __name__ = "NovafileCom" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'http://(?:www\.)?novafile\.com/\w{12}' - - __description__ = """Novafile.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("stickell", "l.stickell@yahoo.it")] - - - ERROR_PATTERN = r'class="alert[^"]*alert-separate"[^>]*>\s*(?:<p>)?(.*?)\s*</' - WAIT_PATTERN = r'<p>Please wait <span id="count"[^>]*>(\d+)</span> seconds</p>' - - LINK_PATTERN = r'<a href="(http://s\d+\.novafile\.com/.*?)" class="btn btn-green">Download File</a>' - - -getInfo = create_getInfo(NovafileCom) diff --git a/module/plugins/hoster/NowDownloadSx.py b/module/plugins/hoster/NowDownloadSx.py deleted file mode 100644 index 44a24471b..000000000 --- a/module/plugins/hoster/NowDownloadSx.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo -from pyload.utils import fixup - - -class NowDownloadSx(SimpleHoster): - __name__ = "NowDownloadSx" - __type__ = "hoster" - __version__ = "0.07" - - __pattern__ = r'http://(?:www\.)?(nowdownload\.(at|ch|co|eu|sx)/(dl/|download\.php\?id=)|likeupload\.org/)\w+' - - __description__ = """NowDownload.sx hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("godofdream", "soilfiction@gmail.com"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - INFO_PATTERN = r'Downloading</span> <br> (?P<N>.*) (?P<S>[\d.,]+) (?P<U>[\w^_]+) </h4>' - OFFLINE_PATTERN = r'>This file does not exist' - - TOKEN_PATTERN = r'"(/api/token\.php\?token=\w+)"' - CONTINUE_PATTERN = r'"(/dl2/\w+/\w+)"' - WAIT_PATTERN = r'\.countdown\(\{until: \+(\d+),' - LINK_FREE_PATTERN = r'(http://s\d+\.coolcdn\.info/nowdownload/.+?)["\']' - - NAME_REPLACEMENTS = [("&#?\w+;", fixup), (r'<[^>]*>', '')] - - - def setup(self): - self.resumeDownload = True - self.multiDL = True - self.chunkLimit = -1 - - - def handleFree(self, pyfile): - tokenlink = re.search(self.TOKEN_PATTERN, self.html) - continuelink = re.search(self.CONTINUE_PATTERN, self.html) - if tokenlink is None or continuelink is None: - self.error() - - m = re.search(self.WAIT_PATTERN, self.html) - if m: - wait = int(m.group(1)) - else: - wait = 60 - - baseurl = "http://www.nowdownload.at" - self.html = self.load(baseurl + str(tokenlink.group(1))) - self.wait(wait) - - self.html = self.load(baseurl + str(continuelink.group(1))) - - url = re.search(self.LINK_FREE_PATTERN, self.html) - if url is None: - self.error(_("Download link not found")) - - self.download(str(url.group(1))) - - -getInfo = create_getInfo(NowDownloadSx) diff --git a/module/plugins/hoster/NowVideoSx.py b/module/plugins/hoster/NowVideoSx.py deleted file mode 100644 index fc1d06d19..000000000 --- a/module/plugins/hoster/NowVideoSx.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class NowVideoSx(SimpleHoster): - __name__ = "NowVideoSx" - __type__ = "hoster" - __version__ = "0.10" - - __pattern__ = r'http://(?:www\.)?nowvideo\.(at|ch|co|eu|li|sx)/(video|mobile/#/videos)/(?P<ID>\w+)' - - __description__ = """NowVideo.sx hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - URL_REPLACEMENTS = [(__pattern__ + ".*", r'http://www.nowvideo.sx/video/\g<ID>')] - - NAME_PATTERN = r'<h4>(?P<N>.+?)<' - OFFLINE_PATTERN = r'>This file no longer exists' - - LINK_FREE_PATTERN = r'<source src="(.+?)"' - LINK_PREMIUM_PATTERN = r'<div id="content_player" >\s*<a href="(.+?)"' - - - def setup(self): - self.resumeDownload = True - self.multiDL = True - - - def handleFree(self, pyfile): - self.html = self.load("http://www.nowvideo.sx/mobile/video.php", get={'id': self.info['pattern']['ID']}) - - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("Free download link not found")) - - self.download(m.group(1)) - - -getInfo = create_getInfo(NowVideoSx) diff --git a/module/plugins/hoster/OneFichierCom.py b/module/plugins/hoster/OneFichierCom.py deleted file mode 100644 index 5be05ea17..000000000 --- a/module/plugins/hoster/OneFichierCom.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class OneFichierCom(SimpleHoster): - __name__ = "OneFichierCom" - __type__ = "hoster" - __version__ = "0.78" - - __pattern__ = r'https?://(?:www\.)?(?:(?P<ID1>\w+)\.)?(?P<HOST>1fichier\.com|alterupload\.com|cjoint\.net|d(es)?fichiers\.com|dl4free\.com|megadl\.fr|mesfichiers\.org|piecejointe\.net|pjointe\.com|tenvoi\.com)(?:/\?(?P<ID2>\w+))?' - - __description__ = """1fichier.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("fragonib", "fragonib[AT]yahoo[DOT]es"), - ("the-razer", "daniel_ AT gmx DOT net"), - ("zoidberg", "zoidberg@mujmail.cz"), - ("imclem", ""), - ("stickell", "l.stickell@yahoo.it"), - ("Elrick69", "elrick69[AT]rocketmail[DOT]com"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - NAME_PATTERN = r'>FileName :</td>\s*<td.*>(?P<N>.+?)<' - SIZE_PATTERN = r'>Size :</td>\s*<td.*>(?P<S>[\d.,]+) (?P<U>[\w^_]+)' - - OFFLINE_PATTERN = r'File not found !\s*<' - - COOKIES = [("1fichier.com", "LG", "en")] - DISPOSITION = False #: Remove in 0.4.10 - - WAIT_PATTERN = r'>You must wait (\d+) minutes' - - - def setup(self): - self.multiDL = self.premium - self.resumeDownload = True - - - def handleFree(self, pyfile): - id = self.info['pattern']['ID1'] or self.info['pattern']['ID2'] - url, inputs = self.parseHtmlForm('action="https://1fichier.com/\?%s' % id) - - if not url: - self.fail(_("Download link not found")) - - if "pass" in inputs: - inputs['pass'] = self.getPassword() - - inputs['submit'] = "Download" - - self.download(url, post=inputs) - - - def handlePremium(self, pyfile): - self.download(pyfile.url, post={'dl': "Download", 'did': 0}) - - -getInfo = create_getInfo(OneFichierCom) diff --git a/module/plugins/hoster/OronCom.py b/module/plugins/hoster/OronCom.py deleted file mode 100644 index cbbaedae0..000000000 --- a/module/plugins/hoster/OronCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class OronCom(DeadHoster): - __name__ = "OronCom" - __type__ = "hoster" - __version__ = "0.14" - - __pattern__ = r'https?://(?:www\.)?oron\.com/\w{12}' - - __description__ = """Oron.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("chrox", "chrox@pyload.org"), - ("DHMH", "DHMH@pyload.org")] - - -getInfo = create_getInfo(OronCom) diff --git a/module/plugins/hoster/OverLoadMe.py b/module/plugins/hoster/OverLoadMe.py deleted file mode 100644 index 67563ca3d..000000000 --- a/module/plugins/hoster/OverLoadMe.py +++ /dev/null @@ -1,76 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from random import randrange -from urllib import unquote - -from module.common.json_layer import json_loads -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo -from module.utils import parseFileSize - - -class OverLoadMe(MultiHoster): - __name__ = "OverLoadMe" - __type__ = "hoster" - __version__ = "0.09" - - __pattern__ = r'https?://.*overload\.me/.+' - - __description__ = """Over-Load.me multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("marley", "marley@over-load.me")] - - - def getFilename(self, url): - try: - name = unquote(url.rsplit("/", 1)[1]) - except IndexError: - name = "Unknown_Filename..." - - if name.endswith("..."): #: incomplete filename, append random stuff - name += "%s.tmp" % randrange(100, 999) - - return name - - - def setup(self): - self.chunkLimit = 5 - - - def handlePremium(self, pyfile): - https = "https" if self.getConfig("ssl") else "http" - data = self.account.getAccountData(self.user) - page = self.load(https + "://api.over-load.me/getdownload.php", - get={'auth': data['password'], - 'link': pyfile.url}) - - data = json_loads(page) - - self.logDebug(data) - - if data['error'] == 1: - self.logWarning(data['msg']) - self.tempOffline() - else: - if pyfile.name is not None and pyfile.name.endswith('.tmp') and data['filename']: - pyfile.name = data['filename'] - pyfile.size = parseFileSize(data['filesize']) - - http_repl = ["http://", "https://"] - self.link = data['downloadlink'].replace(*http_repl if self.getConfig("ssl") else *http_repl[::-1]) - - if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown") or pyfile.name.endswith('..'): - # only use when name wasn't already set - pyfile.name = self.getFilename(self.link) - - - def checkFile(self): - if self.checkDownload({"error": "<title>An error occured while processing your request</title>"}) - # usual this download can safely be retried - self.retry(wait_time=60, reason=_("An error occured while generating link.")) - - return super(OverLoadMe, self).checkFile() - - -getInfo = create_getInfo(OverLoadMe) diff --git a/module/plugins/hoster/PandaplaNet.py b/module/plugins/hoster/PandaplaNet.py deleted file mode 100644 index a078ca3c9..000000000 --- a/module/plugins/hoster/PandaplaNet.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class PandaplaNet(DeadHoster): - __name__ = "PandaplaNet" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?pandapla\.net/\w{12}' - - __description__ = """Pandapla.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("t4skforce", "t4skforce1337[AT]gmail[DOT]com")] - - -getInfo = create_getInfo(PandaplaNet) diff --git a/module/plugins/hoster/PotloadCom.py b/module/plugins/hoster/PotloadCom.py deleted file mode 100644 index bcbcb57d0..000000000 --- a/module/plugins/hoster/PotloadCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class PotloadCom(DeadHoster): - __name__ = "PotloadCom" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?potload\.com/\w{12}' - - __description__ = """Potload.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - -getInfo = create_getInfo(PotloadCom) diff --git a/module/plugins/hoster/PremiumTo.py b/module/plugins/hoster/PremiumTo.py deleted file mode 100644 index b66b9a505..000000000 --- a/module/plugins/hoster/PremiumTo.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -from os import remove - -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo -from module.utils import fs_encode - - -class PremiumTo(MultiHoster): - __name__ = "PremiumTo" - __type__ = "hoster" - __version__ = "0.21" - - __pattern__ = r'^unmatchable$' - - __description__ = """Premium.to multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("zoidberg", "zoidberg@mujmail.cz"), - ("stickell", "l.stickell@yahoo.it")] - - - CHECK_TRAFFIC = True - - - def handlePremium(self, pyfile): - #raise timeout to 2min - self.download("http://premium.to/api/getfile.php", - get={'username': self.account.username, - 'password': self.account.password, - 'link' : pyfile.url}, - disposition=True) - - - def checkFile(self): - if self.checkDownload({'nopremium': "No premium account available"}): - self.retry(60, 5 * 60, "No premium account available") - - err = '' - if self.req.http.code == '420': - # Custom error code send - fail - file = fs_encode(self.lastDownload) - with open(file, "rb") as f: - err = f.read(256).strip() - remove(file) - - if err: - self.fail(err) - - return super(PremiumTo, self).checkFile() - - -getInfo = create_getInfo(PremiumTo) diff --git a/module/plugins/hoster/PremiumizeMe.py b/module/plugins/hoster/PremiumizeMe.py deleted file mode 100644 index 3d19c88ac..000000000 --- a/module/plugins/hoster/PremiumizeMe.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.common.json_layer import json_loads -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo - - -class PremiumizeMe(MultiHoster): - __name__ = "PremiumizeMe" - __type__ = "hoster" - __version__ = "0.16" - - __pattern__ = r'^unmatchable$' #: Since we want to allow the user to specify the list of hoster to use we let MultiHoster.coreReady - - __description__ = """Premiumize.me multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Florian Franzen", "FlorianFranzen@gmail.com")] - - - def handlePremium(self, pyfile): - # In some cases hostsers do not supply us with a filename at download, so we - # are going to set a fall back filename (e.g. for freakshare or xfileshare) - pyfile.name = pyfile.name.split('/').pop() # Remove everthing before last slash - - # Correction for automatic assigned filename: Removing html at end if needed - suffix_to_remove = ["html", "htm", "php", "php3", "asp", "shtm", "shtml", "cfml", "cfm"] - temp = pyfile.name.split('.') - if temp.pop() in suffix_to_remove: - pyfile.name = ".".join(temp) - - # Get account data - user, data = self.account.selectAccount() - - # Get rewritten link using the premiumize.me api v1 (see https://secure.premiumize.me/?show=api) - data = json_loads(self.load("https://api.premiumize.me/pm-api/v1.php", - get={'method' : "directdownloadlink", - 'params[login]': user, - 'params[pass]' : data['password'], - 'params[link]' : pyfile.url})) - - # Check status and decide what to do - status = data['status'] - - if status == 200: - self.link = data['result']['location'] - return - - elif status == 400: - self.fail(_("Invalid link")) - - elif status == 404: - self.offline() - - elif status >= 500: - self.tempOffline() - - else: - self.fail(data['statusmessage']) - - -getInfo = create_getInfo(PremiumizeMe) diff --git a/module/plugins/hoster/PromptfileCom.py b/module/plugins/hoster/PromptfileCom.py deleted file mode 100644 index 2aaf14736..000000000 --- a/module/plugins/hoster/PromptfileCom.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class PromptfileCom(SimpleHoster): - __name__ = "PromptfileCom" - __type__ = "hoster" - __version__ = "0.13" - - __pattern__ = r'https?://(?:www\.)?promptfile\.com/' - - __description__ = """Promptfile.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("igel", "igelkun@myopera.com")] - - - INFO_PATTERN = r'<span style="[^"]*" title="[^"]*">(?P<N>.*?) \((?P<S>[\d.,]+) (?P<U>[\w^_]+)\)</span>' - OFFLINE_PATTERN = r'<span style="[^"]*" title="File Not Found">File Not Found</span>' - - CHASH_PATTERN = r'<input type="hidden" name="chash" value="([^"]*)" />' - LINK_FREE_PATTERN = r'<a href=\"(.+)\" target=\"_blank\" class=\"view_dl_link\">Download File</a>' - - - def handleFree(self, pyfile): - # STAGE 1: get link to continue - m = re.search(self.CHASH_PATTERN, self.html) - if m is None: - self.error(_("CHASH_PATTERN not found")) - chash = m.group(1) - self.logDebug("Read chash %s" % chash) - # continue to stage2 - self.html = self.load(pyfile.url, decode=True, post={'chash': chash}) - - # STAGE 2: get the direct link - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("LINK_FREE_PATTERN not found")) - - self.link = m.group(1) - - -getInfo = create_getInfo(PromptfileCom) diff --git a/module/plugins/hoster/PrzeklejPl.py b/module/plugins/hoster/PrzeklejPl.py deleted file mode 100644 index ff19c770e..000000000 --- a/module/plugins/hoster/PrzeklejPl.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class PrzeklejPl(DeadHoster): - __name__ = "PrzeklejPl" - __type__ = "hoster" - __version__ = "0.11" - - __pattern__ = r'http://(?:www\.)?przeklej\.pl/plik/.+' - - __description__ = """Przeklej.pl hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(PrzeklejPl) diff --git a/module/plugins/hoster/PutdriveCom.py b/module/plugins/hoster/PutdriveCom.py deleted file mode 100644 index 7f4b7b6cc..000000000 --- a/module/plugins/hoster/PutdriveCom.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.hoster.ZeveraCom import ZeveraCom - - -class PutdriveCom(ZeveraCom): - __name__ = "PutdriveCom" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'https?://(?:www\.)putdrive\.com/(getFiles\.ashx|Members/download\.ashx)\?.*ourl=.+' - - __description__ = """Multihosters.com multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] diff --git a/module/plugins/hoster/QuickshareCz.py b/module/plugins/hoster/QuickshareCz.py deleted file mode 100644 index 5a3fd871b..000000000 --- a/module/plugins/hoster/QuickshareCz.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class QuickshareCz(SimpleHoster): - __name__ = "QuickshareCz" - __type__ = "hoster" - __version__ = "0.56" - - __pattern__ = r'http://(?:[^/]*\.)?quickshare\.cz/stahnout-soubor/.+' - - __description__ = """Quickshare.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<th width="145px">Název:</th>\s*<td style="word-wrap:break-word;">(?P<N>[^<]+)</td>' - SIZE_PATTERN = r'<th>Velikost:</th>\s*<td>(?P<S>[\d.,]+) (?P<U>[\w^_]+)</td>' - OFFLINE_PATTERN = r'<script type="text/javascript">location\.href=\'/chyba\';</script>' - - - def process(self, pyfile): - self.html = self.load(pyfile.url, decode=True) - self.getFileInfo() - - # parse js variables - self.jsvars = dict((x, y.strip("'")) for x, y in re.findall(r"var (\w+) = ([\d.]+|'[^']*')", self.html)) - self.logDebug(self.jsvars) - pyfile.name = self.jsvars['ID3'] - - # determine download type - free or premium - if self.premium: - if 'UU_prihlasen' in self.jsvars: - if self.jsvars['UU_prihlasen'] == '0': - self.logWarning(_("User not logged in")) - self.relogin(self.user) - self.retry() - elif float(self.jsvars['UU_kredit']) < float(self.jsvars['kredit_odecet']): - self.logWarning(_("Not enough credit left")) - self.premium = False - - if self.premium: - self.handlePremium(pyfile) - else: - self.handleFree(pyfile) - - if self.checkDownload({"error": re.compile(r"\AChyba!")}, max_size=100): - self.fail(_("File not m or plugin defect")) - - - def handleFree(self, pyfile): - # get download url - download_url = '%s/download.php' % self.jsvars['server'] - data = dict((x, self.jsvars[x]) for x in self.jsvars if x in ("ID1", "ID2", "ID3", "ID4")) - self.logDebug("FREE URL1:" + download_url, data) - - self.load(download_url, post=data, follow_location=False) - self.header = self.req.http.header - - m = re.search(r'Location\s*:\s*(.+)', self.header, re.I) - if m is None: - self.fail(_("File not found")) - download_url = m.group(1) - self.logDebug("FREE URL2:" + download_url) - - # check errors - m = re.search(r'/chyba/(\d+)', download_url) - if m: - if m.group(1) == '1': - self.retry(60, 2 * 60, "This IP is already downloading") - elif m.group(1) == '2': - self.retry(60, 60, "No free slots available") - else: - self.fail(_("Error %d") % m.group(1)) - - # download file - self.download(download_url) - - - def handlePremium(self, pyfile): - download_url = '%s/download_premium.php' % self.jsvars['server'] - data = dict((x, self.jsvars[x]) for x in self.jsvars if x in ("ID1", "ID2", "ID4", "ID5")) - self.download(download_url, get=data) - - -getInfo = create_getInfo(QuickshareCz) diff --git a/module/plugins/hoster/RPNetBiz.py b/module/plugins/hoster/RPNetBiz.py deleted file mode 100644 index 8ab8cb7c4..000000000 --- a/module/plugins/hoster/RPNetBiz.py +++ /dev/null @@ -1,80 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo -from module.common.json_layer import json_loads - - -class RPNetBiz(MultiHoster): - __name__ = "RPNetBiz" - __type__ = "hoster" - __version__ = "0.14" - - __description__ = """RPNet.biz multi-hoster plugin""" - __license__ = "GPLv3" - - __pattern__ = r'https?://.+rpnet\.biz' - __authors__ = [("Dman", "dmanugm@gmail.com")] - - - def setup(self): - self.chunkLimit = -1 - - - def handlePremium(self, pyfile): - user, data = self.account.selectAccount() - - # Get the download link - res = self.load("https://premium.rpnet.biz/client_api.php", - get={"username": user, - "password": data['password'], - "action" : "generate", - "links" : pyfile.url}) - - self.logDebug("JSON data: %s" % res) - link_status = json_loads(res)['links'][0] # get the first link... since we only queried one - - # Check if we only have an id as a HDD link - if 'id' in link_status: - self.logDebug("Need to wait at least 30 seconds before requery") - self.setWait(30) # wait for 30 seconds - self.wait() - # Lets query the server again asking for the status on the link, - # we need to keep doing this until we reach 100 - max_tries = 30 - my_try = 0 - while (my_try <= max_tries): - self.logDebug("Try: %d ; Max Tries: %d" % (my_try, max_tries)) - res = self.load("https://premium.rpnet.biz/client_api.php", - get={"username": user, - "password": data['password'], - "action": "downloadInformation", - "id": link_status['id']}) - self.logDebug("JSON data hdd query: %s" % res) - download_status = json_loads(res)['download'] - - if download_status['status'] == '100': - link_status['generated'] = download_status['rpnet_link'] - self.logDebug("Successfully downloaded to rpnet HDD: %s" % link_status['generated']) - break - else: - self.logDebug("At %s%% for the file download" % download_status['status']) - - self.setWait(30) - self.wait() - my_try += 1 - - if my_try > max_tries: # We went over the limit! - self.fail(_("Waited for about 15 minutes for download to finish but failed")) - - if 'generated' in link_status: - self.link = link_status['generated'] - return - elif 'error' in link_status: - self.fail(link_status['error']) - else: - self.fail(_("Something went wrong, not supposed to enter here")) - - -getInfo = create_getInfo(RPNetBiz) diff --git a/module/plugins/hoster/RapideoPl.py b/module/plugins/hoster/RapideoPl.py deleted file mode 100644 index 85591f51f..000000000 --- a/module/plugins/hoster/RapideoPl.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.common.json_layer import json_loads -from module.plugins.internal.MultiHoster import MultiHoster - - -class RapideoPl(MultiHoster): - __name__ = "RapideoPl" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'^unmatchable$' - - __description__ = """Rapideo.pl multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("goddie", "dev@rapideo.pl")] - - - API_URL = "http://enc.rapideo.pl" - - API_QUERY = {'site' : "newrd", - 'output' : "json", - 'username': "", - 'password': "", - 'url' : ""} - - ERROR_CODES = {0 : "[%s] Incorrect login credentials", - 1 : "[%s] Not enough transfer to download - top-up your account", - 2 : "[%s] Incorrect / dead link", - 3 : "[%s] Error connecting to hosting, try again later", - 9 : "[%s] Premium account has expired", - 15: "[%s] Hosting no longer supported", - 80: "[%s] Too many incorrect login attempts, account blocked for 24h"} - - - def prepare(self): - super(RapideoPl, self).prepare() - - data = self.account.getAccountData(self.user) - - self.usr = data['usr'] - self.pwd = data['pwd'] - - - def runFileQuery(self, url, mode=None): - query = self.API_QUERY.copy() - - query["username"] = self.usr - query["password"] = self.pwd - query["url"] = url - - if mode == "fileinfo": - query['check'] = 2 - query['loc'] = 1 - - self.logDebug(query) - - return self.load(self.API_URL, post=query) - - - def handleFree(self, pyfile): - try: - data = self.runFileQuery(pyfile.url, 'fileinfo') - - except Exception: - self.logDebug("RunFileQuery error") - self.tempOffline() - - try: - parsed = json_loads(data) - - except Exception: - self.logDebug("Loads error") - self.tempOffline() - - self.logDebug(parsed) - - if "errno" in parsed.keys(): - if parsed["errno"] in self.ERROR_CODES: - # error code in known - self.fail(self.ERROR_CODES[parsed["errno"]] % self.__name__) - else: - # error code isn't yet added to plugin - self.fail( - parsed["errstring"] - or _("Unknown error (code: %s)") % parsed["errno"] - ) - - if "sdownload" in parsed: - if parsed["sdownload"] == "1": - self.fail( - _("Download from %s is possible only using Rapideo.pl website \ - directly") % parsed["hosting"]) - - pyfile.name = parsed["filename"] - pyfile.size = parsed["filesize"] - - try: - self.link = self.runFileQuery(pyfile.url, 'filedownload') - - except Exception: - self.logDebug("runFileQuery error #2") - self.tempOffline() diff --git a/module/plugins/hoster/RapidfileshareNet.py b/module/plugins/hoster/RapidfileshareNet.py deleted file mode 100644 index 6d54f72f2..000000000 --- a/module/plugins/hoster/RapidfileshareNet.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class RapidfileshareNet(XFSHoster): - __name__ = "RapidfileshareNet" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?rapidfileshare\.net/\w{12}' - - __description__ = """Rapidfileshare.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("guidobelix", "guidobelix@hotmail.it")] - - - NAME_PATTERN = r'<input type="hidden" name="fname" value="(?P<N>.+?)">' - SIZE_PATTERN = r'>http://www.rapidfileshare.net/\w+?</font> \((?P<S>[\d.,]+) (?P<U>[\w^_]+)\)</font>' - - OFFLINE_PATTERN = r'>No such file with this filename' - TEMP_OFFLINE_PATTERN = r'The page may have been renamed, removed or be temporarily unavailable.<' - - -getInfo = create_getInfo(RapidfileshareNet) diff --git a/module/plugins/hoster/RapidgatorNet.py b/module/plugins/hoster/RapidgatorNet.py deleted file mode 100644 index 2dfd8f59c..000000000 --- a/module/plugins/hoster/RapidgatorNet.py +++ /dev/null @@ -1,172 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pycurl import HTTPHEADER - -from module.common.json_layer import json_loads -from module.network.HTTPRequest import BadHeader -from module.plugins.internal.CaptchaService import AdsCaptcha, ReCaptcha, SolveMedia -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, secondsToMidnight - - -class RapidgatorNet(SimpleHoster): - __name__ = "RapidgatorNet" - __type__ = "hoster" - __version__ = "0.32" - - __pattern__ = r'http://(?:www\.)?(rapidgator\.net|rg\.to)/file/\w+' - - __description__ = """Rapidgator.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("chrox", ""), - ("stickell", "l.stickell@yahoo.it"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - API_URL = "http://rapidgator.net/api/file" - - COOKIES = [("rapidgator.net", "lang", "en")] - - NAME_PATTERN = r'<title>Download file (?P<N>.*)</title>' - SIZE_PATTERN = r'File size:\s*<strong>(?P<S>[\d.,]+) (?P<U>[\w^_]+)</strong>' - OFFLINE_PATTERN = r'>(File not found|Error 404)' - - JSVARS_PATTERN = r'\s+var\s*(startTimerUrl|getDownloadUrl|captchaUrl|fid|secs)\s*=\s*\'?(.*?)\'?;' - - PREMIUM_ONLY_PATTERN = r'You can download files up to|This file can be downloaded by premium only<' - ERROR_PATTERN = r'You have reached your (daily|hourly) downloads limit' - WAIT_PATTERN = r'(Delay between downloads must be not less than|Try again in).+' - - LINK_FREE_PATTERN = r'return \'(http://\w+.rapidgator.net/.*)\';' - - RECAPTCHA_PATTERN = r'"http://api\.recaptcha\.net/challenge\?k=(.*?)"' - ADSCAPTCHA_PATTERN = r'(http://api\.adscaptcha\.com/Get\.aspx[^"\']*)' - SOLVEMEDIA_PATTERN = r'http://api\.solvemedia\.com/papi/challenge\.script\?k=(.*?)"' - - - def setup(self): - if self.account: - self.sid = self.account.getAccountInfo(self.user).get('sid', None) - else: - self.sid = None - - if self.sid: - self.premium = True - - self.resumeDownload = self.multiDL = self.premium - self.chunkLimit = 1 - - - def api_response(self, cmd): - try: - json = self.load('%s/%s' % (self.API_URL, cmd), - get={'sid': self.sid, - 'url': self.pyfile.url}, decode=True) - self.logDebug("API:%s" % cmd, json, "SID: %s" % self.sid) - json = json_loads(json) - status = json['response_status'] - msg = json['response_details'] - - except BadHeader, e: - self.logError("API: %s" % cmd, e, "SID: %s" % self.sid) - status = e.code - msg = e - - if status == 200: - return json['response'] - - elif status == 423: - self.account.empty(self.user) - self.retry() - - else: - self.account.relogin(self.user) - self.retry(wait_time=60) - - - def handlePremium(self, pyfile): - self.api_data = self.api_response('info') - self.api_data['md5'] = self.api_data['hash'] - - pyfile.name = self.api_data['filename'] - pyfile.size = self.api_data['size'] - - self.link = self.api_response('download')['url'] - - - def handleFree(self, pyfile): - jsvars = dict(re.findall(self.JSVARS_PATTERN, self.html)) - self.logDebug(jsvars) - - self.req.http.lastURL = pyfile.url - self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) - - url = "http://rapidgator.net%s?fid=%s" % ( - jsvars.get('startTimerUrl', '/download/AjaxStartTimer'), jsvars['fid']) - jsvars.update(self.getJsonResponse(url)) - - self.wait(jsvars.get('secs', 45), False) - - url = "http://rapidgator.net%s?sid=%s" % ( - jsvars.get('getDownloadUrl', '/download/AjaxGetDownload'), jsvars['sid']) - jsvars.update(self.getJsonResponse(url)) - - self.req.http.lastURL = pyfile.url - self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With:"]) - - url = "http://rapidgator.net%s" % jsvars.get('captchaUrl', '/download/captcha') - self.html = self.load(url) - - for _i in xrange(5): - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m: - self.link = m.group(1) - break - else: - captcha, captcha_key = self.handleCaptcha() - response, challenge = captcha.challenge(captcha_key) - - self.html = self.load(url, post={'DownloadCaptchaForm[captcha]': "", - 'adcopy_challenge' : challenge, - 'adcopy_response' : response}) - - if "The verification code is incorrect" in self.html: - self.invalidCaptcha() - else: - self.correctCaptcha() - else: - self.error(_("Download link")) - - - def handleCaptcha(self): - m = re.search(self.ADSCAPTCHA_PATTERN, self.html) - if m: - captcha_key = m.group(1) - captcha = AdsCaptcha(self) - else: - m = re.search(self.RECAPTCHA_PATTERN, self.html) - if m: - captcha_key = m.group(1) - captcha = ReCaptcha(self) - else: - m = re.search(self.SOLVEMEDIA_PATTERN, self.html) - if m: - captcha_key = m.group(1) - captcha = SolveMedia(self) - else: - self.error(_("Captcha")) - - return captcha, captcha_key - - - def getJsonResponse(self, url): - res = self.load(url, decode=True) - if not res.startswith('{'): - self.retry() - self.logDebug(url, res) - return json_loads(res) - - -getInfo = create_getInfo(RapidgatorNet) diff --git a/module/plugins/hoster/RapiduNet.py b/module/plugins/hoster/RapiduNet.py deleted file mode 100644 index 5c12bf924..000000000 --- a/module/plugins/hoster/RapiduNet.py +++ /dev/null @@ -1,86 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pycurl import HTTPHEADER -from time import time, altzone - -from pyload.utils import json_loads -from pyload.plugin.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class RapiduNet(SimpleHoster): - __name__ = "RapiduNet" - __type__ = "hoster" - __version__ = "0.07" - - __pattern__ = r'https?://(?:www\.)?rapidu\.net/(?P<ID>\d{10})' - - __description__ = """Rapidu.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("prOq", "")] - - - COOKIES = [("rapidu.net", "rapidu_lang", "en")] - - INFO_PATTERN = r'<h1 title="(?P<N>.*)">.*</h1>\s*<small>(?P<S>\d+(\.\d+)?)\s(?P<U>\w+)</small>' - OFFLINE_PATTERN = r'404 - File not found' - - ERROR_PATTERN = r'<div class="error">' - - RECAPTCHA_KEY = r'6Ld12ewSAAAAAHoE6WVP_pSfCdJcBQScVweQh8Io' - - - def setup(self): - self.resumeDownload = True - self.multiDL = self.premium - - - def handleFree(self, pyfile): - self.req.http.lastURL = pyfile.url - self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) - - jsvars = self.getJsonResponse("https://rapidu.net/ajax.php", - get={'a': "getLoadTimeToDownload"}, - post={'_go': ""}, - decode=True) - - if str(jsvars['timeToDownload']) is "stop": - t = (24 * 60 * 60) - (int(time()) % (24 * 60 * 60)) + altzone - - self.logInfo("You've reach your daily download transfer") - - self.retry(10, 10 if t < 1 else None, _("Try tomorrow again")) #@NOTE: check t in case of not synchronised clock - - else: - self.wait(int(jsvars['timeToDownload']) - int(time())) - - recaptcha = ReCaptcha(self) - - for _i in xrange(10): - response, challenge = recaptcha.challenge(self.RECAPTCHA_KEY) - - jsvars = self.getJsonResponse("https://rapidu.net/ajax.php", - get={'a': "getCheckCaptcha"}, - post={'_go' : "", - 'captcha1': challenge, - 'captcha2': response, - 'fileId' : self.info['pattern']['ID']}, - decode=True) - if jsvars['message'] == 'success': - self.download(jsvars['url']) - break - - - def getJsonResponse(self, *args, **kwargs): - res = self.load(*args, **kwargs) - if not res.startswith('{'): - self.retry() - - self.logDebug(res) - - return json_loads(res) - - -getInfo = create_getInfo(RapiduNet) diff --git a/module/plugins/hoster/RarefileNet.py b/module/plugins/hoster/RarefileNet.py deleted file mode 100644 index 8f0bf8834..000000000 --- a/module/plugins/hoster/RarefileNet.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class RarefileNet(XFSHoster): - __name__ = "RarefileNet" - __type__ = "hoster" - __version__ = "0.09" - - __pattern__ = r'http://(?:www\.)?rarefile\.net/\w{12}' - - __description__ = """Rarefile.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - LINK_PATTERN = r'<a href="(.+?)">\1</a>' - - -getInfo = create_getInfo(RarefileNet) diff --git a/module/plugins/hoster/RealdebridCom.py b/module/plugins/hoster/RealdebridCom.py deleted file mode 100644 index d0010b3bd..000000000 --- a/module/plugins/hoster/RealdebridCom.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from random import randrange -from urllib import unquote -from time import time - -from module.common.json_layer import json_loads -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo -from module.utils import parseFileSize - - -class RealdebridCom(MultiHoster): - __name__ = "RealdebridCom" - __type__ = "hoster" - __version__ = "0.64" - - __pattern__ = r'https?://((?:www\.|s\d+\.)?real-debrid\.com/dl/|[\w^_]\.rdb\.so/d/)[\w^_]+' - - __description__ = """Real-Debrid.com multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Devirex Hazzard", "naibaf_11@yahoo.de")] - - - def getFilename(self, url): - try: - name = unquote(url.rsplit("/", 1)[1]) - except IndexError: - name = "Unknown_Filename..." - if not name or name.endswith(".."): #: incomplete filename, append random stuff - name += "%s.tmp" % randrange(100, 999) - return name - - - def setup(self): - self.chunkLimit = 3 - - - def handlePremium(self, pyfile): - data = json_loads(self.load("https://real-debrid.com/ajax/unrestrict.php", - get={'lang' : "en", - 'link' : pyfile.url, - 'password': self.getPassword(), - 'time' : int(time() * 1000)})) - - self.logDebug("Returned Data: %s" % data) - - if data['error'] != 0: - if data['message'] == "Your file is unavailable on the hoster.": - self.offline() - else: - self.logWarning(data['message']) - self.tempOffline() - else: - if pyfile.name is not None and pyfile.name.endswith('.tmp') and data['file_name']: - pyfile.name = data['file_name'] - pyfile.size = parseFileSize(data['file_size']) - self.link = data['generated_links'][0][-1] - - if self.getConfig("ssl"): - self.link = self.link.replace("http://", "https://") - else: - self.link = self.link.replace("https://", "http://") - - if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown") or pyfile.name.endswith('..'): - #only use when name wasnt already set - pyfile.name = self.getFilename(self.link) - - - def checkFile(self): - if self.checkDownload({"error": "<title>An error occured while processing your request</title>"}): - #usual this download can safely be retried - self.retry(wait_time=60, reason=_("An error occured while generating link")) - - return super(RealdebridCom, self).checkFile() - - -getInfo = create_getInfo(RealdebridCom) diff --git a/module/plugins/hoster/RehostTo.py b/module/plugins/hoster/RehostTo.py deleted file mode 100644 index 28de35d08..000000000 --- a/module/plugins/hoster/RehostTo.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- - -from urllib import unquote - -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo - - -class RehostTo(MultiHoster): - __name__ = "RehostTo" - __type__ = "hoster" - __version__ = "0.21" - - __pattern__ = r'https?://.*rehost\.to\..+' - - __description__ = """Rehost.com multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org")] - - - def handlePremium(self, pyfile): - self.download("http://rehost.to/process_download.php", - get={'user': "cookie", - 'pass': self.account.getAccountInfo(self.user)['session'], - 'dl' : pyfile.url}, - disposition=True) - - -getInfo = create_getInfo(RehostTo) diff --git a/module/plugins/hoster/RemixshareCom.py b/module/plugins/hoster/RemixshareCom.py deleted file mode 100644 index b1587ad6d..000000000 --- a/module/plugins/hoster/RemixshareCom.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# http://remixshare.com/download/p946u -# -# Note: -# The remixshare.com website is very very slow, so -# if your download not starts because of pycurl timeouts: -# Adjust timeouts in /usr/share/pyload/pyload/network/HTTPRequest.py - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class RemixshareCom(SimpleHoster): - __name__ = "RemixshareCom" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'https?://remixshare\.com/(download|dl)/\w+' - - __description__ = """Remixshare.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - INFO_PATTERN = r'title=\'.+?\'>(?P<N>.+?)</span><span class=\'light2\'> \((?P<S>\d+) (?P<U>[\w^_]+)\)<' - OFFLINE_PATTERN = r'<h1>Ooops!<' - - LINK_FREE_PATTERN = r'(http://remixshare\.com/downloadfinal/.+?)"' - TOKEN_PATTERN = r'var acc = (\d+)' - WAIT_PATTERN = r'var XYZ = r"(\d+)"' - - - def setup(self): - self.multiDL = True - self.chunkLimit = 1 - - - def handleFree(self, pyfile): - b = re.search(self.LINK_FREE_PATTERN, self.html) - if not b: - self.error(_("Cannot parse download url")) - - c = re.search(self.TOKEN_PATTERN, self.html) - if not c: - self.error(_("Cannot parse file token")) - - self.link = b.group(1) + c.group(1) - - #Check if we have to wait - seconds = re.search(self.WAIT_PATTERN, self.html) - if seconds: - self.logDebug("Wait " + seconds.group(1)) - self.wait(seconds.group(1)) - - -getInfo = create_getInfo(RemixshareCom) diff --git a/module/plugins/hoster/RgHostNet.py b/module/plugins/hoster/RgHostNet.py deleted file mode 100644 index 7a16598b2..000000000 --- a/module/plugins/hoster/RgHostNet.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class RgHostNet(SimpleHoster): - __name__ = "RgHostNet" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?rghost\.net/\d+(?:r=\d+)?' - - __description__ = """RgHost.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("z00nx", "z00nx0@gmail.com")] - - - INFO_PATTERN = r'<h1>\s+(<a[^>]+>)?(?P<N>[^<]+)(</a>)?\s+<small[^>]+>\s+\((?P<S>[^)]+)\)\s+</small>\s+</h1>' - OFFLINE_PATTERN = r'File is deleted|this page is not found' - - LINK_FREE_PATTERN = r'<a\s+href="([^"]+)"\s+class="btn\s+large\s+download"[^>]+>Download</a>' - - -getInfo = create_getInfo(RgHostNet) diff --git a/module/plugins/hoster/SafesharingEu.py b/module/plugins/hoster/SafesharingEu.py deleted file mode 100644 index c1fc9c68d..000000000 --- a/module/plugins/hoster/SafesharingEu.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class SafesharingEu(XFSHoster): - __name__ = "SafesharingEu" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'https?://(?:www\.)?safesharing\.eu/\w{12}' - - __description__ = """Safesharing.eu hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] - - - ERROR_PATTERN = r'(?:<div class="alert alert-danger">)(.+?)(?:</div>)' - - -getInfo = create_getInfo(SafesharingEu) diff --git a/module/plugins/hoster/SecureUploadEu.py b/module/plugins/hoster/SecureUploadEu.py deleted file mode 100644 index 0b2b603bf..000000000 --- a/module/plugins/hoster/SecureUploadEu.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class SecureUploadEu(XFSHoster): - __name__ = "SecureUploadEu" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'https?://(?:www\.)?secureupload\.eu/\w{12}' - - __description__ = """SecureUpload.eu hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("z00nx", "z00nx0@gmail.com")] - - - INFO_PATTERN = r'<h3>Downloading (?P<N>[^<]+) \((?P<S>[^<]+)\)</h3>' - - -getInfo = create_getInfo(SecureUploadEu) diff --git a/module/plugins/hoster/SendspaceCom.py b/module/plugins/hoster/SendspaceCom.py deleted file mode 100644 index 5310051d1..000000000 --- a/module/plugins/hoster/SendspaceCom.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class SendspaceCom(SimpleHoster): - __name__ = "SendspaceCom" - __type__ = "hoster" - __version__ = "0.17" - - __pattern__ = r'https?://(?:www\.)?sendspace\.com/file/\w+' - - __description__ = """Sendspace.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<h2 class="bgray">\s*<(?:b|strong)>(?P<N>[^<]+)</' - SIZE_PATTERN = r'<div class="file_description reverse margin_center">\s*<b>File Size:</b>\s*(?P<S>[\d.,]+)(?P<U>[\w^_]+)\s*</div>' - OFFLINE_PATTERN = r'<div class="msg error" style="cursor: default">Sorry, the file you requested is not available.</div>' - - LINK_FREE_PATTERN = r'<a id="download_button" href="([^"]+)"' - - CAPTCHA_PATTERN = r'<td><img src="(/captchas/captcha\.php?captcha=([^"]+))"></td>' - USER_CAPTCHA_PATTERN = r'<td><img src="/captchas/captcha\.php?user=([^"]+))"></td>' - - - def handleFree(self, pyfile): - params = {} - for _i in xrange(3): - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m: - if 'captcha_hash' in params: - self.correctCaptcha() - download_url = m.group(1) - break - - m = re.search(self.CAPTCHA_PATTERN, self.html) - if m: - if 'captcha_hash' in params: - self.invalidCaptcha() - captcha_url1 = "http://www.sendspace.com/" + m.group(1) - m = re.search(self.USER_CAPTCHA_PATTERN, self.html) - captcha_url2 = "http://www.sendspace.com/" + m.group(1) - params = {'captcha_hash': m.group(2), - 'captcha_submit': 'Verify', - 'captcha_answer': self.decryptCaptcha(captcha_url1) + " " + self.decryptCaptcha(captcha_url2)} - else: - params = {'download': "Regular Download"} - - self.logDebug(params) - self.html = self.load(pyfile.url, post=params) - else: - self.fail(_("Download link not found")) - - self.download(download_url) - - -getInfo = create_getInfo(SendspaceCom) diff --git a/module/plugins/hoster/Share4WebCom.py b/module/plugins/hoster/Share4WebCom.py deleted file mode 100644 index 0c2ee358e..000000000 --- a/module/plugins/hoster/Share4WebCom.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.hoster.UnibytesCom import UnibytesCom -from pyload.plugin.internal.SimpleHoster import create_getInfo - - -class Share4WebCom(UnibytesCom): - __name__ = "Share4WebCom" - __type__ = "hoster" - __version__ = "0.11" - - __pattern__ = r'https?://(?:www\.)?share4web\.com/get/\w+' - - __description__ = """Share4web.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - HOSTER_DOMAIN = "share4web.com" - - -getInfo = create_getInfo(Share4WebCom) diff --git a/module/plugins/hoster/Share76Com.py b/module/plugins/hoster/Share76Com.py deleted file mode 100644 index 7f2cea757..000000000 --- a/module/plugins/hoster/Share76Com.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class Share76Com(DeadHoster): - __name__ = "Share76Com" - __type__ = "hoster" - __version__ = "0.04" - - __pattern__ = r'http://(?:www\.)?share76\.com/\w{12}' - - __description__ = """Share76.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [] - - -getInfo = create_getInfo(Share76Com) diff --git a/module/plugins/hoster/ShareFilesCo.py b/module/plugins/hoster/ShareFilesCo.py deleted file mode 100644 index dd5c9b85d..000000000 --- a/module/plugins/hoster/ShareFilesCo.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class ShareFilesCo(DeadHoster): - __name__ = "ShareFilesCo" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?sharefiles\.co/\w{12}' - - __description__ = """Sharefiles.co hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - -getInfo = create_getInfo(ShareFilesCo) diff --git a/module/plugins/hoster/SharebeesCom.py b/module/plugins/hoster/SharebeesCom.py deleted file mode 100644 index 3843a352b..000000000 --- a/module/plugins/hoster/SharebeesCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class SharebeesCom(DeadHoster): - __name__ = "SharebeesCom" - __type__ = "hoster" - __version__ = "0.02" - - __pattern__ = r'http://(?:www\.)?sharebees\.com/\w{12}' - - __description__ = """ShareBees hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(SharebeesCom) diff --git a/module/plugins/hoster/ShareonlineBiz.py b/module/plugins/hoster/ShareonlineBiz.py deleted file mode 100644 index b37b4b0bc..000000000 --- a/module/plugins/hoster/ShareonlineBiz.py +++ /dev/null @@ -1,187 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from time import time -from urllib import unquote -from urlparse import urlparse - -from pyload.network.RequestFactory import getURL -from pyload.plugin.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class ShareonlineBiz(SimpleHoster): - __name__ = "ShareonlineBiz" - __type__ = "hoster" - __version__ = "0.48" - - __pattern__ = r'https?://(?:www\.)?(share-online\.biz|egoshare\.com)/(download\.php\?id=|dl/)(?P<ID>\w+)' - - __description__ = """Shareonline.biz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("spoob", "spoob@pyload.org"), - ("mkaay", "mkaay@mkaay.de"), - ("zoidberg", "zoidberg@mujmail.cz"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - URL_REPLACEMENTS = [(__pattern__ + ".*", "http://www.share-online.biz/dl/\g<ID>")] - - CHECK_TRAFFIC = True - - RECAPTCHA_KEY = "6LdatrsSAAAAAHZrB70txiV5p-8Iv8BtVxlTtjKX" - - ERROR_PATTERN = r'<p class="b">Information:</p>\s*<div>\s*<strong>(.*?)</strong>' - - - @classmethod - def getInfo(cls, url="", html=""): - info = {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 3 if url else 1, 'url': url} - - if url: - info['pattern'] = re.match(cls.__pattern__, url).groupdict() - - field = getURL("http://api.share-online.biz/linkcheck.php", - get={'md5': "1"}, - post={'links': info['pattern']['ID']}, - decode=True).split(";") - - if field[1] == "OK": - info['fileid'] = field[0] - info['status'] = 2 - info['name'] = field[2] - info['size'] = field[3] #: in bytes - info['md5'] = field[4].strip().lower().replace("\n\n", "") #: md5 - - elif field[1] in ("DELETED", "NOT FOUND"): - info['status'] = 1 - - return info - - - def setup(self): - self.resumeDownload = self.premium - self.multiDL = False - - - def handleCaptcha(self): - recaptcha = ReCaptcha(self) - - for _i in xrange(5): - response, challenge = recaptcha.challenge(self.RECAPTCHA_KEY) - - m = re.search(r'var wait=(\d+);', self.html) - self.setWait(int(m.group(1)) if m else 30) - - res = self.load("%s/free/captcha/%d" % (self.pyfile.url, int(time() * 1000)), - post={'dl_free' : "1", - 'recaptcha_challenge_field': challenge, - 'recaptcha_response_field' : response}) - if not res == '0': - self.correctCaptcha() - return res - else: - self.invalidCaptcha() - else: - self.invalidCaptcha() - self.fail(_("No valid captcha solution received")) - - - def handleFree(self, pyfile): - self.wait(3) - - self.html = self.load("%s/free/" % pyfile.url, - post={'dl_free': "1", 'choice': "free"}, - decode=True) - - self.checkErrors() - - res = self.handleCaptcha() - download_url = res.decode('base64') - - if not download_url.startswith("http://"): - self.error(_("Wrong download url")) - - self.wait() - - self.download(download_url) - - - def checkFile(self): - check = self.checkDownload({'cookie': re.compile(r'<div id="dl_failure"'), - 'fail' : re.compile(r"<title>Share-Online")}) - - if check == "cookie": - self.invalidCaptcha() - self.retry(5, 60, _("Cookie failure")) - - elif check == "fail": - self.invalidCaptcha() - self.retry(5, 5 * 60, _("Download failed")) - - return super(ShareonlineBiz, self).checkFile() - - - def handlePremium(self, pyfile): #: should be working better loading (account) api internally - html = self.load("http://api.share-online.biz/account.php", - get={'username': self.user, - 'password': self.account.getAccountData(self.user)['password'], - 'act' : "download", - 'lid' : self.info['fileid']}) - - self.api_data = dlinfo = {} - - for line in html.splitlines(): - key, value = line.split(": ") - dlinfo[key.lower()] = value - - self.logDebug(dlinfo) - - if not dlinfo['status'] == "online": - self.offline() - else: - pyfile.name = dlinfo['name'] - pyfile.size = int(dlinfo['size']) - - dlLink = dlinfo['url'] - - if dlLink == "server_under_maintenance": - self.tempOffline() - else: - self.multiDL = True - self.download(dlLink) - - - def checkErrors(self): - m = re.search(r"/failure/(.*?)/1", self.req.lastEffectiveURL) - if m is None: - self.info.pop('error', None) - return - - errmsg = m.group(1).lower() - - try: - self.logError(errmsg, re.search(self.ERROR_PATTERN, self.html).group(1)) - except Exception: - self.logError("Unknown error occurred", errmsg) - - if errmsg is "invalid": - self.fail(_("File not available")) - - elif errmsg in ("freelimit", "size", "proxy"): - self.fail(_("Premium account needed")) - - elif errmsg in ("expired", "server"): - self.retry(wait_time=600, reason=errmsg) - - elif 'slot' in errmsg: - self.wantReconnect = True - self.retry(24, 3600, errmsg) - - else: - self.wantReconnect = True - self.retry(wait_time=60, reason=errmsg) - - -getInfo = create_getInfo(ShareonlineBiz) diff --git a/module/plugins/hoster/SharingmatrixCom.py b/module/plugins/hoster/SharingmatrixCom.py deleted file mode 100644 index a20a36543..000000000 --- a/module/plugins/hoster/SharingmatrixCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class SharingmatrixCom(DeadHoster): - __name__ = "SharingmatrixCom" - __type__ = "hoster" - __version__ = "0.01" - - __pattern__ = r'http://(?:www\.)?sharingmatrix\.com/file/\w+' - - __description__ = """Sharingmatrix.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("jeix", "jeix@hasnomail.de"), - ("paulking", "")] - - -getInfo = create_getInfo(SharingmatrixCom) diff --git a/module/plugins/hoster/ShragleCom.py b/module/plugins/hoster/ShragleCom.py deleted file mode 100644 index cf975b2f5..000000000 --- a/module/plugins/hoster/ShragleCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class ShragleCom(DeadHoster): - __name__ = "ShragleCom" - __type__ = "hoster" - __version__ = "0.22" - - __pattern__ = r'http://(?:www\.)?(cloudnator|shragle)\.com/files/(?P<ID>.+?)/' - - __description__ = """Cloudnator.com (Shragle.com) hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(ShragleCom) diff --git a/module/plugins/hoster/SimplyPremiumCom.py b/module/plugins/hoster/SimplyPremiumCom.py deleted file mode 100644 index a87e7533f..000000000 --- a/module/plugins/hoster/SimplyPremiumCom.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from datetime import datetime, timedelta - -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo -from module.plugins.internal.SimpleHoster import secondsToMidnight - - -class SimplyPremiumCom(MultiHoster): - __name__ = "SimplyPremiumCom" - __type__ = "hoster" - __version__ = "0.08" - - __pattern__ = r'https?://.+simply-premium\.com' - - __description__ = """Simply-Premium.com multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("EvolutionClip", "evolutionclip@live.de")] - - - def setup(self): - self.chunkLimit = 16 - - - def checkErrors(self): - if '<valid>0</valid>' in self.html or ( - "You are not allowed to download from this host" in self.html and self.premium): - self.account.relogin(self.user) - self.retry() - - elif "NOTFOUND" in self.html: - self.offline() - - elif "downloadlimit" in self.html: - self.logWarning(_("Reached maximum connctions")) - self.retry(5, 60, _("Reached maximum connctions")) - - elif "trafficlimit" in self.html: - self.logWarning(_("Reached daily limit for this host")) - self.retry(wait_time=secondsToMidnight(gmt=2), reason="Daily limit for this host reached") - - elif "hostererror" in self.html: - self.logWarning(_("Hoster temporarily unavailable, waiting 1 minute and retry")) - self.retry(5, 60, _("Hoster is temporarily unavailable")) - - - def handlePremium(self, pyfile): - for i in xrange(5): - self.html = self.load("http://www.simply-premium.com/premium.php", get={'info': "", 'link': self.pyfile.url}) - - if self.html: - self.logDebug("JSON data: " + self.html) - break - else: - self.logInfo(_("Unable to get API data, waiting 1 minute and retry")) - self.retry(5, 60, _("Unable to get API data")) - - self.checkErrors() - - try: - self.pyfile.name = re.search(r'<name>([^<]+)</name>', self.html).group(1) - - except AttributeError: - self.pyfile.name = "" - - try: - self.pyfile.size = re.search(r'<size>(\d+)</size>', self.html).group(1) - - except AttributeError: - self.pyfile.size = 0 - - try: - self.link = re.search(r'<download>([^<]+)</download>', self.html).group(1) - - except AttributeError: - self.link = 'http://www.simply-premium.com/premium.php?link=' + self.pyfile.url - - -getInfo = create_getInfo(SimplyPremiumCom) diff --git a/module/plugins/hoster/SimplydebridCom.py b/module/plugins/hoster/SimplydebridCom.py deleted file mode 100644 index 24811d6aa..000000000 --- a/module/plugins/hoster/SimplydebridCom.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo, replace_patterns - - -class SimplydebridCom(MultiHoster): - __name__ = "SimplydebridCom" - __type__ = "hoster" - __version__ = "0.15" - - __pattern__ = r'http://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/sd\.php' - - __description__ = """Simply-debrid.com multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Kagenoshin", "kagenoshin@gmx.ch")] - - - def handlePremium(self, pyfile): - #fix the links for simply-debrid.com! - self.link = replace_patterns(pyfile.url, [("clz.to", "cloudzer.net/file") - ("http://share-online", "http://www.share-online") - ("ul.to", "uploaded.net/file") - ("uploaded.com", "uploaded.net") - ("filerio.com", "filerio.in") - ("lumfile.com", "lumfile.se")] - - if 'fileparadox' in self.link: - self.link = self.link.replace("http://", "https://") - - self.html = self.load("http://simply-debrid.com/api.php", get={'dl': self.link}) - if 'tiger Link' in self.html or 'Invalid Link' in self.html or ('API' in self.html and 'ERROR' in self.html): - self.error(_("Unable to unrestrict link")) - - self.link = self.html - - self.wait(5) - - - def checkFile(self): - if self.checkDownload({"error": "No address associated with hostname"}): - self.retry(24, 3 * 60, _("Bad file downloaded")) - - return super(SimplydebridCom, self).checkFile() - - -getInfo = create_getInfo(SimplydebridCom) diff --git a/module/plugins/hoster/SmoozedCom.py b/module/plugins/hoster/SmoozedCom.py deleted file mode 100644 index bd653ff59..000000000 --- a/module/plugins/hoster/SmoozedCom.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.common.json_layer import json_loads -from module.plugins.internal.MultiHoster import MultiHoster - - -class SmoozedCom(MultiHoster): - __name__ = "SmoozedCom" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'^unmatchable$' #: Since we want to allow the user to specify the list of hoster to use we let MultiHoster.coreReady - - __description__ = """Smoozed.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("", "")] - - - def handlePremium(self, pyfile): - # In some cases hostsers do not supply us with a filename at download, so we - # are going to set a fall back filename (e.g. for freakshare or xfileshare) - pyfile.name = pyfile.name.split('/').pop() # Remove everthing before last slash - - # Correction for automatic assigned filename: Removing html at end if needed - suffix_to_remove = ["html", "htm", "php", "php3", "asp", "shtm", "shtml", "cfml", "cfm"] - temp = pyfile.name.split('.') - - if temp.pop() in suffix_to_remove: - pyfile.name = ".".join(temp) - - # Check the link - get_data = {'session_key': self.account.getAccountInfo(self.user)['session'], - 'url' : pyfile.url} - - data = json_loads(self.load("http://www2.smoozed.com/api/check", get=get_data)) - - if data["state"] != "ok": - self.fail(data["message"]) - - if data["data"].get("state", "ok") != "ok": - if data["data"] == "Offline": - self.offline() - else: - self.fail(data["data"]["message"]) - - pyfile.name = data["data"]["name"] - pyfile.size = int(data["data"]["size"]) - - # Start the download - header = self.load("http://www2.smoozed.com/api/download", get=get_data, just_header=True) - - if not "location" in header: - self.fail(_("Unable to initialize download")) - else: - self.link = header["location"][-1] if isinstance(header["location"], list) else header["location"] - - - def checkFile(self): - if self.checkDownload({'error': '{"state":"error"}', - 'retry': '{"state":"retry"}'}): - self.fail(_("Error response received")) - - return super(SmoozedCom, self).checkFile() diff --git a/module/plugins/hoster/SockshareCom.py b/module/plugins/hoster/SockshareCom.py deleted file mode 100644 index e85a74e49..000000000 --- a/module/plugins/hoster/SockshareCom.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class SockshareCom(DeadHoster): - __name__ = "SockshareCom" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'http://(?:www\.)?sockshare\.com/(mobile/)?(file|embed)/(?P<ID>\w+)' - - __description__ = """Sockshare.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("jeix", "jeix@hasnomail.de"), - ("stickell", "l.stickell@yahoo.it"), - ("Walter Purcaro", "vuolter@gmail.com")] - - -getInfo = create_getInfo(SockshareCom) diff --git a/module/plugins/hoster/SpeedLoadOrg.py b/module/plugins/hoster/SpeedLoadOrg.py deleted file mode 100644 index 588eb26a3..000000000 --- a/module/plugins/hoster/SpeedLoadOrg.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class SpeedLoadOrg(DeadHoster): - __name__ = "SpeedLoadOrg" - __type__ = "hoster" - __version__ = "1.02" - - __pattern__ = r'http://(?:www\.)?speedload\.org/(?P<ID>\w+)' - - __description__ = """Speedload.org hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - -getInfo = create_getInfo(SpeedLoadOrg) diff --git a/module/plugins/hoster/SpeedfileCz.py b/module/plugins/hoster/SpeedfileCz.py deleted file mode 100644 index 3f17bbbe6..000000000 --- a/module/plugins/hoster/SpeedfileCz.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class SpeedfileCz(DeadHoster): - __name__ = "SpeedFileCz" - __type__ = "hoster" - __version__ = "0.32" - - __pattern__ = r'http://(?:www\.)?speedfile\.cz/.+' - - __description__ = """Speedfile.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(SpeedfileCz) diff --git a/module/plugins/hoster/SpeedyshareCom.py b/module/plugins/hoster/SpeedyshareCom.py deleted file mode 100644 index 078cbf6c8..000000000 --- a/module/plugins/hoster/SpeedyshareCom.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# http://speedy.sh/ep2qY/Zapp-Brannigan.jpg - -import re - -from urlparse import urljoin - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class SpeedyshareCom(SimpleHoster): - __name__ = "SpeedyshareCom" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'https?://(?:www\.)?(speedyshare\.com|speedy\.sh)/\w+' - - __description__ = """Speedyshare.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] - - - NAME_PATTERN = r'class=downloadfilename>(?P<N>.*)</span></td>' - SIZE_PATTERN = r'class=sizetagtext>(?P<S>.*) (?P<U>[kKmM]?[iI]?[bB]?)</div>' - - OFFLINE_PATTERN = r'class=downloadfilenamenotfound>.*</span>' - - LINK_FREE_PATTERN = r'<a href=\'(.*)\'><img src=/gf/slowdownload\.png alt=\'Slow Download\' border=0' - - - def setup(self): - self.multiDL = False - self.chunkLimit = 1 - - - def handleFree(self, pyfile): - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.link = m.group(1) - - -getInfo = create_getInfo(SpeedyshareCom) diff --git a/module/plugins/hoster/StorageTo.py b/module/plugins/hoster/StorageTo.py deleted file mode 100644 index 4b18c69da..000000000 --- a/module/plugins/hoster/StorageTo.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class StorageTo(DeadHoster): - __name__ = "StorageTo" - __type__ = "hoster" - __version__ = "0.01" - - __pattern__ = r'http://(?:www\.)?storage\.to/get/.+' - - __description__ = """Storage.to hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("mkaay", "mkaay@mkaay.de")] - - -getInfo = create_getInfo(StorageTo) diff --git a/module/plugins/hoster/StreamcloudEu.py b/module/plugins/hoster/StreamcloudEu.py deleted file mode 100644 index c47c2c6a1..000000000 --- a/module/plugins/hoster/StreamcloudEu.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class StreamcloudEu(XFSHoster): - __name__ = "StreamcloudEu" - __type__ = "hoster" - __version__ = "0.10" - - __pattern__ = r'http://(?:www\.)?streamcloud\.eu/\w{12}' - - __description__ = """Streamcloud.eu hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("seoester", "seoester@googlemail.com")] - - - WAIT_PATTERN = r'var count = (\d+)' - - LINK_PATTERN = r'file: "(http://(stor|cdn)\d+\.streamcloud\.eu:?\d*/.*/video\.(mp4|flv))",' - - - def setup(self): - self.multiDL = True - self.chunkLimit = 1 - self.resumeDownload = self.premium - - -getInfo = create_getInfo(StreamcloudEu) diff --git a/module/plugins/hoster/TurbobitNet.py b/module/plugins/hoster/TurbobitNet.py deleted file mode 100644 index 811136405..000000000 --- a/module/plugins/hoster/TurbobitNet.py +++ /dev/null @@ -1,167 +0,0 @@ -# -*- coding: utf-8 -*- - -import random -import re -import time - -from Crypto.Cipher import ARC4 -from binascii import hexlify, unhexlify -from pycurl import HTTPHEADER -from urllib import quote - -from pyload.network.RequestFactory import getURL -from pyload.plugin.internal.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo, timestamp - - -class TurbobitNet(SimpleHoster): - __name__ = "TurbobitNet" - __type__ = "hoster" - __version__ = "0.19" - - __pattern__ = r'http://(?:www\.)?turbobit\.net/(?:download/free/)?(?P<ID>\w+)' - - __description__ = """Turbobit.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("prOq", "")] - - - URL_REPLACEMENTS = [(__pattern__ + ".*", "http://turbobit.net/\g<ID>.html")] - - COOKIES = [("turbobit.net", "user_lang", "en")] - - NAME_PATTERN = r'id="file-title">(?P<N>.+?)<' - SIZE_PATTERN = r'class="file-size">(?P<S>[\d.,]+) (?P<U>[\w^_]+)' - OFFLINE_PATTERN = r'<h2>File Not Found</h2>|html\(\'File (?:was )?not found' - - LINK_FREE_PATTERN = LINK_PREMIUM_PATTERN = r'(/download/redirect/[^"\']+)' - - LIMIT_WAIT_PATTERN = r'<div id=\'timeout\'>(\d+)<' - CAPTCHA_PATTERN = r'<img alt="Captcha" src="(.+?)"' - - - def handleFree(self, pyfile): - self.html = self.load("http://turbobit.net/download/free/%s" % self.info['pattern']['ID'], - decode=True) - - rtUpdate = self.getRtUpdate() - - self.solveCaptcha() - - self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) - - self.html = self.load(self.getDownloadUrl(rtUpdate)) - - self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With:"]) - - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m: - self.link = m.group(1) - - - def solveCaptcha(self): - for _i in xrange(5): - m = re.search(self.LIMIT_WAIT_PATTERN, self.html) - if m: - wait_time = int(m.group(1)) - self.wait(wait_time, wait_time > 60) - self.retry() - - action, inputs = self.parseHtmlForm("action='#'") - if not inputs: - self.error(_("Captcha form not found")) - self.logDebug(inputs) - - if inputs['captcha_type'] == 'recaptcha': - recaptcha = ReCaptcha(self) - inputs['recaptcha_response_field'], inputs['recaptcha_challenge_field'] = recaptcha.challenge() - else: - m = re.search(self.CAPTCHA_PATTERN, self.html) - if m is None: - self.error(_("captcha")) - captcha_url = m.group(1) - inputs['captcha_response'] = self.decryptCaptcha(captcha_url) - - self.logDebug(inputs) - self.html = self.load(self.url, post=inputs) - - if '<div class="captcha-error">Incorrect, try again!<' in self.html: - self.invalidCaptcha() - else: - self.correctCaptcha() - break - else: - self.fail(_("Invalid captcha")) - - - def getRtUpdate(self): - rtUpdate = self.getStorage("rtUpdate") - if not rtUpdate: - if self.getStorage("version") != self.__version__ \ - or int(self.getStorage("timestamp", 0)) + 86400000 < timestamp(): - # that's right, we are even using jdownloader updates - rtUpdate = getURL("http://update0.jdownloader.org/pluginstuff/tbupdate.js") - rtUpdate = self.decrypt(rtUpdate.splitlines()[1]) - # but we still need to fix the syntax to work with other engines than rhino - rtUpdate = re.sub(r'for each\(var (\w+) in(\[[^\]]+\])\)\{', - r'zza=\2;for(var zzi=0;zzi<zza.length;zzi++){\1=zza[zzi];', rtUpdate) - rtUpdate = re.sub(r"for\((\w+)=", r"for(var \1=", rtUpdate) - - self.setStorage("rtUpdate", rtUpdate) - self.setStorage("timestamp", timestamp()) - self.setStorage("version", self.__version__) - else: - self.logError(_("Unable to download, wait for update...")) - self.tempOffline() - - return rtUpdate - - - def getDownloadUrl(self, rtUpdate): - self.req.http.lastURL = self.url - - m = re.search("(/\w+/timeout\.js\?\w+=)([^\"\'<>]+)", self.html) - if m: - url = "http://turbobit.net%s%s" % m.groups() - else: - url = "http://turbobit.net/files/timeout.js?ver=%s" % "".join(random.choice('0123456789ABCDEF') for _i in xrange(32)) - - fun = self.load(url) - - self.setWait(65, False) - - for b in [1, 3]: - self.jscode = "var id = \'%s\';var b = %d;var inn = \'%s\';%sout" % ( - self.info['pattern']['ID'], b, quote(fun), rtUpdate) - - try: - out = self.js.eval(self.jscode) - self.logDebug("URL", self.js.engine, out) - if out.startswith('/download/'): - return "http://turbobit.net%s" % out.strip() - - except Exception, e: - self.logError(e) - else: - if self.retries >= 2: - # retry with updated js - self.delStorage("rtUpdate") - else: - self.retry() - - self.wait() - - - def decrypt(self, data): - cipher = ARC4.new(hexlify('E\x15\xa1\x9e\xa3M\xa0\xc6\xa0\x84\xb6H\x83\xa8o\xa0')) - return unhexlify(cipher.encrypt(unhexlify(data))) - - - def getLocalTimeString(self): - lt = time.localtime() - tz = time.altzone if lt.tm_isdst else time.timezone - return "%s GMT%+03d%02d" % (time.strftime("%a %b %d %Y %H:%M:%S", lt), -tz // 3600, tz % 3600) - - -getInfo = create_getInfo(TurbobitNet) diff --git a/module/plugins/hoster/TurbouploadCom.py b/module/plugins/hoster/TurbouploadCom.py deleted file mode 100644 index f821438dd..000000000 --- a/module/plugins/hoster/TurbouploadCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class TurbouploadCom(DeadHoster): - __name__ = "TurbouploadCom" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?turboupload\.com/(\w+)' - - __description__ = """Turboupload.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(TurbouploadCom) diff --git a/module/plugins/hoster/TusfilesNet.py b/module/plugins/hoster/TusfilesNet.py deleted file mode 100644 index 9fdb6eae1..000000000 --- a/module/plugins/hoster/TusfilesNet.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.network.HTTPRequest import BadHeader -from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo - - -class TusfilesNet(XFSHoster): - __name__ = "TusfilesNet" - __type__ = "hoster" - __version__ = "0.09" - - __pattern__ = r'https?://(?:www\.)?tusfiles\.net/\w{12}' - - __description__ = """Tusfiles.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com"), - ("guidobelix", "guidobelix@hotmail.it")] - - - INFO_PATTERN = r'\](?P<N>.+) - (?P<S>[\d.,]+) (?P<U>[\w^_]+)\[' - OFFLINE_PATTERN = r'>File Not Found|<Title>TusFiles - Fast Sharing Files!|The file you are trying to download is no longer available' - - - def setup(self): - self.chunkLimit = -1 - self.multiDL = True - self.resumeDownload = True - - - def downloadLink(self, link): - try: - return super(TusfilesNet, self).downloadLink(link) - - except BadHeader, e: - if e.code is 503: - self.multiDL = False - raise Retry("503") - - -getInfo = create_getInfo(TusfilesNet) diff --git a/module/plugins/hoster/TwoSharedCom.py b/module/plugins/hoster/TwoSharedCom.py deleted file mode 100644 index 53911762d..000000000 --- a/module/plugins/hoster/TwoSharedCom.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class TwoSharedCom(SimpleHoster): - __name__ = "TwoSharedCom" - __type__ = "hoster" - __version__ = "0.13" - - __pattern__ = r'http://(?:www\.)?2shared\.com/(account/)?(download|get|file|document|photo|video|audio)/.+' - - __description__ = """2Shared.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<h1>(?P<N>.*)</h1>' - SIZE_PATTERN = r'<span class="dtitle">File size:</span>\s*(?P<S>[\d.,]+) (?P<U>[\w^_]+)' - OFFLINE_PATTERN = r'The file link that you requested is not valid\.|This file was deleted\.' - - LINK_FREE_PATTERN = r'window.location =\'(.+?)\';' - - - def setup(self): - self.resumeDownload = True - self.multiDL = True - - -getInfo = create_getInfo(TwoSharedCom) diff --git a/module/plugins/hoster/UlozTo.py b/module/plugins/hoster/UlozTo.py deleted file mode 100644 index 104209a66..000000000 --- a/module/plugins/hoster/UlozTo.py +++ /dev/null @@ -1,158 +0,0 @@ -# -*- coding: utf-8 -*- - -import re -import time - -from pyload.utils import json_loads -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -def convertDecimalPrefix(m): - # decimal prefixes used in filesize and traffic - return ("%%.%df" % {'k': 3, 'M': 6, 'G': 9}[m.group(2)] % float(m.group(1))).replace('.', '') - - -class UlozTo(SimpleHoster): - __name__ = "UlozTo" - __type__ = "hoster" - __version__ = "1.04" - - __pattern__ = r'http://(?:www\.)?(uloz\.to|ulozto\.(cz|sk|net)|bagruj\.cz|zachowajto\.pl)/(?:live/)?(?P<ID>\w+/[^/?]*)' - - __description__ = """Uloz.to hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - INFO_PATTERN = r'<p>File <strong>(?P<N>[^<]+)</strong> is password protected</p>' - NAME_PATTERN = r'<title>(?P<N>[^<]+) \| Uloz\.to</title>' - SIZE_PATTERN = r'<span id="fileSize">.*?(?P<S>[\d.,]+\s[kMG]?B)</span>' - OFFLINE_PATTERN = r'<title>404 - Page not found</title>|<h1 class="h1">File (has been deleted|was banned)</h1>' - - URL_REPLACEMENTS = [(r"(?<=http://)([^/]+)", "www.ulozto.net")] - SIZE_REPLACEMENTS = [('([\d.]+)\s([kMG])B', convertDecimalPrefix)] - - ADULT_PATTERN = r'<form action="([^\"]*)" method="post" id="frm-askAgeForm">' - PASSWD_PATTERN = r'<div class="passwordProtectedFile">' - VIPLINK_PATTERN = r'<a href="[^"]*\?disclaimer=1" class="linkVip">' - TOKEN_PATTERN = r'<input type="hidden" name="_token_" .*?value="(.+?)"' - - - def setup(self): - self.chunkLimit = 16 if self.premium else 1 - self.multiDL = self.premium - self.resumeDownload = True - - - def process(self, pyfile): - pyfile.url = re.sub(r"(?<=http://)([^/]+)", "www.ulozto.net", pyfile.url) - self.html = self.load(pyfile.url, decode=True, cookies=True) - - if re.search(self.ADULT_PATTERN, self.html): - self.logInfo(_("Adult content confirmation needed")) - - m = re.search(self.TOKEN_PATTERN, self.html) - if m is None: - self.error(_("TOKEN_PATTERN not found")) - token = m.group(1) - - self.html = self.load(pyfile.url, get={'do': "askAgeForm-submit"}, - post={"agree": "Confirm", "_token_": token}, cookies=True) - - if self.PASSWD_PATTERN in self.html: - password = self.getPassword() - - if password: - self.logInfo(_("Password protected link, trying ") + password) - self.html = self.load(pyfile.url, get={'do': "passwordProtectedForm-submit"}, - post={"password": password, "password_send": 'Send'}, cookies=True) - - if self.PASSWD_PATTERN in self.html: - self.fail(_("Incorrect password")) - else: - self.fail(_("No password found")) - - if re.search(self.VIPLINK_PATTERN, self.html): - self.html = self.load(pyfile.url, get={'disclaimer': "1"}) - - self.getFileInfo() - - if self.premium and self.checkTrafficLeft(): - self.handlePremium(pyfile) - else: - self.handleFree(pyfile) - - self.doCheckDownload() - - - def handleFree(self, pyfile): - action, inputs = self.parseHtmlForm('id="frm-downloadDialog-freeDownloadForm"') - if not action or not inputs: - self.error(_("Free download form not found")) - - self.logDebug("inputs.keys = " + str(inputs.keys())) - # get and decrypt captcha - if all(key in inputs for key in ("captcha_value", "captcha_id", "captcha_key")): - # Old version - last seen 9.12.2013 - self.logDebug('Using "old" version') - - captcha_value = self.decryptCaptcha("http://img.uloz.to/captcha/%s.png" % inputs['captcha_id']) - self.logDebug("CAPTCHA ID: " + inputs['captcha_id'] + ", CAPTCHA VALUE: " + captcha_value) - - inputs.update({'captcha_id': inputs['captcha_id'], 'captcha_key': inputs['captcha_key'], 'captcha_value': captcha_value}) - - elif all(key in inputs for key in ("captcha_value", "timestamp", "salt", "hash")): - # New version - better to get new parameters (like captcha reload) because of image url - since 6.12.2013 - self.logDebug('Using "new" version') - - xapca = self.load("http://www.ulozto.net/reloadXapca.php", get={'rnd': str(int(time.time()))}) - self.logDebug("xapca = " + str(xapca)) - - data = json_loads(xapca) - captcha_value = self.decryptCaptcha(str(data['image'])) - self.logDebug("CAPTCHA HASH: " + data['hash'], "CAPTCHA SALT: " + str(data['salt']), "CAPTCHA VALUE: " + captcha_value) - - inputs.update({'timestamp': data['timestamp'], 'salt': data['salt'], 'hash': data['hash'], 'captcha_value': captcha_value}) - else: - self.error(_("CAPTCHA form changed")) - - self.multiDL = True - self.download("http://www.ulozto.net" + action, post=inputs, cookies=True, disposition=True) - - - def handlePremium(self, pyfile): - self.download(pyfile.url, get={'do': "directDownload"}, disposition=True) - - - def doCheckDownload(self): - check = self.checkDownload({ - "wrong_captcha": re.compile(r'<ul class="error">\s*<li>Error rewriting the text.</li>'), - "offline" : re.compile(self.OFFLINE_PATTERN), - "passwd" : self.PASSWD_PATTERN, - "server_error" : 'src="http://img.ulozto.cz/error403/vykricnik.jpg"', # paralell dl, server overload etc. - "not_found" : "<title>UloÅŸ.to</title>" - }) - - if check == "wrong_captcha": - #self.delStorage("captcha_id") - #self.delStorage("captcha_text") - self.invalidCaptcha() - self.retry(reason=_("Wrong captcha code")) - - elif check == "offline": - self.offline() - - elif check == "passwd": - self.fail(_("Wrong password")) - - elif check == "server_error": - self.logError(_("Server error, try downloading later")) - self.multiDL = False - self.wait(1 * 60 * 60, True) - self.retry() - - elif check == "not_found": - self.fail(_("Server error - file not downloadable")) - - -getInfo = create_getInfo(UlozTo) diff --git a/module/plugins/hoster/UloziskoSk.py b/module/plugins/hoster/UloziskoSk.py deleted file mode 100644 index 862429af5..000000000 --- a/module/plugins/hoster/UloziskoSk.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class UloziskoSk(SimpleHoster): - __name__ = "UloziskoSk" - __type__ = "hoster" - __version__ = "0.25" - - __pattern__ = r'http://(?:www\.)?ulozisko\.sk/.+' - - __description__ = """Ulozisko.sk hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<div class="down1">(?P<N>[^<]+)</div>' - SIZE_PATTERN = ur'VeÄŸkosÅ¥ súboru: <strong>(?P<S>[\d.,]+) (?P<U>[\w^_]+)</strong><br />' - OFFLINE_PATTERN = ur'<span class = "red">ZadanÃœ súbor neexistuje z jedného z nasledujúcich dÃŽvodov:</span>' - - LINK_FREE_PATTERN = r'<form name = "formular" action = "([^"]+)" method = "post">' - ID_PATTERN = r'<input type = "hidden" name = "id" value = "([^"]+)" />' - CAPTCHA_PATTERN = r'<img src="(/obrazky/obrazky\.php\?fid=[^"]+)" alt="" />' - IMG_PATTERN = ur'<strong>PRE ZVÃÄÅ ENIE KLIKNITE NA OBRÃZOK</strong><br /><a href = "([^"]+)">' - - - def process(self, pyfile): - self.html = self.load(pyfile.url, decode=True) - self.getFileInfo() - - m = re.search(self.IMG_PATTERN, self.html) - if m: - url = "http://ulozisko.sk" + m.group(1) - self.download(url) - else: - self.handleFree(pyfile) - - - def handleFree(self, pyfile): - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("LINK_FREE_PATTERN not found")) - parsed_url = 'http://www.ulozisko.sk' + m.group(1) - - m = re.search(self.ID_PATTERN, self.html) - if m is None: - self.error(_("ID_PATTERN not found")) - id = m.group(1) - - self.logDebug("URL:" + parsed_url + ' ID:' + id) - - m = re.search(self.CAPTCHA_PATTERN, self.html) - if m is None: - self.error(_("CAPTCHA_PATTERN not found")) - captcha_url = 'http://www.ulozisko.sk' + m.group(1) - - captcha = self.decryptCaptcha(captcha_url, cookies=True) - - self.logDebug("CAPTCHA_URL:" + captcha_url + ' CAPTCHA:' + captcha) - - self.download(parsed_url, - post={"antispam": captcha, - "id" : id, - "name" : pyfile.name, - "but" : "++++STIAHNI+S%DABOR++++"}) - - -getInfo = create_getInfo(UloziskoSk) diff --git a/module/plugins/hoster/UnibytesCom.py b/module/plugins/hoster/UnibytesCom.py deleted file mode 100644 index dadbe2fec..000000000 --- a/module/plugins/hoster/UnibytesCom.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urlparse import urljoin - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class UnibytesCom(SimpleHoster): - __name__ = "UnibytesCom" - __type__ = "hoster" - __version__ = "0.12" - - __pattern__ = r'https?://(?:www\.)?unibytes\.com/[\w .-]{11}B' - - __description__ = """UniBytes.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - HOSTER_DOMAIN = "unibytes.com" - - INFO_PATTERN = r'<span[^>]*?id="fileName"[^>]*>(?P<N>[^>]+)</span>\s*\((?P<S>\d.*?)\)' - - WAIT_PATTERN = r'Wait for <span id="slowRest">(\d+)</span> sec' - LINK_FREE_PATTERN = r'<a href="([^"]+)">Download</a>' - - - def handleFree(self, pyfile): - domain = "http://www.%s/" % self.HOSTER_DOMAIN - action, post_data = self.parseHtmlForm('id="startForm"') - - - for _i in xrange(8): - self.logDebug(action, post_data) - self.html = self.load(urljoin(domain, action), post=post_data, follow_location=False) - - m = re.search(r'location:\s*(\S+)', self.req.http.header, re.I) - if m: - url = m.group(1) - break - - if '>Somebody else is already downloading using your IP-address<' in self.html: - self.wait(10 * 60, True) - self.retry() - - if post_data['step'] == 'last': - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m: - url = m.group(1) - self.correctCaptcha() - break - else: - self.invalidCaptcha() - - last_step = post_data['step'] - action, post_data = self.parseHtmlForm('id="stepForm"') - - if last_step == 'timer': - m = re.search(self.WAIT_PATTERN, self.html) - self.wait(m.group(1) if m else 60, False) - - elif last_step in ("captcha", "last"): - post_data['captcha'] = self.decryptCaptcha(urljoin(domain, "/captcha.jpg")) - - else: - self.fail(_("No valid captcha code entered")) - - self.download(url) - - -getInfo = create_getInfo(UnibytesCom) diff --git a/module/plugins/hoster/UnrestrictLi.py b/module/plugins/hoster/UnrestrictLi.py deleted file mode 100644 index 99fe01257..000000000 --- a/module/plugins/hoster/UnrestrictLi.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.common.json_layer import json_loads -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo -from module.plugins.internal.SimpleHoster import secondsToMidnight - - -class UnrestrictLi(MultiHoster): - __name__ = "UnrestrictLi" - __type__ = "hoster" - __version__ = "0.21" - - __pattern__ = r'https?://(?:www\.)?(unrestrict|unr)\.li/dl/[\w^_]+' - - __description__ = """Unrestrict.li multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - LOGIN_ACCOUNT = False - - - def setup(self): - self.chunkLimit = 16 - self.resumeDownload = True - - - def handleFree(self, pyfile): - for _i in xrange(5): - self.html = self.load('https://unrestrict.li/unrestrict.php', - post={'link': pyfile.url, 'domain': 'long'}) - - self.logDebug("JSON data: " + self.html) - - if self.html: - break - else: - self.logInfo(_("Unable to get API data, waiting 1 minute and retry")) - self.retry(5, 60, "Unable to get API data") - - if 'Expired session' in self.html \ - or ("You are not allowed to download from this host" in self.html and self.premium): - self.account.relogin(self.user) - self.retry() - - elif "File offline" in self.html: - self.offline() - - elif "You are not allowed to download from this host" in self.html: - self.fail(_("You are not allowed to download from this host")) - - elif "You have reached your daily limit for this host" in self.html: - self.logWarning(_("Reached daily limit for this host")) - self.retry(5, secondsToMidnight(gmt=2), "Daily limit for this host reached") - - elif "ERROR_HOSTER_TEMPORARILY_UNAVAILABLE" in self.html: - self.logInfo(_("Hoster temporarily unavailable, waiting 1 minute and retry")) - self.retry(5, 60, "Hoster is temporarily unavailable") - - self.html = json_loads(self.html) - self.link = self.html.keys()[0] - self.api_data = self.html[self.link] - - if hasattr(self, 'api_data'): - self.setNameSize() - - - def checkFile(self): - super(UnrestrictLi, self).checkFile() - - if self.getConfig("history"): - self.load("https://unrestrict.li/history/", get={'delete': "all"}) - self.logInfo(_("Download history deleted")) - - - def setNameSize(self): - if 'name' in self.api_data: - self.pyfile.name = self.api_data['name'] - if 'size' in self.api_data: - self.pyfile.size = self.api_data['size'] - - -getInfo = create_getInfo(UnrestrictLi) diff --git a/module/plugins/hoster/UpleaCom.py b/module/plugins/hoster/UpleaCom.py deleted file mode 100644 index d14f2fdc5..000000000 --- a/module/plugins/hoster/UpleaCom.py +++ /dev/null @@ -1,59 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urlparse import urljoin - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class UpleaCom(XFSHoster): - __name__ = "UpleaCom" - __type__ = "hoster" - __version__ = "0.06" - - __pattern__ = r'https?://(?:www\.)?uplea\.com/dl/\w{15}' - - __description__ = """Uplea.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Redleon", "")] - - - NAME_PATTERN = r'class="agmd size18">(?P<N>.+?)<' - SIZE_PATTERN = r'size14">(?P<S>[\d.,]+) (?P<U>[\w^_])</span>' - - OFFLINE_PATTERN = r'>You followed an invalid or expired link' - - LINK_PATTERN = r'"(http?://\w+\.uplea\.com/anonym/.*?)"' - - WAIT_PATTERN = r'timeText:([\d.]+),' - STEP_PATTERN = r'<a href="(/step/.+)">' - - - def setup(self): - self.multiDL = False - self.chunkLimit = 1 - self.resumeDownload = True - - - def handleFree(self, pyfile): - m = re.search(self.STEP_PATTERN, self.html) - if m is None: - self.error(_("STEP_PATTERN not found")) - - self.html = self.load(urljoin("http://uplea.com/", m.group(1))) - - m = re.search(self.WAIT_PATTERN, self.html) - if m: - self.wait(m.group(1), True) - self.retry() - - m = re.search(self.LINK_PATTERN, self.html) - if m is None: - self.error(_("LINK_PATTERN not found")) - - self.link = m.group(1) - self.wait(15) - - -getInfo = create_getInfo(UpleaCom) diff --git a/module/plugins/hoster/UploadStationCom.py b/module/plugins/hoster/UploadStationCom.py deleted file mode 100644 index daa7a9e81..000000000 --- a/module/plugins/hoster/UploadStationCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class UploadStationCom(DeadHoster): - __name__ = "UploadStationCom" - __type__ = "hoster" - __version__ = "0.52" - - __pattern__ = r'http://(?:www\.)?uploadstation\.com/file/(?P<ID>\w+)' - - __description__ = """UploadStation.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("fragonib", "fragonib[AT]yahoo[DOT]es"), - ("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(UploadStationCom) diff --git a/module/plugins/hoster/UploadableCh.py b/module/plugins/hoster/UploadableCh.py deleted file mode 100644 index bddd26f57..000000000 --- a/module/plugins/hoster/UploadableCh.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from time import sleep - -from pyload.plugin.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class UploadableCh(SimpleHoster): - __name__ = "UploadableCh" - __type__ = "hoster" - __version__ = "0.08" - - __pattern__ = r'http://(?:www\.)?uploadable\.ch/file/(?P<ID>\w+)' - - __description__ = """Uploadable.ch hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - URL_REPLACEMENTS = [(__pattern__ + ".*", r'http://www.uploadable.ch/file/\g<ID>')] - - INFO_PATTERN = r'div id=\"file_name\" title=.*>(?P<N>.+)<span class=\"filename_normal\">\((?P<S>[\d.]+) (?P<U>\w+)\)</span><' - - OFFLINE_PATTERN = r'>(File not available|This file is no longer available)' - TEMP_OFFLINE_PATTERN = r'<div class="icon_err">' - - WAIT_PATTERN = r'>Please wait.+?<' - - RECAPTCHA_KEY = "6LdlJuwSAAAAAPJbPIoUhyqOJd7-yrah5Nhim5S3" - - - def handleFree(self, pyfile): - # Click the "free user" button and wait - a = self.load(pyfile.url, cookies=True, post={'downloadLink': "wait"}, decode=True) - self.logDebug(a) - - self.wait(30) - - # Make the recaptcha appear and show it the pyload interface - b = self.load(pyfile.url, cookies=True, post={'checkDownload': "check"}, decode=True) - self.logDebug(b) #: Expected output: {"success":"showCaptcha"} - - recaptcha = ReCaptcha(self) - - response, challenge = recaptcha.challenge(self.RECAPTCHA_KEY) - - # Submit the captcha solution - self.load("http://www.uploadable.ch/checkReCaptcha.php", - cookies=True, - post={'recaptcha_challenge_field' : challenge, - 'recaptcha_response_field' : response, - 'recaptcha_shortencode_field': self.info['pattern']['ID']}, - decode=True) - - self.wait(3) - - # Get ready for downloading - self.load(pyfile.url, cookies=True, post={'downloadLink': "show"}, decode=True) - - self.wait(3) - - # Download the file - self.download(pyfile.url, cookies=True, post={'download': "normal"}, disposition=True) - - - def checkFile(self): - if self.checkDownload({'wait': re.compile("Please wait for")}): - self.logInfo("Downloadlimit reached, please wait or reconnect") - self.wait(60 * 60, True) - self.retry() - - return super(UploadableCh, self).checkFile() - - -getInfo = create_getInfo(UploadableCh) diff --git a/module/plugins/hoster/UploadboxCom.py b/module/plugins/hoster/UploadboxCom.py deleted file mode 100644 index 6285b56c5..000000000 --- a/module/plugins/hoster/UploadboxCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class UploadboxCom(DeadHoster): - __name__ = "Uploadbox" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'http://(?:www\.)?uploadbox\.com/files/.+' - - __description__ = """UploadBox.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(UploadboxCom) diff --git a/module/plugins/hoster/UploadedTo.py b/module/plugins/hoster/UploadedTo.py deleted file mode 100644 index 83a16c251..000000000 --- a/module/plugins/hoster/UploadedTo.py +++ /dev/null @@ -1,120 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from time import sleep - -from module.network.RequestFactory import getURL -from module.plugins.internal.CaptchaService import ReCaptcha -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class UploadedTo(SimpleHoster): - __name__ = "UploadedTo" - __type__ = "hoster" - __version__ = "0.84" - - __pattern__ = r'https?://(?:www\.)?(uploaded\.(to|net)|ul\.to)(/file/|/?\?id=|.*?&id=|/)(?P<ID>\w+)' - - __description__ = """Uploaded.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - API_KEY = "lhF2IeeprweDfu9ccWlxXVVypA5nA3EL" - - URL_REPLACEMENTS = [(__pattern__ + ".*", r'http://uploaded.net/file/\g<ID>')] - - LINK_PREMIUM_PATTERN = r'<div class="tfree".*\s*<form method="post" action="(.+?)"' - - WAIT_PATTERN = r'Current waiting period: <span>(\d+)' - DL_LIMIT_ERROR = r'You have reached the max. number of possible free downloads for this hour' - - - @classmethod - def apiInfo(cls, url="", get={}, post={}): - info = super(UploadedTo, cls).apiInfo(url) - - for _i in xrange(5): - html = getURL("http://uploaded.net/api/filemultiple", - get={"apikey": cls.API_KEY, 'id_0': re.match(cls.__pattern__, url).group('ID')}, - decode=True) - - if html != "can't find request": - api = html.split(",", 4) - if api[0] == "online": - info.update({'name': api[4].strip(), 'size': api[2], 'status': 2}) - else: - info['status'] = 1 - break - else: - sleep(3) - - return info - - - def setup(self): - self.multiDL = self.resumeDownload = self.premium - self.chunkLimit = 1 # critical problems with more chunks - - - def checkErrors(self): - if 'var free_enabled = false;' in self.html: - self.logError(_("Free-download capacities exhausted")) - self.retry(24, 5 * 60) - - elif "limit-size" in self.html: - self.fail(_("File too big for free download")) - - elif "limit-slot" in self.html: # Temporary restriction so just wait a bit - self.wait(30 * 60, True) - self.retry() - - elif "limit-parallel" in self.html: - self.fail(_("Cannot download in parallel")) - - elif "limit-dl" in self.html or self.DL_LIMIT_ERROR in self.html: # limit-dl - self.wait(3 * 60 * 60, True) - self.retry() - - elif '"err":"captcha"' in self.html: - self.invalidCaptcha() - - else: - m = re.search(self.WAIT_PATTERN, self.html) - if m: - self.wait(m.group(1)) - - - def handleFree(self, pyfile): - self.load("http://uploaded.net/language/en", just_header=True) - - self.html = self.load("http://uploaded.net/js/download.js", decode=True) - - recaptcha = ReCaptcha(self) - response, challenge = recaptcha.challenge() - - self.html = self.load("http://uploaded.net/io/ticket/captcha/%s" % self.info['pattern']['ID'], - post={'recaptcha_challenge_field': challenge, - 'recaptcha_response_field' : response}) - - if "type:'download'" in self.html: - self.correctCaptcha() - try: - self.link = re.search("url:'([^']+)", self.html).group(1) - - except Exception: - pass - - self.checkErrors() - - - def checkFile(self): - if self.checkDownload({'limit-dl': self.DL_LIMIT_ERROR}): - self.wait(3 * 60 * 60, True) - self.retry() - - return super(UploadedTo, self).checkFile() - - -getInfo = create_getInfo(UploadedTo) diff --git a/module/plugins/hoster/UploadhereCom.py b/module/plugins/hoster/UploadhereCom.py deleted file mode 100644 index 64b235eda..000000000 --- a/module/plugins/hoster/UploadhereCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class UploadhereCom(DeadHoster): - __name__ = "UploadhereCom" - __type__ = "hoster" - __version__ = "0.12" - - __pattern__ = r'http://(?:www\.)?uploadhere\.com/\w{10}' - - __description__ = """Uploadhere.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(UploadhereCom) diff --git a/module/plugins/hoster/UploadheroCom.py b/module/plugins/hoster/UploadheroCom.py deleted file mode 100644 index a0a9cffcb..000000000 --- a/module/plugins/hoster/UploadheroCom.py +++ /dev/null @@ -1,76 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# http://uploadhero.co/dl/wQBRAVSM - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class UploadheroCom(SimpleHoster): - __name__ = "UploadheroCom" - __type__ = "hoster" - __version__ = "0.17" - - __pattern__ = r'http://(?:www\.)?uploadhero\.com?/dl/\w+' - - __description__ = """UploadHero.co plugin""" - __license__ = "GPLv3" - __authors__ = [("mcmyst", "mcmyst@hotmail.fr"), - ("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'<div class="nom_de_fichier">(?P<N>.*?)</div>' - SIZE_PATTERN = r'Taille du fichier : </span><strong>(?P<S>.*?)</strong>' - OFFLINE_PATTERN = r'<p class="titre_dl_2">|<div class="raison"><strong>Le lien du fichier ci-dessus n\'existe plus.' - - COOKIES = [("uploadhero.co", "lang", "en")] - - IP_BLOCKED_PATTERN = r'href="(/lightbox_block_download\.php\?min=.*?)"' - IP_WAIT_PATTERN = r'<span id="minutes">(\d+)</span>.*\s*<span id="seconds">(\d+)</span>' - - CAPTCHA_PATTERN = r'"(/captchadl\.php\?\w+)"' - - LINK_FREE_PATTERN = r'var magicomfg = \'<a href="(http://[^<>"]*?)"|"(http://storage\d+\.uploadhero\.co/\?d=\w+/[^<>"/]+)"' - LINK_PREMIUM_PATTERN = r'<a href="([^"]+)" id="downloadnow"' - - - def handleFree(self, pyfile): - self.checkErrors() - - m = re.search(self.CAPTCHA_PATTERN, self.html) - if m is None: - self.error(_("CAPTCHA_PATTERN not found")) - captcha_url = "http://uploadhero.co" + m.group(1) - - for _i in xrange(5): - captcha = self.decryptCaptcha(captcha_url) - self.html = self.load(pyfile.url, get={"code": captcha}) - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m: - self.correctCaptcha() - download_url = m.group(1) or m.group(2) - break - else: - self.invalidCaptcha() - else: - self.fail(_("No valid captcha code entered")) - - self.download(download_url) - - - def checkErrors(self): - m = re.search(self.IP_BLOCKED_PATTERN, self.html) - if m: - self.html = self.load("http://uploadhero.co%s" % m.group(1)) - - m = re.search(self.IP_WAIT_PATTERN, self.html) - wait_time = (int(m.group(1)) * 60 + int(m.group(2))) if m else 5 * 60 - self.wait(wait_time, True) - self.retry() - - self.info.pop('error', None) - - -getInfo = create_getInfo(UploadheroCom) diff --git a/module/plugins/hoster/UploadingCom.py b/module/plugins/hoster/UploadingCom.py deleted file mode 100644 index a315d3466..000000000 --- a/module/plugins/hoster/UploadingCom.py +++ /dev/null @@ -1,99 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pycurl import HTTPHEADER - -from pyload.utils import json_loads -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo, timestamp - - -class UploadingCom(SimpleHoster): - __name__ = "UploadingCom" - __type__ = "hoster" - __version__ = "0.40" - - __pattern__ = r'http://(?:www\.)?uploading\.com/files/(?:get/)?(?P<ID>\w+)' - - __description__ = """Uploading.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("jeix", "jeix@hasnomail.de"), - ("mkaay", "mkaay@mkaay.de"), - ("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'id="file_title">(?P<N>.+)</' - SIZE_PATTERN = r'size tip_container">(?P<S>[\d.,]+) (?P<U>[\w^_]+)<' - OFFLINE_PATTERN = r'(Page|file) not found' - - COOKIES = [("uploading.com", "lang", "1"), - (".uploading.com", "language", "1"), - (".uploading.com", "setlang", "en"), - (".uploading.com", "_lang", "en")] - - - def process(self, pyfile): - if not "/get/" in pyfile.url: - pyfile.url = pyfile.url.replace("/files", "/files/get") - - self.html = self.load(pyfile.url, decode=True) - self.getFileInfo() - - if self.premium: - self.handlePremium(pyfile) - else: - self.handleFree(pyfile) - - - def handlePremium(self, pyfile): - postData = {'action': 'get_link', - 'code' : self.info['pattern']['ID'], - 'pass' : 'undefined'} - - self.html = self.load('http://uploading.com/files/get/?JsHttpRequest=%d-xml' % timestamp(), post=postData) - url = re.search(r'"link"\s*:\s*"(.*?)"', self.html) - if url: - url = url.group(1).replace("\\/", "/") - self.download(url) - - raise Exception("Plugin defect") - - - def handleFree(self, pyfile): - m = re.search('<h2>((Daily )?Download Limit)</h2>', self.html) - if m: - pyfile.error = m.group(1) - self.logWarning(pyfile.error) - self.retry(6, (6 * 60 if m.group(2) else 15) * 60, pyfile.error) - - ajax_url = "http://uploading.com/files/get/?ajax" - self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) - self.req.http.lastURL = pyfile.url - - res = json_loads(self.load(ajax_url, post={'action': 'second_page', 'code': self.info['pattern']['ID']})) - - if 'answer' in res and 'wait_time' in res['answer']: - wait_time = int(res['answer']['wait_time']) - self.logInfo(_("Waiting %d seconds") % wait_time) - self.wait(wait_time) - else: - self.error(_("No AJAX/WAIT")) - - res = json_loads(self.load(ajax_url, post={'action': 'get_link', 'code': self.info['pattern']['ID'], 'pass': 'false'})) - - if 'answer' in res and 'link' in res['answer']: - url = res['answer']['link'] - else: - self.error(_("No AJAX/URL")) - - self.html = self.load(url) - m = re.search(r'<form id="file_form" action="(.*?)"', self.html) - if m: - url = m.group(1) - else: - self.error(_("No URL")) - - self.download(url) - - -getInfo = create_getInfo(UploadingCom) diff --git a/module/plugins/hoster/UploadkingCom.py b/module/plugins/hoster/UploadkingCom.py deleted file mode 100644 index a490d0d48..000000000 --- a/module/plugins/hoster/UploadkingCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class UploadkingCom(DeadHoster): - __name__ = "UploadkingCom" - __type__ = "hoster" - __version__ = "0.14" - - __pattern__ = r'http://(?:www\.)?uploadking\.com/\w{10}' - - __description__ = """UploadKing.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - -getInfo = create_getInfo(UploadkingCom) diff --git a/module/plugins/hoster/UpstoreNet.py b/module/plugins/hoster/UpstoreNet.py deleted file mode 100644 index b1ceb7df1..000000000 --- a/module/plugins/hoster/UpstoreNet.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.captcha import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class UpstoreNet(SimpleHoster): - __name__ = "UpstoreNet" - __type__ = "hoster" - __version__ = "0.05" - - __pattern__ = r'https?://(?:www\.)?upstore\.net/' - - __description__ = """Upstore.Net File Download Hoster""" - __license__ = "GPLv3" - __authors__ = [("igel", "igelkun@myopera.com")] - - - INFO_PATTERN = r'<div class="comment">.*?</div>\s*\n<h2 style="margin:0">(?P<N>.*?)</h2>\s*\n<div class="comment">\s*\n\s*(?P<S>[\d.,]+) (?P<U>[\w^_]+)' - OFFLINE_PATTERN = r'<span class="error">File not found</span>' - - WAIT_PATTERN = r'var sec = (\d+)' - CHASH_PATTERN = r'<input type="hidden" name="hash" value="([^"]*)">' - LINK_FREE_PATTERN = r'<a href="(https?://.*?)" target="_blank"><b>' - - - def handleFree(self, pyfile): - # STAGE 1: get link to continue - m = re.search(self.CHASH_PATTERN, self.html) - if m is None: - self.error(_("CHASH_PATTERN not found")) - chash = m.group(1) - self.logDebug("Read hash " + chash) - # continue to stage2 - post_data = {'hash': chash, 'free': 'Slow download'} - self.html = self.load(pyfile.url, post=post_data, decode=True) - - # STAGE 2: solv captcha and wait - # first get the infos we need: recaptcha key and wait time - recaptcha = ReCaptcha(self) - - # try the captcha 5 times - for i in xrange(5): - m = re.search(self.WAIT_PATTERN, self.html) - if m is None: - self.error(_("Wait pattern not found")) - wait_time = int(m.group(1)) - - # then, do the waiting - self.wait(wait_time) - - # then, handle the captcha - response, challenge = recaptcha.challenge() - post_data.update({'recaptcha_challenge_field': challenge, - 'recaptcha_response_field' : response}) - - self.html = self.load(pyfile.url, post=post_data, decode=True) - - # STAGE 3: get direct link - m = re.search(self.LINK_FREE_PATTERN, self.html, re.S) - if m: - break - - if m is None: - self.error(_("Download link not found")) - - self.link = m.group(1) - - -getInfo = create_getInfo(UpstoreNet) diff --git a/module/plugins/hoster/UptoboxCom.py b/module/plugins/hoster/UptoboxCom.py deleted file mode 100644 index 3d3505f90..000000000 --- a/module/plugins/hoster/UptoboxCom.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class UptoboxCom(XFSHoster): - __name__ = "UptoboxCom" - __type__ = "hoster" - __version__ = "0.17" - - __pattern__ = r'https?://(?:www\.)?(uptobox|uptostream)\.com/\w{12}' - - __description__ = """Uptobox.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - INFO_PATTERN = r'"para_title">(?P<N>.+) \((?P<S>[\d.,]+) (?P<U>[\w^_]+)\)' - OFFLINE_PATTERN = r'>(File not found|Access Denied|404 Not Found)' - - LINK_PATTERN = r'"(https?://\w+\.uptobox\.com/d/.*?)"' - - ERROR_PATTERN = r'>(You have to wait.+till next download.)<' #@TODO: Check XFSHoster ERROR_PATTERN - - - def setup(self): - self.multiDL = True - self.chunkLimit = 1 - self.resumeDownload = True - - -getInfo = create_getInfo(UptoboxCom) diff --git a/module/plugins/hoster/VeohCom.py b/module/plugins/hoster/VeohCom.py deleted file mode 100644 index cb3e896d6..000000000 --- a/module/plugins/hoster/VeohCom.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class VeohCom(SimpleHoster): - __name__ = "VeohCom" - __type__ = "hoster" - __version__ = "0.22" - - __pattern__ = r'http://(?:www\.)?veoh\.com/(tv/)?(watch|videos)/(?P<ID>v\w+)' - __config__ = [("quality", "Low;High;Auto", "Quality", "Auto")] - - __description__ = """Veoh.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - NAME_PATTERN = r'<meta name="title" content="(?P<N>.*?)"' - OFFLINE_PATTERN = r'>Sorry, we couldn\'t find the video you were looking for' - - URL_REPLACEMENTS = [(__pattern__ + ".*", r'http://www.veoh.com/watch/\g<ID>')] - - COOKIES = [("veoh.com", "lassieLocale", "en")] - - - def setup(self): - self.resumeDownload = True - self.multiDL = True - self.chunkLimit = -1 - - - def handleFree(self, pyfile): - quality = self.getConfig("quality") - if quality == "Auto": - quality = ("High", "Low") - - for q in quality: - pattern = r'"fullPreviewHash%sPath":"(.+?)"' % q - m = re.search(pattern, self.html) - if m: - pyfile.name += ".mp4" - link = m.group(1).replace("\\", "") - self.download(link) - return - else: - self.logInfo(_("No %s quality video found") % q.upper()) - else: - self.fail(_("No video found!")) - - -getInfo = create_getInfo(VeohCom) diff --git a/module/plugins/hoster/VidPlayNet.py b/module/plugins/hoster/VidPlayNet.py deleted file mode 100644 index 5f979e856..000000000 --- a/module/plugins/hoster/VidPlayNet.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Test links: -# BigBuckBunny_320x180.mp4 - 61.7 Mb - http://vidplay.net/38lkev0h3jv0 - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class VidPlayNet(XFSHoster): - __name__ = "VidPlayNet" - __type__ = "hoster" - __version__ = "0.04" - - __pattern__ = r'https?://(?:www\.)?vidplay\.net/\w{12}' - - __description__ = """VidPlay.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("t4skforce", "t4skforce1337[AT]gmail[DOT]com")] - - - NAME_PATTERN = r'<b>Password:</b></div>\s*<h[1-6]>(?P<N>[^<]+)</h[1-6]>' - - -getInfo = create_getInfo(VidPlayNet) diff --git a/module/plugins/hoster/VimeoCom.py b/module/plugins/hoster/VimeoCom.py deleted file mode 100644 index 7ca6c962b..000000000 --- a/module/plugins/hoster/VimeoCom.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class VimeoCom(SimpleHoster): - __name__ = "VimeoCom" - __type__ = "hoster" - __version__ = "0.04" - - __pattern__ = r'https?://(?:www\.)?(player\.)?vimeo\.com/(video/)?(?P<ID>\d+)' - __config__ = [("quality", "Lowest;Mobile;SD;HD;Highest", "Quality", "Highest"), - ("original", "bool", "Try to download the original file first", True)] - - __description__ = """Vimeo.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - NAME_PATTERN = r'<title>(?P<N>.+) on Vimeo<' - OFFLINE_PATTERN = r'class="exception_header"' - TEMP_OFFLINE_PATTERN = r'Please try again in a few minutes.<' - - URL_REPLACEMENTS = [(__pattern__ + ".*", r'https://www.vimeo.com/\g<ID>')] - - COOKIES = [("vimeo.com", "language", "en")] - - - def setup(self): - self.resumeDownload = True - self.multiDL = True - self.chunkLimit = -1 - - - def handleFree(self, pyfile): - password = self.getPassword() - - if self.js and 'class="btn iconify_down_b"' in self.html: - html = self.js.eval(self.load(pyfile.url, get={'action': "download", 'password': password}, decode=True)) - pattern = r'href="(?P<URL>http://vimeo\.com.+?)".*?\>(?P<QL>.+?) ' - else: - html = self.load("https://player.vimeo.com/video/" + self.info['pattern']['ID'], get={'password': password}) - pattern = r'"(?P<QL>\w+)":{"profile".*?"(?P<URL>http://pdl\.vimeocdn\.com.+?)"' - - link = dict((l.group('QL').lower(), l.group('URL')) for l in re.finditer(pattern, html)) - - if self.getConfig("original"): - if "original" in link: - self.download(link[q]) - return - else: - self.logInfo(_("Original file not downloadable")) - - quality = self.getConfig("quality") - if quality == "Highest": - qlevel = ("hd", "sd", "mobile") - elif quality == "Lowest": - qlevel = ("mobile", "sd", "hd") - else: - qlevel = quality.lower() - - for q in qlevel: - if q in link: - self.download(link[q]) - return - else: - self.logInfo(_("No %s quality video found") % q.upper()) - else: - self.fail(_("No video found!")) - - -getInfo = create_getInfo(VimeoCom) diff --git a/module/plugins/hoster/Vipleech4UCom.py b/module/plugins/hoster/Vipleech4UCom.py deleted file mode 100644 index dec67e7a4..000000000 --- a/module/plugins/hoster/Vipleech4UCom.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class Vipleech4UCom(DeadHoster): - __name__ = "Vipleech4UCom" - __type__ = "hoster" - __version__ = "0.20" - - __pattern__ = r'http://(?:www\.)?vipleech4u\.com/manager\.php' - - __description__ = """Vipleech4u.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Kagenoshin", "kagenoshin@gmx.ch")] - - -getInfo = create_getInfo(Vipleech4UCom) diff --git a/module/plugins/hoster/WarserverCz.py b/module/plugins/hoster/WarserverCz.py deleted file mode 100644 index 1631a021d..000000000 --- a/module/plugins/hoster/WarserverCz.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class WarserverCz(DeadHoster): - __name__ = "WarserverCz" - __type__ = "hoster" - __version__ = "0.13" - - __pattern__ = r'http://(?:www\.)?warserver\.cz/stahnout/\d+' - - __description__ = """Warserver.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - -getInfo = create_getInfo(WarserverCz) diff --git a/module/plugins/hoster/WebshareCz.py b/module/plugins/hoster/WebshareCz.py deleted file mode 100644 index 98187d46a..000000000 --- a/module/plugins/hoster/WebshareCz.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.network.RequestFactory import getURL -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class WebshareCz(SimpleHoster): - __name__ = "WebshareCz" - __type__ = "hoster" - __version__ = "0.16" - - __pattern__ = r'https?://(?:www\.)?webshare\.cz/(?:#/)?file/(?P<ID>\w+)' - - __description__ = """WebShare.cz hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it"), - ("rush", "radek.senfeld@gmail.com")] - - - @classmethod - def getInfo(cls, url="", html=""): - info = super(WebshareCz, cls).getInfo(url, html) - - if url: - info['pattern'] = re.match(cls.__pattern__, url).groupdict() - - api_data = getURL("https://webshare.cz/api/file_info/", - post={'ident': info['pattern']['ID']}, - decode=True) - - if 'File not found' in api_data: - info['status'] = 1 - else: - info["status"] = 2 - info['name'] = re.search('<name>(.+)</name>', api_data).group(1) or info['name'] - info['size'] = re.search('<size>(.+)</size>', api_data).group(1) or info['size'] - - return info - - - def handleFree(self, pyfile): - wst = self.account.infos['wst'] if self.account and 'wst' in self.account.infos else "" - - api_data = getURL('https://webshare.cz/api/file_link/', - post={'ident': self.info['pattern']['ID'], 'wst': wst}, - decode=True) - - self.logDebug("API data: " + api_data) - - m = re.search('<link>(.+)</link>', api_data) - if m is None: - self.error(_("Unable to detect direct link")) - - self.link = m.group(1) - - - def handlePremium(self, pyfile): - return self.handleFree(pyfile) - - -getInfo = create_getInfo(WebshareCz) diff --git a/module/plugins/hoster/WrzucTo.py b/module/plugins/hoster/WrzucTo.py deleted file mode 100644 index 631f9d3c6..000000000 --- a/module/plugins/hoster/WrzucTo.py +++ /dev/null @@ -1,52 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pycurl import HTTPHEADER - -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class WrzucTo(SimpleHoster): - __name__ = "WrzucTo" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'http://(?:www\.)?wrzuc\.to/(\w+(\.wt|\.html)|(\w+/?linki/\w+))' - - __description__ = """Wrzuc.to hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'id="file_info">\s*<strong>(?P<N>.*?)</strong>' - SIZE_PATTERN = r'class="info">\s*<tr>\s*<td>(?P<S>.*?)</td>' - - COOKIES = [("wrzuc.to", "language", "en")] - - - def setup(self): - self.multiDL = True - - - def handleFree(self, pyfile): - data = dict(re.findall(r'(md5|file): "(.*?)"', self.html)) - if len(data) != 2: - self.error(_("No file ID")) - - self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) - self.req.http.lastURL = pyfile.url - self.load("http://www.wrzuc.to/ajax/server/prepair", post={"md5": data['md5']}) - - self.req.http.lastURL = pyfile.url - self.html = self.load("http://www.wrzuc.to/ajax/server/download_link", post={"file": data['file']}) - - data.update(re.findall(r'"(download_link|server_id)":"(.*?)"', self.html)) - if len(data) != 4: - self.error(_("No download URL")) - - download_url = "http://%s.wrzuc.to/pobierz/%s" % (data['server_id'], data['download_link']) - self.download(download_url) - - -getInfo = create_getInfo(WrzucTo) diff --git a/module/plugins/hoster/WuploadCom.py b/module/plugins/hoster/WuploadCom.py deleted file mode 100644 index a73ac92e0..000000000 --- a/module/plugins/hoster/WuploadCom.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class WuploadCom(DeadHoster): - __name__ = "WuploadCom" - __type__ = "hoster" - __version__ = "0.23" - - __pattern__ = r'http://(?:www\.)?wupload\..+?/file/((\w+/)?\d+)(/.*)?' - - __description__ = """Wupload.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("jeix", "jeix@hasnomail.de"), - ("Paul King", "")] - - -getInfo = create_getInfo(WuploadCom) diff --git a/module/plugins/hoster/X7To.py b/module/plugins/hoster/X7To.py deleted file mode 100644 index 6ccc6d637..000000000 --- a/module/plugins/hoster/X7To.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class X7To(DeadHoster): - __name__ = "X7To" - __type__ = "hoster" - __version__ = "0.41" - - __pattern__ = r'http://(?:www\.)?x7\.to/' - - __description__ = """X7.to hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("ernieb", "ernieb")] - - -getInfo = create_getInfo(X7To) diff --git a/module/plugins/hoster/XFileSharingPro.py b/module/plugins/hoster/XFileSharingPro.py deleted file mode 100644 index 23af6e7fc..000000000 --- a/module/plugins/hoster/XFileSharingPro.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.plugin.internal.XFSHoster import XFSHoster, create_getInfo - - -class XFileSharingPro(XFSHoster): - __name__ = "XFileSharingPro" - __type__ = "hoster" - __version__ = "0.44" - - __pattern__ = r'^unmatchable$' - - __description__ = """XFileSharingPro dummy hoster plugin for hook""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - URL_REPLACEMENTS = [("/embed-", "/")] - - - def _log(self, type, args): - msg = " | ".join(str(a).strip() for a in args if a) - logger = getattr(self.log, type) - logger("%s: %s: %s" % (self.__name__, self.HOSTER_NAME, msg or _("%s MARK" % type.upper()))) - - - def init(self): - super(XFileSharingPro, self).init() - - self.__pattern__ = self.core.pluginManager.hosterPlugins[self.__name__]['pattern'] - - self.HOSTER_DOMAIN = re.match(self.__pattern__, self.pyfile.url).group("DOMAIN").lower() - self.HOSTER_NAME = "".join(part.capitalize() for part in re.split(r'(\.|\d+)', self.HOSTER_DOMAIN) if part != '.') - - if self.HOSTER_NAME[0].isdigit(): - self.HOSTER_NAME = 'X' + self.HOSTER_NAME - - account = self.core.accountManager.getAccountPlugin(self.HOSTER_NAME) - - if account and account.canUse(): - self.account = account - - elif self.account: - self.account.HOSTER_DOMAIN = self.HOSTER_DOMAIN - - else: - return - - self.user, data = self.account.selectAccount() - self.req = self.account.getAccountRequest(self.user) - self.premium = self.account.isPremium(self.user) - - - def setup(self): - self.chunkLimit = 1 - self.resumeDownload = self.premium - self.multiDL = True - - -getInfo = create_getInfo(XFileSharingPro) diff --git a/module/plugins/hoster/XdadevelopersCom.py b/module/plugins/hoster/XdadevelopersCom.py deleted file mode 100644 index 7d50d4f57..000000000 --- a/module/plugins/hoster/XdadevelopersCom.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- coding: utf-8 -* -# -# Test links: -# http://forum.xda-developers.com/devdb/project/dl/?id=10885 - -import re - -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class XdadevelopersCom(SimpleHoster): - __name__ = "XdadevelopersCom" - __type__ = "hoster" - __version__ = "0.03" - - __pattern__ = r'https?://(?:www\.)?forum\.xda-developers\.com/devdb/project/dl/\?id=\d+' - - __description__ = """Xda-developers.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] - - - NAME_PATTERN = r'<label>Filename:</label>\s*<div>\s*(?P<N>.*?)\n' - SIZE_PATTERN = r'<label>Size:</label>\s*<div>\s*(?P<S>[\d.,]+)(?P<U>[\w^_]+)' - OFFLINE_PATTERN = r'</i> Device Filter</h3>' - - - def setup(self): - self.multiDL = True - self.resumeDownload = True - self.chunkLimit = 1 - - - def handleFree(self, pyfile): - self.link = pyfile.url + "&task=get" #@TODO: Revert to `get={'task': "get"}` in 0.4.10 - - -getInfo = create_getInfo(XdadevelopersCom) diff --git a/module/plugins/hoster/YibaishiwuCom.py b/module/plugins/hoster/YibaishiwuCom.py deleted file mode 100644 index 6da5cff33..000000000 --- a/module/plugins/hoster/YibaishiwuCom.py +++ /dev/null @@ -1,59 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pyload.utils import json_loads -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class YibaishiwuCom(SimpleHoster): - __name__ = "YibaishiwuCom" - __type__ = "hoster" - __version__ = "0.14" - - __pattern__ = r'http://(?:www\.)?(?:u\.)?115\.com/file/(?P<ID>\w+)' - - __description__ = """115.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - NAME_PATTERN = r'file_name: \'(?P<N>.+?)\'' - SIZE_PATTERN = r'file_size: \'(?P<S>.+?)\'' - OFFLINE_PATTERN = ur'<h3><i style="color:red;">ååïŒæåç äžååšïŒäžåŠšææçå§ïŒ</i></h3>' - - LINK_FREE_PATTERN = r'(/\?ct=(pickcode|download)[^"\']+)' - - - def handleFree(self, pyfile): - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("LINK_FREE_PATTERN not found")) - - url = m.group(1) - - self.logDebug(('FREEUSER' if m.group(2) == 'download' else 'GUEST') + ' URL', url) - - res = json_loads(self.load("http://115.com" + url, decode=False)) - if "urls" in res: - mirrors = res['urls'] - - elif "data" in res: - mirrors = res['data'] - - else: - mirrors = None - - for mr in mirrors: - try: - url = mr['url'].replace("\\", "") - self.logDebug("Trying URL: " + url) - self.download(url) - break - except Exception: - continue - else: - self.fail(_("No working link found")) - - -getInfo = create_getInfo(YibaishiwuCom) diff --git a/module/plugins/hoster/ZShareNet.py b/module/plugins/hoster/ZShareNet.py deleted file mode 100644 index a6a34143f..000000000 --- a/module/plugins/hoster/ZShareNet.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.internal.DeadHoster import DeadHoster, create_getInfo - - -class ZShareNet(DeadHoster): - __name__ = "ZShareNet" - __type__ = "hoster" - __version__ = "0.21" - - __pattern__ = r'https?://(?:ww[2w]\.)?zshares?\.net/.+' - - __description__ = """ZShare.net hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("espes", ""), - ("Cptn Sandwich", "")] - - -getInfo = create_getInfo(ZShareNet) diff --git a/module/plugins/hoster/ZeveraCom.py b/module/plugins/hoster/ZeveraCom.py deleted file mode 100644 index 665b64789..000000000 --- a/module/plugins/hoster/ZeveraCom.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urlparse import urljoin - -from module.plugins.internal.MultiHoster import MultiHoster, create_getInfo - - -class ZeveraCom(MultiHoster): - __name__ = "ZeveraCom" - __type__ = "hoster" - __version__ = "0.28" - - __pattern__ = r'https?://(?:www\.)zevera\.com/(getFiles\.ashx|Members/download\.ashx)\?.*ourl=.+' - - __description__ = """Zevera.com multi-hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - def handlePremium(self, pyfile): - self.link = "https://%s/getFiles.ashx?ourl=%s" % (self.account.HOSTER_DOMAIN, pyfile.url) - - - def checkFile(self): - if self.checkDownload({"error": 'action="ErrorDownload.aspx'}): - self.fail(_("Error response received")) - - return super(ZeveraCom, self).checkFile() - - -getInfo = create_getInfo(ZeveraCom) diff --git a/module/plugins/hoster/ZippyshareCom.py b/module/plugins/hoster/ZippyshareCom.py deleted file mode 100644 index f08fb7dae..000000000 --- a/module/plugins/hoster/ZippyshareCom.py +++ /dev/null @@ -1,65 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.CaptchaService import ReCaptcha -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo - - -class ZippyshareCom(SimpleHoster): - __name__ = "ZippyshareCom" - __type__ = "hoster" - __version__ = "0.72" - - __pattern__ = r'http://www\d{0,2}\.zippyshare\.com/v(/|iew\.jsp.*key=)(?P<KEY>[\w^_]+)' - - __description__ = """Zippyshare.com hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - COOKIES = [("zippyshare.com", "ziplocale", "en")] - - NAME_PATTERN = r'("\d{6,}/"[ ]*\+.+?"/|<title>Zippyshare.com - )(?P<N>.+?)("|</title>)' - SIZE_PATTERN = r'>Size:.+?">(?P<S>[\d.,]+) (?P<U>[\w^_]+)' - OFFLINE_PATTERN = r'>File does not exist on this server' - - LINK_PREMIUM_PATTERN = r'document.location = \'(.+?)\'' - - - def setup(self): - self.chunkLimit = -1 - self.multiDL = True - self.resumeDownload = True - - - def handleFree(self, pyfile): - recaptcha = ReCaptcha(self) - captcha_key = recaptcha.detect_key() - - if captcha_key: - try: - self.link = re.search(self.LINK_PREMIUM_PATTERN, self.html) - recaptcha.challenge() - - except Exception, e: - self.error(e) - - else: - self.link = '/'.join(("d", self.info['pattern']['KEY'], str(self.get_checksum()), self.pyfile.name)) - - - def get_checksum(self): - try: - n = 2 - b = int(re.search(r'var b = (\d+)', self.html).group(1)) - checksum = int("%d3" % (n + n * 2 + b)) - - except Exception: - self.error(_("Unable to calculate checksum")) - - else: - return checksum - - -getInfo = create_getInfo(ZippyshareCom) diff --git a/module/plugins/internal/BasePlugin.py b/module/plugins/internal/BasePlugin.py deleted file mode 100644 index 792497449..000000000 --- a/module/plugins/internal/BasePlugin.py +++ /dev/null @@ -1,95 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urllib import unquote -from urlparse import urljoin, urlparse - -from module.network.HTTPRequest import BadHeader -from module.plugins.internal.SimpleHoster import create_getInfo, fileUrl -from module.plugins.Hoster import Hoster - - -class BasePlugin(Hoster): - __name__ = "BasePlugin" - __type__ = "hoster" - __version__ = "0.34" - - __pattern__ = r'^unmatchable$' - - __description__ = """Base plugin when any other didnt fit""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - @classmethod - def getInfo(cls, url="", html=""): #@TODO: Move to hoster class in 0.4.10 - url = unquote(url) - url_p = urlparse(url) - return {'name' : (url_p.path.split('/')[-1] - or url_p.query.split('=', 1)[::-1][0].split('&', 1)[0] - or url_p.netloc.split('.', 1)[0]), - 'size' : 0, - 'status': 3 if url else 8, - 'url' : url} - - - def setup(self): - self.chunkLimit = -1 - self.multiDL = True - self.resumeDownload = True - - - def process(self, pyfile): - """main function""" - - pyfile.name = self.getInfo(pyfile.url)['name'] - - if not pyfile.url.startswith("http"): - self.fail(_("No plugin matched")) - - for _i in xrange(5): - try: - link = fileUrl(self, unquote(pyfile.url)) - - if link: - self.download(link, ref=False, disposition=True) - else: - self.fail(_("File not found")) - - except BadHeader, e: - if e.code is 404: - self.offline() - - elif e.code in (401, 403): - self.logDebug("Auth required", "Received HTTP status code: %d" % e.code) - - account = self.core.accountManager.getAccountPlugin('Http') - servers = [x['login'] for x in account.getAllAccounts()] - server = urlparse(pyfile.url).netloc - - if server in servers: - self.logDebug("Logging on to %s" % server) - self.req.addAuth(account.getAccountData(server)['password']) - else: - pwd = self.getPassword() - if ':' in pwd: - self.req.addAuth(pwd) - else: - self.fail(_("Authorization required")) - else: - self.fail(e) - else: - break - else: - self.fail(_("No file downloaded")) #@TODO: Move to hoster class in 0.4.10 - - check = self.checkDownload({'empty file': re.compile(r'\A\Z'), - 'html file' : re.compile(r'\A\s*<!DOCTYPE html'), - 'html error': re.compile(r'\A\s*(<.+>)?\d{3}(\Z|\s+)')}) - if check: - self.fail(check.capitalize()) - - -getInfo = create_getInfo(BasePlugin) diff --git a/module/plugins/internal/CaptchaService.py b/module/plugins/internal/CaptchaService.py deleted file mode 100644 index 6f2c8e06d..000000000 --- a/module/plugins/internal/CaptchaService.py +++ /dev/null @@ -1,522 +0,0 @@ -# -*- coding: utf-8 -*- - -import re -import time - -from base64 import b64encode -from random import random, randint -from urlparse import urljoin, urlparse - -from module.common.json_layer import json_loads -from module.plugins.Plugin import Base - - -#@TODO: Extend (new) Plugin class; remove all `html` args -class CaptchaService(Base): - __name__ = "CaptchaService" - __version__ = "0.25" - - __description__ = """Base captcha service plugin""" - __license__ = "GPLv3" - __authors__ = [("pyLoad Team", "admin@pyload.org")] - - - key = None #: last key detected - - - def __init__(self, plugin): - self.plugin = plugin - super(CaptchaService, self).__init__(plugin.core) - - - def detect_key(self, html=None): - raise NotImplementedError - - - def challenge(self, key=None, html=None): - raise NotImplementedError - - - def result(self, server, challenge): - raise NotImplementedError - - -class ReCaptcha(CaptchaService): - __name__ = "ReCaptcha" - __version__ = "0.14" - - __description__ = """ReCaptcha captcha service plugin""" - __license__ = "GPLv3" - __authors__ = [("pyLoad Team", "admin@pyload.org"), - ("Walter Purcaro", "vuolter@gmail.com"), - ("zapp-brannigan", "fuerst.reinje@web.de")] - - - KEY_V2_PATTERN = r'(?:data-sitekey=["\']|["\']sitekey["\']:\s*["\'])([\w-]+)' - KEY_V1_PATTERN = r'(?:recaptcha(?:/api|\.net)/(?:challenge|noscript)\?k=|Recaptcha\.create\s*\(\s*["\'])([\w-]+)' - - - def detect_key(self, html=None): - if not html: - if hasattr(self.plugin, "html") and self.plugin.html: - html = self.plugin.html - else: - errmsg = _("ReCaptcha html not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - m = re.search(self.KEY_V2_PATTERN, html) or re.search(self.KEY_V1_PATTERN, html) - if m: - self.key = m.group(1).strip() - self.logDebug("Key: %s" % self.key) - return self.key - else: - self.logDebug("Key not found") - return None - - - def challenge(self, key=None, html=None, version=None): - if not key: - if self.detect_key(html): - key = self.key - else: - errmsg = _("ReCaptcha key not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - if version in (1, 2): - return getattr(self, "_challenge_v%s" % version)(key) - - elif not html and hasattr(self.plugin, "html") and self.plugin.html: - version = 2 if re.search(self.KEY_V2_PATTERN, self.plugin.html) else 1 - return self.challenge(key, self.plugin.html, version) - - else: - errmsg = _("ReCaptcha html not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - - def _challenge_v1(self, key): - html = self.plugin.req.load("http://www.google.com/recaptcha/api/challenge", - get={'k': key}) - try: - challenge = re.search("challenge : '(.+?)',", html).group(1) - server = re.search("server : '(.+?)',", html).group(1) - - except AttributeError: - errmsg = _("ReCaptcha challenge pattern not found") - self.plugin.fail(errmsg) - raise AttributeError(errmsg) - - self.logDebug("Challenge: %s" % challenge) - - return self.result(server, challenge), challenge - - - def result(self, server, challenge): - result = self.plugin.decryptCaptcha("%simage" % server, - get={'c': challenge}, - cookies=True, - forceUser=True, - imgtype="jpg") - - self.logDebug("Result: %s" % result) - - return result - - - def _collectApiInfo(self): - html = self.plugin.req.load("http://www.google.com/recaptcha/api.js") - a = re.search(r'po.src = \'(.*?)\';', html).group(1) - vers = a.split("/")[5] - - self.logDebug("API version: %s" %vers) - - language = a.split("__")[1].split(".")[0] - - self.logDebug("API language: %s" % language) - - html = self.plugin.req.load("https://apis.google.com/js/api.js") - b = re.search(r'"h":"(.*?)","', html).group(1) - jsh = b.decode('unicode-escape') - - self.logDebug("API jsh-string: %s" % jsh) - - return vers, language, jsh - - - def _prepareTimeAndRpc(self): - self.plugin.req.load("http://www.google.com/recaptcha/api2/demo") - - millis = int(round(time.time() * 1000)) - - self.logDebug("Time: %s" % millis) - - rand = randint(1, 99999999) - a = "0.%s" % str(rand * 2147483647) - rpc = int(100000000 * float(a)) - - self.logDebug("Rpc-token: %s" % rpc) - - return millis, rpc - - - def _challenge_v2(self, key, parent=None): - if parent is None: - try: - parent = urljoin("http://", urlparse(self.plugin.pyfile.url).netloc) - - except Exception: - parent = "" - - botguardstring = "!A" - vers, language, jsh = self._collectApiInfo() - millis, rpc = self._prepareTimeAndRpc() - - html = self.plugin.req.load("https://www.google.com/recaptcha/api2/anchor", - get={'k' : key, - 'hl' : language, - 'v' : vers, - 'usegapi' : "1", - 'jsh' : "%s#id=IO_%s" % (jsh, millis), - 'parent' : parent, - 'pfname' : "", - 'rpctoken': rpc}) - - token1 = re.search(r'id="recaptcha-token" value="(.*?)">', html) - self.logDebug("Token #1: %s" % token1.group(1)) - - html = self.plugin.req.load("https://www.google.com/recaptcha/api2/frame", - get={'c' : token1.group(1), - 'hl' : language, - 'v' : vers, - 'bg' : botguardstring, - 'k' : key, - 'usegapi': "1", - 'jsh' : jsh}).decode('unicode-escape') - - token2 = re.search(r'"finput","(.*?)",', html) - self.logDebug("Token #2: %s" % token2.group(1)) - - token3 = re.search(r'."asconf".\s,".*?".\s,"(.*?)".', html) - self.logDebug("Token #3: %s" % token3.group(1)) - - html = self.plugin.req.load("https://www.google.com/recaptcha/api2/reload", - post={'k' : key, - 'c' : token2.group(1), - 'reason': "fi", - 'fbg' : token3.group(1)}) - - token4 = re.search(r'"rresp","(.*?)",', html) - self.logDebug("Token #4: %s" % token4.group(1)) - - millis_captcha_loading = int(round(time.time() * 1000)) - captcha_response = self.plugin.decryptCaptcha("https://www.google.com/recaptcha/api2/payload", - get={'c':token4.group(1), 'k':key}, - cookies=True, - forceUser=True) - response = b64encode('{"response":"%s"}' % captcha_response) - - self.logDebug("Result: %s" % response) - - timeToSolve = int(round(time.time() * 1000)) - millis_captcha_loading - timeToSolveMore = timeToSolve + int(float("0." + str(randint(1, 99999999))) * 500) - - html = self.plugin.req.load("https://www.google.com/recaptcha/api2/userverify", - post={'k' : key, - 'c' : token4.group(1), - 'response': response, - 't' : timeToSolve, - 'ct' : timeToSolveMore, - 'bg' : botguardstring}) - - token5 = re.search(r'"uvresp","(.*?)",', html) - self.logDebug("Token #5: %s" % token5.group(1)) - - result = token5.group(1) - - return result, None - - - -class AdsCaptcha(CaptchaService): - __name__ = "AdsCaptcha" - __version__ = "0.08" - - __description__ = """AdsCaptcha captcha service plugin""" - __license__ = "GPLv3" - __authors__ = [("pyLoad Team", "admin@pyload.org")] - - - CAPTCHAID_PATTERN = r'api\.adscaptcha\.com/Get\.aspx\?[^"\']*CaptchaId=(\d+)' - PUBLICKEY_PATTERN = r'api\.adscaptcha\.com/Get\.aspx\?[^"\']*PublicKey=([\w-]+)' - - - def detect_key(self, html=None): - if not html: - if hasattr(self.plugin, "html") and self.plugin.html: - html = self.plugin.html - else: - errmsg = _("AdsCaptcha html not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - m = re.search(self.PUBLICKEY_PATTERN, html) - n = re.search(self.CAPTCHAID_PATTERN, html) - if m and n: - self.key = (m.group(1).strip(), n.group(1).strip()) #: key is the tuple(PublicKey, CaptchaId) - self.logDebug("Key|id: %s | %s" % self.key) - return self.key - else: - self.logDebug("Key or id not found") - return None - - - def challenge(self, key=None, html=None): - if not key: - if self.detect_key(html): - key = self.key - else: - errmsg = _("AdsCaptcha key not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - PublicKey, CaptchaId = key - - html = self.plugin.req.load("http://api.adscaptcha.com/Get.aspx", - get={'CaptchaId': CaptchaId, - 'PublicKey': PublicKey}) - try: - challenge = re.search("challenge: '(.+?)',", html).group(1) - server = re.search("server: '(.+?)',", html).group(1) - - except AttributeError: - errmsg = _("AdsCaptcha challenge pattern not found") - self.plugin.fail(errmsg) - raise AttributeError(errmsg) - - self.logDebug("Challenge: %s" % challenge) - - return self.result(server, challenge), challenge - - - def result(self, server, challenge): - result = self.plugin.decryptCaptcha("%sChallenge.aspx" % server, - get={'cid': challenge, 'dummy': random()}, - cookies=True, - imgtype="jpg") - - self.logDebug("Result: %s" % result) - - return result - - -class SolveMedia(CaptchaService): - __name__ = "SolveMedia" - __version__ = "0.12" - - __description__ = """SolveMedia captcha service plugin""" - __license__ = "GPLv3" - __authors__ = [("pyLoad Team", "admin@pyload.org")] - - - KEY_PATTERN = r'api\.solvemedia\.com/papi/challenge\.(?:no)?script\?k=(.+?)["\']' - - - def detect_key(self, html=None): - if not html: - if hasattr(self.plugin, "html") and self.plugin.html: - html = self.plugin.html - else: - errmsg = _("SolveMedia html not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - m = re.search(self.KEY_PATTERN, html) - if m: - self.key = m.group(1).strip() - self.logDebug("Key: %s" % self.key) - return self.key - else: - self.logDebug("Key not found") - return None - - - def challenge(self, key=None, html=None): - if not key: - if self.detect_key(html): - key = self.key - else: - errmsg = _("SolveMedia key not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - html = self.plugin.req.load("http://api.solvemedia.com/papi/challenge.noscript", - get={'k': key}) - try: - challenge = re.search(r'<input type=hidden name="adcopy_challenge" id="adcopy_challenge" value="([^"]+)">', - html).group(1) - server = "http://api.solvemedia.com/papi/media" - - except AttributeError: - errmsg = _("SolveMedia challenge pattern not found") - self.plugin.fail(errmsg) - raise AttributeError(errmsg) - - self.logDebug("Challenge: %s" % challenge) - - result = self.result(server, challenge) - - try: - magic = re.search(r'name="magic" value="(.+?)"', html).group(1) - - except AttributeError: - self.logDebug("Magic code not found") - - else: - if not self._verify(key, magic, result, challenge): - self.logDebug("Captcha code was invalid") - - return result, challenge - - - def _verify(self, key, magic, result, challenge, ref=None): #@TODO: Clean up - if ref is None: - try: - ref = self.plugin.pyfile.url - - except Exception: - ref = "" - - html = self.plugin.req.load("http://api.solvemedia.com/papi/verify.noscript", - post={'adcopy_response' : result, - 'k' : key, - 'l' : "en", - 't' : "img", - 's' : "standard", - 'magic' : magic, - 'adcopy_challenge' : challenge, - 'ref' : ref}) - try: - html = self.plugin.req.load(re.search(r'URL=(.+?)">', html).group(1)) - gibberish = re.search(r'id=gibberish>(.+?)</textarea>', html).group(1) - - except Exception: - return False - - else: - return True - - - def result(self, server, challenge): - result = self.plugin.decryptCaptcha(server, - get={'c': challenge}, - cookies=True, - imgtype="gif") - - self.logDebug("Result: %s" % result) - - return result - - -class AdYouLike(CaptchaService): - __name__ = "AdYouLike" - __version__ = "0.05" - - __description__ = """AdYouLike captcha service plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - AYL_PATTERN = r'Adyoulike\.create\s*\((.+?)\)' - CALLBACK_PATTERN = r'(Adyoulike\.g\._jsonp_\d+)' - - - def detect_key(self, html=None): - if not html: - if hasattr(self.plugin, "html") and self.plugin.html: - html = self.plugin.html - else: - errmsg = _("AdYouLike html not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - m = re.search(self.AYL_PATTERN, html) - n = re.search(self.CALLBACK_PATTERN, html) - if m and n: - self.key = (m.group(1).strip(), n.group(1).strip()) - self.logDebug("Ayl|callback: %s | %s" % self.key) - return self.key #: key is the tuple(ayl, callback) - else: - self.logDebug("Ayl or callback not found") - return None - - - def challenge(self, key=None, html=None): - if not key: - if self.detect_key(html): - key = self.key - else: - errmsg = _("AdYouLike key not found") - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - ayl, callback = key - - # {"adyoulike":{"key":"P~zQ~O0zV0WTiAzC-iw0navWQpCLoYEP"}, - # "all":{"element_id":"ayl_private_cap_92300","lang":"fr","env":"prod"}} - ayl = json_loads(ayl) - - html = self.plugin.req.load("http://api-ayl.appspot.com/challenge", - get={'key' : ayl['adyoulike']['key'], - 'env' : ayl['all']['env'], - 'callback': callback}) - try: - challenge = json_loads(re.search(callback + r'\s*\((.+?)\)', html).group(1)) - - except AttributeError: - errmsg = _("AdYouLike challenge pattern not found") - self.plugin.fail(errmsg) - raise AttributeError(errmsg) - - self.logDebug("Challenge: %s" % challenge) - - return self.result(ayl, challenge), challenge - - - def result(self, server, challenge): - # Adyoulike.g._jsonp_5579316662423138 - # ({"translations":{"fr":{"instructions_visual":"Recopiez « Soonnight » ci-dessous :"}}, - # "site_under":true,"clickable":true,"pixels":{"VIDEO_050":[],"DISPLAY":[],"VIDEO_000":[],"VIDEO_100":[], - # "VIDEO_025":[],"VIDEO_075":[]},"medium_type":"image/adyoulike", - # "iframes":{"big":"<iframe src=\"http://www.soonnight.com/campagn.html\" scrolling=\"no\" - # height=\"250\" width=\"300\" frameborder=\"0\"></iframe>"},"shares":{},"id":256, - # "token":"e6QuI4aRSnbIZJg02IsV6cp4JQ9~MjA1","formats":{"small":{"y":300,"x":0,"w":300,"h":60}, - # "big":{"y":0,"x":0,"w":300,"h":250},"hover":{"y":440,"x":0,"w":300,"h":60}}, - # "tid":"SqwuAdxT1EZoi4B5q0T63LN2AkiCJBg5"}) - - if isinstance(server, basestring): - server = json_loads(server) - - if isinstance(challenge, basestring): - challenge = json_loads(challenge) - - try: - instructions_visual = challenge['translations'][server['all']['lang']]['instructions_visual'] - result = re.search(u'«(.+?)»', instructions_visual).group(1).strip() - - except AttributeError: - errmsg = _("AdYouLike result not found") - self.plugin.fail(errmsg) - raise AttributeError(errmsg) - - result = {'_ayl_captcha_engine' : "adyoulike", - '_ayl_env' : server['all']['env'], - '_ayl_tid' : challenge['tid'], - '_ayl_token_challenge': challenge['token'], - '_ayl_response' : response} - - self.logDebug("Result: %s" % result) - - return result diff --git a/module/plugins/internal/DeadCrypter.py b/module/plugins/internal/DeadCrypter.py deleted file mode 100644 index ce56947fc..000000000 --- a/module/plugins/internal/DeadCrypter.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.Crypter import Crypter as _Crypter -from pyload.plugin.internal.SimpleCrypter import create_getInfo - - -class DeadCrypter(_Crypter): - __name__ = "DeadCrypter" - __type__ = "crypter" - __version__ = "0.04" - - __pattern__ = r'^unmatchable$' - - __description__ = """Crypter is no longer available""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - @classmethod - def apiInfo(cls, url="", get={}, post={}): - api = super(DeadCrypter, self).apiInfo(url, get, post) - api['status'] = 1 - return api - - - def setup(self): - self.pyfile.error = "Crypter is no longer available" - self.offline() #@TODO: self.offline("Crypter is no longer available") - - -getInfo = create_getInfo(DeadCrypter) diff --git a/module/plugins/internal/DeadHoster.py b/module/plugins/internal/DeadHoster.py deleted file mode 100644 index 132e4741a..000000000 --- a/module/plugins/internal/DeadHoster.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- - -from pyload.plugin.Hoster import Hoster as _Hoster -from pyload.plugin.internal.SimpleHoster import create_getInfo - - -class DeadHoster(_Hoster): - __name__ = "DeadHoster" - __type__ = "hoster" - __version__ = "0.14" - - __pattern__ = r'^unmatchable$' - - __description__ = """Hoster is no longer available""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - - - @classmethod - def apiInfo(cls, url="", get={}, post={}): - api = super(DeadHoster, self).apiInfo(url, get, post) - api['status'] = 1 - return api - - - def setup(self): - self.pyfile.error = "Hoster is no longer available" - self.offline() #@TODO: self.offline("Hoster is no longer available") - - -getInfo = create_getInfo(DeadHoster) diff --git a/module/plugins/internal/Extractor.py b/module/plugins/internal/Extractor.py deleted file mode 100644 index b445f1497..000000000 --- a/module/plugins/internal/Extractor.py +++ /dev/null @@ -1,139 +0,0 @@ -# -*- coding: utf-8 -*- - -import os - -from module.PyFile import PyFile - - -class ArchiveError(Exception): - pass - - -class CRCError(Exception): - pass - - -class PasswordError(Exception): - pass - - -class Extractor: - __name__ = "Extractor" - __version__ = "0.20" - - __description__ = """Base extractor plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "ranan@pyload.org"), - ("Walter Purcaro", "vuolter@gmail.com"), - ("Immenz", "immenz@gmx.net")] - - - EXTENSIONS = [] - VERSION = "" - - - @classmethod - def isArchive(cls, filename): - name = os.path.basename(filename).lower() - return any(name.endswith(ext) for ext in cls.EXTENSIONS) and not cls.isMultipart(filename) - - - @classmethod - def isMultipart(cls,filename): - return False - - - @classmethod - def isUsable(cls): - """ Check if system statisfy dependencies - :return: boolean - """ - return None - - - @classmethod - def getTargets(cls, files_ids): - """ Filter suited targets from list of filename id tuple list - :param files_ids: List of filepathes - :return: List of targets, id tuple list - """ - return [(fname, id, fout) for fname, id, fout in files_ids if cls.isArchive(fname)] - - - def __init__(self, manager, filename, out, - fullpath=True, - overwrite=False, - excludefiles=[], - renice=0, - delete=False, - keepbroken=False, - fid=None): - """ Initialize extractor for specific file """ - self.manager = manager - self.filename = filename - self.out = out - self.fullpath = fullpath - self.overwrite = overwrite - self.excludefiles = excludefiles - self.renice = renice - self.delete = delete - self.keepbroken = keepbroken - self.files = [] #: Store extracted files here - - pyfile = self.manager.core.files.getFile(fid) if fid else None - self.notifyProgress = lambda x: pyfile.setProgress(x) if pyfile else lambda x: None - - - def init(self): - """ Initialize additional data structures """ - pass - - - def check(self): - """Check if password if needed. Raise ArchiveError if integrity is - questionable. - - :return: boolean - :raises ArchiveError - """ - raise PasswordError - - - def isPassword(self, password): - """ Check if the given password is/might be correct. - If it can not be decided at this point return true. - - :param password: - :return: boolean - """ - return None - - - def repair(self): - return None - - - def extract(self, password=None): - """Extract the archive. Raise specific errors in case of failure. - - :param progress: Progress function, call this to update status - :param password password to use - :raises PasswordError - :raises CRCError - :raises ArchiveError - :return: - """ - raise NotImplementedError - - - def getDeleteFiles(self): - """Return list of files to delete, do *not* delete them here. - - :return: List with paths of files to delete - """ - return [self.filename] - - - def list(self, password=None): - """Populate self.files at some point while extracting""" - return self.files diff --git a/module/plugins/internal/MultiHook.py b/module/plugins/internal/MultiHook.py deleted file mode 100644 index 652443098..000000000 --- a/module/plugins/internal/MultiHook.py +++ /dev/null @@ -1,308 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from time import sleep - -from module.plugins.Hook import Hook -from module.utils import decode, remove_chars - - -class MultiHook(Hook): - __name__ = "MultiHook" - __type__ = "hook" - __version__ = "0.37" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Hook plugin for multi hoster/crypter""" - __license__ = "GPLv3" - __authors__ = [("pyLoad Team", "admin@pyload.org"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - MIN_INTERVAL = 1 * 60 * 60 - - DOMAIN_REPLACEMENTS = [(r'180upload\.com' , "hundredeightyupload.com"), - (r'1fichier\.com' , "onefichier.com" ), - (r'2shared\.com' , "twoshared.com" ), - (r'4shared\.com' , "fourshared.com" ), - (r'bayfiles\.net' , "bayfiles.com" ), - (r'cloudnator\.com' , "shragle.com" ), - (r'dfiles\.eu' , "depositfiles.com" ), - (r'easy-share\.com' , "crocko.com" ), - (r'freakshare\.net' , "freakshare.com" ), - (r'hellshare\.com' , "hellshare.cz" ), - (r'ifile\.it' , "filecloud.io" ), - (r'nowdownload\.\w+', "nowdownload.sx" ), - (r'nowvideo\.\w+' , "nowvideo.sx" ), - (r'putlocker\.com' , "firedrive.com" ), - (r'share-?rapid\.cz', "multishare.cz" ), - (r'ul\.to' , "uploaded.to" ), - (r'uploaded\.net' , "uploaded.to" ), - (r'uploadhero\.co' , "uploadhero.com" ), - (r'zshares\.net' , "zshare.net" ), - (r'(\d+.+)' , "X\1" )] - - - def setup(self): - self.plugins = [] - self.supported = [] - self.new_supported = [] - - self.account = None - self.pluginclass = None - self.pluginmodule = None - self.pluginname = None - self.plugintype = None - - self._initPlugin() - - - def _initPlugin(self): - plugin, type = self.core.pluginManager.findPlugin(self.__name__) - - if not plugin: - self.logWarning("Hook plugin will be deactivated due missing plugin reference") - self.setConfig('activated', False) - else: - self.pluginname = self.__name__ - self.plugintype = type - self.pluginmodule = self.core.pluginManager.loadModule(type, self.__name__) - self.pluginclass = getattr(self.pluginmodule, self.__name__) - - - def _loadAccount(self): - self.account = self.core.accountManager.getAccountPlugin(self.pluginname) - - if self.account and not self.account.canUse(): - self.account = None - - if not self.account and hasattr(self.pluginclass, "LOGIN_ACCOUNT") and self.pluginclass.LOGIN_ACCOUNT: - self.logWarning("Hook plugin will be deactivated due missing account reference") - self.setConfig('activated', False) - - - def coreReady(self): - self._loadAccount() - - - def getURL(self, *args, **kwargs): #@TODO: Remove in 0.4.10 - """ see HTTPRequest for argument list """ - h = pyreq.getHTTPRequest(timeout=120) - try: - if not 'decode' in kwargs: - kwargs['decode'] = True - rep = h.load(*args, **kwargs) - finally: - h.close() - - return rep - - - def getConfig(self, option, default=''): - """getConfig with default value - sublass may not implements all config options""" - try: - return self.getConf(option) - - except KeyError: - return default - - - def pluginsCached(self): - if self.plugins: - return self.plugins - - for _i in xrange(3): - try: - pluginset = self._pluginSet(self.getHosters() if self.plugintype == "hoster" else self.getCrypters()) - - except Exception, e: - self.logError(e, "Waiting 1 minute and retry") - sleep(60) - - else: - break - else: - return list() - - try: - configmode = self.getConfig("pluginmode", 'all') - if configmode in ("listed", "unlisted"): - pluginlist = self.getConfig("pluginlist", '').replace('|', ',').replace(';', ',').split(',') - configset = self._pluginSet(pluginlist) - - if configmode == "listed": - pluginset &= configset - else: - pluginset -= configset - - except Exception, e: - self.logError(e) - - self.plugins = list(pluginset) - - return self.plugins - - - def _pluginSet(self, plugins): - plugins = set((decode(x).strip().lower() for x in plugins if '.' in x)) - - for rf, rt in self.DOMAIN_REPLACEMENTS: - regex = re.compile(rf) - for p in filter(lambda x: regex.match(x), plugins): - plugins.remove(p) - plugins.add(re.sub(rf, rt, p)) - - plugins.discard('') - - return plugins - - - def getHosters(self): - """Load list of supported hoster - - :return: List of domain names - """ - raise NotImplementedError - - - def getCrypters(self): - """Load list of supported crypters - - :return: List of domain names - """ - raise NotImplementedError - - - def periodical(self): - """reload plugin list periodically""" - self.logInfo(_("Reloading supported %s list") % self.plugintype) - - old_supported = self.supported - - self.supported = [] - self.new_supported = [] - self.plugins = [] - - self.overridePlugins() - - old_supported = [plugin for plugin in old_supported if plugin not in self.supported] - - if old_supported: - self.logDebug("Unload: %s" % ", ".join(old_supported)) - for plugin in old_supported: - self.unloadPlugin(plugin) - - if self.getConfig("reload", True): - self.interval = max(self.getConfig("reloadinterval", 12) * 60 * 60, self.MIN_INTERVAL) - else: - self.core.scheduler.removeJob(self.cb) - self.cb = None - - - def overridePlugins(self): - excludedList = [] - - if self.plugintype == "hoster": - pluginMap = dict((name.lower(), name) for name in self.core.pluginManager.hosterPlugins.iterkeys()) - accountList = [account.type.lower() for account in self.core.api.getAccounts(False) if account.valid and account.premium] - else: - pluginMap = {} - accountList = [name[::-1].replace("Folder"[::-1], "", 1).lower()[::-1] for name in self.core.pluginManager.crypterPlugins.iterkeys()] - - for plugin in self.pluginsCached(): - name = remove_chars(plugin, "-.") - - if name in accountList: - excludedList.append(plugin) - else: - if name in pluginMap: - self.supported.append(pluginMap[name]) - else: - self.new_supported.append(plugin) - - if not self.supported and not self.new_supported: - self.logError(_("No %s loaded") % self.plugintype) - return - - # inject plugin plugin - self.logDebug("Overwritten %ss: %s" % (self.plugintype, ", ".join(sorted(self.supported)))) - - for plugin in self.supported: - hdict = self.core.pluginManager.plugins[self.plugintype][plugin] - hdict['new_module'] = self.pluginmodule - hdict['new_name'] = self.pluginname - - if excludedList: - self.logInfo(_("%ss not overwritten: %s") % (self.plugintype.capitalize(), ", ".join(sorted(excludedList)))) - - if self.new_supported: - plugins = sorted(self.new_supported) - - self.logDebug("New %ss: %s" % (self.plugintype, ", ".join(plugins))) - - # create new regexp - regexp = r'.*(?P<DOMAIN>%s).*' % "|".join([x.replace(".", "\.") for x in plugins]) - if hasattr(self.pluginclass, "__pattern__") and isinstance(self.pluginclass.__pattern__, basestring) and '://' in self.pluginclass.__pattern__: - regexp = r'%s|%s' % (self.pluginclass.__pattern__, regexp) - - self.logDebug("Regexp: %s" % regexp) - - hdict = self.core.pluginManager.plugins[self.plugintype][self.pluginname] - hdict['pattern'] = regexp - hdict['re'] = re.compile(regexp) - - - def unloadPlugin(self, plugin): - hdict = self.core.pluginManager.plugins[self.plugintype][plugin] - if "module" in hdict: - del hdict['module'] - - if "new_module" in hdict: - del hdict['new_module'] - del hdict['new_name'] - - - def unload(self): - """Remove override for all plugins. Scheduler job is removed by hookmanager""" - for plugin in self.supported: - self.unloadPlugin(plugin) - - # reset pattern - hdict = self.core.pluginManager.plugins[self.plugintype][self.pluginname] - - hdict['pattern'] = getattr(self.pluginclass, "__pattern__", r'^unmatchable$') - hdict['re'] = re.compile(hdict['pattern']) - - - def downloadFailed(self, pyfile): - """remove plugin override if download fails but not if file is offline/temp.offline""" - if pyfile.status != 8 or not self.getConfig("revertfailed", True): - return - - hdict = self.core.pluginManager.plugins[self.plugintype][pyfile.pluginname] - if "new_name" in hdict and hdict['new_name'] == self.pluginname: - if pyfile.error == "MultiHook": - self.logDebug("Unload MultiHook", pyfile.pluginname, hdict) - self.unloadPlugin(pyfile.pluginname) - pyfile.setStatus("queued") - pyfile.sync() - else: - retries = max(self.getConfig("retry", 10), 0) - wait_time = max(self.getConfig("retryinterval", 1), 0) - - if 0 < retries > pyfile.plugin.retries: - self.logInfo(_("Retrying: %s") % pyfile.name) - pyfile.setCustomStatus("MultiHook", "queued") - pyfile.sync() - - pyfile.plugin.retries += 1 - pyfile.plugin.setWait(wait_time) - pyfile.plugin.wait() diff --git a/module/plugins/internal/MultiHoster.py b/module/plugins/internal/MultiHoster.py deleted file mode 100644 index 63b7d76b1..000000000 --- a/module/plugins/internal/MultiHoster.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, replace_patterns, set_cookies - - -class MultiHoster(SimpleHoster): - __name__ = "MultiHoster" - __type__ = "hoster" - __version__ = "0.37" - - __pattern__ = r'^unmatchable$' - - __description__ = """Multi hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - LOGIN_ACCOUNT = True - - - def setup(self): - self.chunkLimit = 1 - self.multiDL = bool(self.account) - self.resumeDownload = self.premium - - - def prepare(self): - self.info = {} - self.html = "" - self.link = "" #@TODO: Move to hoster class in 0.4.10 - self.directDL = False #@TODO: Move to hoster class in 0.4.10 - - if self.LOGIN_ACCOUNT and not self.account: - self.fail(_("Required account not found")) - - self.req.setOption("timeout", 120) - - if isinstance(self.COOKIES, list): - set_cookies(self.req.cj, self.COOKIES) - - if self.DIRECT_LINK is None: - self.directDL = self.__pattern__ != r'^unmatchable$' and re.match(self.__pattern__, self.pyfile.url) - else: - self.directDL = self.DIRECT_LINK - - self.pyfile.url = replace_patterns(self.pyfile.url, self.URL_REPLACEMENTS) - - - def process(self, pyfile): - self.prepare() - - if self.directDL: - self.checkInfo() - self.logDebug("Looking for direct download link...") - self.handleDirect(pyfile) - - if not self.link and not self.lastDownload: - self.preload() - - self.checkErrors() - self.checkStatus(getinfo=False) - - if self.premium and (not self.CHECK_TRAFFIC or self.checkTrafficLeft()): - self.logDebug("Handled as premium download") - self.handlePremium(pyfile) - - elif not self.LOGIN_ACCOUNT or (not self.CHECK_TRAFFIC or self.checkTrafficLeft()): - self.logDebug("Handled as free download") - self.handleFree(pyfile) - - self.downloadLink(self.link, True) - self.checkFile() - - - def handlePremium(self, pyfile): - return self.handleFree(pyfile) - - - def handleFree(self, pyfile): - if self.premium: - raise NotImplementedError - else: - self.fail(_("Required premium account not found")) diff --git a/module/plugins/internal/SevenZip.py b/module/plugins/internal/SevenZip.py deleted file mode 100644 index 7ad6b0d7a..000000000 --- a/module/plugins/internal/SevenZip.py +++ /dev/null @@ -1,155 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import re - -from subprocess import Popen, PIPE - -from module.plugins.internal.UnRar import ArchiveError, CRCError, PasswordError, UnRar, renice -from module.utils import fs_encode, save_join - - -class SevenZip(UnRar): - __name__ = "SevenZip" - __version__ = "0.08" - - __description__ = """7-Zip extractor plugin""" - __license__ = "GPLv3" - __authors__ = [("Michael Nowak", ""), - ("Walter Purcaro", "vuolter@gmail.com")] - - - CMD = "7z" - VERSION = "" - - EXTENSIONS = [".7z", ".xz", ".zip", ".gz", ".gzip", ".tgz", ".bz2", ".bzip2", - ".tbz2", ".tbz", ".tar", ".wim", ".swm", ".lzma", ".rar", ".cab", - ".arj", ".z", ".taz", ".cpio", ".rpm", ".deb", ".lzh", ".lha", - ".chm", ".chw", ".hxs", ".iso", ".msi", ".doc", ".xls", ".ppt", - ".dmg", ".xar", ".hfs", ".exe", ".ntfs", ".fat", ".vhd", ".mbr", - ".squashfs", ".cramfs", ".scap"] - - - #@NOTE: there are some more uncovered 7z formats - re_filelist = re.compile(r'([\d\:]+)\s+([\d\:]+)\s+([\w\.]+)\s+(\d+)\s+(\d+)\s+(.+)') - re_wrongpwd = re.compile(r'(Can not open encrypted archive|Wrong password)', re.I) - re_wrongcrc = re.compile(r'Encrypted\s+\=\s+\+', re.I) - re_version = re.compile(r'7-Zip\s(?:\[64\]\s)?(\d+\.\d+)', re.I) - - - @classmethod - def isUsable(cls): - if os.name == "nt": - cls.CMD = os.path.join(pypath, "7z.exe") - p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE) - out,err = p.communicate() - else: - p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE) - out, err = p.communicate() - - cls.VERSION = cls.re_version.search(out).group(1) - - return True - - - def check(self): - file = fs_encode(self.filename) - - p = self.call_cmd("t", file) - out, err = p.communicate() - - if p.returncode > 1: - raise CRCError(err) - - p = self.call_cmd("l", "-slt", file) - out, err = p.communicate() - - if p.returncode > 1: - raise ArchiveError(_("Process return code: %d") % p.returncode) - - # check if output or error macthes the 'wrong password'-Regexp - if self.re_wrongpwd.search(out): - raise PasswordError - - # check if output matches 'Encrypted = +' - if self.re_wrongcrc.search(out): - raise CRCError(_("Header protected")) - - - def isPassword(self, password): - p = self.call_cmd("l", fs_encode(self.filename), password=password) - p.communicate() - return p.returncode == 0 - - - def repair(self): - return False - - - def extract(self, password=None): - command = "x" if self.fullpath else "e" - - p = self.call_cmd(command, '-o' + self.out, fs_encode(self.filename), password=password) - - renice(p.pid, self.renice) - - # communicate and retrieve stderr - self._progress(p) - err = p.stderr.read().strip() - - if err: - if self.re_wrongpwd.search(err): - raise PasswordError - - elif self.re_wrongcrc.search(err): - raise CRCError(err) - - else: #: raise error if anything is on stderr - raise ArchiveError(err) - - if p.returncode > 1: - raise ArchiveError(_("Process return code: %d") % p.returncode) - - self.files = self.list(password) - - - def list(self, password=None): - command = "l" if self.fullpath else "l" - - p = self.call_cmd(command, fs_encode(self.filename), password=password) - out, err = p.communicate() - - if "Can not open" in err: - raise ArchiveError(_("Cannot open file")) - - if p.returncode > 1: - raise ArchiveError(_("Process return code: %d") % p.returncode) - - result = set() - for groups in self.re_filelist.findall(out): - f = groups[-1].strip() - result.add(save_join(self.out, f)) - - return list(result) - - - def call_cmd(self, command, *xargs, **kwargs): - args = [] - - #overwrite flag - if self.overwrite: - args.append("-y") - - #set a password - if "password" in kwargs and kwargs["password"]: - args.append("-p'%s'" % kwargs["password"]) - else: - args.append("-p-") - - #@NOTE: return codes are not reliable, some kind of threading, cleanup whatever issue - call = [self.CMD, command] + args + list(xargs) - - self.manager.logDebug(" ".join(call)) - - p = Popen(call, stdout=PIPE, stderr=PIPE) - return p diff --git a/module/plugins/internal/SimpleCrypter.py b/module/plugins/internal/SimpleCrypter.py deleted file mode 100644 index dc34f864f..000000000 --- a/module/plugins/internal/SimpleCrypter.py +++ /dev/null @@ -1,157 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urlparse import urljoin, urlparse - -from pyload.plugin.Crypter import Crypter -from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo, replace_patterns, set_cookies -from pyload.utils import fixup - - -class SimpleCrypter(Crypter, SimpleHoster): - __name__ = "SimpleCrypter" - __type__ = "crypter" - __version__ = "0.43" - - __pattern__ = r'^unmatchable$' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), #: Overrides core.config['general']['folder_per_package'] - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Simple decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it"), - ("zoidberg", "zoidberg@mujmail.cz"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - """ - Following patterns should be defined by each crypter: - - LINK_PATTERN: Download link or regex to catch links in group(1) - example: LINK_PATTERN = r'<div class="link"><a href="(.+?)"' - - NAME_PATTERN: (optional) folder name or page title - example: NAME_PATTERN = r'<title>Files of: (?P<N>[^<]+) folder</title>' - - OFFLINE_PATTERN: (optional) Checks if the page is unreachable - example: OFFLINE_PATTERN = r'File (deleted|not found)' - - TEMP_OFFLINE_PATTERN: (optional) Checks if the page is temporarily unreachable - example: TEMP_OFFLINE_PATTERN = r'Server maintainance' - - - You can override the getLinks method if you need a more sophisticated way to extract the links. - - - If the links are splitted on multiple pages you can define the PAGES_PATTERN regex: - - PAGES_PATTERN: (optional) group(1) should be the number of overall pages containing the links - example: PAGES_PATTERN = r'Pages: (\d+)' - - and its loadPage method: - - - def loadPage(self, page_n): - return the html of the page number page_n - """ - - LINK_PATTERN = None - - NAME_REPLACEMENTS = [("&#?\w+;", fixup)] - URL_REPLACEMENTS = [] - - TEXT_ENCODING = False #: Set to True or encoding name if encoding in http header is not correct - COOKIES = True #: or False or list of tuples [(domain, name, value)] - - LOGIN_ACCOUNT = False - LOGIN_PREMIUM = False - - - def prepare(self): - self.pyfile.error = "" #@TODO: Remove in 0.4.10 - - self.info = {} - self.html = "" - self.links = [] #@TODO: Move to hoster class in 0.4.10 - - if self.LOGIN_PREMIUM and not self.premium: - self.fail(_("Required premium account not found")) - - if self.LOGIN_ACCOUNT and not self.account: - self.fail(_("Required account not found")) - - self.req.setOption("timeout", 120) - - if isinstance(self.COOKIES, list): - set_cookies(self.req.cj, self.COOKIES) - - self.pyfile.url = replace_patterns(self.pyfile.url, self.URL_REPLACEMENTS) - - - def decrypt(self, pyfile): - self.prepare() - - self.preload() - self.checkInfo() - - self.links = self.getLinks() - - if hasattr(self, 'PAGES_PATTERN') and hasattr(self, 'loadPage'): - self.handlePages(pyfile) - - self.logDebug("Package has %d links" % len(self.links)) - - if self.links: - self.packages = [(self.info['name'], self.links, self.info['folder'])] - - elif not self.urls and not self.packages: #@TODO: Remove in 0.4.10 - self.fail(_("No link grabbed")) - - - def checkNameSize(self, getinfo=True): - if not self.info or getinfo: - self.logDebug("File info (BEFORE): %s" % self.info) - self.info.update(self.getInfo(self.pyfile.url, self.html)) - self.logDebug("File info (AFTER): %s" % self.info) - - try: - url = self.info['url'].strip() - name = self.info['name'].strip() - if name and name != url: - self.pyfile.name = name - - except Exception: - pass - - try: - folder = self.info['folder'] = self.pyfile.name - - except Exception: - pass - - self.logDebug("File name: %s" % self.pyfile.name, - "File folder: %s" % self.pyfile.name) - - - def getLinks(self): - """ - Returns the links extracted from self.html - You should override this only if it's impossible to extract links using only the LINK_PATTERN. - """ - url_p = urlparse(self.pyfile.url) - baseurl = "%s://%s" % (url_p.scheme, url_p.netloc) - - return [urljoin(baseurl, link) if not urlparse(link).scheme else link \ - for link in re.findall(self.LINK_PATTERN, self.html)] - - - def handlePages(self, pyfile): - try: - pages = int(re.search(self.PAGES_PATTERN, self.html).group(1)) - except Exception: - pages = 1 - - for p in xrange(2, pages + 1): - self.html = self.loadPage(p) - self.links += self.getLinks() diff --git a/module/plugins/internal/SimpleDereferer.py b/module/plugins/internal/SimpleDereferer.py deleted file mode 100644 index bd00f5d25..000000000 --- a/module/plugins/internal/SimpleDereferer.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from urllib import unquote - -from module.plugins.Crypter import Crypter -from module.plugins.internal.SimpleHoster import fileUrl, set_cookies - - -class SimpleDereferer(Crypter): - __name__ = "SimpleDereferer" - __type__ = "crypter" - __version__ = "0.07" - - __pattern__ = r'^unmatchable$' - __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), - ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] - - __description__ = """Simple dereferer plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - """ - Following patterns should be defined by each crypter: - - LINK_PATTERN: Regex to catch the redirect url in group(1) - example: LINK_PATTERN = r'<div class="link"><a href="(.+?)"' - - OFFLINE_PATTERN: (optional) Checks if the page is unreachable - example: OFFLINE_PATTERN = r'File (deleted|not found)' - - TEMP_OFFLINE_PATTERN: (optional) Checks if the page is temporarily unreachable - example: TEMP_OFFLINE_PATTERN = r'Server maintainance' - - - You can override the getLinks method if you need a more sophisticated way to extract the redirect url. - """ - - LINK_PATTERN = None - - TEXT_ENCODING = False - COOKIES = True - - - def decrypt(self, pyfile): - link = fileUrl(self, pyfile.url) - - if not link: - try: - link = unquote(re.match(self.__pattern__, pyfile.url).group('LINK')) - - except Exception: - self.prepare() - self.preload() - self.checkStatus() - - link = self.getLink() - - if link.strip(): - self.urls = [link.strip()] #@TODO: Remove `.strip()` in 0.4.10 - - elif not self.urls and not self.packages: #@TODO: Remove in 0.4.10 - self.fail(_("No link grabbed")) - - - def prepare(self): - self.info = {} - self.html = "" - - self.req.setOption("timeout", 120) - - if isinstance(self.COOKIES, list): - set_cookies(self.req.cj, self.COOKIES) - - - def preload(self): - self.html = self.load(self.pyfile.url, cookies=bool(self.COOKIES), decode=not self.TEXT_ENCODING) - - if isinstance(self.TEXT_ENCODING, basestring): - self.html = unicode(self.html, self.TEXT_ENCODING) - - - def checkStatus(self): - if hasattr(self, "OFFLINE_PATTERN") and re.search(self.OFFLINE_PATTERN, self.html): - self.offline() - - elif hasattr(self, "TEMP_OFFLINE_PATTERN") and re.search(self.TEMP_OFFLINE_PATTERN, self.html): - self.tempOffline() - - - def getLink(self): - try: - return re.search(self.LINK_PATTERN, self.html).group(1) - - except Exception: - pass diff --git a/module/plugins/internal/SimpleHoster.py b/module/plugins/internal/SimpleHoster.py deleted file mode 100644 index e4ff1a2d8..000000000 --- a/module/plugins/internal/SimpleHoster.py +++ /dev/null @@ -1,701 +0,0 @@ -# -*- coding: utf-8 -*- - -import mimetypes -import os -import re - -from datetime import datetime, timedelta -from inspect import isclass -from time import time -from urllib import unquote -from urlparse import urljoin, urlparse - -from module.PyFile import statusMap as _statusMap -from module.network.CookieJar import CookieJar -from module.network.HTTPRequest import BadHeader -from module.network.RequestFactory import getURL -from module.plugins.Hoster import Hoster -from module.plugins.Plugin import Fail -from module.utils import fixup, fs_encode, parseFileSize - - -#@TODO: Adapt and move to PyFile in 0.4.10 -statusMap = dict((v, k) for k, v in _statusMap.iteritems()) - - -#@TODO: Remove in 0.4.10 and redirect to self.error instead -def _error(self, reason, type): - if not reason and not type: - type = "unknown" - - msg = _("%s error") % type.strip().capitalize() if type else _("Error") - msg += ": %s" % reason.strip() if reason else "" - msg += _(" | Plugin may be out of date") - - raise Fail(msg) - - -#@TODO: Remove in 0.4.10 -def _wait(self, seconds, reconnect): - if seconds: - self.setWait(int(seconds) + 1) - - if reconnect is not None: - self.wantReconnect = reconnect - - super(SimpleHoster, self).wait() - - -def replace_patterns(string, ruleslist): - for r in ruleslist: - rf, rt = r - string = re.sub(rf, rt, string) - return string - - -def set_cookies(cj, cookies): - for cookie in cookies: - if isinstance(cookie, tuple) and len(cookie) == 3: - domain, name, value = cookie - cj.setCookie(domain, name, value) - - -def parseHtmlTagAttrValue(attr_name, tag): - m = re.search(r"%s\s*=\s*([\"']?)((?<=\")[^\"]+|(?<=')[^']+|[^>\s\"'][^>\s]*)\1" % attr_name, tag, re.I) - return m.group(2) if m else None - - -def parseHtmlForm(attr_str, html, input_names={}): - for form in re.finditer(r"(?P<TAG><form[^>]*%s[^>]*>)(?P<CONTENT>.*?)</?(form|body|html)[^>]*>" % attr_str, - html, re.S | re.I): - inputs = {} - action = parseHtmlTagAttrValue("action", form.group('TAG')) - - for inputtag in re.finditer(r'(<(input|textarea)[^>]*>)([^<]*(?=</\2)|)', form.group('CONTENT'), re.S | re.I): - name = parseHtmlTagAttrValue("name", inputtag.group(1)) - if name: - value = parseHtmlTagAttrValue("value", inputtag.group(1)) - if not value: - inputs[name] = inputtag.group(3) or '' - else: - inputs[name] = value - - if input_names: - # check input attributes - for key, val in input_names.iteritems(): - if key in inputs: - if isinstance(val, basestring) and inputs[key] == val: - continue - elif isinstance(val, tuple) and inputs[key] in val: - continue - elif hasattr(val, "search") and re.match(val, inputs[key]): - continue - break #: attibute value does not match - else: - break #: attibute name does not match - else: - return action, inputs #: passed attribute check - else: - # no attribute check - return action, inputs - - return {}, None #: no matching form found - - -#: Deprecated -def parseFileInfo(plugin, url="", html=""): - if hasattr(plugin, "getInfo"): - info = plugin.getInfo(url, html) - res = info['name'], info['size'], info['status'], info['url'] - else: - url = unquote(url) - url_p = urlparse(url) - res = ((url_p.path.split('/')[-1] - or url_p.query.split('=', 1)[::-1][0].split('&', 1)[0] - or url_p.netloc.split('.', 1)[0]), - 0, - 3 if url else 8, - url) - - return res - - -#@TODO: Remove in 0.4.10 -#@NOTE: Every plugin must have own parseInfos classmethod to work with 0.4.10 -def create_getInfo(plugin): - - def generator(list): - for x in list: - yield x - - if hasattr(plugin, "parseInfos"): - fn = lambda urls: generator((info['name'], info['size'], info['status'], info['url']) for info in plugin.parseInfos(urls)) - else: - fn = lambda urls: generator(parseFileInfo(url) for url in urls) - - return fn - - -def timestamp(): - return int(time() * 1000) - - -#@TODO: Move to hoster class in 0.4.10 -def fileUrl(self, url, follow_location=None): - link = "" - redirect = 1 - - if type(follow_location) is int: - redirect = max(follow_location, 1) - else: - redirect = 5 - - for i in xrange(redirect): - try: - self.logDebug("Redirect #%d to: %s" % (i, url)) - header = self.load(url, ref=True, cookies=True, just_header=True, decode=True) - - except Exception: #: Bad bad bad... - req = pyreq.getHTTPRequest() - res = req.load(url, cookies=True, just_header=True, decode=True) - - req.close() - - header = {"code": req.code} - for line in res.splitlines(): - line = line.strip() - if not line or ":" not in line: - continue - - key, none, value = line.partition(":") - key = key.lower().strip() - value = value.strip() - - if key in header: - if type(header[key]) == list: - header[key].append(value) - else: - header[key] = [header[key], value] - else: - header[key] = value - - if 'content-disposition' in header: - link = url - - elif 'location' in header and header['location'].strip(): - location = header['location'] - - if not urlparse(location).scheme: - url_p = urlparse(url) - baseurl = "%s://%s" % (url_p.scheme, url_p.netloc) - location = urljoin(baseurl, location) - - if 'code' in header and header['code'] == 302: - link = location - - if follow_location: - url = location - continue - - else: - extension = os.path.splitext(urlparse(url).path.split('/')[-1])[-1] - - if 'content-type' in header and header['content-type'].strip(): - mimetype = header['content-type'].split(';')[0].strip() - - elif extension: - mimetype = mimetypes.guess_type(extension, False)[0] or "application/octet-stream" - - else: - mimetype = "" - - if mimetype and (link or 'html' not in mimetype): - link = url - else: - link = "" - - break - - else: - try: - self.logError(_("Too many redirects")) - except Exception: - pass - - return link - - -def secondsToMidnight(gmt=0): - now = datetime.utcnow() + timedelta(hours=gmt) - - if now.hour is 0 and now.minute < 10: - midnight = now - else: - midnight = now + timedelta(days=1) - - td = midnight.replace(hour=0, minute=10, second=0, microsecond=0) - now - - if hasattr(td, 'total_seconds'): - res = td.total_seconds() - else: #@NOTE: work-around for python 2.5 and 2.6 missing timedelta.total_seconds - res = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6 - - return int(res) - - -class SimpleHoster(Hoster): - __name__ = "SimpleHoster" - __type__ = "hoster" - __version__ = "1.15" - - __pattern__ = r'^unmatchable$' - - __description__ = """Simple hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("stickell", "l.stickell@yahoo.it"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - """ - Info patterns should be defined by each hoster: - - INFO_PATTERN: (optional) Name and Size of the file - example: INFO_PATTERN = r'(?P<N>file_name) (?P<S>file_size) (?P<U>size_unit)' - or - NAME_PATTERN: (optional) Name that will be set for the file - example: NAME_PATTERN = r'(?P<N>file_name)' - SIZE_PATTERN: (optional) Size that will be checked for the file - example: SIZE_PATTERN = r'(?P<S>file_size) (?P<U>size_unit)' - - HASHSUM_PATTERN: (optional) Hash code and type of the file - example: HASHSUM_PATTERN = r'(?P<H>hash_code) (?P<T>MD5)' - - OFFLINE_PATTERN: (optional) Check if the page is unreachable - example: OFFLINE_PATTERN = r'File (deleted|not found)' - - TEMP_OFFLINE_PATTERN: (optional) Check if the page is temporarily unreachable - example: TEMP_OFFLINE_PATTERN = r'Server (maintenance|maintainance)' - - - Error handling patterns are all optional: - - WAIT_PATTERN: (optional) Detect waiting time - example: WAIT_PATTERN = r'' - - PREMIUM_ONLY_PATTERN: (optional) Check if the file can be downloaded only with a premium account - example: PREMIUM_ONLY_PATTERN = r'Premium account required' - - ERROR_PATTERN: (optional) Detect any error preventing download - example: ERROR_PATTERN = r'' - - - Instead overriding handleFree and handlePremium methods you can define the following patterns for direct download: - - LINK_FREE_PATTERN: (optional) group(1) should be the direct link for free download - example: LINK_FREE_PATTERN = r'<div class="link"><a href="(.+?)"' - - LINK_PREMIUM_PATTERN: (optional) group(1) should be the direct link for premium download - example: LINK_PREMIUM_PATTERN = r'<div class="link"><a href="(.+?)"' - """ - - NAME_REPLACEMENTS = [("&#?\w+;", fixup)] - SIZE_REPLACEMENTS = [] - URL_REPLACEMENTS = [] - - TEXT_ENCODING = False #: Set to True or encoding name if encoding value in http header is not correct - COOKIES = True #: or False or list of tuples [(domain, name, value)] - CHECK_TRAFFIC = False #: Set to True to force checking traffic left for premium account - DIRECT_LINK = None #: Set to True to looking for direct link (as defined in handleDirect method), set to None to do it if self.account is True else False - MULTI_HOSTER = False #: Set to True to leech other hoster link (as defined in handleMulti method) - LOGIN_ACCOUNT = False #: Set to True to require account login - DISPOSITION = True #: Work-around to `filename*=UTF-8` bug; remove in 0.4.10 - - directLink = fileUrl #@TODO: Remove in 0.4.10 - - - @classmethod - def parseInfos(cls, urls): #@TODO: Built-in in 0.4.10 core, then remove from plugins - for url in urls: - url = replace_patterns(url, cls.URL_REPLACEMENTS) - yield cls.getInfo(url) - - - @classmethod - def apiInfo(cls, url="", get={}, post={}): - url = unquote(url) - url_p = urlparse(url) - return {'name' : (url_p.path.split('/')[-1] - or url_p.query.split('=', 1)[::-1][0].split('&', 1)[0] - or url_p.netloc.split('.', 1)[0]), - 'size' : 0, - 'status': 3 if url else 8, - 'url' : url} - - - @classmethod - def getInfo(cls, url="", html=""): - info = cls.apiInfo(url) - online = False if info['status'] != 2 else True - - try: - info['pattern'] = re.match(cls.__pattern__, url).groupdict() #: pattern groups will be saved here - - except Exception: - info['pattern'] = {} - - if not html and not online: - if not url: - info['error'] = "missing url" - info['status'] = 1 - - elif info['status'] is 3 and not fileUrl(None, url): - try: - html = getURL(url, cookies=cls.COOKIES, decode=not cls.TEXT_ENCODING) - - if isinstance(cls.TEXT_ENCODING, basestring): - html = unicode(html, cls.TEXT_ENCODING) - - except BadHeader, e: - info['error'] = "%d: %s" % (e.code, e.content) - - if e.code is 404: - info['status'] = 1 - - elif e.code is 503: - info['status'] = 6 - - if html: - if hasattr(cls, "OFFLINE_PATTERN") and re.search(cls.OFFLINE_PATTERN, html): - info['status'] = 1 - - elif hasattr(cls, "TEMP_OFFLINE_PATTERN") and re.search(cls.TEMP_OFFLINE_PATTERN, html): - info['status'] = 6 - - else: - for pattern in ("INFO_PATTERN", "NAME_PATTERN", "SIZE_PATTERN", "HASHSUM_PATTERN"): - try: - attr = getattr(cls, pattern) - pdict = re.search(attr, html).groupdict() - - if all(True for k in pdict if k not in info['pattern']): - info['pattern'].update(pdict) - - except AttributeError: - continue - - else: - online = True - - if online: - info['status'] = 2 - - if 'N' in info['pattern']: - info['name'] = replace_patterns(unquote(info['pattern']['N'].strip()), - cls.NAME_REPLACEMENTS) - - if 'S' in info['pattern']: - size = replace_patterns(info['pattern']['S'] + info['pattern']['U'] if 'U' in info['pattern'] else info['pattern']['S'], - cls.SIZE_REPLACEMENTS) - info['size'] = parseFileSize(size) - - elif isinstance(info['size'], basestring): - unit = info['units'] if 'units' in info else None - info['size'] = parseFileSize(info['size'], unit) - - if 'H' in info['pattern']: - hashtype = info['pattern']['T'] if 'T' in info['pattern'] else "hash" - info[hashtype] = info['pattern']['H'] - - if not info['pattern']: - info.pop('pattern', None) - - return info - - - def setup(self): - self.resumeDownload = self.multiDL = self.premium - - - def prepare(self): - self.pyfile.error = "" #@TODO: Remove in 0.4.10 - - self.info = {} - self.html = "" - self.link = "" #@TODO: Move to hoster class in 0.4.10 - self.directDL = False #@TODO: Move to hoster class in 0.4.10 - self.multihost = False #@TODO: Move to hoster class in 0.4.10 - - if self.LOGIN_ACCOUNT and not self.account: - self.fail(_("Required account not found")) - - self.req.setOption("timeout", 120) - - if isinstance(self.COOKIES, list): - set_cookies(self.req.cj, self.COOKIES) - - if (self.MULTI_HOSTER - and (self.__pattern__ != self.core.pluginManager.hosterPlugins[self.__name__]['pattern'] - or re.match(self.__pattern__, self.pyfile.url) is None)): - self.multihost = True - return - - if self.DIRECT_LINK is None: - self.directDL = bool(self.account) - else: - self.directDL = self.DIRECT_LINK - - self.pyfile.url = replace_patterns(self.pyfile.url, self.URL_REPLACEMENTS) - - - def preload(self): - self.html = self.load(self.pyfile.url, cookies=bool(self.COOKIES), decode=not self.TEXT_ENCODING) - - if isinstance(self.TEXT_ENCODING, basestring): - self.html = unicode(self.html, self.TEXT_ENCODING) - - - def process(self, pyfile): - self.prepare() - self.checkInfo() - - if self.directDL: - self.logDebug("Looking for direct download link...") - self.handleDirect(pyfile) - - if self.multihost and not self.link and not self.lastDownload: - self.logDebug("Looking for leeched download link...") - self.handleMulti(pyfile) - - if not self.link and not self.lastDownload: - self.MULTI_HOSTER = False - self.retry(1, reason="Multi hoster fails") - - if not self.link and not self.lastDownload: - self.preload() - self.checkInfo() - - if self.premium and (not self.CHECK_TRAFFIC or self.checkTrafficLeft()): - self.logDebug("Handled as premium download") - self.handlePremium(pyfile) - - elif not self.LOGIN_ACCOUNT or (not self.CHECK_TRAFFIC or self.checkTrafficLeft()): - self.logDebug("Handled as free download") - self.handleFree(pyfile) - - self.downloadLink(self.link, self.DISPOSITION) #: Remove `self.DISPOSITION` in 0.4.10 - self.checkFile() - - - def downloadLink(self, link, disposition=True): - if link and isinstance(link, basestring): - self.correctCaptcha() - - if not urlparse(link).scheme: - url_p = urlparse(self.pyfile.url) - baseurl = "%s://%s" % (url_p.scheme, url_p.netloc) - link = urljoin(baseurl, link) - - self.download(link, ref=False, disposition=disposition) - - - def checkFile(self): - if self.cTask and not self.lastDownload: - self.invalidCaptcha() - self.retry(10, reason=_("Wrong captcha")) - - elif not self.lastDownload or not os.path.exists(fs_encode(self.lastDownload)): - self.lastDownload = "" - self.error(self.pyfile.error or _("No file downloaded")) - - else: - rules = {'empty file': re.compile(r'\A\Z'), - 'html file' : re.compile(r'\A\s*<!DOCTYPE html'), - 'html error': re.compile(r'\A\s*(<.+>)?\d{3}(\Z|\s+)')} - - if hasattr(self, 'ERROR_PATTERN'): - rules['error'] = re.compile(self.ERROR_PATTERN) - - check = self.checkDownload(rules) - if check: #@TODO: Move to hoster in 0.4.10 - errmsg = check.strip().capitalize() - if self.lastCheck: - errmsg += " | " + self.lastCheck.group(0).strip() - - self.lastDownload = "" - self.retry(10, 60, errmsg) - - - def checkErrors(self): - if not self.html: - self.logWarning(_("No html code to check")) - return - - if hasattr(self, 'PREMIUM_ONLY_PATTERN') and not self.premium and re.search(self.PREMIUM_ONLY_PATTERN, self.html): - self.fail(_("Link require a premium account to be handled")) - - elif hasattr(self, 'ERROR_PATTERN'): - m = re.search(self.ERROR_PATTERN, self.html) - if m: - errmsg = self.info['error'] = m.group(1) - self.error(errmsg) - - elif hasattr(self, 'WAIT_PATTERN'): - m = re.search(self.WAIT_PATTERN, self.html) - if m: - wait_time = sum(int(v) * {"hr": 3600, "hour": 3600, "min": 60, "sec": 1}[u.lower()] for v, u in - re.findall(r'(\d+)\s*(hr|hour|min|sec)', m.group(0), re.I)) - self.wait(wait_time, wait_time > 300) - return - - self.info.pop('error', None) - - - def checkStatus(self, getinfo=True): - if not self.info or getinfo: - self.logDebug("Update file info...") - self.logDebug("Previous file info: %s" % self.info) - self.info.update(self.getInfo(self.pyfile.url, self.html)) - self.logDebug("Current file info: %s" % self.info) - - try: - status = self.info['status'] - - if status is 1: - self.offline() - - elif status is 6: - self.tempOffline() - - elif status is 8: - self.fail() - - finally: - self.logDebug("File status: %s" % statusMap[status]) - - - def checkNameSize(self, getinfo=True): - if not self.info or getinfo: - self.logDebug("Update file info...") - self.logDebug("Previous file info: %s" % self.info) - self.info.update(self.getInfo(self.pyfile.url, self.html)) - self.logDebug("Current file info: %s" % self.info) - - try: - url = self.info['url'].strip() - name = self.info['name'].strip() - if name and name != url: - self.pyfile.name = name - - except Exception: - pass - - try: - size = self.info['size'] - if size > 0: - self.pyfile.size = size - - except Exception: - pass - - self.logDebug("File name: %s" % self.pyfile.name, - "File size: %s byte" % self.pyfile.size if self.pyfile.size > 0 else "File size: Unknown") - - - def checkInfo(self): - self.checkNameSize() - - if self.html: - self.checkErrors() - self.checkNameSize() - - self.checkStatus(getinfo=False) - - - #: Deprecated - def getFileInfo(self): - self.info = {} - self.checkInfo() - return self.info - - - def handleDirect(self, pyfile): - link = self.directLink(pyfile.url, self.resumeDownload) - - if link: - self.logInfo(_("Direct download link detected")) - - self.link = link - else: - self.logDebug("Direct download link not found") - - - def handleMulti(self, pyfile): #: Multi-hoster handler - pass - - - def handleFree(self, pyfile): - if not hasattr(self, 'LINK_FREE_PATTERN'): - self.logError(_("Free download not implemented")) - - m = re.search(self.LINK_FREE_PATTERN, self.html) - if m is None: - self.error(_("Free download link not found")) - else: - self.link = m.group(1) - - - def handlePremium(self, pyfile): - if not hasattr(self, 'LINK_PREMIUM_PATTERN'): - self.logError(_("Premium download not implemented")) - self.logDebug("Handled as free download") - self.handleFree(pyfile) - - m = re.search(self.LINK_PREMIUM_PATTERN, self.html) - if m is None: - self.error(_("Premium download link not found")) - else: - self.link = m.group(1) - - - def longWait(self, wait_time=None, max_tries=3): - if wait_time and isinstance(wait_time, (int, long, float)): - time_str = "%dh %dm" % divmod(wait_time / 60, 60) - else: - wait_time = 900 - time_str = _("(unknown time)") - max_tries = 100 - - self.logInfo(_("Download limit reached, reconnect or wait %s") % time_str) - - self.wait(wait_time, True) - self.retry(max_tries=max_tries, reason=_("Download limit reached")) - - - def parseHtmlForm(self, attr_str="", input_names={}): - return parseHtmlForm(attr_str, self.html, input_names) - - - def checkTrafficLeft(self): - if not self.account: - return True - - traffic = self.account.getAccountInfo(self.user, True)['trafficleft'] - - if traffic is None: - return False - elif traffic == -1: - return True - else: - size = self.pyfile.size / 1024 - self.logInfo(_("Filesize: %i KiB, Traffic left for user %s: %i KiB") % (size, self.user, traffic)) - return size <= traffic - - - #@TODO: Remove in 0.4.10 - def wait(self, seconds=0, reconnect=None): - return _wait(self, seconds, reconnect) - - - def error(self, reason="", type="parse"): - return _error(self, reason, type) diff --git a/module/plugins/internal/UnRar.py b/module/plugins/internal/UnRar.py deleted file mode 100644 index 54d64c430..000000000 --- a/module/plugins/internal/UnRar.py +++ /dev/null @@ -1,248 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import re - -from glob import glob -from string import digits -from subprocess import Popen, PIPE - -from module.plugins.internal.Extractor import Extractor, ArchiveError, CRCError, PasswordError -from module.utils import decode, fs_encode, save_join - - -def renice(pid, value): - if value and os.name != "nt": - try: - Popen(["renice", str(value), str(pid)], stdout=PIPE, stderr=PIPE, bufsize=-1) - - except Exception: - pass - - -class UnRar(Extractor): - __name__ = "UnRar" - __version__ = "1.13" - - __description__ = """Rar extractor plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("Walter Purcaro", "vuolter@gmail.com"), - ("Immenz", "immenz@gmx.net"),] - - - CMD = "unrar" - VERSION = "" - - EXTENSIONS = [".rar"] - - - re_multipart = re.compile(r'\.(part|r)(\d+)(?:\.rar)?',re.I) - - re_filefixed = re.compile(r'Building (.+)') - re_filelist = re.compile(r'^(.)(\s*[\w\.\-]+)\s+(\d+\s+)+(?:\d+\%\s+)?[\d\-]{8}\s+[\d\:]{5}', re.M|re.I) - - re_wrongpwd = re.compile(r'password', re.I) - re_wrongcrc = re.compile(r'encrypted|damaged|CRC failed|checksum error', re.I) - - re_version = re.compile(r'UNRAR\s(\d+\.\d+)', re.I) - - - @classmethod - def isUsable(cls): - if os.name == "nt": - cls.CMD = os.path.join(pypath, "UnRAR.exe") - p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE) - out, err = p.communicate() - else: - try: - p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE) - out, err = p.communicate() - - except OSError: #: fallback to rar - cls.CMD = "rar" - p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE) - out, err = p.communicate() - - cls.VERSION = cls.re_version.search(out).group(1) - - return True - - - @classmethod - def isMultipart(cls,filename): - multipart = cls.re_multipart.search(filename) - if multipart: - # First Multipart file (part1.rar for *.part1-9.rar format or *.rar for .r1-9 format) handled as normal Archive - return False if (multipart.group(1) == "part" and int(multipart.group(2)) == 1) else True - - return False - - - def check(self): - p = self.call_cmd("l", "-v", fs_encode(self.filename)) - out, err = p.communicate() - - if self.re_wrongpwd.search(err): - raise PasswordError - - if self.re_wrongcrc.search(err): - raise CRCError(err) - - # output only used to check if passworded files are present - for attr in self.re_filelist.findall(out): - if attr[0].startswith("*"): - raise PasswordError - - - def isPassword(self, password): - # at this point we can only verify header protected files - p = self.call_cmd("l", "-v", fs_encode(self.filename), password=password) - out, err = p.communicate() - return False if self.re_wrongpwd.search(err) else True - - - def repair(self): - p = self.call_cmd("rc", fs_encode(self.filename)) - - # communicate and retrieve stderr - self._progress(p) - err = p.stderr.read().strip() - - if err or p.returncode: - p = self.call_cmd("r", fs_encode(self.filename)) - - # communicate and retrieve stderr - self._progress(p) - err = p.stderr.read().strip() - - if err or p.returncode: - return False - else: - dir = os.path.dirname(filename) - name = re_filefixed.search(out).group(1) - - self.filename = os.path.join(dir, name) - - return True - - - def _progress(self, process): - s = "" - while True: - c = process.stdout.read(1) - # quit loop on eof - if not c: - break - # reading a percentage sign -> set progress and restart - if c == '%': - self.notifyProgress(int(s)) - s = "" - # not reading a digit -> therefore restart - elif c not in digits: - s = "" - # add digit to progressstring - else: - s += c - - - def extract(self, password=None): - command = "x" if self.fullpath else "e" - - p = self.call_cmd(command, fs_encode(self.filename), self.out, password=password) - - renice(p.pid, self.renice) - - # communicate and retrieve stderr - self._progress(p) - err = p.stderr.read().strip() - - if err: - if self.re_wrongpwd.search(err): - raise PasswordError - - elif self.re_wrongcrc.search(err): - raise CRCError(err) - - else: #: raise error if anything is on stderr - raise ArchiveError(err) - - if p.returncode: - raise ArchiveError(_("Process return code: %d") % p.returncode) - - self.files = self.list(password) - - - def getDeleteFiles(self): - dir, name = os.path.split(self.filename) - - # actually extracted file - files = [self.filename] - - # eventually Multipart Files - files.extend(save_join(dir, os.path.basename(file)) for file in filter(self.isMultipart, os.listdir(dir)) - if re.sub(self.re_multipart,".rar",name) == re.sub(self.re_multipart,".rar",file)) - - return files - - - def list(self, password=None): - command = "vb" if self.fullpath else "lb" - - p = self.call_cmd(command, "-v", fs_encode(self.filename), password=password) - out, err = p.communicate() - - if "Cannot open" in err: - raise ArchiveError(_("Cannot open file")) - - if err.strip(): #: only log error at this point - self.manager.logError(err.strip()) - - result = set() - if not self.fullpath and self.VERSION.startswith('5'): - # NOTE: Unrar 5 always list full path - for f in decode(out).splitlines(): - f = save_join(self.out, os.path.basename(f.strip())) - if os.path.isfile(f): - result.add(save_join(self.out, os.path.basename(f))) - else: - for f in decode(out).splitlines(): - f = f.strip() - result.add(save_join(self.out, f)) - - return list(result) - - - def call_cmd(self, command, *xargs, **kwargs): - args = [] - - # overwrite flag - if self.overwrite: - args.append("-o+") - else: - args.append("-o-") - if self.delete: - args.append("-or") - - for word in self.excludefiles: - args.append("-x'%s'" % word.strip()) - - # assume yes on all queries - args.append("-y") - - # set a password - if "password" in kwargs and kwargs['password']: - args.append("-p%s" % kwargs['password']) - else: - args.append("-p-") - - if self.keepbroken: - args.append("-kb") - - # NOTE: return codes are not reliable, some kind of threading, cleanup whatever issue - call = [self.CMD, command] + args + list(xargs) - - self.manager.logDebug(" ".join(call)) - - p = Popen(call, stdout=PIPE, stderr=PIPE) - return p diff --git a/module/plugins/internal/UnZip.py b/module/plugins/internal/UnZip.py deleted file mode 100644 index 704b49ca0..000000000 --- a/module/plugins/internal/UnZip.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import os -import sys -import zipfile - -from module.plugins.internal.Extractor import Extractor, ArchiveError, CRCError, PasswordError -from module.utils import fs_encode - - -class UnZip(Extractor): - __name__ = "UnZip" - __version__ = "1.10" - - __description__ = """Zip extractor plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - EXTENSIONS = [".zip", ".zip64"] - VERSION ="(python %s.%s.%s)" % (sys.version_info[0], sys.version_info[1], sys.version_info[2]) - - - @classmethod - def isUsable(cls): - return sys.version_info[:2] >= (2, 6) - - - def list(self, password=None): - with zipfile.ZipFile(fs_encode(self.filename), 'r', allowZip64=True) as z: - z.setpassword(password) - return z.namelist() - - - def check(self): - with zipfile.ZipFile(fs_encode(self.filename), 'r', allowZip64=True) as z: - badfile = z.testzip() - - if badfile: - raise CRCError(badfile) - else: - raise PasswordError - - - def extract(self, password=None): - try: - with zipfile.ZipFile(fs_encode(self.filename), 'r', allowZip64=True) as z: - z.setpassword(password) - - badfile = z.testzip() - - if badfile: - raise CRCError(badfile) - else: - z.extractall(self.out) - - except (zipfile.BadZipfile, zipfile.LargeZipFile), e: - raise ArchiveError(e) - - except RuntimeError, e: - if "encrypted" in e: - raise PasswordError - else: - raise ArchiveError(e) - else: - self.files = z.namelist() diff --git a/module/plugins/internal/UpdateManager.py b/module/plugins/internal/UpdateManager.py deleted file mode 100644 index 7bbfc0c79..000000000 --- a/module/plugins/internal/UpdateManager.py +++ /dev/null @@ -1,300 +0,0 @@ -# -*- coding: utf-8 -*- - -import re -import sys - -from operator import itemgetter -from os import path, remove, stat - -from pyload.network.RequestFactory import getURL -from pyload.plugin.Addon import Expose, Addon, threaded -from pyload.utils import safe_join - - -class UpdateManager(Addon): - __name__ = "UpdateManager" - __type__ = "addon" - __version__ = "0.40" - - __config__ = [("activated" , "bool" , "Activated" , True ), - ("mode" , "pyLoad + plugins;plugins only", "Check updates for" , "pyLoad + plugins"), - ("interval" , "int" , "Check interval in hours" , 8 ), - ("reloadplugins", "bool" , "Monitor plugins for code changes (debug mode only)", True ), - ("nodebugupdate", "bool" , "Don't check for updates in debug mode" , True )] - - __description__ = """Check for updates""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - # event_list = ["pluginConfigChanged"] - - SERVER_URL = "http://updatemanager.pyload.org" - MIN_INTERVAL = 6 * 60 * 60 #: 6h minimum check interval (value is in seconds) - - - def pluginConfigChanged(self, plugin, name, value): - if name == "interval": - interval = value * 60 * 60 - if self.MIN_INTERVAL <= interval != self.interval: - self.core.scheduler.removeJob(self.cb) - self.interval = interval - self.initPeriodical() - else: - self.logDebug("Invalid interval value, kept current") - - elif name == "reloadplugins": - if self.cb2: - self.core.scheduler.removeJob(self.cb2) - if value is True and self.core.debug: - self.periodical2() - - - def activate(self): - self.pluginConfigChanged(self.__name__, "interval", self.getConfig("interval")) - x = lambda: self.pluginConfigChanged(self.__name__, "reloadplugins", self.getConfig("reloadplugins")) - self.core.scheduler.addJob(10, x, threaded=False) - - - def deactivate(self): - self.pluginConfigChanged(self.__name__, "reloadplugins", False) - - - def setup(self): - self.cb2 = None - self.interval = self.MIN_INTERVAL - self.updating = False - self.info = {'pyload': False, 'version': None, 'plugins': False} - self.mtimes = {} #: store modification time for each plugin - - - def periodical2(self): - if not self.updating: - self.autoreloadPlugins() - - self.cb2 = self.core.scheduler.addJob(4, self.periodical2, threaded=False) - - - @Expose - def autoreloadPlugins(self): - """ reload and reindex all modified plugins """ - modules = filter( - lambda m: m and (m.__name__.startswith("pyload.plugin.") or - m.__name__.startswith("userplugins.")) and - m.__name__.count(".") >= 2, sys.modules.itervalues() - ) - - reloads = [] - - for m in modules: - root, type, name = m.__name__.rsplit(".", 2) - id = (type, name) - if type in self.core.pluginManager.plugins: - f = m.__file__.replace(".pyc", ".py") - if not path.isfile(f): - continue - - mtime = stat(f).st_mtime - - if id not in self.mtimes: - self.mtimes[id] = mtime - elif self.mtimes[id] < mtime: - reloads.append(id) - self.mtimes[id] = mtime - - return True if self.core.pluginManager.reloadPlugins(reloads) else False - - - def periodical(self): - if self.info['pyload'] or self.getConfig("nodebugupdate") and self.core.debug: - return - - self.updateThread() - - - def server_request(self): - try: - return getURL(self.SERVER_URL, get={'v': self.core.api.getServerVersion()}).splitlines() - except Exception: - self.logWarning(_("Unable to contact server to get updates")) - - - @threaded - def updateThread(self): - self.updating = True - - status = self.update(onlyplugin=self.getConfig("mode") == "plugins only") - - if status == 2: - self.core.api.restart() - else: - self.updating = False - - - @Expose - def updatePlugins(self): - """ simple wrapper for calling plugin update quickly """ - return self.update(onlyplugin=True) - - - @Expose - def update(self, onlyplugin=False): - """ check for updates """ - data = self.server_request() - - if not data: - exitcode = 0 - - elif data[0] == "None": - self.logInfo(_("No new pyLoad version available")) - updates = data[1:] - exitcode = self._updatePlugins(updates) - - elif onlyplugin: - exitcode = 0 - - else: - newversion = data[0] - self.logInfo(_("*** New pyLoad Version %s available ***") % newversion) - self.logInfo(_("*** Get it here: https://github.com/pyload/pyload/releases ***")) - exitcode = 3 - self.info['pyload'] = True - self.info['version'] = newversion - - return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required; 3 = No plugins updated, new pyLoad version available - - - def _updatePlugins(self, updates): - """ check for plugin updates """ - - if self.info['plugins']: - return False #: plugins were already updated - - exitcode = 0 - updated = [] - - vre = re.compile(r'__version__.*=.*("|\')([\d.]+)') - url = updates[0] - schema = updates[1].split('|') - - if "BLACKLIST" in updates: - blacklist = updates[updates.index('BLACKLIST') + 1:] - updates = updates[2:updates.index('BLACKLIST')] - else: - blacklist = None - updates = updates[2:] - - upgradable = sorted(map(lambda x: dict(zip(schema, x.split('|'))), updates), - key=itemgetter("type", "name")) - - for plugin in upgradable: - filename = plugin['name'] - type = plugin['type'] - version = plugin['version'] - - if filename.endswith(".pyc"): - name = filename[:filename.find("_")] - else: - name = filename.replace(".py", "") - - plugins = getattr(self.core.pluginManager, "%sPlugins" % type) - - oldver = float(plugins[name]['version']) if name in plugins else None - newver = float(version) - - if not oldver: - msg = "New plugin: [%(type)s] %(name)s (v%(newver).2f)" - elif newver > oldver: - msg = "New version of plugin: [%(type)s] %(name)s (v%(oldver).2f -> v%(newver).2f)" - else: - continue - - self.logInfo(_(msg) % {'type' : type, - 'name' : name, - 'oldver': oldver, - 'newver': newver}) - try: - content = getURL(url % plugin) - m = vre.search(content) - - if m and m.group(2) == version: - f = open(safe_join("userplugins", prefix, filename), "wb") - f.write(content) - f.close() - updated.append((prefix, name)) - else: - raise Exception, _("Version mismatch") - - except Exception, e: - self.logError(_("Error updating plugin %s") % filename, e) - - if blacklist: - blacklisted = map(lambda x: (x.split('|')[0], x.split('|')[1].rsplit('.', 1)[0]), blacklist) - - # Always protect internal plugins from removing - for i, n, t in blacklisted.enumerate(): - if t == "internal": - del blacklisted[i] - - blacklisted = sorted(blacklisted) - removed = self.removePlugins(blacklisted) - for t, n in removed: - self.logInfo(_("Removed blacklisted plugin [%(type)s] %(name)s") % { - 'type': t, - 'name': n, - }) - - if updated: - reloaded = self.core.pluginManager.reloadPlugins(updated) - if reloaded: - self.logInfo(_("Plugins updated and reloaded")) - exitcode = 1 - else: - self.logInfo(_("*** Plugins have been updated, but need a pyLoad restart to be reloaded ***")) - self.info['plugins'] = True - exitcode = 2 - else: - self.logInfo(_("No plugin updates available")) - - return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required - - - @Expose - def removePlugins(self, type_plugins): - """ delete plugins from disk """ - - if not type_plugins: - return - - self.logDebug("Requested deletion of plugins: %s" % type_plugins) - - removed = [] - - for type, name in type_plugins: - err = False - file = name + ".py" - - for root in ("userplugins", path.join(pypath, "pyload", "plugins")): - - filename = safe_join(root, type, file) - try: - remove(filename) - except Exception, e: - self.logDebug("Error deleting: %s" % path.basename(filename), e) - err = True - - filename += "c" - if path.isfile(filename): - try: - if type == "addon": - self.manager.deactivateAddon(name) - remove(filename) - except Exception, e: - self.logDebug("Error deleting: %s" % path.basename(filename), e) - err = True - - if not err: - id = (type, name) - removed.append(id) - - return removed #: return a list of the plugins successfully removed diff --git a/module/plugins/internal/XFSCrypter.py b/module/plugins/internal/XFSCrypter.py deleted file mode 100644 index 665e13b18..000000000 --- a/module/plugins/internal/XFSCrypter.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo - - -class XFSCrypter(SimpleCrypter): - __name__ = "XFSCrypter" - __type__ = "crypter" - __version__ = "0.06" - - __pattern__ = r'^unmatchable$' - - __description__ = """XFileSharing decrypter plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - HOSTER_DOMAIN = None - - URL_REPLACEMENTS = [(r'&?per_page=\d+', ""), (r'[?/&]+$', ""), (r'(.+/[^?]+)$', r'\1?'), (r'$', r'&per_page=10000')] - - LINK_PATTERN = r'<(?:td|TD).*?>\s*<a href="(.+?)".*?>.+?(?:</a>)?\s*</(?:td|TD)>' - NAME_PATTERN = r'<[tT]itle>.*?\: (?P<N>.+) folder</[tT]itle>' - - OFFLINE_PATTERN = r'>\s*\w+ (Not Found|file (was|has been) removed)' - TEMP_OFFLINE_PATTERN = r'>\s*\w+ server (is in )?(maintenance|maintainance)' - - - def prepare(self): - if not self.HOSTER_DOMAIN: - if self.account: - account = self.account - else: - account_name = (self.__name__ + ".py").replace("Folder.py", "").replace(".py", "") - account = self.pyfile.m.core.accountManager.getAccountPlugin(account_name) - - if account and hasattr(account, "HOSTER_DOMAIN") and account.HOSTER_DOMAIN: - self.HOSTER_DOMAIN = account.HOSTER_DOMAIN - else: - self.fail(_("Missing HOSTER_DOMAIN")) - - if isinstance(self.COOKIES, list): - self.COOKIES.insert((self.HOSTER_DOMAIN, "lang", "english")) - - return super(XFSCrypter, self).prepare() diff --git a/module/plugins/internal/XFSHoster.py b/module/plugins/internal/XFSHoster.py deleted file mode 100644 index ecdd2f125..000000000 --- a/module/plugins/internal/XFSHoster.py +++ /dev/null @@ -1,326 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from random import random -from time import sleep -from urlparse import urljoin, urlparse - -from pyload.plugin.internal.captcha import ReCaptcha, SolveMedia -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, secondsToMidnight -from pyload.utils import html_unescape - - -class XFSHoster(SimpleHoster): - __name__ = "XFSHoster" - __type__ = "hoster" - __version__ = "0.44" - - __pattern__ = r'^unmatchable$' - - __description__ = """XFileSharing hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("stickell", "l.stickell@yahoo.it"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - HOSTER_DOMAIN = None - - TEXT_ENCODING = False - DIRECT_LINK = None - MULTI_HOSTER = True #@NOTE: Should be default to False for safe, but I'm lazy... - - NAME_PATTERN = r'(Filename[ ]*:[ ]*</b>(</td><td nowrap>)?|name="fname"[ ]+value="|<[\w^_]+ class="(file)?name">)\s*(?P<N>.+?)(\s*<|")' - SIZE_PATTERN = r'(Size[ ]*:[ ]*</b>(</td><td>)?|File:.*>|</font>\s*\(|<[\w^_]+ class="size">)\s*(?P<S>[\d.,]+)\s*(?P<U>[\w^_]+)' - - OFFLINE_PATTERN = r'>\s*\w+ (Not Found|file (was|has been) removed)' - TEMP_OFFLINE_PATTERN = r'>\s*\w+ server (is in )?(maintenance|maintainance)' - - WAIT_PATTERN = r'<span id="countdown_str">.*?>(\d+)</span>|id="countdown" value=".*?(\d+).*?"' - PREMIUM_ONLY_PATTERN = r'>This file is available for Premium Users only' - ERROR_PATTERN = r'(?:class=["\']err["\'].*?>|<[Cc]enter><b>|>Error</td>|>\(ERROR:)(?:\s*<.+?>\s*)*(.+?)(?:["\']|<|\))' - - LINK_LEECH_PATTERN = r'<h2>Download Link</h2>\s*<textarea[^>]*>([^<]+)' - LINK_PATTERN = None #: final download url pattern - - CAPTCHA_PATTERN = r'(https?://[^"\']+?/captchas?/[^"\']+)' - CAPTCHA_BLOCK_PATTERN = r'>Enter code.*?<div.*?>(.+?)</div>' - RECAPTCHA_PATTERN = None - SOLVEMEDIA_PATTERN = None - - FORM_PATTERN = None - FORM_INPUTS_MAP = None #: dict passed as input_names to parseHtmlForm - - - def setup(self): - self.chunkLimit = -1 if self.premium else 1 - self.resumeDownload = self.multiDL = self.premium - - - def prepare(self): - """ Initialize important variables """ - if not self.HOSTER_DOMAIN: - if self.account: - account = self.account - else: - account = self.pyfile.m.core.accountManager.getAccountPlugin(self.__name__) - - if account and hasattr(account, "HOSTER_DOMAIN") and account.HOSTER_DOMAIN: - self.HOSTER_DOMAIN = account.HOSTER_DOMAIN - else: - self.fail(_("Missing HOSTER_DOMAIN")) - - if isinstance(self.COOKIES, list): - self.COOKIES.insert((self.HOSTER_DOMAIN, "lang", "english")) - - if not self.LINK_PATTERN: - pattern = r'(https?://(?:www\.)?([^/]*?%s|\d+\.\d+\.\d+\.\d+)(\:\d+)?(/d/|(/files)?/\d+/\w+/).+?)["\'<]' - self.LINK_PATTERN = pattern % self.HOSTER_DOMAIN.replace('.', '\.') - - self.captcha = None - self.errmsg = None - - super(XFSHoster, self).prepare() - - if self.DIRECT_LINK is None: - self.directDL = self.premium - - - def handleFree(self, pyfile): - for i in xrange(1, 6): - self.logDebug("Getting download link: #%d" % i) - - self.checkErrors() - - m = re.search(self.LINK_PATTERN, self.html, re.S) - if m: - break - - data = self.getPostParameters() - - self.html = self.load(self.pyfile.url, post=data, ref=True, decode=True, follow_location=False) - - m = re.search(r'Location\s*:\s*(.+)', self.req.http.header, re.I) - if m and not "op=" in m.group(1): - break - - m = re.search(self.LINK_PATTERN, self.html, re.S) - if m: - break - else: - self.logError(data['op'] if 'op' in data else _("UNKNOWN")) - return "" - - self.link = m.group(1).strip() #@TODO: Remove .strip() in 0.4.10 - - - def handlePremium(self, pyfile): - return self.handleFree(pyfile) - - - def handleMulti(self, pyfile): - if not self.account: - self.fail(_("Only registered or premium users can use url leech feature")) - - #only tested with easybytez.com - self.html = self.load("http://www.%s/" % self.HOSTER_DOMAIN) - - action, inputs = self.parseHtmlForm() - - upload_id = "%012d" % int(random() * 10 ** 12) - action += upload_id + "&js_on=1&utype=prem&upload_type=url" - - inputs['tos'] = '1' - inputs['url_mass'] = pyfile.url - inputs['up1oad_type'] = 'url' - - self.logDebug(action, inputs) - - self.req.setOption("timeout", 600) #: wait for file to upload to easybytez.com - - self.html = self.load(action, post=inputs) - - self.checkErrors() - - action, inputs = self.parseHtmlForm('F1') - if not inputs: - if self.errmsg: - self.retry(reason=self.errmsg) - else: - self.error(_("TEXTAREA F1 not found")) - - self.logDebug(inputs) - - stmsg = inputs['st'] - - if stmsg == 'OK': - self.html = self.load(action, post=inputs) - - elif 'Can not leech file' in stmsg: - self.retry(20, 3 * 60, _("Can not leech file")) - - elif 'today' in stmsg: - self.retry(wait_time=secondsToMidnight(gmt=2), reason=_("You've used all Leech traffic today")) - - else: - self.fail(stmsg) - - #get easybytez.com link for uploaded file - m = re.search(self.LINK_LEECH_PATTERN, self.html) - if m is None: - self.error(_("LINK_LEECH_PATTERN not found")) - - header = self.load(m.group(1), just_header=True, decode=True) - - if 'location' in header: #: Direct download link - self.link = header['location'] - - - def checkErrors(self): - m = re.search(self.ERROR_PATTERN, self.html) - if m is None: - self.errmsg = None - else: - self.errmsg = m.group(1).strip() - - self.logWarning(re.sub(r"<.*?>", " ", self.errmsg)) - - if 'wait' in self.errmsg: - wait_time = sum(int(v) * {"hr": 3600, "hour": 3600, "min": 60, "sec": 1}[u.lower()] for v, u in - re.findall(r'(\d+)\s*(hr|hour|min|sec)', self.errmsg, re.I)) - self.wait(wait_time, True) - - elif 'country' in self.errmsg: - self.fail(_("Downloads are disabled for your country")) - - elif 'captcha' in self.errmsg: - self.invalidCaptcha() - - elif 'premium' in self.errmsg and 'require' in self.errmsg: - self.fail(_("File can be downloaded by premium users only")) - - elif 'limit' in self.errmsg: - if 'days' in self.errmsg: - delay = secondsToMidnight(gmt=2) - retries = 3 - else: - delay = 1 * 60 * 60 - retries = 24 - - self.wantReconnect = True - self.retry(retries, delay, _("Download limit exceeded")) - - elif 'countdown' in self.errmsg or 'Expired' in self.errmsg: - self.retry(reason=_("Link expired")) - - elif 'maintenance' in self.errmsg or 'maintainance' in self.errmsg: - self.tempOffline() - - elif 'up to' in self.errmsg: - self.fail(_("File too large for free download")) - - else: - self.wantReconnect = True - self.retry(wait_time=60, reason=self.errmsg) - - if self.errmsg: - self.info['error'] = self.errmsg - else: - self.info.pop('error', None) - - - def getPostParameters(self): - if self.FORM_PATTERN or self.FORM_INPUTS_MAP: - action, inputs = self.parseHtmlForm(self.FORM_PATTERN or "", self.FORM_INPUTS_MAP or {}) - else: - action, inputs = self.parseHtmlForm(input_names={'op': re.compile(r'^download')}) - - if not inputs: - action, inputs = self.parseHtmlForm('F1') - if not inputs: - if self.errmsg: - self.retry(reason=self.errmsg) - else: - self.error(_("TEXTAREA F1 not found")) - - self.logDebug(inputs) - - if 'op' in inputs: - if "password" in inputs: - password = self.getPassword() - if password: - inputs['password'] = password - else: - self.fail(_("Missing password")) - - if not self.premium: - m = re.search(self.WAIT_PATTERN, self.html) - if m: - wait_time = int(m.group(1)) - self.setWait(wait_time, False) - - self.captcha = self.handleCaptcha(inputs) - - self.wait() - else: - inputs['referer'] = self.pyfile.url - - if self.premium: - inputs['method_premium'] = "Premium Download" - inputs.pop('method_free', None) - else: - inputs['method_free'] = "Free Download" - inputs.pop('method_premium', None) - - return inputs - - - def handleCaptcha(self, inputs): - m = re.search(self.CAPTCHA_PATTERN, self.html) - if m: - captcha_url = m.group(1) - inputs['code'] = self.decryptCaptcha(captcha_url) - return 1 - - m = re.search(self.CAPTCHA_BLOCK_PATTERN, self.html, re.S) - if m: - captcha_div = m.group(1) - numerals = re.findall(r'<span.*?padding-left\s*:\s*(\d+).*?>(\d)</span>', html_unescape(captcha_div)) - - self.logDebug(captcha_div) - - inputs['code'] = "".join(a[1] for a in sorted(numerals, key=lambda num: int(num[0]))) - - self.logDebug("Captcha code: %s" % inputs['code'], numerals) - return 2 - - recaptcha = ReCaptcha(self) - try: - captcha_key = re.search(self.RECAPTCHA_PATTERN, self.html).group(1) - - except Exception: - captcha_key = recaptcha.detect_key() - - else: - self.logDebug("ReCaptcha key: %s" % captcha_key) - - if captcha_key: - inputs['recaptcha_response_field'], inputs['recaptcha_challenge_field'] = recaptcha.challenge(captcha_key) - return 3 - - solvemedia = SolveMedia(self) - try: - captcha_key = re.search(self.SOLVEMEDIA_PATTERN, self.html).group(1) - - except Exception: - captcha_key = solvemedia.detect_key() - - else: - self.logDebug("SolveMedia key: %s" % captcha_key) - - if captcha_key: - inputs['adcopy_response'], inputs['adcopy_challenge'] = solvemedia.challenge(captcha_key) - return 4 - - return 0 diff --git a/module/Core.py b/pyload/Core.py index fe4ae566e..fe4ae566e 100644 --- a/module/Core.py +++ b/pyload/Core.py diff --git a/module/__init__.py b/pyload/__init__.py index e29c81ad7..e29c81ad7 100644 --- a/module/__init__.py +++ b/pyload/__init__.py diff --git a/module/api/__init__.py b/pyload/api/__init__.py index 387481da2..387481da2 100644 --- a/module/api/__init__.py +++ b/pyload/api/__init__.py diff --git a/module/api/types.py b/pyload/api/types.py index 81385bf9f..81385bf9f 100644 --- a/module/api/types.py +++ b/pyload/api/types.py diff --git a/module/cli/AddPackage.py b/pyload/cli/AddPackage.py index f7e30b64e..f7e30b64e 100644 --- a/module/cli/AddPackage.py +++ b/pyload/cli/AddPackage.py diff --git a/module/cli/Cli.py b/pyload/cli/Cli.py index d8c8602fc..d8c8602fc 100644 --- a/module/cli/Cli.py +++ b/pyload/cli/Cli.py diff --git a/module/cli/Handler.py b/pyload/cli/Handler.py index 4aab3f0e2..4aab3f0e2 100644 --- a/module/cli/Handler.py +++ b/pyload/cli/Handler.py diff --git a/module/cli/ManageFiles.py b/pyload/cli/ManageFiles.py index ca1070113..ca1070113 100644 --- a/module/cli/ManageFiles.py +++ b/pyload/cli/ManageFiles.py diff --git a/module/cli/__init__.py b/pyload/cli/__init__.py index a64fc0c0c..a64fc0c0c 100644 --- a/module/cli/__init__.py +++ b/pyload/cli/__init__.py diff --git a/module/config/Parser.py b/pyload/config/Parser.py index e21eaba9f..e21eaba9f 100644 --- a/module/config/Parser.py +++ b/pyload/config/Parser.py diff --git a/module/config/Setup.py b/pyload/config/Setup.py index 8b88daa48..8b88daa48 100644 --- a/module/config/Setup.py +++ b/pyload/config/Setup.py diff --git a/module/config/__init__.py b/pyload/config/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/config/__init__.py +++ b/pyload/config/__init__.py diff --git a/module/config/default.conf b/pyload/config/default.conf index 6e2fb7749..6e2fb7749 100644 --- a/module/config/default.conf +++ b/pyload/config/default.conf diff --git a/module/database/DatabaseBackend.py b/pyload/database/DatabaseBackend.py index 4b63dd284..4b63dd284 100644 --- a/module/database/DatabaseBackend.py +++ b/pyload/database/DatabaseBackend.py diff --git a/pyload/database/File.py b/pyload/database/File.py new file mode 100644 index 000000000..0b22805a7 --- /dev/null +++ b/pyload/database/File.py @@ -0,0 +1,875 @@ +# -*- coding: utf-8 -*- +# @author: RaNaN, mkaay + +from threading import RLock +from time import time + +from pyload.utils import formatSize, lock +from pyload.manager.Event import InsertEvent, ReloadAllEvent, RemoveEvent, UpdateEvent +from pyload.datatype.Package import PyPackage +from pyload.datatype.File import PyFile +from pyload.database import style, DatabaseBackend + +try: + from pysqlite2 import dbapi2 as sqlite3 +except Exception: + import sqlite3 + + +class FileHandler(object): + """Handles all request made to obtain information, + modify status or other request for links or packages""" + + def __init__(self, core): + """Constructor""" + self.core = core + + # translations + self.statusMsg = [_("finished"), _("offline"), _("online"), _("queued"), _("skipped"), _("waiting"), _("temp. offline"), _("starting"), _("failed"), _("aborted"), _("decrypting"), _("custom"), _("downloading"), _("processing"), _("unknown")] + + self.cache = {} #holds instances for files + self.packageCache = {} # same for packages + #@TODO: purge the cache + + self.jobCache = {} + + self.lock = RLock() #@TODO should be a Lock w/o R + #self.lock._Verbose__verbose = True + + self.filecount = -1 # if an invalid value is set get current value from db + self.queuecount = -1 #number of package to be loaded + self.unchanged = False #determines if any changes was made since last call + + self.db = self.core.db + + def change(func): + def new(*args): + args[0].unchanged = False + args[0].filecount = -1 + args[0].queuecount = -1 + args[0].jobCache = {} + return func(*args) + return new + + #-------------------------------------------------------------------------- + def save(self): + """saves all data to backend""" + self.db.commit() + + #-------------------------------------------------------------------------- + def syncSave(self): + """saves all data to backend and waits until all data are written""" + pyfiles = self.cache.values() + for pyfile in pyfiles: + pyfile.sync() + + pypacks = self.packageCache.values() + for pypack in pypacks: + pypack.sync() + + self.db.syncSave() + + @lock + def getCompleteData(self, queue=1): + """gets a complete data representation""" + + data = self.db.getAllLinks(queue) + packs = self.db.getAllPackages(queue) + + data.update([(x.id, x.toDbDict()[x.id]) for x in self.cache.values()]) + + for x in self.packageCache.itervalues(): + if x.queue != queue or x.id not in packs: continue + packs[x.id].update(x.toDict()[x.id]) + + for key, value in data.iteritems(): + if value["package"] in packs: + packs[value["package"]]["links"][key] = value + + return packs + + @lock + def getInfoData(self, queue=1): + """gets a data representation without links""" + + packs = self.db.getAllPackages(queue) + for x in self.packageCache.itervalues(): + if x.queue != queue or x.id not in packs: continue + packs[x.id].update(x.toDict()[x.id]) + + return packs + + @lock + @change + def addLinks(self, urls, package): + """adds links""" + + self.core.addonManager.dispatchEvent("links-added", urls, package) + + data = self.core.pluginManager.parseUrls(urls) + + self.db.addLinks(data, package) + self.core.threadManager.createInfoThread(data, package) + + #@TODO change from reloadAll event to package update event + self.core.pullManager.addEvent(ReloadAllEvent("collector")) + + #-------------------------------------------------------------------------- + @lock + @change + def addPackage(self, name, folder, queue=0): + """adds a package, default to link collector""" + lastID = self.db.addPackage(name, folder, queue) + p = self.db.getPackage(lastID) + e = InsertEvent("pack", lastID, p.order, "collector" if not queue else "queue") + self.core.pullManager.addEvent(e) + return lastID + + #-------------------------------------------------------------------------- + @lock + @change + def deletePackage(self, id): + """delete package and all contained links""" + + p = self.getPackage(id) + if not p: + if id in self.packageCache: del self.packageCache[id] + return + + oldorder = p.order + queue = p.queue + + e = RemoveEvent("pack", id, "collector" if not p.queue else "queue") + + pyfiles = self.cache.values() + + for pyfile in pyfiles: + if pyfile.packageid == id: + pyfile.abortDownload() + pyfile.release() + + self.db.deletePackage(p) + self.core.pullManager.addEvent(e) + self.core.addonManager.dispatchEvent("package-deleted", id) + + if id in self.packageCache: + del self.packageCache[id] + + packs = self.packageCache.values() + for pack in packs: + if pack.queue == queue and pack.order > oldorder: + pack.order -= 1 + pack.notifyChange() + + #-------------------------------------------------------------------------- + @lock + @change + def deleteLink(self, id): + """deletes links""" + + f = self.getFile(id) + if not f: + return None + + pid = f.packageid + e = RemoveEvent("file", id, "collector" if not f.package().queue else "queue") + + oldorder = f.order + + if id in self.core.threadManager.processingIds(): + self.cache[id].abortDownload() + + if id in self.cache: + del self.cache[id] + + self.db.deleteLink(f) + + self.core.pullManager.addEvent(e) + + p = self.getPackage(pid) + if not len(p.getChildren()): + p.delete() + + pyfiles = self.cache.values() + for pyfile in pyfiles: + if pyfile.packageid == pid and pyfile.order > oldorder: + pyfile.order -= 1 + pyfile.notifyChange() + + #-------------------------------------------------------------------------- + def releaseLink(self, id): + """removes pyfile from cache""" + if id in self.cache: + del self.cache[id] + + #-------------------------------------------------------------------------- + def releasePackage(self, id): + """removes package from cache""" + if id in self.packageCache: + del self.packageCache[id] + + #-------------------------------------------------------------------------- + def updateLink(self, pyfile): + """updates link""" + self.db.updateLink(pyfile) + + e = UpdateEvent("file", pyfile.id, "collector" if not pyfile.package().queue else "queue") + self.core.pullManager.addEvent(e) + + #-------------------------------------------------------------------------- + def updatePackage(self, pypack): + """updates a package""" + self.db.updatePackage(pypack) + + e = UpdateEvent("pack", pypack.id, "collector" if not pypack.queue else "queue") + self.core.pullManager.addEvent(e) + + #-------------------------------------------------------------------------- + def getPackage(self, id): + """return package instance""" + + if id in self.packageCache: + return self.packageCache[id] + else: + return self.db.getPackage(id) + + #-------------------------------------------------------------------------- + def getPackageData(self, id): + """returns dict with package information""" + pack = self.getPackage(id) + + if not pack: + return None + + pack = pack.toDict()[id] + + data = self.db.getPackageData(id) + + tmplist = [] + + cache = self.cache.values() + for x in cache: + if int(x.toDbDict()[x.id]["package"]) == int(id): + tmplist.append((x.id, x.toDbDict()[x.id])) + data.update(tmplist) + + pack["links"] = data + + return pack + + #-------------------------------------------------------------------------- + def getFileData(self, id): + """returns dict with file information""" + if id in self.cache: + return self.cache[id].toDbDict() + + return self.db.getLinkData(id) + + #-------------------------------------------------------------------------- + def getFile(self, id): + """returns pyfile instance""" + if id in self.cache: + return self.cache[id] + else: + return self.db.getFile(id) + + #-------------------------------------------------------------------------- + @lock + def getJob(self, occ): + """get suitable job""" + + #@TODO clean mess + #@TODO improve selection of valid jobs + + if occ in self.jobCache: + if self.jobCache[occ]: + id = self.jobCache[occ].pop() + if id == "empty": + pyfile = None + self.jobCache[occ].append("empty") + else: + pyfile = self.getFile(id) + else: + jobs = self.db.getJob(occ) + jobs.reverse() + if not jobs: + self.jobCache[occ].append("empty") + pyfile = None + else: + self.jobCache[occ].extend(jobs) + pyfile = self.getFile(self.jobCache[occ].pop()) + + else: + self.jobCache = {} #better not caching to much + jobs = self.db.getJob(occ) + jobs.reverse() + self.jobCache[occ] = jobs + + if not jobs: + self.jobCache[occ].append("empty") + pyfile = None + else: + pyfile = self.getFile(self.jobCache[occ].pop()) + + #@TODO: maybe the new job has to be approved... + + + #pyfile = self.getFile(self.jobCache[occ].pop()) + return pyfile + + @lock + def getDecryptJob(self): + """return job for decrypting""" + if "decrypt" in self.jobCache: + return None + + plugins = self.core.pluginManager.crypterPlugins.keys() + self.core.pluginManager.containerPlugins.keys() + plugins = str(tuple(plugins)) + + jobs = self.db.getPluginJob(plugins) + if jobs: + return self.getFile(jobs[0]) + else: + self.jobCache["decrypt"] = "empty" + return None + + def getFileCount(self): + """returns number of files""" + + if self.filecount == -1: + self.filecount = self.db.filecount(1) + + return self.filecount + + def getQueueCount(self, force=False): + """number of files that have to be processed""" + if self.queuecount == -1 or force: + self.queuecount = self.db.queuecount(1) + + return self.queuecount + + def checkAllLinksFinished(self): + """checks if all files are finished and dispatch event""" + + if not self.getQueueCount(True): + self.core.addonManager.dispatchEvent("all_downloads-finished") + self.core.log.debug("All downloads finished") + return True + + return False + + def checkAllLinksProcessed(self, fid): + """checks if all files was processed and pyload would idle now, needs fid which will be ignored when counting""" + + # reset count so statistic will update (this is called when dl was processed) + self.resetCount() + + if not self.db.processcount(1, fid): + self.core.addonManager.dispatchEvent("all_downloads-processed") + self.core.log.debug("All downloads processed") + return True + + return False + + def resetCount(self): + self.queuecount = -1 + + @lock + @change + def restartPackage(self, id): + """restart package""" + pyfiles = self.cache.values() + for pyfile in pyfiles: + if pyfile.packageid == id: + self.restartFile(pyfile.id) + + self.db.restartPackage(id) + + if id in self.packageCache: + self.packageCache[id].setFinished = False + + e = UpdateEvent("pack", id, "collector" if not self.getPackage(id).queue else "queue") + self.core.pullManager.addEvent(e) + + @lock + @change + def restartFile(self, id): + """ restart file""" + if id in self.cache: + self.cache[id].status = 3 + self.cache[id].name = self.cache[id].url + self.cache[id].error = "" + self.cache[id].abortDownload() + + + self.db.restartFile(id) + + e = UpdateEvent("file", id, "collector" if not self.getFile(id).package().queue else "queue") + self.core.pullManager.addEvent(e) + + @lock + @change + def setPackageLocation(self, id, queue): + """push package to queue""" + + p = self.db.getPackage(id) + oldorder = p.order + + e = RemoveEvent("pack", id, "collector" if not p.queue else "queue") + self.core.pullManager.addEvent(e) + + self.db.clearPackageOrder(p) + + p = self.db.getPackage(id) + + p.queue = queue + self.db.updatePackage(p) + + self.db.reorderPackage(p, -1, True) + + packs = self.packageCache.values() + for pack in packs: + if pack.queue != queue and pack.order > oldorder: + pack.order -= 1 + pack.notifyChange() + + self.db.commit() + self.releasePackage(id) + p = self.getPackage(id) + + e = InsertEvent("pack", id, p.order, "collector" if not p.queue else "queue") + self.core.pullManager.addEvent(e) + + @lock + @change + def reorderPackage(self, id, position): + p = self.getPackage(id) + + e = RemoveEvent("pack", id, "collector" if not p.queue else "queue") + self.core.pullManager.addEvent(e) + self.db.reorderPackage(p, position) + + packs = self.packageCache.values() + for pack in packs: + if pack.queue != p.queue or pack.order < 0 or pack == p: continue + if p.order > position: + if pack.order >= position and pack.order < p.order: + pack.order += 1 + pack.notifyChange() + elif p.order < position: + if pack.order <= position and pack.order > p.order: + pack.order -= 1 + pack.notifyChange() + + p.order = position + self.db.commit() + + e = InsertEvent("pack", id, position, "collector" if not p.queue else "queue") + self.core.pullManager.addEvent(e) + + @lock + @change + def reorderFile(self, id, position): + f = self.getFileData(id) + f = f[id] + + e = RemoveEvent("file", id, "collector" if not self.getPackage(f["package"]).queue else "queue") + self.core.pullManager.addEvent(e) + + self.db.reorderLink(f, position) + + pyfiles = self.cache.values() + for pyfile in pyfiles: + if pyfile.packageid != f["package"] or pyfile.order < 0: continue + if f["order"] > position: + if pyfile.order >= position and pyfile.order < f["order"]: + pyfile.order += 1 + pyfile.notifyChange() + elif f["order"] < position: + if pyfile.order <= position and pyfile.order > f["order"]: + pyfile.order -= 1 + pyfile.notifyChange() + + if id in self.cache: + self.cache[id].order = position + + self.db.commit() + + e = InsertEvent("file", id, position, "collector" if not self.getPackage(f["package"]).queue else "queue") + self.core.pullManager.addEvent(e) + + @change + def updateFileInfo(self, data, pid): + """ updates file info (name, size, status, url)""" + ids = self.db.updateLinkInfo(data) + e = UpdateEvent("pack", pid, "collector" if not self.getPackage(pid).queue else "queue") + self.core.pullManager.addEvent(e) + + def checkPackageFinished(self, pyfile): + """ checks if package is finished and calls AddonManager """ + + ids = self.db.getUnfinished(pyfile.packageid) + if not ids or (pyfile.id in ids and len(ids) == 1): + if not pyfile.package().setFinished: + self.core.log.info(_("Package finished: %s") % pyfile.package().name) + self.core.addonManager.packageFinished(pyfile.package()) + pyfile.package().setFinished = True + + + def reCheckPackage(self, pid): + """ recheck links in package """ + data = self.db.getPackageData(pid) + + urls = [] + + for pyfile in data.itervalues(): + if pyfile["status"] not in (0, 12, 13): + urls.append((pyfile["url"], pyfile["plugin"])) + + self.core.threadManager.createInfoThread(urls, pid) + + @lock + @change + def deleteFinishedLinks(self): + """ deletes finished links and packages, return deleted packages """ + + old_packs = self.getInfoData(0) + old_packs.update(self.getInfoData(1)) + + self.db.deleteFinished() + + new_packs = self.db.getAllPackages(0) + new_packs.update(self.db.getAllPackages(1)) + #get new packages only from db + + deleted = [] + for id in old_packs.iterkeys(): + if id not in new_packs: + deleted.append(id) + self.deletePackage(int(id)) + + return deleted + + @lock + @change + def restartFailed(self): + """ restart all failed links """ + self.db.restartFailed() + +class FileMethods(object): + @style.queue + def filecount(self, queue): + """returns number of files in queue""" + self.c.execute("SELECT COUNT(*) FROM links as l INNER JOIN packages as p ON l.package=p.id WHERE p.queue=?", (queue,)) + return self.c.fetchone()[0] + + @style.queue + def queuecount(self, queue): + """ number of files in queue not finished yet""" + self.c.execute("SELECT COUNT(*) FROM links as l INNER JOIN packages as p ON l.package=p.id WHERE p.queue=? AND l.status NOT IN (0, 4)", (queue,)) + return self.c.fetchone()[0] + + @style.queue + def processcount(self, queue, fid): + """ number of files which have to be proccessed """ + self.c.execute("SELECT COUNT(*) FROM links as l INNER JOIN packages as p ON l.package=p.id WHERE p.queue=? AND l.status IN (2, 3, 5, 7, 12) AND l.id != ?", (queue, str(fid))) + return self.c.fetchone()[0] + + @style.inner + def _nextPackageOrder(self, queue=0): + self.c.execute('SELECT MAX(packageorder) FROM packages WHERE queue=?', (queue,)) + max = self.c.fetchone()[0] + if max is not None: + return max + 1 + else: + return 0 + + @style.inner + def _nextFileOrder(self, package): + self.c.execute('SELECT MAX(linkorder) FROM links WHERE package=?', (package,)) + max = self.c.fetchone()[0] + if max is not None: + return max + 1 + else: + return 0 + + @style.queue + def addLink(self, url, name, plugin, package): + order = self._nextFileOrder(package) + self.c.execute('INSERT INTO links(url, name, plugin, package, linkorder) VALUES(?,?,?,?,?)', (url, name, (plugintype, pluginname), package, order)) + return self.c.lastrowid + + @style.queue + def addLinks(self, links, package): + """ links is a list of tupels (url, plugin)""" + order = self._nextFileOrder(package) + orders = [order + x for x in range(len(links))] + links = [(x[0], x[0], (x[1], x[2]), package, o) for x, o in zip(links, orders)] + self.c.executemany('INSERT INTO links(url, name, plugin, package, linkorder) VALUES(?,?,?,?,?)', links) + + @style.queue + def addPackage(self, name, folder, queue): + order = self._nextPackageOrder(queue) + self.c.execute('INSERT INTO packages(name, folder, queue, packageorder) VALUES(?,?,?,?)', (name, folder, queue, order)) + return self.c.lastrowid + + @style.queue + def deletePackage(self, p): + + self.c.execute('DELETE FROM links WHERE package=?', (str(p.id),)) + self.c.execute('DELETE FROM packages WHERE id=?', (str(p.id),)) + self.c.execute('UPDATE packages SET packageorder=packageorder-1 WHERE packageorder > ? AND queue=?', (p.order, p.queue)) + + @style.queue + def deleteLink(self, f): + + self.c.execute('DELETE FROM links WHERE id=?', (str(f.id),)) + self.c.execute('UPDATE links SET linkorder=linkorder-1 WHERE linkorder > ? AND package=?', (f.order, str(f.packageid))) + + + @style.queue + def getAllLinks(self, q): + """return information about all links in queue q + + q0 queue + q1 collector + + format: + + { + id: {'name': name, ... 'package': id }, ... + } + + """ + self.c.execute('SELECT l.id, l.url, l.name, l.size, l.status, l.error, l.plugin, l.package, l.linkorder FROM links as l INNER JOIN packages as p ON l.package=p.id WHERE p.queue=? ORDER BY l.linkorder', (q,)) + data = {} + for r in self.c: + data[r[0]] = { + 'id': r[0], + 'url': r[1], + 'name': r[2], + 'size': r[3], + 'format_size': formatSize(r[3]), + 'status': r[4], + 'statusmsg': self.manager.statusMsg[r[4]], + 'error': r[5], + 'plugin': r[6], + 'package': r[7], + 'order': r[8], + } + + return data + + @style.queue + def getAllPackages(self, q): + """return information about packages in queue q + (only useful in get all data) + + q0 queue + q1 collector + + format: + + { + id: {'name': name ... 'links': {}}, ... + } + """ + self.c.execute('SELECT p.id, p.name, p.folder, p.site, p.password, p.queue, p.packageorder, s.sizetotal, s.sizedone, s.linksdone, s.linkstotal \ + FROM packages p JOIN pstats s ON p.id = s.id \ + WHERE p.queue=? ORDER BY p.packageorder', str(q)) + + data = {} + for r in self.c: + data[r[0]] = { + 'id': r[0], + 'name': r[1], + 'folder': r[2], + 'site': r[3], + 'password': r[4], + 'queue': r[5], + 'order': r[6], + 'sizetotal': int(r[7]), + 'sizedone': r[8] if r[8] else 0, #these can be None + 'linksdone': r[9] if r[9] else 0, + 'linkstotal': r[10], + 'links': {} + } + + return data + + @style.queue + def getLinkData(self, id): + """get link information as dict""" + self.c.execute('SELECT id, url, name, size, status, error, plugin, package, linkorder FROM links WHERE id=?', (str(id),)) + data = {} + r = self.c.fetchone() + if not r: + return None + data[r[0]] = { + 'id': r[0], + 'url': r[1], + 'name': r[2], + 'size': r[3], + 'format_size': formatSize(r[3]), + 'status': r[4], + 'statusmsg': self.manager.statusMsg[r[4]], + 'error': r[5], + 'plugin': r[6], + 'package': r[7], + 'order': r[8], + } + + return data + + @style.queue + def getPackageData(self, id): + """get data about links for a package""" + self.c.execute('SELECT id, url, name, size, status, error, plugin, package, linkorder FROM links WHERE package=? ORDER BY linkorder', (str(id),)) + + data = {} + for r in self.c: + data[r[0]] = { + 'id': r[0], + 'url': r[1], + 'name': r[2], + 'size': r[3], + 'format_size': formatSize(r[3]), + 'status': r[4], + 'statusmsg': self.manager.statusMsg[r[4]], + 'error': r[5], + 'plugin': r[6], + 'package': r[7], + 'order': r[8], + } + + return data + + + @style.async + def updateLink(self, f): + self.c.execute('UPDATE links SET url=?, name=?, size=?, status=?, error=?, package=? WHERE id=?', (f.url, f.name, f.size, f.status, f.error, str(f.packageid), str(f.id))) + + @style.queue + def updatePackage(self, p): + self.c.execute('UPDATE packages SET name=?, folder=?, site=?, password=?, queue=? WHERE id=?', (p.name, p.folder, p.site, p.password, p.queue, str(p.id))) + + @style.queue + def updateLinkInfo(self, data): + """ data is list of tupels (name, size, status, url) """ + self.c.executemany('UPDATE links SET name=?, size=?, status=? WHERE url=? AND status IN (1, 2, 3, 14)', data) + ids = [] + self.c.execute('SELECT id FROM links WHERE url IN (\'%s\')' % "','".join([x[3] for x in data])) + for r in self.c: + ids.append(int(r[0])) + return ids + + @style.queue + def reorderPackage(self, p, position, noMove=False): + if position == -1: + position = self._nextPackageOrder(p.queue) + if not noMove: + if p.order > position: + self.c.execute('UPDATE packages SET packageorder=packageorder+1 WHERE packageorder >= ? AND packageorder < ? AND queue=? AND packageorder >= 0', (position, p.order, p.queue)) + elif p.order < position: + self.c.execute('UPDATE packages SET packageorder=packageorder-1 WHERE packageorder <= ? AND packageorder > ? AND queue=? AND packageorder >= 0', (position, p.order, p.queue)) + + self.c.execute('UPDATE packages SET packageorder=? WHERE id=?', (position, str(p.id))) + + @style.queue + def reorderLink(self, f, position): + """ reorder link with f as dict for pyfile """ + if f["order"] > position: + self.c.execute('UPDATE links SET linkorder=linkorder+1 WHERE linkorder >= ? AND linkorder < ? AND package=?', (position, f["order"], f["package"])) + elif f["order"] < position: + self.c.execute('UPDATE links SET linkorder=linkorder-1 WHERE linkorder <= ? AND linkorder > ? AND package=?', (position, f["order"], f["package"])) + + self.c.execute('UPDATE links SET linkorder=? WHERE id=?', (position, f["id"])) + + @style.queue + def clearPackageOrder(self, p): + self.c.execute('UPDATE packages SET packageorder=? WHERE id=?', (-1, str(p.id))) + self.c.execute('UPDATE packages SET packageorder=packageorder-1 WHERE packageorder > ? AND queue=? AND id != ?', (p.order, p.queue, str(p.id))) + + @style.async + def restartFile(self, id): + self.c.execute('UPDATE links SET status=3, error="" WHERE id=?', (str(id),)) + + @style.async + def restartPackage(self, id): + self.c.execute('UPDATE links SET status=3 WHERE package=?', (str(id),)) + + @style.queue + def getPackage(self, id): + """return package instance from id""" + self.c.execute("SELECT name, folder, site, password, queue, packageorder FROM packages WHERE id=?", (str(id),)) + r = self.c.fetchone() + if not r: return None + return PyPackage(self.manager, id, * r) + + #-------------------------------------------------------------------------- + @style.queue + def getFile(self, id): + """return link instance from id""" + self.c.execute("SELECT url, name, size, status, error, plugin, package, linkorder FROM links WHERE id=?", (str(id),)) + r = self.c.fetchone() + if not r: return None + return PyFile(self.manager, id, * r) + + + @style.queue + def getJob(self, occ): + """return pyfile ids, which are suitable for download and dont use a occupied plugin""" + + #@TODO improve this hardcoded method + pre = "('CCF', 'DLC', 'LinkList', 'RSDF', 'TXT')" #plugins which are processed in collector + + cmd = "(" + for i, item in enumerate(occ): + if i: cmd += ", " + cmd += "'%s'" % item + + cmd += ")" + + cmd = "SELECT l.id FROM links as l INNER JOIN packages as p ON l.package=p.id WHERE ((p.queue=1 AND l.plugin NOT IN %s) OR l.plugin IN %s) AND l.status IN (2, 3, 14) ORDER BY p.packageorder ASC, l.linkorder ASC LIMIT 5" % (cmd, pre) + + self.c.execute(cmd) # very bad! + + return [x[0] for x in self.c] + + @style.queue + def getPluginJob(self, plugins): + """returns pyfile ids with suited plugins""" + cmd = "SELECT l.id FROM links as l INNER JOIN packages as p ON l.package=p.id WHERE l.plugin IN %s AND l.status IN (2, 3, 14) ORDER BY p.packageorder ASC, l.linkorder ASC LIMIT 5" % plugins + + self.c.execute(cmd) # very bad! + + return [x[0] for x in self.c] + + @style.queue + def getUnfinished(self, pid): + """return list of max length 3 ids with pyfiles in package not finished or processed""" + + self.c.execute("SELECT id FROM links WHERE package=? AND status NOT IN (0, 4, 13) LIMIT 3", (str(pid),)) + return [r[0] for r in self.c] + + @style.queue + def deleteFinished(self): + self.c.execute("DELETE FROM links WHERE status IN (0, 4)") + self.c.execute("DELETE FROM packages WHERE NOT EXISTS(SELECT 1 FROM links WHERE packages.id=links.package)") + + @style.queue + def restartFailed(self): + self.c.execute("UPDATE links SET status=3, error='' WHERE status IN (6, 8, 9)") + + @style.queue + def findDuplicates(self, id, folder, filename): + """ checks if filename exists with different id and same package """ + self.c.execute("SELECT l.plugin FROM links as l INNER JOIN packages as p ON l.package=p.id AND p.folder=? WHERE l.id!=? AND l.status=0 AND l.name=?", (folder, id, filename)) + return self.c.fetchone() + + @style.queue + def purgeLinks(self): + self.c.execute("DELETE FROM links;") + self.c.execute("DELETE FROM packages;") + +DatabaseBackend.registerSub(FileMethods) diff --git a/module/database/Storage.py b/pyload/database/Storage.py index 75e166d39..75e166d39 100644 --- a/module/database/Storage.py +++ b/pyload/database/Storage.py diff --git a/module/database/User.py b/pyload/database/User.py index 67cb62ab9..67cb62ab9 100644 --- a/module/database/User.py +++ b/pyload/database/User.py diff --git a/module/database/__init__.py b/pyload/database/__init__.py index 64f049be1..64f049be1 100644 --- a/module/database/__init__.py +++ b/pyload/database/__init__.py diff --git a/module/datatype/File.py b/pyload/datatype/File.py index 1df0a8590..1df0a8590 100644 --- a/module/datatype/File.py +++ b/pyload/datatype/File.py diff --git a/module/datatype/Package.py b/pyload/datatype/Package.py index bf3edffea..bf3edffea 100644 --- a/module/datatype/Package.py +++ b/pyload/datatype/Package.py diff --git a/module/datatype/__init__.py b/pyload/datatype/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/datatype/__init__.py +++ b/pyload/datatype/__init__.py diff --git a/module/manager/Account.py b/pyload/manager/Account.py index 3acf70311..3acf70311 100644 --- a/module/manager/Account.py +++ b/pyload/manager/Account.py diff --git a/module/manager/Addon.py b/pyload/manager/Addon.py index d293109c7..d293109c7 100644 --- a/module/manager/Addon.py +++ b/pyload/manager/Addon.py diff --git a/module/manager/Captcha.py b/pyload/manager/Captcha.py index e54eacf30..e54eacf30 100644 --- a/module/manager/Captcha.py +++ b/pyload/manager/Captcha.py diff --git a/module/manager/Event.py b/pyload/manager/Event.py index 20897290e..20897290e 100644 --- a/module/manager/Event.py +++ b/pyload/manager/Event.py diff --git a/module/manager/Plugin.py b/pyload/manager/Plugin.py index 879430be2..879430be2 100644 --- a/module/manager/Plugin.py +++ b/pyload/manager/Plugin.py diff --git a/module/manager/Remote.py b/pyload/manager/Remote.py index 910881164..910881164 100644 --- a/module/manager/Remote.py +++ b/pyload/manager/Remote.py diff --git a/module/manager/Thread.py b/pyload/manager/Thread.py index 2ace9c789..2ace9c789 100644 --- a/module/manager/Thread.py +++ b/pyload/manager/Thread.py diff --git a/module/manager/__init__.py b/pyload/manager/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/manager/__init__.py +++ b/pyload/manager/__init__.py diff --git a/module/manager/event/Scheduler.py b/pyload/manager/event/Scheduler.py index fd428a956..fd428a956 100644 --- a/module/manager/event/Scheduler.py +++ b/pyload/manager/event/Scheduler.py diff --git a/module/manager/event/__init__.py b/pyload/manager/event/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/manager/event/__init__.py +++ b/pyload/manager/event/__init__.py diff --git a/module/manager/thread/Addon.py b/pyload/manager/thread/Addon.py index 7feec227e..7feec227e 100644 --- a/module/manager/thread/Addon.py +++ b/pyload/manager/thread/Addon.py diff --git a/module/manager/thread/Decrypter.py b/pyload/manager/thread/Decrypter.py index 51544d1b9..51544d1b9 100644 --- a/module/manager/thread/Decrypter.py +++ b/pyload/manager/thread/Decrypter.py diff --git a/module/manager/thread/Download.py b/pyload/manager/thread/Download.py index c7d21a4ba..c7d21a4ba 100644 --- a/module/manager/thread/Download.py +++ b/pyload/manager/thread/Download.py diff --git a/module/manager/thread/Info.py b/pyload/manager/thread/Info.py index 4526a07ed..4526a07ed 100644 --- a/module/manager/thread/Info.py +++ b/pyload/manager/thread/Info.py diff --git a/module/manager/thread/Plugin.py b/pyload/manager/thread/Plugin.py index 20d57c933..20d57c933 100644 --- a/module/manager/thread/Plugin.py +++ b/pyload/manager/thread/Plugin.py diff --git a/module/manager/thread/Server.py b/pyload/manager/thread/Server.py index f3f174e74..f3f174e74 100644 --- a/module/manager/thread/Server.py +++ b/pyload/manager/thread/Server.py diff --git a/module/manager/thread/__init__.py b/pyload/manager/thread/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/manager/thread/__init__.py +++ b/pyload/manager/thread/__init__.py diff --git a/module/network/Browser.py b/pyload/network/Browser.py index 89341ff25..89341ff25 100644 --- a/module/network/Browser.py +++ b/pyload/network/Browser.py diff --git a/module/network/Bucket.py b/pyload/network/Bucket.py index 408a1e240..408a1e240 100644 --- a/module/network/Bucket.py +++ b/pyload/network/Bucket.py diff --git a/module/network/CookieJar.py b/pyload/network/CookieJar.py index a2b302776..a2b302776 100644 --- a/module/network/CookieJar.py +++ b/pyload/network/CookieJar.py diff --git a/module/network/HTTPChunk.py b/pyload/network/HTTPChunk.py index 41752b940..41752b940 100644 --- a/module/network/HTTPChunk.py +++ b/pyload/network/HTTPChunk.py diff --git a/module/network/HTTPDownload.py b/pyload/network/HTTPDownload.py index 3b2bf26ca..3b2bf26ca 100644 --- a/module/network/HTTPDownload.py +++ b/pyload/network/HTTPDownload.py diff --git a/module/network/HTTPRequest.py b/pyload/network/HTTPRequest.py index eac03a365..eac03a365 100644 --- a/module/network/HTTPRequest.py +++ b/pyload/network/HTTPRequest.py diff --git a/module/network/JsEngine.py b/pyload/network/JsEngine.py index 2e98fa37d..2e98fa37d 100644 --- a/module/network/JsEngine.py +++ b/pyload/network/JsEngine.py diff --git a/module/network/RequestFactory.py b/pyload/network/RequestFactory.py index 579eafea7..579eafea7 100644 --- a/module/network/RequestFactory.py +++ b/pyload/network/RequestFactory.py diff --git a/module/network/XDCCRequest.py b/pyload/network/XDCCRequest.py index c49f418c4..c49f418c4 100644 --- a/module/network/XDCCRequest.py +++ b/pyload/network/XDCCRequest.py diff --git a/module/network/__init__.py b/pyload/network/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/network/__init__.py +++ b/pyload/network/__init__.py diff --git a/module/plugins/Account.py b/pyload/plugin/Account.py index f8014908f..f8014908f 100644 --- a/module/plugins/Account.py +++ b/pyload/plugin/Account.py diff --git a/pyload/plugin/Addon.py b/pyload/plugin/Addon.py new file mode 100644 index 000000000..3525d4e4d --- /dev/null +++ b/pyload/plugin/Addon.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- + +from traceback import print_exc + +from pyload.plugin.Plugin import Base +from pyload.utils import has_method + + +class Expose(object): + """ used for decoration to declare rpc services """ + + def __new__(cls, f, *args, **kwargs): + addonManager.addRPC(f.__module__, f.func_name, f.func_doc) + return f + + +def threaded(fn): + + def run(*args,**kwargs): + addonManager.startThread(fn, *args, **kwargs) + + return run + + +class Addon(Base): + __name__ = "Addon" + __type__ = "addon" + __version__ = "0.01" + + __config__ = [] #: [("name", "type", "desc", "default")] + + __description__ = """Base addon plugin""" + __license__ = "GPLv3" + __authors__ = [("mkaay", "mkaay@mkaay.de"), + ("RaNaN", "RaNaN@pyload.org")] + + + #: automatically register event listeners for functions, attribute will be deleted dont use it yourself + event_map = {} + + # Deprecated alternative to event_map + #: List of events the plugin can handle, name the functions exactly like eventname. + event_list = [] #@NOTE: dont make duplicate entries in event_map + + + def __init__(self, core, manager): + Base.__init__(self, core) + + #: Provide information in dict here, usable by API `getInfo` + self.info = {} + + #: Callback of periodical job task, used by AddonManager + self.cb = None + self.interval = 60 + + #: `AddonManager` + self.manager = manager + + #register events + if self.event_map: + for event, funcs in self.event_map.iteritems(): + if type(funcs) in (list, tuple): + for f in funcs: + self.manager.addEvent(event, getattr(self,f)) + else: + self.manager.addEvent(event, getattr(self,funcs)) + + #delete for various reasons + self.event_map = None + + if self.event_list: + for f in self.event_list: + self.manager.addEvent(f, getattr(self,f)) + + self.event_list = None + + self.setup() + + # self.initPeriodical() + + + def initPeriodical(self, delay=0, threaded=False): + self.cb = self.core.scheduler.addJob(delay, self._periodical, args=[threaded], threaded=threaded) + + + def _periodical(self, threaded): + if self.interval < 0: + self.cb = None + return + + try: + self.periodical() + + except Exception, e: + self.logError(_("Error executing addon: %s") % e) + if self.core.debug: + print_exc() + + self.cb = self.core.scheduler.addJob(self.interval, self._periodical, threaded=threaded) + + + def __repr__(self): + return "<Addon %s>" % self.__name__ + + + def setup(self): + """ more init stuff if needed """ + pass + + + def deactivate(self): + """ called when addon was deactivated """ + if has_method(self.__class__, "unload"): + self.unload() + + def unload(self): # Deprecated, use method deactivate() instead + pass + + + def isActivated(self): + """ checks if addon is activated""" + return self.core.config.getPlugin(self.__name__, "activated") + + + # Event methods - overwrite these if needed + def activate(self): + """ called when addon was activated """ + if has_method(self.__class__, "coreReady"): + self.coreReady() + + def coreReady(self): # Deprecated, use method activate() instead + pass + + + def exit(self): + """ called by core.shutdown just before pyLoad exit """ + if has_method(self.__class__, "coreExiting"): + self.coreExiting() + + def coreExiting(self): # Deprecated, use method exit() instead + pass + + + def downloadPreparing(self, pyfile): + pass + + + def downloadFinished(self, pyfile): + pass + + + def downloadFailed(self, pyfile): + pass + + + def packageFinished(self, pypack): + pass + + + def beforeReconnecting(self, ip): + pass + + + def afterReconnecting(self, ip): + pass + + + def periodical(self): + pass + + + def captchaTask(self, task): + """ new captcha task for the plugin, it MUST set the handler and timeout or will be ignored """ + pass + + + def captchaCorrect(self, task): + pass + + + def captchaInvalid(self, task): + pass diff --git a/pyload/plugin/Captcha.py b/pyload/plugin/Captcha.py new file mode 100644 index 000000000..36b60f026 --- /dev/null +++ b/pyload/plugin/Captcha.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.Plugin import Base + + +#@TODO: Extend Plugin class; remove all `html` args +class Captcha(Base): + __name__ = "Captcha" + __type__ = "captcha" + __version__ = "0.25" + + __description__ = """Base captcha service plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + def __init__(self, plugin): + self.plugin = plugin + self.key = None #: last key detected + super(CaptchaService, self).__init__(plugin.core) + + + def detect_key(self, html=None): + raise NotImplementedError + + + def challenge(self, key=None, html=None): + raise NotImplementedError + + + def result(self, server, challenge): + raise NotImplementedError diff --git a/module/plugins/Container.py b/pyload/plugin/Container.py index bfc5713a7..bfc5713a7 100644 --- a/module/plugins/Container.py +++ b/pyload/plugin/Container.py diff --git a/module/plugins/Crypter.py b/pyload/plugin/Crypter.py index f93ee254a..f93ee254a 100644 --- a/module/plugins/Crypter.py +++ b/pyload/plugin/Crypter.py diff --git a/pyload/plugin/Extractor.py b/pyload/plugin/Extractor.py new file mode 100644 index 000000000..27573f860 --- /dev/null +++ b/pyload/plugin/Extractor.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- + +import os + +from pyload.datatype.File import PyFile +from pyload.plugin.Plugin import Base + + +class ArchiveError(Exception): + pass + + +class CRCError(Exception): + pass + + +class PasswordError(Exception): + pass + + +class Extractor(Base): + __name__ = "Extractor" + __version__ = "0.20" + + __description__ = """Base extractor plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "ranan@pyload.org"), + ("Walter Purcaro", "vuolter@gmail.com"), + ("Immenz", "immenz@gmx.net")] + + + EXTENSIONS = [] + VERSION = "" + + + @classmethod + def isArchive(cls, filename): + name = os.path.basename(filename).lower() + return any(name.endswith(ext) for ext in cls.EXTENSIONS) and not cls.isMultipart(filename) + + + @classmethod + def isMultipart(cls,filename): + return False + + + @classmethod + def isUsable(cls): + """ Check if system statisfy dependencies + :return: boolean + """ + return None + + + @classmethod + def getTargets(cls, files_ids): + """ Filter suited targets from list of filename id tuple list + :param files_ids: List of filepathes + :return: List of targets, id tuple list + """ + return [(fname, id, fout) for fname, id, fout in files_ids if cls.isArchive(fname)] + + + def __init__(self, manager, filename, out, + fullpath=True, + overwrite=False, + excludefiles=[], + renice=0, + delete=False, + keepbroken=False, + fid=None): + """ Initialize extractor for specific file """ + self.manager = manager + self.filename = filename + self.out = out + self.fullpath = fullpath + self.overwrite = overwrite + self.excludefiles = excludefiles + self.renice = renice + self.delete = delete + self.keepbroken = keepbroken + self.files = [] #: Store extracted files here + + pyfile = self.manager.core.files.getFile(fid) if fid else None + self.notifyProgress = lambda x: pyfile.setProgress(x) if pyfile else lambda x: None + + + def init(self): + """ Initialize additional data structures """ + pass + + + def check(self): + """Check if password if needed. Raise ArchiveError if integrity is + questionable. + + :return: boolean + :raises ArchiveError + """ + raise PasswordError + + + def isPassword(self, password): + """ Check if the given password is/might be correct. + If it can not be decided at this point return true. + + :param password: + :return: boolean + """ + return None + + + def repair(self): + return None + + + def extract(self, password=None): + """Extract the archive. Raise specific errors in case of failure. + + :param progress: Progress function, call this to update status + :param password password to use + :raises PasswordError + :raises CRCError + :raises ArchiveError + :return: + """ + raise NotImplementedError + + + def getDeleteFiles(self): + """Return list of files to delete, do *not* delete them here. + + :return: List with paths of files to delete + """ + return [self.filename] + + + def list(self, password=None): + """Populate self.files at some point while extracting""" + return self.files diff --git a/pyload/plugin/Hook.py b/pyload/plugin/Hook.py new file mode 100644 index 000000000..58dda9d8b --- /dev/null +++ b/pyload/plugin/Hook.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.Addon import Addon, threaded + + +class Hook(Addon): + __name__ = "Hook" + __type__ = "hook" + __version__ = "0.03" + + __config__ = [] #: [("name", "type", "desc", "default")] + + __description__ = """Base hook plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] diff --git a/module/plugins/Hoster.py b/pyload/plugin/Hoster.py index 2d43ee845..2d43ee845 100644 --- a/module/plugins/Hoster.py +++ b/pyload/plugin/Hoster.py diff --git a/pyload/plugin/OCR.py b/pyload/plugin/OCR.py new file mode 100644 index 000000000..623f02865 --- /dev/null +++ b/pyload/plugin/OCR.py @@ -0,0 +1,319 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +try: + from PIL import Image, GifImagePlugin, JpegImagePlugin, PngImagePlugin, TiffImagePlugin + +except ImportError: + import Image, GifImagePlugin, JpegImagePlugin, PngImagePlugin, TiffImagePlugin + +import logging +import os +import subprocess +#import tempfile + +from pyload.plugin.Plugin import Base +from pyload.utils import safe_join + + +class OCR(Base): + __name__ = "OCR" + __type__ = "ocr" + __version__ = "0.11" + + __description__ = """OCR base plugin""" + __license__ = "GPLv3" + __authors__ = [("pyLoad Team", "admin@pyload.org")] + + + def __init__(self): + self.logger = logging.getLogger("log") + + + def load_image(self, image): + self.image = Image.open(image) + self.pixels = self.image.load() + self.result_captcha = '' + + + def deactivate(self): + """delete all tmp images""" + pass + + + def threshold(self, value): + self.image = self.image.point(lambda a: a * value + 10) + + + def run(self, command): + """Run a command""" + + popen = subprocess.Popen(command, bufsize=-1, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + popen.wait() + output = popen.stdout.read() + " | " + popen.stderr.read() + popen.stdout.close() + popen.stderr.close() + self.logger.debug("Tesseract ReturnCode %s Output: %s" % (popen.returncode, output)) + + + def run_tesser(self, subset=False, digits=True, lowercase=True, uppercase=True): + #tmpTif = tempfile.NamedTemporaryFile(suffix=".tif") + try: + tmpTif = open(safe_join("tmp", "tmpTif_%s.tif" % self.__name__), "wb") + tmpTif.close() + + #tmpTxt = tempfile.NamedTemporaryFile(suffix=".txt") + tmpTxt = open(safe_join("tmp", "tmpTxt_%s.txt" % self.__name__), "wb") + tmpTxt.close() + + except IOError, e: + self.logError(e) + return + + self.logger.debug("save tiff") + self.image.save(tmpTif.name, 'TIFF') + + if os.name == "nt": + tessparams = [os.path.join(pypath, "tesseract", "tesseract.exe")] + else: + tessparams = ["tesseract"] + + tessparams.extend([os.path.abspath(tmpTif.name), os.path.abspath(tmpTxt.name).replace(".txt", "")] ) + + if subset and (digits or lowercase or uppercase): + #tmpSub = tempfile.NamedTemporaryFile(suffix=".subset") + with open(safe_join("tmp", "tmpSub_%s.subset" % self.__name__), "wb") as tmpSub: + tmpSub.write("tessedit_char_whitelist ") + + if digits: + tmpSub.write("0123456789") + if lowercase: + tmpSub.write("abcdefghijklmnopqrstuvwxyz") + if uppercase: + tmpSub.write("ABCDEFGHIJKLMNOPQRSTUVWXYZ") + + tmpSub.write("\n") + tessparams.append("nobatch") + tessparams.append(os.path.abspath(tmpSub.name)) + + self.logger.debug("run tesseract") + self.run(tessparams) + self.logger.debug("read txt") + + try: + with open(tmpTxt.name, 'r') as f: + self.result_captcha = f.read().replace("\n", "") + except Exception: + self.result_captcha = "" + + self.logger.debug(self.result_captcha) + try: + os.remove(tmpTif.name) + os.remove(tmpTxt.name) + if subset and (digits or lowercase or uppercase): + os.remove(tmpSub.name) + except Exception: + pass + + + def get_captcha(self, name): + raise NotImplementedError + + + def to_greyscale(self): + if self.image.mode != 'L': + self.image = self.image.convert('L') + + self.pixels = self.image.load() + + + def eval_black_white(self, limit): + self.pixels = self.image.load() + w, h = self.image.size + for x in xrange(w): + for y in xrange(h): + if self.pixels[x, y] > limit: + self.pixels[x, y] = 255 + else: + self.pixels[x, y] = 0 + + + def clean(self, allowed): + pixels = self.pixels + + w, h = self.image.size + + for x in xrange(w): + for y in xrange(h): + if pixels[x, y] == 255: + continue + # No point in processing white pixels since we only want to remove black pixel + count = 0 + + try: + if pixels[x - 1, y - 1] != 255: + count += 1 + if pixels[x - 1, y] != 255: + count += 1 + if pixels[x - 1, y + 1] != 255: + count += 1 + if pixels[x, y + 1] != 255: + count += 1 + if pixels[x + 1, y + 1] != 255: + count += 1 + if pixels[x + 1, y] != 255: + count += 1 + if pixels[x + 1, y - 1] != 255: + count += 1 + if pixels[x, y - 1] != 255: + count += 1 + except Exception: + pass + + # not enough neighbors are dark pixels so mark this pixel + # to be changed to white + if count < allowed: + pixels[x, y] = 1 + + # second pass: this time set all 1's to 255 (white) + for x in xrange(w): + for y in xrange(h): + if pixels[x, y] == 1: + pixels[x, y] = 255 + + self.pixels = pixels + + + def derotate_by_average(self): + """rotate by checking each angle and guess most suitable""" + + w, h = self.image.size + pixels = self.pixels + + for x in xrange(w): + for y in xrange(h): + if pixels[x, y] == 0: + pixels[x, y] = 155 + + highest = {} + counts = {} + + for angle in xrange(-45, 45): + + tmpimage = self.image.rotate(angle) + + pixels = tmpimage.load() + + w, h = self.image.size + + for x in xrange(w): + for y in xrange(h): + if pixels[x, y] == 0: + pixels[x, y] = 255 + + count = {} + + for x in xrange(w): + count[x] = 0 + for y in xrange(h): + if pixels[x, y] == 155: + count[x] += 1 + + sum = 0 + cnt = 0 + + for x in count.values(): + if x != 0: + sum += x + cnt += 1 + + avg = sum / cnt + counts[angle] = cnt + highest[angle] = 0 + for x in count.values(): + if x > highest[angle]: + highest[angle] = x + + highest[angle] = highest[angle] - avg + + hkey = 0 + hvalue = 0 + + for key, value in highest.iteritems(): + if value > hvalue: + hkey = key + hvalue = value + + self.image = self.image.rotate(hkey) + pixels = self.image.load() + + for x in xrange(w): + for y in xrange(h): + if pixels[x, y] == 0: + pixels[x, y] = 255 + + if pixels[x, y] == 155: + pixels[x, y] = 0 + + self.pixels = pixels + + + def split_captcha_letters(self): + captcha = self.image + started = False + letters = [] + width, height = captcha.size + bottomY, topY = 0, height + pixels = captcha.load() + + for x in xrange(width): + black_pixel_in_col = False + for y in xrange(height): + if pixels[x, y] != 255: + if not started: + started = True + firstX = x + lastX = x + + if y > bottomY: + bottomY = y + if y < topY: + topY = y + if x > lastX: + lastX = x + + black_pixel_in_col = True + + if black_pixel_in_col is False and started is True: + rect = (firstX, topY, lastX, bottomY) + new_captcha = captcha.crop(rect) + + w, h = new_captcha.size + if w > 5 and h > 5: + letters.append(new_captcha) + + started = False + bottomY, topY = 0, height + + return letters + + + def correct(self, values, var=None): + if var: + result = var + else: + result = self.result_captcha + + for key, item in values.iteritems(): + + if key.__class__ == str: + result = result.replace(key, item) + else: + for expr in key: + result = result.replace(expr, item) + + if var: + return result + else: + self.result_captcha = result diff --git a/module/plugins/Plugin.py b/pyload/plugin/Plugin.py index 0a9c647fb..0a9c647fb 100644 --- a/module/plugins/Plugin.py +++ b/pyload/plugin/Plugin.py diff --git a/module/plugins/__init__.py b/pyload/plugin/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/plugins/__init__.py +++ b/pyload/plugin/__init__.py diff --git a/module/plugins/accounts/AlldebridCom.py b/pyload/plugin/account/AlldebridCom.py index 7fc11e343..7fc11e343 100644 --- a/module/plugins/accounts/AlldebridCom.py +++ b/pyload/plugin/account/AlldebridCom.py diff --git a/pyload/plugin/account/BackinNet.py b/pyload/plugin/account/BackinNet.py new file mode 100644 index 000000000..ac751c8fb --- /dev/null +++ b/pyload/plugin/account/BackinNet.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSAccount import XFSAccount + + +class BackinNet(XFSAccount): + __name__ = "BackinNet" + __type__ = "account" + __version__ = "0.01" + + __description__ = """Backin.net account plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + HOSTER_DOMAIN = "backin.net" diff --git a/module/plugins/accounts/BillionuploadsCom.py b/pyload/plugin/account/BillionuploadsCom.py index a3325c427..a3325c427 100644 --- a/module/plugins/accounts/BillionuploadsCom.py +++ b/pyload/plugin/account/BillionuploadsCom.py diff --git a/module/plugins/accounts/BitshareCom.py b/pyload/plugin/account/BitshareCom.py index 4774b9062..4774b9062 100644 --- a/module/plugins/accounts/BitshareCom.py +++ b/pyload/plugin/account/BitshareCom.py diff --git a/module/plugins/accounts/CatShareNet.py b/pyload/plugin/account/CatShareNet.py index a604ebff1..a604ebff1 100644 --- a/module/plugins/accounts/CatShareNet.py +++ b/pyload/plugin/account/CatShareNet.py diff --git a/pyload/plugin/account/CloudzillaTo.py b/pyload/plugin/account/CloudzillaTo.py new file mode 100644 index 000000000..a07621234 --- /dev/null +++ b/pyload/plugin/account/CloudzillaTo.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.Account import Account + + +class CloudzillaTo(Account): + __name__ = "CloudzillaTo" + __type__ = "account" + __version__ = "0.02" + + __description__ = """Cloudzilla.to account plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + PREMIUM_PATTERN = r'<h2>account type</h2>\s*Premium Account' + + + def loadAccountInfo(self, user, req): + html = req.load("http://www.cloudzilla.to/") + + premium = True if re.search(self.PREMIUM_PATTERN, html) else False + + return {'validuntil': -1, 'trafficleft': -1, 'premium': premium} + + + def login(self, user, data, req): + html = req.load("http://www.cloudzilla.to/", + post={'lusername': user, + 'lpassword': data['password'], + 'w' : "dologin"}, + decode=True) + + if "ERROR" in html: + self.wrongPassword() diff --git a/module/plugins/accounts/CramitIn.py b/pyload/plugin/account/CramitIn.py index 21503f625..21503f625 100644 --- a/module/plugins/accounts/CramitIn.py +++ b/pyload/plugin/account/CramitIn.py diff --git a/module/plugins/accounts/CzshareCom.py b/pyload/plugin/account/CzshareCom.py index dfe78c21c..dfe78c21c 100644 --- a/module/plugins/accounts/CzshareCom.py +++ b/pyload/plugin/account/CzshareCom.py diff --git a/module/plugins/accounts/DebridItaliaCom.py b/pyload/plugin/account/DebridItaliaCom.py index de97f6e64..de97f6e64 100644 --- a/module/plugins/accounts/DebridItaliaCom.py +++ b/pyload/plugin/account/DebridItaliaCom.py diff --git a/module/plugins/accounts/DepositfilesCom.py b/pyload/plugin/account/DepositfilesCom.py index b3e896d31..b3e896d31 100644 --- a/module/plugins/accounts/DepositfilesCom.py +++ b/pyload/plugin/account/DepositfilesCom.py diff --git a/pyload/plugin/account/DropboxCom.py b/pyload/plugin/account/DropboxCom.py new file mode 100644 index 000000000..862b7a8df --- /dev/null +++ b/pyload/plugin/account/DropboxCom.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class DropboxCom(SimpleHoster): + __name__ = "DropboxCom" + __type__ = "hoster" + __version__ = "0.04" + + __pattern__ = r'https?://(?:www\.)?dropbox\.com/.+' + + __description__ = """Dropbox.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] + + + NAME_PATTERN = r'<title>Dropbox - (?P<N>.+?)<' + SIZE_PATTERN = r' · (?P<S>[\d.,]+) (?P<U>[\w^_]+)' + + OFFLINE_PATTERN = r'<title>Dropbox - (404|Shared link error)<' + + COOKIES = [("dropbox.com", "lang", "en")] + + + def setup(self): + self.multiDL = True + self.chunkLimit = 1 + self.resumeDownload = True + + + def handleFree(self, pyfile): + self.download(pyfile.url, get={'dl': "1"}) diff --git a/module/plugins/accounts/EasybytezCom.py b/pyload/plugin/account/EasybytezCom.py index c7d717474..c7d717474 100644 --- a/module/plugins/accounts/EasybytezCom.py +++ b/pyload/plugin/account/EasybytezCom.py diff --git a/module/plugins/accounts/EuroshareEu.py b/pyload/plugin/account/EuroshareEu.py index b37fc68fa..b37fc68fa 100644 --- a/module/plugins/accounts/EuroshareEu.py +++ b/pyload/plugin/account/EuroshareEu.py diff --git a/pyload/plugin/account/ExashareCom.py b/pyload/plugin/account/ExashareCom.py new file mode 100644 index 000000000..efd2587c0 --- /dev/null +++ b/pyload/plugin/account/ExashareCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSAccount import XFSAccount + + +class ExashareCom(XFSAccount): + __name__ = "ExashareCom" + __type__ = "account" + __version__ = "0.01" + + __description__ = """Exashare.com account plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + HOSTER_DOMAIN = "exashare.com" diff --git a/module/plugins/accounts/FastixRu.py b/pyload/plugin/account/FastixRu.py index 69f78c3d9..69f78c3d9 100644 --- a/module/plugins/accounts/FastixRu.py +++ b/pyload/plugin/account/FastixRu.py diff --git a/module/plugins/accounts/FastshareCz.py b/pyload/plugin/account/FastshareCz.py index 8fe98438b..8fe98438b 100644 --- a/module/plugins/accounts/FastshareCz.py +++ b/pyload/plugin/account/FastshareCz.py diff --git a/module/plugins/accounts/File4SafeCom.py b/pyload/plugin/account/File4SafeCom.py index c48956d38..c48956d38 100644 --- a/module/plugins/accounts/File4SafeCom.py +++ b/pyload/plugin/account/File4SafeCom.py diff --git a/module/plugins/accounts/FileParadoxIn.py b/pyload/plugin/account/FileParadoxIn.py index 02b923519..02b923519 100644 --- a/module/plugins/accounts/FileParadoxIn.py +++ b/pyload/plugin/account/FileParadoxIn.py diff --git a/module/plugins/accounts/FilecloudIo.py b/pyload/plugin/account/FilecloudIo.py index 6d2dcb92a..6d2dcb92a 100644 --- a/module/plugins/accounts/FilecloudIo.py +++ b/pyload/plugin/account/FilecloudIo.py diff --git a/module/plugins/accounts/FilefactoryCom.py b/pyload/plugin/account/FilefactoryCom.py index 3395b3f90..3395b3f90 100644 --- a/module/plugins/accounts/FilefactoryCom.py +++ b/pyload/plugin/account/FilefactoryCom.py diff --git a/module/plugins/accounts/FilejungleCom.py b/pyload/plugin/account/FilejungleCom.py index 2c476bffb..2c476bffb 100644 --- a/module/plugins/accounts/FilejungleCom.py +++ b/pyload/plugin/account/FilejungleCom.py diff --git a/module/plugins/accounts/FileomCom.py b/pyload/plugin/account/FileomCom.py index 36a11e411..36a11e411 100644 --- a/module/plugins/accounts/FileomCom.py +++ b/pyload/plugin/account/FileomCom.py diff --git a/module/plugins/accounts/FilerNet.py b/pyload/plugin/account/FilerNet.py index f3cc42367..f3cc42367 100644 --- a/module/plugins/accounts/FilerNet.py +++ b/pyload/plugin/account/FilerNet.py diff --git a/module/plugins/accounts/FilerioCom.py b/pyload/plugin/account/FilerioCom.py index 1d9f8744b..1d9f8744b 100644 --- a/module/plugins/accounts/FilerioCom.py +++ b/pyload/plugin/account/FilerioCom.py diff --git a/module/plugins/accounts/FilesMailRu.py b/pyload/plugin/account/FilesMailRu.py index e6afd0168..e6afd0168 100644 --- a/module/plugins/accounts/FilesMailRu.py +++ b/pyload/plugin/account/FilesMailRu.py diff --git a/module/plugins/accounts/FileserveCom.py b/pyload/plugin/account/FileserveCom.py index 9aab88d2b..9aab88d2b 100644 --- a/module/plugins/accounts/FileserveCom.py +++ b/pyload/plugin/account/FileserveCom.py diff --git a/module/plugins/accounts/FourSharedCom.py b/pyload/plugin/account/FourSharedCom.py index 127f9d58a..127f9d58a 100644 --- a/module/plugins/accounts/FourSharedCom.py +++ b/pyload/plugin/account/FourSharedCom.py diff --git a/module/plugins/accounts/FreakshareCom.py b/pyload/plugin/account/FreakshareCom.py index 9c61ac513..9c61ac513 100644 --- a/module/plugins/accounts/FreakshareCom.py +++ b/pyload/plugin/account/FreakshareCom.py diff --git a/module/plugins/accounts/FreeWayMe.py b/pyload/plugin/account/FreeWayMe.py index dcd9d34cf..dcd9d34cf 100644 --- a/module/plugins/accounts/FreeWayMe.py +++ b/pyload/plugin/account/FreeWayMe.py diff --git a/module/plugins/accounts/FshareVn.py b/pyload/plugin/account/FshareVn.py index 282a17751..282a17751 100644 --- a/module/plugins/accounts/FshareVn.py +++ b/pyload/plugin/account/FshareVn.py diff --git a/module/plugins/accounts/Ftp.py b/pyload/plugin/account/Ftp.py index 67cde2cdd..67cde2cdd 100644 --- a/module/plugins/accounts/Ftp.py +++ b/pyload/plugin/account/Ftp.py diff --git a/module/plugins/accounts/HellshareCz.py b/pyload/plugin/account/HellshareCz.py index 94467b375..94467b375 100644 --- a/module/plugins/accounts/HellshareCz.py +++ b/pyload/plugin/account/HellshareCz.py diff --git a/module/plugins/accounts/Http.py b/pyload/plugin/account/Http.py index 2571ef712..2571ef712 100644 --- a/module/plugins/accounts/Http.py +++ b/pyload/plugin/account/Http.py diff --git a/module/plugins/accounts/HugefilesNet.py b/pyload/plugin/account/HugefilesNet.py index eb383fb17..eb383fb17 100644 --- a/module/plugins/accounts/HugefilesNet.py +++ b/pyload/plugin/account/HugefilesNet.py diff --git a/module/plugins/accounts/HundredEightyUploadCom.py b/pyload/plugin/account/HundredEightyUploadCom.py index 72185a4bb..72185a4bb 100644 --- a/module/plugins/accounts/HundredEightyUploadCom.py +++ b/pyload/plugin/account/HundredEightyUploadCom.py diff --git a/pyload/plugin/account/JunkyvideoCom.py b/pyload/plugin/account/JunkyvideoCom.py new file mode 100644 index 000000000..3380b8dc7 --- /dev/null +++ b/pyload/plugin/account/JunkyvideoCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSAccount import XFSAccount + + +class JunkyvideoCom(XFSAccount): + __name__ = "JunkyvideoCom" + __type__ = "account" + __version__ = "0.01" + + __description__ = """Junkyvideo.com account plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + HOSTER_DOMAIN = "junkyvideo.com" diff --git a/module/plugins/accounts/JunocloudMe.py b/pyload/plugin/account/JunocloudMe.py index 0ffa92eb6..0ffa92eb6 100644 --- a/module/plugins/accounts/JunocloudMe.py +++ b/pyload/plugin/account/JunocloudMe.py diff --git a/module/plugins/accounts/Keep2ShareCc.py b/pyload/plugin/account/Keep2ShareCc.py index 7ed15dc62..7ed15dc62 100644 --- a/module/plugins/accounts/Keep2ShareCc.py +++ b/pyload/plugin/account/Keep2ShareCc.py diff --git a/module/plugins/accounts/LetitbitNet.py b/pyload/plugin/account/LetitbitNet.py index d0f08d0bb..d0f08d0bb 100644 --- a/module/plugins/accounts/LetitbitNet.py +++ b/pyload/plugin/account/LetitbitNet.py diff --git a/module/plugins/accounts/LinestorageCom.py b/pyload/plugin/account/LinestorageCom.py index 7a5d63a47..7a5d63a47 100644 --- a/module/plugins/accounts/LinestorageCom.py +++ b/pyload/plugin/account/LinestorageCom.py diff --git a/module/plugins/accounts/LinksnappyCom.py b/pyload/plugin/account/LinksnappyCom.py index 0b1176ee9..0b1176ee9 100644 --- a/module/plugins/accounts/LinksnappyCom.py +++ b/pyload/plugin/account/LinksnappyCom.py diff --git a/module/plugins/accounts/MegaDebridEu.py b/pyload/plugin/account/MegaDebridEu.py index c2e64bcc7..c2e64bcc7 100644 --- a/module/plugins/accounts/MegaDebridEu.py +++ b/pyload/plugin/account/MegaDebridEu.py diff --git a/module/plugins/accounts/MegaRapidCz.py b/pyload/plugin/account/MegaRapidCz.py index 5596fd623..5596fd623 100644 --- a/module/plugins/accounts/MegaRapidCz.py +++ b/pyload/plugin/account/MegaRapidCz.py diff --git a/module/plugins/accounts/MegasharesCom.py b/pyload/plugin/account/MegasharesCom.py index 53b854f65..53b854f65 100644 --- a/module/plugins/accounts/MegasharesCom.py +++ b/pyload/plugin/account/MegasharesCom.py diff --git a/module/plugins/accounts/MovReelCom.py b/pyload/plugin/account/MovReelCom.py index 4d2855de1..4d2855de1 100644 --- a/module/plugins/accounts/MovReelCom.py +++ b/pyload/plugin/account/MovReelCom.py diff --git a/pyload/plugin/account/MultihostersCom.py b/pyload/plugin/account/MultihostersCom.py new file mode 100644 index 000000000..3f5d90c4e --- /dev/null +++ b/pyload/plugin/account/MultihostersCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.account.ZeveraCom import ZeveraCom + + +class MultihostersCom(ZeveraCom): + __name__ = "MultihostersCom" + __type__ = "account" + __version__ = "0.03" + + __description__ = """Multihosters.com account plugin""" + __license__ = "GPLv3" + __authors__ = [("tjeh", "tjeh@gmx.net")] + + + HOSTER_DOMAIN = "multihosters.com" diff --git a/module/plugins/accounts/MultishareCz.py b/pyload/plugin/account/MultishareCz.py index 9b4f4447b..9b4f4447b 100644 --- a/module/plugins/accounts/MultishareCz.py +++ b/pyload/plugin/account/MultishareCz.py diff --git a/module/plugins/accounts/MyfastfileCom.py b/pyload/plugin/account/MyfastfileCom.py index 838a1eefd..838a1eefd 100644 --- a/module/plugins/accounts/MyfastfileCom.py +++ b/pyload/plugin/account/MyfastfileCom.py diff --git a/module/plugins/accounts/NetloadIn.py b/pyload/plugin/account/NetloadIn.py index 68982e828..68982e828 100644 --- a/module/plugins/accounts/NetloadIn.py +++ b/pyload/plugin/account/NetloadIn.py diff --git a/pyload/plugin/account/NoPremiumPl.py b/pyload/plugin/account/NoPremiumPl.py new file mode 100644 index 000000000..929e8f7d9 --- /dev/null +++ b/pyload/plugin/account/NoPremiumPl.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- + +import hashlib + +from datetime import datetime +from time import mktime + +from pyload.plugin.Account import Account +from pyload.utils import json_loads + + +class NoPremiumPl(Account): + __name__ = "NoPremiumPl" + __version__ = "0.01" + __type__ = "account" + __description__ = "NoPremium.pl account plugin" + __license__ = "GPLv3" + __authors__ = [("goddie", "dev@nopremium.pl")] + + _api_url = "http://crypt.nopremium.pl" + + _api_query = { + "site": "nopremium", + "username": "", + "password": "", + "output": "json", + "loc": "1", + "info": "1" + } + + _req = None + _usr = None + _pwd = None + + def loadAccountInfo(self, name, req): + self._req = req + try: + result = json_loads(self.runAuthQuery()) + except Exception: + # todo: return or let it be thrown? + return + + premium = False + valid_untill = -1 + + if "expire" in result.keys() and result["expire"]: + premium = True + valid_untill = mktime(datetime.fromtimestamp(int(result["expire"])).timetuple()) + traffic_left = result["balance"] * 1024 + + return ({ + "validuntil": valid_untill, + "trafficleft": traffic_left, + "premium": premium + }) + + def login(self, user, data, req): + self._usr = user + self._pwd = hashlib.sha1(hashlib.md5(data["password"]).hexdigest()).hexdigest() + self._req = req + + try: + response = json_loads(self.runAuthQuery()) + except Exception: + self.wrongPassword() + + if "errno" in response.keys(): + self.wrongPassword() + data['usr'] = self._usr + data['pwd'] = self._pwd + + def createAuthQuery(self): + query = self._api_query + query["username"] = self._usr + query["password"] = self._pwd + + return query + + def runAuthQuery(self): + data = self._req.load(self._api_url, post=self.createAuthQuery()) + + return data
\ No newline at end of file diff --git a/module/plugins/accounts/NosuploadCom.py b/pyload/plugin/account/NosuploadCom.py index 7fc8b49de..7fc8b49de 100644 --- a/module/plugins/accounts/NosuploadCom.py +++ b/pyload/plugin/account/NosuploadCom.py diff --git a/module/plugins/accounts/NovafileCom.py b/pyload/plugin/account/NovafileCom.py index 71a7dc2dc..71a7dc2dc 100644 --- a/module/plugins/accounts/NovafileCom.py +++ b/pyload/plugin/account/NovafileCom.py diff --git a/module/plugins/accounts/NowVideoSx.py b/pyload/plugin/account/NowVideoSx.py index 8359e0410..8359e0410 100644 --- a/module/plugins/accounts/NowVideoSx.py +++ b/pyload/plugin/account/NowVideoSx.py diff --git a/module/plugins/accounts/OboomCom.py b/pyload/plugin/account/OboomCom.py index 012fb42c3..012fb42c3 100644 --- a/module/plugins/accounts/OboomCom.py +++ b/pyload/plugin/account/OboomCom.py diff --git a/module/plugins/accounts/OneFichierCom.py b/pyload/plugin/account/OneFichierCom.py index 65ec841c4..65ec841c4 100644 --- a/module/plugins/accounts/OneFichierCom.py +++ b/pyload/plugin/account/OneFichierCom.py diff --git a/module/plugins/accounts/OverLoadMe.py b/pyload/plugin/account/OverLoadMe.py index d945dd7bd..d945dd7bd 100644 --- a/module/plugins/accounts/OverLoadMe.py +++ b/pyload/plugin/account/OverLoadMe.py diff --git a/module/plugins/accounts/PremiumTo.py b/pyload/plugin/account/PremiumTo.py index 04bbc10d5..04bbc10d5 100644 --- a/module/plugins/accounts/PremiumTo.py +++ b/pyload/plugin/account/PremiumTo.py diff --git a/module/plugins/accounts/PremiumizeMe.py b/pyload/plugin/account/PremiumizeMe.py index 3cd15ce23..3cd15ce23 100644 --- a/module/plugins/accounts/PremiumizeMe.py +++ b/pyload/plugin/account/PremiumizeMe.py diff --git a/pyload/plugin/account/PutdriveCom.py b/pyload/plugin/account/PutdriveCom.py new file mode 100644 index 000000000..b30fb6565 --- /dev/null +++ b/pyload/plugin/account/PutdriveCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.account.ZeveraCom import ZeveraCom + + +class PutdriveCom(ZeveraCom): + __name__ = "PutdriveCom" + __type__ = "account" + __version__ = "0.02" + + __description__ = """Putdrive.com account plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + HOSTER_DOMAIN = "putdrive.com" diff --git a/module/plugins/accounts/QuickshareCz.py b/pyload/plugin/account/QuickshareCz.py index 2bcde1c9d..2bcde1c9d 100644 --- a/module/plugins/accounts/QuickshareCz.py +++ b/pyload/plugin/account/QuickshareCz.py diff --git a/module/plugins/accounts/RPNetBiz.py b/pyload/plugin/account/RPNetBiz.py index e0b35b68c..e0b35b68c 100644 --- a/module/plugins/accounts/RPNetBiz.py +++ b/pyload/plugin/account/RPNetBiz.py diff --git a/pyload/plugin/account/RapideoPl.py b/pyload/plugin/account/RapideoPl.py new file mode 100644 index 000000000..b4b74fab5 --- /dev/null +++ b/pyload/plugin/account/RapideoPl.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +import hashlib + +from datetime import datetime +from time import mktime + +from pyload.plugin.Account import Account +from pyload.utils import json_loads + + +class RapideoPl(Account): + __name__ = "RapideoPl" + __version__ = "0.01" + __type__ = "account" + __description__ = "Rapideo.pl account plugin" + __license__ = "GPLv3" + __authors__ = [("goddie", "dev@rapideo.pl")] + + _api_url = "http://enc.rapideo.pl" + + _api_query = { + "site": "newrd", + "username": "", + "password": "", + "output": "json", + "loc": "1", + "info": "1" + } + + _req = None + _usr = None + _pwd = None + + def loadAccountInfo(self, name, req): + self._req = req + try: + result = json_loads(self.runAuthQuery()) + except Exception: + # todo: return or let it be thrown? + return + + premium = False + valid_untill = -1 + if "expire" in result.keys() and result["expire"]: + premium = True + valid_untill = mktime(datetime.fromtimestamp(int(result["expire"])).timetuple()) + + traffic_left = result["balance"] + + return ({ + "validuntil": valid_untill, + "trafficleft": traffic_left, + "premium": premium + }) + + def login(self, user, data, req): + self._usr = user + self._pwd = hashlib.md5(data["password"]).hexdigest() + self._req = req + try: + response = json_loads(self.runAuthQuery()) + except Exception: + self.wrongPassword() + + if "errno" in response.keys(): + self.wrongPassword() + data['usr'] = self._usr + data['pwd'] = self._pwd + + def createAuthQuery(self): + query = self._api_query + query["username"] = self._usr + query["password"] = self._pwd + + return query + + def runAuthQuery(self): + data = self._req.load(self._api_url, post=self.createAuthQuery()) + + return data
\ No newline at end of file diff --git a/module/plugins/accounts/RapidfileshareNet.py b/pyload/plugin/account/RapidfileshareNet.py index ec0bf8db4..ec0bf8db4 100644 --- a/module/plugins/accounts/RapidfileshareNet.py +++ b/pyload/plugin/account/RapidfileshareNet.py diff --git a/module/plugins/accounts/RapidgatorNet.py b/pyload/plugin/account/RapidgatorNet.py index 7643f07d2..7643f07d2 100644 --- a/module/plugins/accounts/RapidgatorNet.py +++ b/pyload/plugin/account/RapidgatorNet.py diff --git a/pyload/plugin/account/RapiduNet.py b/pyload/plugin/account/RapiduNet.py new file mode 100644 index 000000000..5c165f486 --- /dev/null +++ b/pyload/plugin/account/RapiduNet.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- + +import re + +from time import time + +from pyload.plugin.Account import Account +from pyload.utils import json_loads + + +class RapiduNet(Account): + __name__ = "RapiduNet" + __type__ = "account" + __version__ = "0.05" + + __description__ = """Rapidu.net account plugin""" + __license__ = "GPLv3" + __authors__ = [("prOq", None), + ("Walter Purcaro", "vuolter@gmail.com")] + + + PREMIUM_PATTERN = r'>Account: <b>Premium' + + VALID_UNTIL_PATTERN = r'>Account: <b>\w+ \((\d+)' + + TRAFFIC_LEFT_PATTERN = r'class="tipsyS"><b>(.+?)<' + + + def loadAccountInfo(self, user, req): + validuntil = None + trafficleft = -1 + premium = False + + html = req.load("https://rapidu.net/", decode=True) + + if re.search(self.PREMIUM_PATTERN, html): + premium = True + + m = re.search(self.VALID_UNTIL_PATTERN, html) + if m: + validuntil = time() + (86400 * int(m.group(1))) + + m = re.search(self.TRAFFIC_LEFT_PATTERN, html) + if m: + trafficleft = self.parseTraffic(m.group(1)) + + return {'validuntil': validuntil, 'trafficleft': trafficleft, 'premium': premium} + + + def login(self, user, data, req): + req.load("https://rapidu.net/ajax.php", + get={'a': "getChangeLang"}, + post={'_go' : "", + 'lang': "en"}) + + json = json_loads(req.load("https://rapidu.net/ajax.php", + get={'a': "getUserLogin"}, + post={'_go' : "", + 'login' : user, + 'pass' : data['password'], + 'remember': "1"})) + + self.logDebug(json) + + if not json['message'] == "success": + self.wrongPassword() diff --git a/module/plugins/accounts/RarefileNet.py b/pyload/plugin/account/RarefileNet.py index 1dc93681c..1dc93681c 100644 --- a/module/plugins/accounts/RarefileNet.py +++ b/pyload/plugin/account/RarefileNet.py diff --git a/module/plugins/accounts/RealdebridCom.py b/pyload/plugin/account/RealdebridCom.py index 07ff70496..07ff70496 100644 --- a/module/plugins/accounts/RealdebridCom.py +++ b/pyload/plugin/account/RealdebridCom.py diff --git a/module/plugins/accounts/RehostTo.py b/pyload/plugin/account/RehostTo.py index d62e1918a..d62e1918a 100644 --- a/module/plugins/accounts/RehostTo.py +++ b/pyload/plugin/account/RehostTo.py diff --git a/module/plugins/accounts/RyushareCom.py b/pyload/plugin/account/RyushareCom.py index 466d971f6..466d971f6 100644 --- a/module/plugins/accounts/RyushareCom.py +++ b/pyload/plugin/account/RyushareCom.py diff --git a/module/plugins/accounts/SafesharingEu.py b/pyload/plugin/account/SafesharingEu.py index f5cbf050e..f5cbf050e 100644 --- a/module/plugins/accounts/SafesharingEu.py +++ b/pyload/plugin/account/SafesharingEu.py diff --git a/module/plugins/accounts/SecureUploadEu.py b/pyload/plugin/account/SecureUploadEu.py index bb47bcba3..bb47bcba3 100644 --- a/module/plugins/accounts/SecureUploadEu.py +++ b/pyload/plugin/account/SecureUploadEu.py diff --git a/module/plugins/accounts/SendmywayCom.py b/pyload/plugin/account/SendmywayCom.py index d64658de3..d64658de3 100644 --- a/module/plugins/accounts/SendmywayCom.py +++ b/pyload/plugin/account/SendmywayCom.py diff --git a/module/plugins/accounts/ShareonlineBiz.py b/pyload/plugin/account/ShareonlineBiz.py index 28bc3b9bc..28bc3b9bc 100644 --- a/module/plugins/accounts/ShareonlineBiz.py +++ b/pyload/plugin/account/ShareonlineBiz.py diff --git a/module/plugins/accounts/SimplyPremiumCom.py b/pyload/plugin/account/SimplyPremiumCom.py index 298ad8d59..298ad8d59 100644 --- a/module/plugins/accounts/SimplyPremiumCom.py +++ b/pyload/plugin/account/SimplyPremiumCom.py diff --git a/module/plugins/accounts/SimplydebridCom.py b/pyload/plugin/account/SimplydebridCom.py index a826e44c7..a826e44c7 100644 --- a/module/plugins/accounts/SimplydebridCom.py +++ b/pyload/plugin/account/SimplydebridCom.py diff --git a/pyload/plugin/account/SmoozedCom.py b/pyload/plugin/account/SmoozedCom.py new file mode 100644 index 000000000..27249c7c2 --- /dev/null +++ b/pyload/plugin/account/SmoozedCom.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +import hashlib + +from beaker.crypto.pbkdf2 import PBKDF2 +from time import time + +from pyload.utils import json_loads +from pyload.plugin.Account import Account + + +class SmoozedCom(Account): + __name__ = "SmoozedCom" + __type__ = "account" + __version__ = "0.03" + + __description__ = """Smoozed.com account plugin""" + __license__ = "GPLv3" + __authors__ = [("", "")] + + + def loadAccountInfo(self, user, req): + # Get user data from premiumize.me + status = self.getAccountStatus(user, req) + + self.logDebug(status) + + if status['state'] != 'ok': + info = {'validuntil' : None, + 'trafficleft': None, + 'premium' : False} + else: + # Parse account info + info = {'validuntil' : float(status["data"]["user"]["user_premium"]), + 'trafficleft': max(0, status["data"]["traffic"][1] - status["data"]["traffic"][0]), + 'session' : status["data"]["session_key"], + 'hosters' : [hoster["name"] for hoster in status["data"]["hoster"]]} + + if info['validuntil'] < time(): + info['premium'] = False + else: + info['premium'] = True + + return info + + + def login(self, user, data, req): + # Get user data from premiumize.me + status = self.getAccountStatus(user, req) + + # Check if user and password are valid + if status['state'] != 'ok': + self.wrongPassword() + + + def getAccountStatus(self, user, req): + password = self.getAccountData(user)['password'] + salt = hashlib.sha256(password).hexdigest() + encrypted = PBKDF2(password, salt, iterations=1000).hexread(32) + + return json_loads(req.load("http://www2.smoozed.com/api/login", + get={'auth': user, 'password': encrypted})) diff --git a/module/plugins/accounts/StahnuTo.py b/pyload/plugin/account/StahnuTo.py index ed8df3b77..ed8df3b77 100644 --- a/module/plugins/accounts/StahnuTo.py +++ b/pyload/plugin/account/StahnuTo.py diff --git a/module/plugins/accounts/StreamcloudEu.py b/pyload/plugin/account/StreamcloudEu.py index 3ac74fbd0..3ac74fbd0 100644 --- a/module/plugins/accounts/StreamcloudEu.py +++ b/pyload/plugin/account/StreamcloudEu.py diff --git a/module/plugins/accounts/TurbobitNet.py b/pyload/plugin/account/TurbobitNet.py index e3c07da2a..e3c07da2a 100644 --- a/module/plugins/accounts/TurbobitNet.py +++ b/pyload/plugin/account/TurbobitNet.py diff --git a/module/plugins/accounts/TusfilesNet.py b/pyload/plugin/account/TusfilesNet.py index 84e9ef9c6..84e9ef9c6 100644 --- a/module/plugins/accounts/TusfilesNet.py +++ b/pyload/plugin/account/TusfilesNet.py diff --git a/module/plugins/accounts/UlozTo.py b/pyload/plugin/account/UlozTo.py index 1570419b0..1570419b0 100644 --- a/module/plugins/accounts/UlozTo.py +++ b/pyload/plugin/account/UlozTo.py diff --git a/module/plugins/accounts/UnrestrictLi.py b/pyload/plugin/account/UnrestrictLi.py index d8d7789bb..d8d7789bb 100644 --- a/module/plugins/accounts/UnrestrictLi.py +++ b/pyload/plugin/account/UnrestrictLi.py diff --git a/pyload/plugin/account/UploadableCh.py b/pyload/plugin/account/UploadableCh.py new file mode 100644 index 000000000..9406118cd --- /dev/null +++ b/pyload/plugin/account/UploadableCh.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.Account import Account + + +class UploadableCh(Account): + __name__ = "UploadableCh" + __type__ = "account" + __version__ = "0.03" + + __description__ = """Uploadable.ch account plugin""" + __license__ = "GPLv3" + __authors__ = [("Sasch", "gsasch@gmail.com")] + + + def loadAccountInfo(self, user, req): + html = req.load("http://www.uploadable.ch/login.php") + + premium = '<a href="/logout.php"' in html + trafficleft = -1 if premium else None + + return {'validuntil': None, 'trafficleft': trafficleft, 'premium': premium} #@TODO: validuntil + + + def login(self, user, data, req): + html = req.load("http://www.uploadable.ch/login.php", + post={'userName' : user, + 'userPassword' : data["password"], + 'autoLogin' : "1", + 'action__login': "normalLogin"}, + decode=True) + + if "Login failed" in html: + self.wrongPassword() diff --git a/module/plugins/accounts/UploadcCom.py b/pyload/plugin/account/UploadcCom.py index 66863c456..66863c456 100644 --- a/module/plugins/accounts/UploadcCom.py +++ b/pyload/plugin/account/UploadcCom.py diff --git a/module/plugins/accounts/UploadedTo.py b/pyload/plugin/account/UploadedTo.py index 3b0d957a5..3b0d957a5 100644 --- a/module/plugins/accounts/UploadedTo.py +++ b/pyload/plugin/account/UploadedTo.py diff --git a/module/plugins/accounts/UploadheroCom.py b/pyload/plugin/account/UploadheroCom.py index c73fc30f5..c73fc30f5 100644 --- a/module/plugins/accounts/UploadheroCom.py +++ b/pyload/plugin/account/UploadheroCom.py diff --git a/module/plugins/accounts/UploadingCom.py b/pyload/plugin/account/UploadingCom.py index 6d54469e8..6d54469e8 100644 --- a/module/plugins/accounts/UploadingCom.py +++ b/pyload/plugin/account/UploadingCom.py diff --git a/module/plugins/accounts/UptoboxCom.py b/pyload/plugin/account/UptoboxCom.py index f7cb7a82e..f7cb7a82e 100644 --- a/module/plugins/accounts/UptoboxCom.py +++ b/pyload/plugin/account/UptoboxCom.py diff --git a/module/plugins/accounts/VidPlayNet.py b/pyload/plugin/account/VidPlayNet.py index 390520a00..390520a00 100644 --- a/module/plugins/accounts/VidPlayNet.py +++ b/pyload/plugin/account/VidPlayNet.py diff --git a/pyload/plugin/account/WebshareCz.py b/pyload/plugin/account/WebshareCz.py new file mode 100644 index 000000000..efa2a0045 --- /dev/null +++ b/pyload/plugin/account/WebshareCz.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- + +import re + +from hashlib import md5, sha1 +from passlib.hash import md5_crypt +from time import mktime, strptime, time + +from pyload.plugin.Account import Account + + +class WebshareCz(Account): + __name__ = "WebshareCz" + __type__ = "account" + __version__ = "0.07" + + __description__ = """Webshare.cz account plugin""" + __license__ = "GPLv3" + __authors__ = [("rush", "radek.senfeld@gmail.com")] + + + VALID_UNTIL_PATTERN = r'<vip_until>(.+)</vip_until>' + + TRAFFIC_LEFT_PATTERN = r'<bytes>(.+)</bytes>' + + + def loadAccountInfo(self, user, req): + html = req.load("https://webshare.cz/api/user_data/", + post={'wst': self.infos['wst']}, + decode=True) + + self.logDebug("Response: " + html) + + expiredate = re.search(self.VALID_UNTIL_PATTERN, html).group(1) + self.logDebug("Expire date: " + expiredate) + + validuntil = mktime(strptime(expiredate, "%Y-%m-%d %H:%M:%S")) + trafficleft = self.parseTraffic(re.search(self.TRAFFIC_LEFT_PATTERN, html).group(1)) + premium = validuntil > time() + + return {'validuntil': validuntil, 'trafficleft': -1, 'premium': premium} + + + def login(self, user, data, req): + salt = req.load("https://webshare.cz/api/salt/", + post={'username_or_email': user, + 'wst' : ""}, + decode=True) + + if "<status>OK</status>" not in salt: + self.wrongPassword() + + salt = re.search('<salt>(.+)</salt>', salt).group(1) + password = sha1(md5_crypt.encrypt(data["password"], salt=salt)).hexdigest() + digest = md5(user + ":Webshare:" + password).hexdigest() + + login = req.load("https://webshare.cz/api/login/", + post={'digest' : digest, + 'keep_logged_in' : 1, + 'password' : password, + 'username_or_email': user, + 'wst' : ""}, + decode=True) + + if "<status>OK</status>" not in login: + self.wrongPassword() + + self.infos['wst'] = re.search('<token>(.+)</token>', login).group(1) diff --git a/module/plugins/accounts/XFileSharingPro.py b/pyload/plugin/account/XFileSharingPro.py index 216af5385..216af5385 100644 --- a/module/plugins/accounts/XFileSharingPro.py +++ b/pyload/plugin/account/XFileSharingPro.py diff --git a/module/plugins/accounts/YibaishiwuCom.py b/pyload/plugin/account/YibaishiwuCom.py index 150b0d931..150b0d931 100644 --- a/module/plugins/accounts/YibaishiwuCom.py +++ b/pyload/plugin/account/YibaishiwuCom.py diff --git a/module/plugins/accounts/ZeveraCom.py b/pyload/plugin/account/ZeveraCom.py index db23170f3..db23170f3 100644 --- a/module/plugins/accounts/ZeveraCom.py +++ b/pyload/plugin/account/ZeveraCom.py diff --git a/module/plugins/accounts/__init__.py b/pyload/plugin/account/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/plugins/accounts/__init__.py +++ b/pyload/plugin/account/__init__.py diff --git a/pyload/plugin/addon/AndroidPhoneNotify.py b/pyload/plugin/addon/AndroidPhoneNotify.py new file mode 100644 index 000000000..2b4f8fcca --- /dev/null +++ b/pyload/plugin/addon/AndroidPhoneNotify.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- + +from time import time + +from pyload.network.RequestFactory import getURL +from pyload.plugin.Addon import Addon + + +class AndroidPhoneNotify(Addon): + __name__ = "AndroidPhoneNotify" + __type__ = "addon" + __version__ = "0.05" + + __config__ = [("apikey" , "str" , "API key" , "" ), + ("notifycaptcha" , "bool", "Notify captcha request" , True ), + ("notifypackage" , "bool", "Notify package finished" , True ), + ("notifyprocessed", "bool", "Notify processed packages status" , True ), + ("timeout" , "int" , "Timeout between captchas in seconds" , 5 ), + ("force" , "bool", "Send notifications if client is connected", False)] + + __description__ = """Send push notifications to your Android Phone using notifymyandroid.com""" + __license__ = "GPLv3" + __authors__ = [("Steven Kosyra", "steven.kosyra@gmail.com"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + event_list = ["allDownloadsProcessed"] + + + def setup(self): + self.info = {} #@TODO: Remove in 0.4.10 + self.last_notify = 0 + + + def newCaptchaTask(self, task): + if not self.getConfig("notifycaptcha"): + return False + + if time() - self.last_notify < self.getConf("timeout"): + return False + + self.notify(_("Captcha"), _("New request waiting user input")) + + + def packageFinished(self, pypack): + if self.getConfig("notifypackage"): + self.notify(_("Package finished"), pypack.name) + + + def allDownloadsProcessed(self): + if not self.getConfig("notifyprocessed"): + return False + + if any(True for pdata in self.core.api.getQueue() if pdata.linksdone < pdata.linkstotal): + self.notify(_("Package failed"), _("One or more packages was not completed successfully")) + else: + self.notify(_("All packages finished")) + + + def notify(self, event, msg=""): + apikey = self.getConfig("apikey") + + if not apikey: + return False + + if self.core.isClientConnected() and not self.getConfig("force"): + return False + + getURL("http://www.notifymyandroid.com/publicapi/notify", + get={'apikey' : apikey, + 'application': "pyLoad", + 'event' : event, + 'description': msg}) + + self.last_notify = time() diff --git a/module/plugins/addon/Checksum.py b/pyload/plugin/addon/Checksum.py index 35be60773..35be60773 100644 --- a/module/plugins/addon/Checksum.py +++ b/pyload/plugin/addon/Checksum.py diff --git a/pyload/plugin/addon/ClickAndLoad.py b/pyload/plugin/addon/ClickAndLoad.py new file mode 100644 index 000000000..cd71e9972 --- /dev/null +++ b/pyload/plugin/addon/ClickAndLoad.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- + +import socket + +from threading import Lock + +from pyload.plugin.Addon import Addon, threaded + + +def forward(source, destination): + try: + bufsize = 1024 + bufdata = source.recv(bufsize) + while bufdata: + destination.sendall(bufdata) + bufdata = source.recv(bufsize) + finally: + destination.shutdown(socket.SHUT_WR) + + +#: create_connection wrapper for python 2.5 socket module +def create_connection(address, timeout=object(), source_address=None): + if hasattr(socket, 'create_connection'): + if type(timeout) == object: + timeout = socket._GLOBAL_DEFAULT_TIMEOUT + + return socket.create_connection(address, timeout, source_address) + + else: + host, port = address + err = None + for res in getaddrinfo(host, port, 0, SOCK_STREAM): + af, socktype, proto, canonname, sa = res + sock = None + try: + sock = socket(af, socktype, proto) + if type(timeout) != object: + sock.settimeout(timeout) + if source_address: + sock.bind(source_address) + sock.connect(sa) + return sock + + except socket.error, _: + err = _ + if sock is not None: + sock.close() + + if err is not None: + raise err + else: + raise socket.error("getaddrinfo returns an empty list") + + +class ClickAndLoad(Addon): + __name__ = "ClickAndLoad" + __type__ = "addon" + __version__ = "0.35" + + __config__ = [("activated", "bool", "Activated" , True), + ("port" , "int" , "Port" , 9666), + ("extern" , "bool", "Listen on the public network interface", True)] + + __description__ = """Click'N'Load addon plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.de"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + def activate(self): + if not self.config['webinterface']['activated']: + return + + ip = socket.gethostbyname(socket.gethostname()) if self.getConfig("extern") else "127.0.0.1" + webport = int(self.config['webinterface']['port']) + cnlport = self.getConfig('port') + + self.proxy(ip, webport, cnlport) + + + @threaded + def proxy(self, ip, webport, cnlport): + self.manager.startThread(self._server, ip, webport, cnlport) + lock = Lock() + lock.acquire() + lock.acquire() + + + def _server(self, ip, webport, cnlport, thread): + try: + server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server_socket.bind((ip, cnlport)) + server_socket.listen(5) + + while True: + client_socket = server_socket.accept()[0] + dock_socket = create_connection(("127.0.0.1", webport)) + + self.manager.startThread(forward, dock_socket, client_socket) + self.manager.startThread(forward, client_socket, dock_socket) + + except socket.error, e: + self.logDebug(e) + self._server(ip, webport, cnlport, thread) + + except Exception, e: + self.logError(e) + + try: + client_socket.close() + dock_socket.close() + except Exception: + pass + + try: + server_socket.close() + except Exception: + pass diff --git a/module/plugins/addon/DeleteFinished.py b/pyload/plugin/addon/DeleteFinished.py index 59f2e3321..59f2e3321 100644 --- a/module/plugins/addon/DeleteFinished.py +++ b/pyload/plugin/addon/DeleteFinished.py diff --git a/module/plugins/addon/DownloadScheduler.py b/pyload/plugin/addon/DownloadScheduler.py index e5e25e389..e5e25e389 100644 --- a/module/plugins/addon/DownloadScheduler.py +++ b/pyload/plugin/addon/DownloadScheduler.py diff --git a/module/plugins/addon/ExternalScripts.py b/pyload/plugin/addon/ExternalScripts.py index 5aebf2338..5aebf2338 100644 --- a/module/plugins/addon/ExternalScripts.py +++ b/pyload/plugin/addon/ExternalScripts.py diff --git a/pyload/plugin/addon/ExtractArchive.py b/pyload/plugin/addon/ExtractArchive.py new file mode 100644 index 000000000..951434e3e --- /dev/null +++ b/pyload/plugin/addon/ExtractArchive.py @@ -0,0 +1,504 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import os +import sys + +from copy import copy +from traceback import print_exc + +# monkey patch bug in python 2.6 and lower +# http://bugs.python.org/issue6122 , http://bugs.python.org/issue1236 , http://bugs.python.org/issue1731717 +if sys.version_info < (2, 7) and os.name != "nt": + import errno + + from subprocess import Popen + + def _eintr_retry_call(func, *args): + while True: + try: + return func(*args) + + except OSError, e: + if e.errno == errno.EINTR: + continue + raise + + + # unsued timeout option for older python version + def wait(self, timeout=0): + """Wait for child process to terminate. Returns returncode + attribute.""" + if self.returncode is None: + try: + pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0) + except OSError, e: + if e.errno != errno.ECHILD: + raise + # This happens if SIGCLD is set to be ignored or waiting + # for child processes has otherwise been disabled for our + # process. This child is dead, we can't get the status. + sts = 0 + self._handle_exitstatus(sts) + return self.returncode + + Popen.wait = wait + +if os.name != "nt": + from grp import getgrnam + from pwd import getpwnam + +from pyload.plugin.Addon import Addon, threaded, Expose +from pyload.plugin.internal.Extractor import ArchiveError, CRCError, PasswordError +from pyload.plugin.internal.SimpleHoster import replace_patterns +from pyload.utils import fs_encode, safe_join, uniqify + + +class ArchiveQueue(object): + + def __init__(self, plugin, storage): + self.plugin = plugin + self.storage = storage + + + def get(self): + try: + return [int(pid) for pid in self.plugin.getStorage("ExtractArchive:%s" % self.storage, "").decode('base64').split()] + except Exception: + return [] + + + def set(self, value): + if isinstance(value, list): + item = str(value)[1:-1].replace(' ', '').replace(',', ' ') + else: + item = str(value).strip() + return self.plugin.setStorage("ExtractArchive:%s" % self.storage, item.encode('base64')[:-1]) + + + def delete(self): + return self.plugin.delStorage("ExtractArchive:%s" % self.storage) + + + def add(self, item): + queue = self.get() + if item not in queue: + return self.set(queue + [item]) + else: + return True + + + def remove(self, item): + queue = self.get() + try: + queue.remove(item) + except ValueError: + pass + if queue == []: + return self.delete() + return self.set(queue) + + + +class ExtractArchive(Addon): + __name__ = "ExtractArchive" + __type__ = "addon" + __version__ = "1.29" + + __config__ = [("activated" , "bool" , "Activated" , True ), + ("fullpath" , "bool" , "Extract with full paths" , True ), + ("overwrite" , "bool" , "Overwrite files" , False ), + ("keepbroken" , "bool" , "Try to extract broken archives" , False ), + ("repair" , "bool" , "Repair broken archives" , True ), + ("usepasswordfile" , "bool" , "Use password file" , True ), + ("passwordfile" , "file" , "Password file" , "archive_password.txt" ), + ("delete" , "bool" , "Delete archive when successfully extracted", False ), + ("subfolder" , "bool" , "Create subfolder for each package" , False ), + ("destination" , "folder", "Extract files to folder" , "" ), + ("extensions" , "str" , "Extract the following extensions" , "7z,bz2,bzip2,gz,gzip,lha,lzh,lzma,rar,tar,taz,tbz,tbz2,tgz,xar,xz,z,zip"), + ("excludefiles" , "str" , "Don't extract the following files" , "*.nfo,*.DS_Store,index.dat,thumb.db" ), + ("recursive" , "bool" , "Extract archives in archives" , True ), + ("waitall" , "bool" , "Wait for all downloads to be finished" , False ), + ("renice" , "int" , "CPU priority" , 0 )] + + __description__ = """Extract different kind of archives""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com"), + ("Immenz" , "immenz@gmx.net" )] + + + event_list = ["allDownloadsProcessed"] + + NAME_REPLACEMENTS = [(r'\.part\d+\.rar$', ".part.rar")] + + + def setup(self): + self.queue = ArchiveQueue(self, "Queue") + self.failed = ArchiveQueue(self, "Failed") + + self.interval = 60 + self.extracting = False + self.extractors = [] + self.passwords = [] + + + def activate(self): + # self.extracting = False + + for p in ("UnRar", "SevenZip", "UnZip"): + try: + module = self.core.pluginManager.loadModule("internal", p) + klass = getattr(module, p) + if klass.isUsable(): + self.extractors.append(klass) + + except OSError, e: + if e.errno == 2: + self.logInfo(_("No %s installed") % p) + else: + self.logWarning(_("Could not activate: %s") % p, e) + if self.core.debug: + print_exc() + + except Exception, e: + self.logWarning(_("Could not activate: %s") % p, e) + if self.core.debug: + print_exc() + + if self.extractors: + self.logInfo(_("Activated") + " " + "|".join("%s %s" % (Extractor.__name__,Extractor.VERSION) for Extractor in self.extractors)) + + if self.getConfig("waitall"): + self.extractPackage(*self.queue.get()) #: Resume unfinished extractions + else: + super(ExtractArchive, self).initPeriodical() + + else: + self.logInfo(_("No Extract plugins activated")) + + + def periodical(self): + if not self.extracting: + self.extractPackage(*self.queue.get()) + + + @Expose + def extractPackage(self, *ids): + """ Extract packages with given id""" + self.manager.startThread(self.extract, ids) + + + def packageFinished(self, pypack): + self.queue.add(pypack.id) + + + @threaded + def allDownloadsProcessed(self, thread): + if self.extract(self.queue.get(), thread): #@NOTE: check only if all gone fine, no failed reporting for now + self.manager.dispatchEvent("all_archives_extracted") + + self.manager.dispatchEvent("all_archives_processed") + + + def extract(self, ids, thread=None): + if not ids: + return False + + self.extracting = True + + processed = [] + extracted = [] + failed = [] + + toList = lambda string: string.replace(' ', '').replace(',', '|').replace(';', '|').split('|') + + destination = self.getConfig("destination") + subfolder = self.getConfig("subfolder") + fullpath = self.getConfig("fullpath") + overwrite = self.getConfig("overwrite") + renice = self.getConfig("renice") + recursive = self.getConfig("recursive") + delete = self.getConfig("delete") + keepbroken = self.getConfig("keepbroken") + + extensions = [x.lstrip('.').lower() for x in toList(self.getConfig("extensions"))] + excludefiles = toList(self.getConfig("excludefiles")) + + if extensions: + self.logDebug("Use for extensions: %s" % "|.".join(extensions)) + + # reload from txt file + self.reloadPasswords() + + # dl folder + dl = self.config['general']['download_folder'] + + #iterate packages -> extractors -> targets + for pid in ids: + pypack = self.core.files.getPackage(pid) + + if not pypack: + continue + + self.logInfo(_("Check package: %s") % pypack.name) + + # determine output folder + out = safe_join(dl, pypack.folder, destination, "") #: force trailing slash + + if subfolder: + out = safe_join(out, pypack.folder) + + if not os.path.exists(out): + os.makedirs(out) + + matched = False + success = True + files_ids = [(safe_join(dl, pypack.folder, pylink['name']), pylink['id'], out) for pylink in pypack.getChildren().itervalues()] + + # check as long there are unseen files + while files_ids: + new_files_ids = [] + + if extensions: + files_ids = [(fname, fid, fout) for fname, fid, fout in files_ids \ + if filter(lambda ext: fname.lower().endswith(ext), extensions)] + + for Extractor in self.extractors: + targets = Extractor.getTargets(files_ids) + if targets: + self.logDebug("Targets for %s: %s" % (Extractor.__name__, targets)) + matched = True + + for fname, fid, fout in targets: + name = os.path.basename(fname) + + if not os.path.exists(fname): + self.logDebug(name, "File not found") + continue + + self.logInfo(name, _("Extract to: %s") % fout) + try: + archive = Extractor(self, + fname, + fout, + fullpath, + overwrite, + excludefiles, + renice, + delete, + keepbroken, + fid) + archive.init() + + new_files = self._extract(archive, fid, pypack.password, thread) + + except Exception, e: + self.logError(name, e) + success = False + continue + + files_ids.remove((fname, fid, fout)) # don't let other extractors spam log + self.logDebug("Extracted files: %s" % new_files) + self.setPermissions(new_files) + + for filename in new_files: + file = fs_encode(safe_join(os.path.dirname(archive.filename), filename)) + if not os.path.exists(file): + self.logDebug("New file %s does not exists" % filename) + continue + + if recursive and os.path.isfile(file): + new_files_ids.append((filename, fid, os.path.dirname(filename))) # append as new target + + files_ids = new_files_ids # also check extracted files + + if matched: + if success: + extracted.append(pid) + self.manager.dispatchEvent("package_extracted", pypack) + else: + failed.append(pid) + self.manager.dispatchEvent("package_extract_failed", pypack) + + self.failed.add(pid) + else: + self.logInfo(_("No files found to extract")) + + if not matched or not success and subfolder: + try: + os.rmdir(out) + + except OSError: + pass + + self.queue.remove(pid) + + self.extracting = False + return True if not failed else False + + + def _extract(self, archive, fid, password, thread): + pyfile = self.core.files.getFile(fid) + name = os.path.basename(archive.filename) + + thread.addActive(pyfile) + pyfile.setStatus("processing") + + encrypted = False + try: + try: + archive.check() + + except CRCError, e: + self.logDebug(name, e) + self.logInfo(name, _("Header protected")) + + if self.getConfig("repair"): + self.logWarning(name, _("Repairing...")) + + pyfile.setCustomStatus(_("repairing")) + pyfile.setProgress(0) + + repaired = archive.repair() + + pyfile.setProgress(100) + + if not repaired and not self.getConfig("keepbroken"): + raise CRCError("Archive damaged") + + except PasswordError: + self.logInfo(name, _("Password protected")) + encrypted = True + + except ArchiveError, e: + raise ArchiveError(e) + + self.logDebug("Password: %s" % (password or "No provided")) + + pyfile.setCustomStatus(_("extracting")) + pyfile.setProgress(0) + + if not encrypted or not self.getConfig("usepasswordfile"): + archive.extract(password) + else: + for pw in filter(None, uniqify([password] + self.getPasswords(False))): + try: + self.logDebug("Try password: %s" % pw) + + ispw = archive.isPassword(pw) + if ispw or ispw is None: + archive.extract(pw) + self.addPassword(pw) + break + + except PasswordError: + self.logDebug("Password was wrong") + else: + raise PasswordError + + pyfile.setProgress(100) + pyfile.setCustomStatus(_("finalizing")) + + if self.core.debug: + self.logDebug("Would delete: %s" % ", ".join(archive.getDeleteFiles())) + + if self.getConfig("delete"): + files = archive.getDeleteFiles() + self.logInfo(_("Deleting %s files") % len(files)) + for f in files: + file = fs_encode(f) + if os.path.exists(file): + os.remove(file) + else: + self.logDebug("%s does not exists" % f) + + self.logInfo(name, _("Extracting finished")) + + extracted_files = archive.files or archive.list() + self.manager.dispatchEvent("archive_extracted", pyfile, archive.out, archive.filename, extracted_files) + + return extracted_files + + except PasswordError: + self.logError(name, _("Wrong password" if password else "No password found")) + + except CRCError, e: + self.logError(name, _("CRC mismatch"), e) + + except ArchiveError, e: + self.logError(name, _("Archive error"), e) + + except Exception, e: + self.logError(name, _("Unknown error"), e) + if self.core.debug: + print_exc() + + finally: + pyfile.finishIfDone() + + self.manager.dispatchEvent("archive_extract_failed", pyfile) + + raise Exception(_("Extract failed")) + + + @Expose + def getPasswords(self, reload=True): + """ List of saved passwords """ + if reload: + self.reloadPasswords() + + return self.passwords + + + def reloadPasswords(self): + try: + passwords = [] + + file = fs_encode(self.getConfig("passwordfile")) + with open(file) as f: + for pw in f.read().splitlines(): + passwords.append(pw) + + except IOError, e: + self.logError(e) + + else: + self.passwords = passwords + + + @Expose + def addPassword(self, password): + """ Adds a password to saved list""" + try: + self.passwords = uniqify([password] + self.passwords) + + file = fs_encode(self.getConfig("passwordfile")) + with open(file, "wb") as f: + for pw in self.passwords: + f.write(pw + '\n') + + except IOError, e: + self.logError(e) + + + def setPermissions(self, files): + for f in files: + if not os.path.exists(f): + continue + + try: + if self.config['permission']['change_file']: + if os.path.isfile(f): + os.chmod(f, int(self.config['permission']['file'], 8)) + + elif os.path.isdir(f): + os.chmod(f, int(self.config['permission']['folder'], 8)) + + if self.config['permission']['change_dl'] and os.name != "nt": + uid = getpwnam(self.config['permission']['user'])[2] + gid = getgrnam(self.config['permission']['group'])[2] + os.chown(f, uid, gid) + + except Exception, e: + self.logWarning(_("Setting User and Group failed"), e) diff --git a/module/plugins/addon/HotFolder.py b/pyload/plugin/addon/HotFolder.py index eb607ac7e..eb607ac7e 100644 --- a/module/plugins/addon/HotFolder.py +++ b/pyload/plugin/addon/HotFolder.py diff --git a/module/plugins/addon/IRCInterface.py b/pyload/plugin/addon/IRCInterface.py index 86d9ea688..86d9ea688 100644 --- a/module/plugins/addon/IRCInterface.py +++ b/pyload/plugin/addon/IRCInterface.py diff --git a/pyload/plugin/addon/JustPremium.py b/pyload/plugin/addon/JustPremium.py new file mode 100644 index 000000000..d3c4d8eff --- /dev/null +++ b/pyload/plugin/addon/JustPremium.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.Addon import Addon + + +class JustPremium(Addon): + __name__ = "JustPremium" + __type__ = "addon" + __version__ = "0.21" + + __config__ = [("excluded", "str", "Exclude hosters (comma separated)", "")] + + __description__ = """Remove all not premium links from urls added""" + __license__ = "GPLv3" + __authors__ = [("mazleu", "mazleica@gmail.com"), + ("Walter Purcaro", "vuolter@gmail.com"), + ("immenz", "immenz@gmx.net")] + + + event_list = ["linksAdded"] + + + def linksAdded(self, links, pid): + hosterdict = self.core.pluginManager.hosterPlugins + linkdict = self.core.api.checkURLs(links) + + premiumplugins = set(account.type for account in self.core.api.getAccounts(False) \ + if account.valid and account.premium) + multihosters = set(hoster for hoster in self.core.pluginManager.hosterPlugins \ + if 'new_name' in hosterdict[hoster] \ + and hosterdict[hoster]['new_name'] in premiumplugins) + + #: Found at least one hoster with account or multihoster + if not any(True for pluginname in linkdict if pluginname in premiumplugins | multihosters): + return + + excluded = map(lambda domain: "".join(part.capitalize() for part in re.split(r'(\.|\d+)', domain) if part != '.'), + self.getConfig('excluded').replace(' ', '').replace(',', '|').replace(';', '|').split('|')) + + for pluginname in set(linkdict.keys()) - (premiumplugins | multihosters).union(excluded): + self.logInfo(_("Remove links of plugin: %s") % pluginname) + for link in linkdict[pluginname]: + self.logDebug("Remove link: %s" % link) + links.remove(link) diff --git a/pyload/plugin/addon/MergeFiles.py b/pyload/plugin/addon/MergeFiles.py new file mode 100644 index 000000000..11e869aee --- /dev/null +++ b/pyload/plugin/addon/MergeFiles.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import os +import re + +from traceback import print_exc + +from pyload.plugin.Addon import Addon, threaded +from pyload.utils import safe_join + + +class MergeFiles(Addon): + __name__ = "MergeFiles" + __type__ = "addon" + __version__ = "0.14" + + __config__ = [("activated", "bool", "Activated", True)] + + __description__ = """Merges parts splitted with hjsplit""" + __license__ = "GPLv3" + __authors__ = [("and9000", "me@has-no-mail.com")] + + + BUFFER_SIZE = 4096 + + + def setup(self): + pass + + + @threaded + def packageFinished(self, pack): + files = {} + fid_dict = {} + for fid, data in pack.getChildren().iteritems(): + if re.search("\.\d{3}$", data['name']): + if data['name'][:-4] not in files: + files[data['name'][:-4]] = [] + files[data['name'][:-4]].append(data['name']) + files[data['name'][:-4]].sort() + fid_dict[data['name']] = fid + + download_folder = self.config['general']['download_folder'] + + if self.config['general']['folder_per_package']: + download_folder = safe_join(download_folder, pack.folder) + + for name, file_list in files.iteritems(): + self.logInfo(_("Starting merging of"), name) + + final_file = open(safe_join(download_folder, name), "wb") + for splitted_file in file_list: + self.logDebug("Merging part", splitted_file) + + pyfile = self.core.files.getFile(fid_dict[splitted_file]) + + pyfile.setStatus("processing") + + try: + with open(safe_join(download_folder, splitted_file), "rb") as s_file: + size_written = 0 + s_file_size = int(os.path.getsize(os.path.join(download_folder, splitted_file))) + + while True: + f_buffer = s_file.read(self.BUFFER_SIZE) + if f_buffer: + final_file.write(f_buffer) + size_written += self.BUFFER_SIZE + pyfile.setProgress((size_written * 100) / s_file_size) + else: + break + + self.logDebug("Finished merging part", splitted_file) + + except Exception, e: + print_exc() + + finally: + pyfile.setProgress(100) + pyfile.setStatus("finished") + pyfile.release() + + self.logInfo(_("Finished merging of"), name) diff --git a/module/plugins/addon/MultiHome.py b/pyload/plugin/addon/MultiHome.py index 521749fc8..521749fc8 100644 --- a/module/plugins/addon/MultiHome.py +++ b/pyload/plugin/addon/MultiHome.py diff --git a/module/plugins/addon/RestartFailed.py b/pyload/plugin/addon/RestartFailed.py index 2fe5f13bf..2fe5f13bf 100644 --- a/module/plugins/addon/RestartFailed.py +++ b/pyload/plugin/addon/RestartFailed.py diff --git a/module/plugins/addon/RestartSlow.py b/pyload/plugin/addon/RestartSlow.py index 332047da7..332047da7 100644 --- a/module/plugins/addon/RestartSlow.py +++ b/pyload/plugin/addon/RestartSlow.py diff --git a/pyload/plugin/addon/SkipRev.py b/pyload/plugin/addon/SkipRev.py new file mode 100644 index 000000000..efc96cb7b --- /dev/null +++ b/pyload/plugin/addon/SkipRev.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- + +from types import MethodType +from urllib import unquote +from urlparse import urlparse + +from pyload.datatype.File import PyFile +from pyload.plugin.Addon import Addon +from pyload.plugin.Plugin import SkipDownload + + +def _setup(self): + self.pyfile.plugin._setup() + if self.pyfile.hasStatus("skipped"): + raise SkipDownload(self.pyfile.statusname or self.pyfile.pluginname) + + +class SkipRev(Addon): + __name__ = "SkipRev" + __type__ = "addon" + __version__ = "0.25" + + __config__ = [("tokeep", "int", "Number of rev files to keep for package (-1 to auto)", -1)] + + __description__ = """Skip files ending with extension rev""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + def _pyname(self, pyfile): + if hasattr(pyfile.pluginmodule, "getInfo"): + return getattr(pyfile.pluginmodule, "getInfo")([pyfile.url]).next()[0] + else: + self.logWarning("Unable to grab file name") + return urlparse(unquote(pyfile.url)).path.split('/')[-1] + + + def _pyfile(self, link): + return PyFile(self.core.files, + link.fid, + link.url, + link.name, + link.size, + link.status, + link.error, + link.plugin, + link.packageID, + link.order) + + + def downloadPreparing(self, pyfile): + if pyfile.statusname is "unskipped" or not self._pyname(pyfile).endswith(".rev"): + return + + tokeep = self.getConfig("tokeep") + + if tokeep: + status_list = (1, 4, 8, 9, 14) if tokeep < 0 else (1, 3, 4, 8, 9, 14) + + queued = [True for link in self.core.api.getPackageData(pyfile.package().id).links \ + if link.name.endswith(".rev") and link.status not in status_list].count(True) + + if not queued or queued < tokeep: #: keep one rev at least in auto mode + return + + pyfile.setCustomStatus("SkipRev", "skipped") + pyfile.plugin._setup = pyfile.plugin.setup + pyfile.plugin.setup = MethodType(_setup, pyfile.plugin) #: work-around: inject status checker inside the preprocessing routine of the plugin + + + def downloadFailed(self, pyfile): + #: Check if pyfile is still "failed", + # maybe might has been restarted in meantime + if pyfile.status != 8: + return + + tokeep = self.getConfig("tokeep") + + if not tokeep: + return + + for link in self.core.api.getPackageData(pyfile.package().id).links: + if link.status is 4 and link.name.endswith(".rev"): + pylink = self._pyfile(link) + + if tokeep > -1 or pyfile.name.endswith(".rev"): + pylink.setStatus("queued") + else: + pylink.setCustomStatus("unskipped", "queued") + + self.core.files.save() + pylink.release() + return diff --git a/pyload/plugin/addon/UnSkipOnFail.py b/pyload/plugin/addon/UnSkipOnFail.py new file mode 100644 index 000000000..7d787d1ed --- /dev/null +++ b/pyload/plugin/addon/UnSkipOnFail.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- + +from pyload.datatype.File import PyFile +from pyload.plugin.Addon import Addon + + +class UnSkipOnFail(Addon): + __name__ = "UnSkipOnFail" + __type__ = "addon" + __version__ = "0.05" + + __config__ = [("activated", "bool", "Activated", True)] + + __description__ = """Queue skipped duplicates when download fails""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + def downloadFailed(self, pyfile): + #: Check if pyfile is still "failed", + # maybe might has been restarted in meantime + if pyfile.status != 8: + return + + msg = _("Looking for skipped duplicates of: %s (pid:%s)") + self.logInfo(msg % (pyfile.name, pyfile.package().id)) + + dup = self.findDuplicate(pyfile) + if dup: + self.logInfo(_("Queue found duplicate: %s (pid:%s)") % (dup.name, dup.packageID)) + + #: Change status of "link" to "new_status". + # "link" has to be a valid FileData object, + # "new_status" has to be a valid status name + # (i.e. "queued" for this Plugin) + # It creates a temporary PyFile object using + # "link" data, changes its status, and tells + # the core.files-manager to save its data. + pylink = _pyfile(link) + + pylink.setCustomStatus("UnSkipOnFail", "queued") + + self.core.files.save() + pylink.release() + + else: + self.logInfo(_("No duplicates found")) + + + def findDuplicate(self, pyfile): + """ Search all packages for duplicate links to "pyfile". + Duplicates are links that would overwrite "pyfile". + To test on duplicity the package-folder and link-name + of twolinks are compared (link.name). + So this method returns a list of all links with equal + package-folders and filenames as "pyfile", but except + the data for "pyfile" iotselöf. + It does MOT check the link's status. + """ + queue = self.core.api.getQueue() #: get packages (w/o files, as most file data is useless here) + + for package in queue: + #: check if package-folder equals pyfile's package folder + if package.folder != pyfile.package().folder: + continue + + #: now get packaged data w/ files/links + pdata = self.core.api.getPackageData(package.pid) + for link in pdata.links: + #: check if link is "skipped" + if link.status != 4: + continue + + #: check if link name collides with pdata's name + #: AND at last check if it is not pyfile itself + if link.name == pyfile.name and link.fid != pyfile.id: + return link + + + def _pyfile(self, link): + return PyFile(self.core.files, + link.fid, + link.url, + link.name, + link.size, + link.status, + link.error, + link.plugin, + link.packageID, + link.order) diff --git a/pyload/plugin/addon/UpdateManager.py b/pyload/plugin/addon/UpdateManager.py new file mode 100644 index 000000000..cf138f64a --- /dev/null +++ b/pyload/plugin/addon/UpdateManager.py @@ -0,0 +1,306 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import re +import sys + +from operator import itemgetter +from os import path, remove, stat + +from pyload.network.RequestFactory import getURL +from pyload.plugin.Addon import Expose, Addon, threaded +from pyload.utils import safe_join + + +class UpdateManager(Addon): + __name__ = "UpdateManager" + __type__ = "addon" + __version__ = "0.43" + + __config__ = [("activated" , "bool" , "Activated" , True ), + ("mode" , "pyLoad + plugins;plugins only", "Check updates for" , "pyLoad + plugins"), + ("interval" , "int" , "Check interval in hours" , 8 ), + ("autorestart" , "bool" , "Automatically restart pyLoad when required" , True ), + ("reloadplugins", "bool" , "Monitor plugins for code changes in debug mode", True ), + ("nodebugupdate", "bool" , "Don't check for updates in debug mode" , False )] + + __description__ = """Check for updates""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + # event_list = ["pluginConfigChanged"] + + SERVER_URL = "http://updatemanager.pyload.org" + VERSION = re.compile(r'__version__.*=.*("|\')([\d.]+)') + MIN_INTERVAL = 3 * 60 * 60 #: 3h minimum check interval (value is in seconds) + + + def pluginConfigChanged(self, plugin, name, value): + if name == "interval": + interval = value * 60 * 60 + if self.MIN_INTERVAL <= interval != self.interval: + self.core.scheduler.removeJob(self.cb) + self.interval = interval + self.initPeriodical() + else: + self.logDebug("Invalid interval value, kept current") + + elif name == "reloadplugins": + if self.cb2: + self.core.scheduler.removeJob(self.cb2) + if value is True and self.core.debug: + self.periodical2() + + + def activate(self): + self.pluginConfigChanged(self.__name__, "interval", self.getConfig("interval")) + x = lambda: self.pluginConfigChanged(self.__name__, "reloadplugins", self.getConfig("reloadplugins")) + self.core.scheduler.addJob(10, x, threaded=False) + + + def deactivate(self): + self.pluginConfigChanged(self.__name__, "reloadplugins", False) + + + def setup(self): + self.cb2 = None + self.interval = 0 + self.updating = False + self.info = {'pyload': False, 'version': None, 'plugins': False} + self.mtimes = {} #: store modification time for each plugin + + + def periodical2(self): + if not self.updating: + self.autoreloadPlugins() + + self.cb2 = self.core.scheduler.addJob(4, self.periodical2, threaded=False) + + + @Expose + def autoreloadPlugins(self): + """ reload and reindex all modified plugins """ + modules = filter( + lambda m: m and (m.__name__.startswith("pyload.plugin.") or + m.__name__.startswith("userplugins.")) and + m.__name__.count(".") >= 2, sys.modules.itervalues() + ) + + reloads = [] + + for m in modules: + root, type, name = m.__name__.rsplit(".", 2) + id = (type, name) + if type in self.core.pluginManager.plugins: + f = m.__file__.replace(".pyc", ".py") + if not path.isfile(f): + continue + + mtime = stat(f).st_mtime + + if id not in self.mtimes: + self.mtimes[id] = mtime + elif self.mtimes[id] < mtime: + reloads.append(id) + self.mtimes[id] = mtime + + return True if self.core.pluginManager.reloadPlugins(reloads) else False + + + def periodical(self): + if self.info['pyload'] or self.getConfig("nodebugupdate") and self.core.debug: + return + + self.updateThread() + + + def server_request(self): + try: + return getURL(self.SERVER_URL, get={'v': self.core.api.getServerVersion()}).splitlines() + except Exception: + self.logWarning(_("Unable to contact server to get updates")) + + + @threaded + def updateThread(self): + self.updating = True + + status = self.update(onlyplugin=self.getConfig("mode") == "plugins only") + + if status is 2 and self.getConfig("autorestart"): + self.core.api.restart() + else: + self.updating = False + + + @Expose + def updatePlugins(self): + """ simple wrapper for calling plugin update quickly """ + return self.update(onlyplugin=True) + + + @Expose + def update(self, onlyplugin=False): + """ check for updates """ + data = self.server_request() + + if not data: + exitcode = 0 + + elif data[0] == "None": + self.logInfo(_("No new pyLoad version available")) + updates = data[1:] + exitcode = self._updatePlugins(updates) + + elif onlyplugin: + exitcode = 0 + + else: + newversion = data[0] + self.logInfo(_("*** New pyLoad Version %s available ***") % newversion) + self.logInfo(_("*** Get it here: https://github.com/pyload/pyload/releases ***")) + exitcode = 3 + self.info['pyload'] = True + self.info['version'] = newversion + + return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required; 3 = No plugins updated, new pyLoad version available + + + def _updatePlugins(self, updates): + """ check for plugin updates """ + + if self.info['plugins']: + return False #: plugins were already updated + + exitcode = 0 + updated = [] + + url = updates[0] + schema = updates[1].split('|') + + if "BLACKLIST" in updates: + blacklist = updates[updates.index('BLACKLIST') + 1:] + updates = updates[2:updates.index('BLACKLIST')] + else: + blacklist = None + updates = updates[2:] + + upgradable = [dict(zip(schema, x.split('|'))) for x in updates] + blacklisted = [(x.split('|')[0], x.split('|')[1].rsplit('.', 1)[0]) for x in blacklist] if blacklist else [] + + if blacklist: + # Protect UpdateManager from self-removing + try: + blacklisted.remove(("addon", "UpdateManager")) + except Exception: + pass + + for t, n in blacklisted: + for idx, plugin in enumerate(upgradable): + if n == plugin['name'] and t == plugin['type']: + upgradable.pop(idx) + break + + for t, n in self.removePlugins(sorted(blacklisted)): + self.logInfo(_("Removed blacklisted plugin [%(type)s] %(name)s") % { + 'type': t, + 'name': n, + }) + + for plugin in sorted(upgradable, key=itemgetter("type", "name")): + filename = plugin['name'] + type = plugin['type'] + version = plugin['version'] + + if filename.endswith(".pyc"): + name = filename[:filename.find("_")] + else: + name = filename.replace(".py", "") + + plugins = getattr(self.core.pluginManager, "%sPlugins" % type) + + oldver = float(plugins[name]['version']) if name in plugins else None + newver = float(version) + + if not oldver: + msg = "New plugin: [%(type)s] %(name)s (v%(newver).2f)" + elif newver > oldver: + msg = "New version of plugin: [%(type)s] %(name)s (v%(oldver).2f -> v%(newver).2f)" + else: + continue + + self.logInfo(_(msg) % {'type' : type, + 'name' : name, + 'oldver': oldver, + 'newver': newver}) + try: + content = getURL(url % plugin) + m = self.VERSION.search(content) + + if m and m.group(2) == version: + with open(safe_join("userplugins", prefix, filename), "wb") as f: + f.write(content) + + updated.append((prefix, name)) + else: + raise Exception, _("Version mismatch") + + except Exception, e: + self.logError(_("Error updating plugin: %s") % filename, str(e)) + + if updated: + reloaded = self.core.pluginManager.reloadPlugins(updated) + if reloaded: + self.logInfo(_("Plugins updated and reloaded")) + exitcode = 1 + else: + self.logInfo(_("*** Plugins have been updated, but need a pyLoad restart to be reloaded ***")) + self.info['plugins'] = True + exitcode = 2 + else: + self.logInfo(_("No plugin updates available")) + + return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required + + + @Expose + def removePlugins(self, type_plugins): + """ delete plugins from disk """ + + if not type_plugins: + return + + self.logDebug("Requested deletion of plugins: %s" % type_plugins) + + removed = [] + + for type, name in type_plugins: + err = False + file = name + ".py" + + for root in ("userplugins", path.join(pypath, "pyload", "plugins")): + + filename = safe_join(root, type, file) + try: + remove(filename) + except Exception, e: + self.logDebug("Error deleting: %s" % path.basename(filename), e) + err = True + + filename += "c" + if path.isfile(filename): + try: + if type == "addon": + self.manager.deactivateAddon(name) + remove(filename) + except Exception, e: + self.logDebug("Error deleting: %s" % path.basename(filename), e) + err = True + + if not err: + id = (type, name) + removed.append(id) + + return removed #: return a list of the plugins successfully removed diff --git a/pyload/plugin/addon/WindowsPhoneNotify.py b/pyload/plugin/addon/WindowsPhoneNotify.py new file mode 100644 index 000000000..b9710c2f0 --- /dev/null +++ b/pyload/plugin/addon/WindowsPhoneNotify.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- + +import httplib + +from time import time + +from pyload.plugin.Addon import Addon + + +class WindowsPhoneNotify(Addon): + __name__ = "WindowsPhoneNotify" + __type__ = "addon" + __version__ = "0.07" + + __config__ = [("id" , "str" , "Push ID" , "" ), + ("url" , "str" , "Push url" , "" ), + ("notifycaptcha" , "bool", "Notify captcha request" , True ), + ("notifypackage" , "bool", "Notify package finished" , True ), + ("notifyprocessed", "bool", "Notify processed packages status" , True ), + ("timeout" , "int" , "Timeout between captchas in seconds" , 5 ), + ("force" , "bool", "Send notifications if client is connected", False)] + + __description__ = """Send push notifications to Windows Phone""" + __license__ = "GPLv3" + __authors__ = [("Andy Voigt", "phone-support@hotmail.de"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + event_list = ["allDownloadsProcessed"] + + + def setup(self): + self.info = {} #@TODO: Remove in 0.4.10 + self.last_notify = 0 + + + def newCaptchaTask(self, task): + if not self.getConfig("notifycaptcha"): + return False + + if time() - self.last_notify < self.getConf("timeout"): + return False + + self.notify(_("Captcha"), _("New request waiting user input")) + + + def packageFinished(self, pypack): + if self.getConfig("notifypackage"): + self.notify(_("Package finished"), pypack.name) + + + def allDownloadsProcessed(self): + if not self.getConfig("notifyprocessed"): + return False + + if any(True for pdata in self.core.api.getQueue() if pdata.linksdone < pdata.linkstotal): + self.notify(_("Package failed"), _("One or more packages was not completed successfully")) + else: + self.notify(_("All packages finished")) + + + def getXmlData(self, msg): + return ("<?xml version='1.0' encoding='utf-8'?> <wp:Notification xmlns:wp='WPNotification'> " + "<wp:Toast> <wp:Text1>pyLoad</wp:Text1> <wp:Text2>%s</wp:Text2> " + "</wp:Toast> </wp:Notification>" % msg) + + + def notify(self, event, msg=""): + id = self.getConfig("id") + url = self.getConfig("url") + + if not id or not url: + return False + + if self.core.isClientConnected() and not self.getConfig("force"): + return False + + request = self.getXmlData("%s: %s" % (event, msg) if msg else event) + webservice = httplib.HTTP(url) + + webservice.putrequest("POST", id) + webservice.putheader("Host", url) + webservice.putheader("Content-type", "text/xml") + webservice.putheader("X-NotificationClass", "2") + webservice.putheader("X-WindowsPhone-Target", "toast") + webservice.putheader("Content-length", "%d" % len(request)) + webservice.endheaders() + webservice.send(request) + webservice.close() + + self.last_notify = time() diff --git a/module/plugins/addon/XMPPInterface.py b/pyload/plugin/addon/XMPPInterface.py index 77a49af6f..77a49af6f 100644 --- a/module/plugins/addon/XMPPInterface.py +++ b/pyload/plugin/addon/XMPPInterface.py diff --git a/module/plugins/addon/__init__.py b/pyload/plugin/addon/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/plugins/addon/__init__.py +++ b/pyload/plugin/addon/__init__.py diff --git a/pyload/plugin/captcha/AdYouLike.py b/pyload/plugin/captcha/AdYouLike.py new file mode 100644 index 000000000..0ff1a799b --- /dev/null +++ b/pyload/plugin/captcha/AdYouLike.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.Captcha import Captcha +from pyload.utils import json_loads + + +class AdYouLike(Captcha): + __name__ = "AdYouLike" + __version__ = "0.05" + + __description__ = """AdYouLike captcha service plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + AYL_PATTERN = r'Adyoulike\.create\s*\((.+?)\)' + CALLBACK_PATTERN = r'(Adyoulike\.g\._jsonp_\d+)' + + + def detect_key(self, html=None): + if not html: + if hasattr(self.plugin, "html") and self.plugin.html: + html = self.plugin.html + else: + errmsg = _("AdYouLike html not found") + self.plugin.fail(errmsg) + raise TypeError(errmsg) + + m = re.search(self.AYL_PATTERN, html) + n = re.search(self.CALLBACK_PATTERN, html) + if m and n: + self.key = (m.group(1).strip(), n.group(1).strip()) + self.logDebug("Ayl|callback: %s | %s" % self.key) + return self.key #: key is the tuple(ayl, callback) + else: + self.logDebug("Ayl or callback not found") + return None + + + def challenge(self, key=None, html=None): + if not key: + if self.detect_key(html): + key = self.key + else: + errmsg = _("AdYouLike key not found") + self.plugin.fail(errmsg) + raise TypeError(errmsg) + + ayl, callback = key + + # {"adyoulike":{"key":"P~zQ~O0zV0WTiAzC-iw0navWQpCLoYEP"}, + # "all":{"element_id":"ayl_private_cap_92300","lang":"fr","env":"prod"}} + ayl = json_loads(ayl) + + html = self.plugin.req.load("http://api-ayl.appspot.com/challenge", + get={'key' : ayl['adyoulike']['key'], + 'env' : ayl['all']['env'], + 'callback': callback}) + try: + challenge = json_loads(re.search(callback + r'\s*\((.+?)\)', html).group(1)) + + except AttributeError: + errmsg = _("AdYouLike challenge pattern not found") + self.plugin.fail(errmsg) + raise AttributeError(errmsg) + + self.logDebug("Challenge: %s" % challenge) + + return self.result(ayl, challenge), challenge + + + def result(self, server, challenge): + # Adyoulike.g._jsonp_5579316662423138 + # ({"translations":{"fr":{"instructions_visual":"Recopiez « Soonnight » ci-dessous :"}}, + # "site_under":true,"clickable":true,"pixels":{"VIDEO_050":[],"DISPLAY":[],"VIDEO_000":[],"VIDEO_100":[], + # "VIDEO_025":[],"VIDEO_075":[]},"medium_type":"image/adyoulike", + # "iframes":{"big":"<iframe src=\"http://www.soonnight.com/campagn.html\" scrolling=\"no\" + # height=\"250\" width=\"300\" frameborder=\"0\"></iframe>"},"shares":{},"id":256, + # "token":"e6QuI4aRSnbIZJg02IsV6cp4JQ9~MjA1","formats":{"small":{"y":300,"x":0,"w":300,"h":60}, + # "big":{"y":0,"x":0,"w":300,"h":250},"hover":{"y":440,"x":0,"w":300,"h":60}}, + # "tid":"SqwuAdxT1EZoi4B5q0T63LN2AkiCJBg5"}) + + if isinstance(server, basestring): + server = json_loads(server) + + if isinstance(challenge, basestring): + challenge = json_loads(challenge) + + try: + instructions_visual = challenge['translations'][server['all']['lang']]['instructions_visual'] + result = re.search(u'«(.+?)»', instructions_visual).group(1).strip() + + except AttributeError: + errmsg = _("AdYouLike result not found") + self.plugin.fail(errmsg) + raise AttributeError(errmsg) + + result = {'_ayl_captcha_engine' : "adyoulike", + '_ayl_env' : server['all']['env'], + '_ayl_tid' : challenge['tid'], + '_ayl_token_challenge': challenge['token'], + '_ayl_response' : response} + + self.logDebug("Result: %s" % result) + + return result diff --git a/pyload/plugin/captcha/AdsCaptcha.py b/pyload/plugin/captcha/AdsCaptcha.py new file mode 100644 index 000000000..75852e36d --- /dev/null +++ b/pyload/plugin/captcha/AdsCaptcha.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- + +import re + +from random import random + +from pyload.plugin.Captcha import Captcha + + +class AdsCaptcha(Captcha): + __name__ = "AdsCaptcha" + __version__ = "0.08" + + __description__ = """AdsCaptcha captcha service plugin""" + __license__ = "GPLv3" + __authors__ = [("pyLoad Team", "admin@pyload.org")] + + + CAPTCHAID_PATTERN = r'api\.adscaptcha\.com/Get\.aspx\?[^"\']*CaptchaId=(\d+)' + PUBLICKEY_PATTERN = r'api\.adscaptcha\.com/Get\.aspx\?[^"\']*PublicKey=([\w-]+)' + + + def detect_key(self, html=None): + if not html: + if hasattr(self.plugin, "html") and self.plugin.html: + html = self.plugin.html + else: + errmsg = _("AdsCaptcha html not found") + self.plugin.fail(errmsg) + raise TypeError(errmsg) + + m = re.search(self.PUBLICKEY_PATTERN, html) + n = re.search(self.CAPTCHAID_PATTERN, html) + if m and n: + self.key = (m.group(1).strip(), n.group(1).strip()) #: key is the tuple(PublicKey, CaptchaId) + self.logDebug("Key|id: %s | %s" % self.key) + return self.key + else: + self.logDebug("Key or id not found") + return None + + + def challenge(self, key=None, html=None): + if not key: + if self.detect_key(html): + key = self.key + else: + errmsg = _("AdsCaptcha key not found") + self.plugin.fail(errmsg) + raise TypeError(errmsg) + + PublicKey, CaptchaId = key + + html = self.plugin.req.load("http://api.adscaptcha.com/Get.aspx", + get={'CaptchaId': CaptchaId, + 'PublicKey': PublicKey}) + try: + challenge = re.search("challenge: '(.+?)',", html).group(1) + server = re.search("server: '(.+?)',", html).group(1) + + except AttributeError: + errmsg = _("AdsCaptcha challenge pattern not found") + self.plugin.fail(errmsg) + raise AttributeError(errmsg) + + self.logDebug("Challenge: %s" % challenge) + + return self.result(server, challenge), challenge + + + def result(self, server, challenge): + result = self.plugin.decryptCaptcha("%sChallenge.aspx" % server, + get={'cid': challenge, 'dummy': random()}, + cookies=True, + imgtype="jpg") + + self.logDebug("Result: %s" % result) + + return result diff --git a/pyload/plugin/captcha/ReCaptcha.py b/pyload/plugin/captcha/ReCaptcha.py new file mode 100644 index 000000000..295491bd8 --- /dev/null +++ b/pyload/plugin/captcha/ReCaptcha.py @@ -0,0 +1,208 @@ +# -*- coding: utf-8 -*- + +import re +import time + +from base64 import b64encode +from random import randint +from urlparse import urljoin, urlparse + +from pyload.plugin.Captcha import Captcha + + +class ReCaptcha(Captcha): + __name__ = "ReCaptcha" + __version__ = "0.14" + + __description__ = """ReCaptcha captcha service plugin""" + __license__ = "GPLv3" + __authors__ = [("pyLoad Team", "admin@pyload.org"), + ("Walter Purcaro", "vuolter@gmail.com"), + ("zapp-brannigan", "fuerst.reinje@web.de")] + + + KEY_V2_PATTERN = r'(?:data-sitekey=["\']|["\']sitekey["\']:\s*["\'])([\w-]+)' + KEY_V1_PATTERN = r'(?:recaptcha(?:/api|\.net)/(?:challenge|noscript)\?k=|Recaptcha\.create\s*\(\s*["\'])([\w-]+)' + + + def detect_key(self, html=None): + if not html: + if hasattr(self.plugin, "html") and self.plugin.html: + html = self.plugin.html + else: + errmsg = _("ReCaptcha html not found") + self.plugin.fail(errmsg) + raise TypeError(errmsg) + + m = re.search(self.KEY_V2_PATTERN, html) or re.search(self.KEY_V1_PATTERN, html) + if m: + self.key = m.group(1).strip() + self.logDebug("Key: %s" % self.key) + return self.key + else: + self.logDebug("Key not found") + return None + + + def challenge(self, key=None, html=None, version=None): + if not key: + if self.detect_key(html): + key = self.key + else: + errmsg = _("ReCaptcha key not found") + self.plugin.fail(errmsg) + raise TypeError(errmsg) + + if version in (1, 2): + return getattr(self, "_challenge_v%s" % version)(key) + + elif not html and hasattr(self.plugin, "html") and self.plugin.html: + version = 2 if re.search(self.KEY_V2_PATTERN, self.plugin.html) else 1 + return self.challenge(key, self.plugin.html, version) + + else: + errmsg = _("ReCaptcha html not found") + self.plugin.fail(errmsg) + raise TypeError(errmsg) + + + def _challenge_v1(self, key): + html = self.plugin.req.load("http://www.google.com/recaptcha/api/challenge", + get={'k': key}) + try: + challenge = re.search("challenge : '(.+?)',", html).group(1) + server = re.search("server : '(.+?)',", html).group(1) + + except AttributeError: + errmsg = _("ReCaptcha challenge pattern not found") + self.plugin.fail(errmsg) + raise AttributeError(errmsg) + + self.logDebug("Challenge: %s" % challenge) + + return self.result(server, challenge), challenge + + + def result(self, server, challenge): + result = self.plugin.decryptCaptcha("%simage" % server, + get={'c': challenge}, + cookies=True, + forceUser=True, + imgtype="jpg") + + self.logDebug("Result: %s" % result) + + return result + + + def _collectApiInfo(self): + html = self.plugin.req.load("http://www.google.com/recaptcha/api.js") + a = re.search(r'po.src = \'(.*?)\';', html).group(1) + vers = a.split("/")[5] + + self.logDebug("API version: %s" %vers) + + language = a.split("__")[1].split(".")[0] + + self.logDebug("API language: %s" % language) + + html = self.plugin.req.load("https://apis.google.com/js/api.js") + b = re.search(r'"h":"(.*?)","', html).group(1) + jsh = b.decode('unicode-escape') + + self.logDebug("API jsh-string: %s" % jsh) + + return vers, language, jsh + + + def _prepareTimeAndRpc(self): + self.plugin.req.load("http://www.google.com/recaptcha/api2/demo") + + millis = int(round(time.time() * 1000)) + + self.logDebug("Time: %s" % millis) + + rand = randint(1, 99999999) + a = "0.%s" % str(rand * 2147483647) + rpc = int(100000000 * float(a)) + + self.logDebug("Rpc-token: %s" % rpc) + + return millis, rpc + + + def _challenge_v2(self, key, parent=None): + if parent is None: + try: + parent = urljoin("http://", urlparse(self.plugin.pyfile.url).netloc) + + except Exception: + parent = "" + + botguardstring = "!A" + vers, language, jsh = self._collectApiInfo() + millis, rpc = self._prepareTimeAndRpc() + + html = self.plugin.req.load("https://www.google.com/recaptcha/api2/anchor", + get={'k' : key, + 'hl' : language, + 'v' : vers, + 'usegapi' : "1", + 'jsh' : "%s#id=IO_%s" % (jsh, millis), + 'parent' : parent, + 'pfname' : "", + 'rpctoken': rpc}) + + token1 = re.search(r'id="recaptcha-token" value="(.*?)">', html) + self.logDebug("Token #1: %s" % token1.group(1)) + + html = self.plugin.req.load("https://www.google.com/recaptcha/api2/frame", + get={'c' : token1.group(1), + 'hl' : language, + 'v' : vers, + 'bg' : botguardstring, + 'k' : key, + 'usegapi': "1", + 'jsh' : jsh}).decode('unicode-escape') + + token2 = re.search(r'"finput","(.*?)",', html) + self.logDebug("Token #2: %s" % token2.group(1)) + + token3 = re.search(r'."asconf".\s,".*?".\s,"(.*?)".', html) + self.logDebug("Token #3: %s" % token3.group(1)) + + html = self.plugin.req.load("https://www.google.com/recaptcha/api2/reload", + post={'k' : key, + 'c' : token2.group(1), + 'reason': "fi", + 'fbg' : token3.group(1)}) + + token4 = re.search(r'"rresp","(.*?)",', html) + self.logDebug("Token #4: %s" % token4.group(1)) + + millis_captcha_loading = int(round(time.time() * 1000)) + captcha_response = self.plugin.decryptCaptcha("https://www.google.com/recaptcha/api2/payload", + get={'c':token4.group(1), 'k':key}, + cookies=True, + forceUser=True) + response = b64encode('{"response":"%s"}' % captcha_response) + + self.logDebug("Result: %s" % response) + + timeToSolve = int(round(time.time() * 1000)) - millis_captcha_loading + timeToSolveMore = timeToSolve + int(float("0." + str(randint(1, 99999999))) * 500) + + html = self.plugin.req.load("https://www.google.com/recaptcha/api2/userverify", + post={'k' : key, + 'c' : token4.group(1), + 'response': response, + 't' : timeToSolve, + 'ct' : timeToSolveMore, + 'bg' : botguardstring}) + + token5 = re.search(r'"uvresp","(.*?)",', html) + self.logDebug("Token #5: %s" % token5.group(1)) + + result = token5.group(1) + + return result, None diff --git a/pyload/plugin/captcha/SolveMedia.py b/pyload/plugin/captcha/SolveMedia.py new file mode 100644 index 000000000..af45101b4 --- /dev/null +++ b/pyload/plugin/captcha/SolveMedia.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.Captcha import Captcha + + +class SolveMedia(Captcha): + __name__ = "SolveMedia" + __version__ = "0.12" + + __description__ = """SolveMedia captcha service plugin""" + __license__ = "GPLv3" + __authors__ = [("pyLoad Team", "admin@pyload.org")] + + + KEY_PATTERN = r'api\.solvemedia\.com/papi/challenge\.(?:no)?script\?k=(.+?)["\']' + + + def detect_key(self, html=None): + if not html: + if hasattr(self.plugin, "html") and self.plugin.html: + html = self.plugin.html + else: + errmsg = _("SolveMedia html not found") + self.plugin.fail(errmsg) + raise TypeError(errmsg) + + m = re.search(self.KEY_PATTERN, html) + if m: + self.key = m.group(1).strip() + self.logDebug("Key: %s" % self.key) + return self.key + else: + self.logDebug("Key not found") + return None + + + def challenge(self, key=None, html=None): + if not key: + if self.detect_key(html): + key = self.key + else: + errmsg = _("SolveMedia key not found") + self.plugin.fail(errmsg) + raise TypeError(errmsg) + + html = self.plugin.req.load("http://api.solvemedia.com/papi/challenge.noscript", + get={'k': key}) + try: + challenge = re.search(r'<input type=hidden name="adcopy_challenge" id="adcopy_challenge" value="([^"]+)">', + html).group(1) + server = "http://api.solvemedia.com/papi/media" + + except AttributeError: + errmsg = _("SolveMedia challenge pattern not found") + self.plugin.fail(errmsg) + raise AttributeError(errmsg) + + self.logDebug("Challenge: %s" % challenge) + + result = self.result(server, challenge) + + try: + magic = re.search(r'name="magic" value="(.+?)"', html).group(1) + + except AttributeError: + self.logDebug("Magic code not found") + + else: + if not self._verify(key, magic, result, challenge): + self.logDebug("Captcha code was invalid") + + return result, challenge + + + def _verify(self, key, magic, result, challenge, ref=None): #@TODO: Clean up + if ref is None: + try: + ref = self.plugin.pyfile.url + + except Exception: + ref = "" + + html = self.plugin.req.load("http://api.solvemedia.com/papi/verify.noscript", + post={'adcopy_response' : result, + 'k' : key, + 'l' : "en", + 't' : "img", + 's' : "standard", + 'magic' : magic, + 'adcopy_challenge' : challenge, + 'ref' : ref}) + try: + html = self.plugin.req.load(re.search(r'URL=(.+?)">', html).group(1)) + gibberish = re.search(r'id=gibberish>(.+?)</textarea>', html).group(1) + + except Exception: + return False + + else: + return True + + + def result(self, server, challenge): + result = self.plugin.decryptCaptcha(server, + get={'c': challenge}, + cookies=True, + imgtype="gif") + + self.logDebug("Result: %s" % result) + + return result diff --git a/module/plugins/captcha/__init__.py b/pyload/plugin/captcha/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/plugins/captcha/__init__.py +++ b/pyload/plugin/captcha/__init__.py diff --git a/pyload/plugin/container/CCF.py b/pyload/plugin/container/CCF.py new file mode 100644 index 000000000..311eb2006 --- /dev/null +++ b/pyload/plugin/container/CCF.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import re + +from urllib2 import build_opener + +from MultipartPostHandler import MultipartPostHandler + +from pyload.plugin.Container import Container +from pyload.utils import fs_encode, safe_join + + +class CCF(Container): + __name__ = "CCF" + __type__ = "container" + __version__ = "0.23" + + __pattern__ = r'.+\.ccf$' + + __description__ = """CCF container decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("Willnix", "Willnix@pyload.org"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + def decrypt(self, pyfile): + file = fs_encode(pyfile.url.strip()) + opener = build_opener(MultipartPostHandler) + + dlc_content = opener.open('http://service.jdownloader.net/dlcrypt/getDLC.php', + {'src' : "ccf", + 'filename': "test.ccf", + 'upload' : open(file, "rb")}).read() + + download_folder = self.config['general']['download_folder'] + dlc_file = safe_join(download_folder, "tmp_%s.dlc" % pyfile.name) + + try: + dlc = re.search(r'<dlc>(.+)</dlc>', dlc_content, re.S).group(1).decode('base64') + + except AttributeError: + self.fail(_("Container is corrupted")) + + with open(dlc_file, "w") as tempdlc: + tempdlc.write(dlc) + + self.urls = [dlc_file] diff --git a/pyload/plugin/container/DLC.py b/pyload/plugin/container/DLC.py new file mode 100644 index 000000000..8b8a0199b --- /dev/null +++ b/pyload/plugin/container/DLC.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import re +import xml.dom.minidom + +from Crypto.Cipher import AES + +from pyload.plugin.Container import Container +from pyload.utils import decode, fs_encode + + +class DLC(Container): + __name__ = "DLC" + __type__ = "container" + __version__ = "0.24" + + __pattern__ = r'.+\.dlc$' + + __description__ = """DLC container decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("spoob", "spoob@pyload.org"), + ("mkaay", "mkaay@mkaay.de"), + ("Schnusch", "Schnusch@users.noreply.github.com"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + KEY = "cb99b5cbc24db398" + IV = "9bc24cb995cb8db3" + API_URL = "http://service.jdownloader.org/dlcrypt/service.php?srcType=dlc&destType=pylo&data=%s" + + + def decrypt(self, pyfile): + file = fs_encode(pyfile.url.strip()) + with open(file) as dlc: + data = dlc.read().strip() + + data += '=' * (-len(data) % 4) + + dlc_key = data[-88:] + dlc_data = data[:-88].decode('base64') + dlc_content = self.load(self.API_URL % dlc_key) + + try: + rc = re.search(r'<rc>(.+)</rc>', dlc_content, re.S).group(1).decode('base64') + + except AttributeError: + self.fail(_("Container is corrupted")) + + cipher = AES.new(self.KEY, AES.MODE_CBC, self.IV).decrypt(rc) + + self.data = AES.new(cipher, AES.MODE_CBC, cipher).decrypt(dlc_data).decode('base64') + self.packages = [(entry[0] if entry[0] else pyfile.name, entry[1], entry[0] if entry[0] else pyfile.name) \ + for entry in self.getPackages()] + + + def getPackages(self): + root = xml.dom.minidom.parseString(self.data).documentElement + content = root.getElementsByTagName("content")[0] + return self.parsePackages(content) + + + def parsePackages(self, startNode): + return [(decode(node.getAttribute("name")).decode('base64'), self.parseLinks(node)) \ + for node in startNode.getElementsByTagName("package")] + + + def parseLinks(self, startNode): + return [node.getElementsByTagName("url")[0].firstChild.data.decode('base64') \ + for node in startNode.getElementsByTagName("file")] diff --git a/pyload/plugin/container/RSDF.py b/pyload/plugin/container/RSDF.py new file mode 100644 index 000000000..c4b743d14 --- /dev/null +++ b/pyload/plugin/container/RSDF.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import binascii +import re + +from Crypto.Cipher import AES + +from pyload.plugin.Container import Container +from pyload.utils import fs_encode + + +class RSDF(Container): + __name__ = "RSDF" + __type__ = "container" + __version__ = "0.27" + + __pattern__ = r'.+\.rsdf$' + + __description__ = """RSDF container decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("spoob", "spoob@pyload.org"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + KEY = "8C35192D964DC3182C6F84F3252239EB4A320D2500000000" + IV = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + + def decrypt(self, pyfile): + KEY = binascii.unhexlify(self.KEY) + IV = AES.new(Key, AES.MODE_ECB).encrypt(binascii.unhexlify(self.IV)) + + cipher = AES.new(KEY, AES.MODE_CFB, IV) + + try: + file = fs_encode(pyfile.url.strip()) + with open(file, 'r') as rsdf: + data = rsdf.read() + + except IOError, e: + self.fail(e) + + if re.search(r"<title>404 - Not Found</title>", data): + return + + for link in binascii.unhexlify(''.join(data.split())).splitlines(): + if link: + link = cipher.decrypt(link.decode('base64')).replace('CCF: ', '') + self.urls.append(link) diff --git a/pyload/plugin/container/TXT.py b/pyload/plugin/container/TXT.py new file mode 100644 index 000000000..2bf5bf2aa --- /dev/null +++ b/pyload/plugin/container/TXT.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- + +import codecs + +from pyload.plugin.Container import Container +from pyload.utils import fs_encode + + +class TXT(Container): + __name__ = "TXT" + __type__ = "container" + __version__ = "0.15" + + __pattern__ = r'.+\.(txt|text)$' + __config__ = [("flush" , "bool" , "Flush list after adding", False ), + ("encoding", "string", "File encoding" , "utf-8")] + + __description__ = """Read link lists in plain text formats""" + __license__ = "GPLv3" + __authors__ = [("spoob", "spoob@pyload.org"), + ("jeix", "jeix@hasnomail.com")] + + + def decrypt(self, pyfile): + try: + encoding = codecs.lookup(self.getConfig("encoding")).name + + except Exception: + encoding = "utf-8" + + file = fs_encode(pyfile.url.strip()) + txt = codecs.open(file, 'r', encoding) + curPack = "Parsed links from %s" % pyfile.name + packages = {curPack:[],} + + for link in txt.readlines(): + link = link.strip() + + if not link: + continue + + if link.startswith(";"): + continue + + if link.startswith("[") and link.endswith("]"): + # new package + curPack = link[1:-1] + packages[curPack] = [] + continue + + packages[curPack].append(link) + + txt.close() + + # empty packages fix + for key, value in packages.iteritems(): + if not value: + packages.pop(key, None) + + if self.getConfig("flush"): + try: + txt = open(file, 'wb') + txt.close() + + except IOError: + self.logWarning(_("Failed to flush list")) + + for name, links in packages.iteritems(): + self.packages.append((name, links, name)) diff --git a/module/plugins/container/__init__.py b/pyload/plugin/container/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/plugins/container/__init__.py +++ b/pyload/plugin/container/__init__.py diff --git a/pyload/plugin/crypter/BitshareCom.py b/pyload/plugin/crypter/BitshareCom.py new file mode 100644 index 000000000..524307127 --- /dev/null +++ b/pyload/plugin/crypter/BitshareCom.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class BitshareCom(SimpleCrypter): + __name__ = "BitshareCom" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?bitshare\.com/\?d=\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Bitshare.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + LINK_PATTERN = r'<a href="(http://bitshare\.com/files/.+)">.+</a></td>' + NAME_PATTERN = r'View public folder "(?P<N>.+)"</h1>' diff --git a/pyload/plugin/crypter/C1NeonCom.py b/pyload/plugin/crypter/C1NeonCom.py new file mode 100644 index 000000000..dc1555b46 --- /dev/null +++ b/pyload/plugin/crypter/C1NeonCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class C1NeonCom(DeadCrypter): + __name__ = "C1NeonCom" + __type__ = "crypter" + __version__ = "0.05" + + __pattern__ = r'http://(?:www\.)?c1neon\.com/.+' + __config__ = [] + + __description__ = """C1neon.com decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("godofdream", "soilfiction@gmail.com")] diff --git a/module/plugins/crypter/ChipDe.py b/pyload/plugin/crypter/ChipDe.py index 2f47236e8..2f47236e8 100644 --- a/module/plugins/crypter/ChipDe.py +++ b/pyload/plugin/crypter/ChipDe.py diff --git a/pyload/plugin/crypter/CloudzillaTo.py b/pyload/plugin/crypter/CloudzillaTo.py new file mode 100644 index 000000000..340892136 --- /dev/null +++ b/pyload/plugin/crypter/CloudzillaTo.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urljoin + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class CloudzillaTo(SimpleHoster): + __name__ = "CloudzillaTo" + __type__ = "crypter" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?cloudzilla\.to/share/folder/(?P<ID>[\w^_]+)' + + __description__ = """Cloudzilla.to folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + INFO_PATTERN = r'<span class="name" title="(?P<N>.+?)"' + OFFLINE_PATTERN = r'>File not found...<' + + LINK_PATTERN = r'<a href="(.+?)" class="item_href">' + + PASSWORD_PATTERN = r'<div id="pwd_protected">' + + + def checkErrors(self): + m = re.search(self.PASSWORD_PATTERN, self.html) + if m: + self.html = self.load(self.pyfile.url, get={'key': self.getPassword()}) + + if re.search(self.PASSWORD_PATTERN, self.html): + self.retry(reason="Wrong password") diff --git a/pyload/plugin/crypter/CrockoCom.py b/pyload/plugin/crypter/CrockoCom.py new file mode 100644 index 000000000..c93f4afab --- /dev/null +++ b/pyload/plugin/crypter/CrockoCom.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class CrockoCom(SimpleCrypter): + __name__ = "CrockoCom" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?crocko\.com/f/.+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Crocko.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + LINK_PATTERN = r'<td class="last"><a href="([^"]+)">download</a>' diff --git a/pyload/plugin/crypter/CryptItCom.py b/pyload/plugin/crypter/CryptItCom.py new file mode 100644 index 000000000..0d72cba61 --- /dev/null +++ b/pyload/plugin/crypter/CryptItCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class CryptItCom(DeadCrypter): + __name__ = "CryptItCom" + __type__ = "crypter" + __version__ = "0.11" + + __pattern__ = r'http://(?:www\.)?crypt-it\.com/(s|e|d|c)/\w+' + __config__ = [] + + __description__ = """Crypt-it.com decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("jeix", "jeix@hasnomail.de")] diff --git a/module/plugins/crypter/CzshareCom.py b/pyload/plugin/crypter/CzshareCom.py index e527d683f..e527d683f 100644 --- a/module/plugins/crypter/CzshareCom.py +++ b/pyload/plugin/crypter/CzshareCom.py diff --git a/module/plugins/crypter/DDLMusicOrg.py b/pyload/plugin/crypter/DDLMusicOrg.py index 2b6738799..2b6738799 100644 --- a/module/plugins/crypter/DDLMusicOrg.py +++ b/pyload/plugin/crypter/DDLMusicOrg.py diff --git a/module/plugins/crypter/DailymotionBatch.py b/pyload/plugin/crypter/DailymotionBatch.py index c66c7c829..c66c7c829 100644 --- a/module/plugins/crypter/DailymotionBatch.py +++ b/pyload/plugin/crypter/DailymotionBatch.py diff --git a/pyload/plugin/crypter/DataHu.py b/pyload/plugin/crypter/DataHu.py new file mode 100644 index 000000000..f69d6ee3e --- /dev/null +++ b/pyload/plugin/crypter/DataHu.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class DataHu(SimpleCrypter): + __name__ = "DataHu" + __type__ = "crypter" + __version__ = "0.06" + + __pattern__ = r'http://(?:www\.)?data\.hu/dir/\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Data.hu folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("crash", ""), + ("stickell", "l.stickell@yahoo.it")] + + + LINK_PATTERN = r'<a href=\'(http://data\.hu/get/.+)\' target=\'_blank\'>\1</a>' + NAME_PATTERN = ur'<title>(?P<N>.+) Let\xf6lt\xe9se</title>' + + + def prepare(self): + super(DataHu, self).prepare() + + if u'K\xe9rlek add meg a jelsz\xf3t' in self.html: # Password protected + password = self.getPassword() + if not password: + self.fail(_("Password required")) + + self.logDebug("The folder is password protected', 'Using password: " + password) + + self.html = self.load(self.pyfile.url, post={'mappa_pass': password}, decode=True) + + if u'Hib\xe1s jelsz\xf3' in self.html: # Wrong password + self.fail(_("Wrong password")) diff --git a/pyload/plugin/crypter/DdlstorageCom.py b/pyload/plugin/crypter/DdlstorageCom.py new file mode 100644 index 000000000..f3744e15d --- /dev/null +++ b/pyload/plugin/crypter/DdlstorageCom.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class DdlstorageCom(DeadCrypter): + __name__ = "DdlstorageCom" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'https?://(?:www\.)?ddlstorage\.com/folder/\w+' + __config__ = [] + + __description__ = """DDLStorage.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("godofdream", "soilfiction@gmail.com"), + ("stickell", "l.stickell@yahoo.it")] diff --git a/pyload/plugin/crypter/DepositfilesCom.py b/pyload/plugin/crypter/DepositfilesCom.py new file mode 100644 index 000000000..24fa9134a --- /dev/null +++ b/pyload/plugin/crypter/DepositfilesCom.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class DepositfilesCom(SimpleCrypter): + __name__ = "DepositfilesCom" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?depositfiles\.com/folders/\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Depositfiles.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + LINK_PATTERN = r'<div class="progressName"[^>]*>\s*<a href="([^"]+)" title="[^"]*" target="_blank">' diff --git a/pyload/plugin/crypter/Dereferer.py b/pyload/plugin/crypter/Dereferer.py new file mode 100644 index 000000000..138282d02 --- /dev/null +++ b/pyload/plugin/crypter/Dereferer.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.Crypter import Crypter + + +class Dereferer(SimpleDereferer): + __name__ = "Dereferer" + __type__ = "crypter" + __version__ = "0.11" + + __pattern__ = r'https?://([^/]+)/.*?(?P<LINK>(ht|f)tps?(://|%3A%2F%2F).+)' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Crypter for dereferers""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/crypter/DevhostSt.py b/pyload/plugin/crypter/DevhostSt.py new file mode 100644 index 000000000..4d1a2ae09 --- /dev/null +++ b/pyload/plugin/crypter/DevhostSt.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# http://d-h.st/users/shine/?fld_id=37263#files + +import re + +from urlparse import urljoin + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class DevhostSt(SimpleCrypter): + __name__ = "DevhostSt" + __type__ = "crypter" + __version__ = "0.04" + + __pattern__ = r'http://(?:www\.)?d-h\.st/users/(?P<USER>\w+)(/\?fld_id=(?P<ID>\d+))?' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """d-h.st folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + LINK_PATTERN = r'(?:/> |;">)<a href="(.+?)"(?!>Back to \w+<)' + OFFLINE_PATTERN = r'"/cHP">test\.png<' + + + def getFileInfo(self): + if re.search(self.OFFLINE_PATTERN, self.html): + self.offline() + + try: + id = re.match(self.__pattern__, self.pyfile.url).group('ID') + if id == "0": + raise + + p = r'href="(.+?)">Back to \w+<' + m = re.search(p, self.html) + html = self.load(urljoin("http://d-h.st", m.group(1)), + cookies=False) + + p = '\?fld_id=%s.*?">(.+?)<' % id + m = re.search(p, html) + name = folder = m.group(1) + + except Exception, e: + self.logDebug(e) + name = folder = re.match(self.__pattern__, self.pyfile.url).group('USER') + + return {'name': name, 'folder': folder} diff --git a/pyload/plugin/crypter/DlProtectCom.py b/pyload/plugin/crypter/DlProtectCom.py new file mode 100644 index 000000000..a5e104f70 --- /dev/null +++ b/pyload/plugin/crypter/DlProtectCom.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- + +import re + +from base64 import urlsafe_b64encode +from time import time + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class DlProtectCom(SimpleCrypter): + __name__ = "DlProtectCom" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'https?://(?:www\.)?dl-protect\.com/((en|fr)/)?\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Dl-protect.com decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + COOKIES = [("dl-protect.com", "l", "en")] + + OFFLINE_PATTERN = r'Unfortunately, the link you are looking for is not found' + + + def getLinks(self): + # Direct link with redirect + if not re.match(r"https?://(?:www\.)?dl-protect\.com/.+", self.req.http.lastEffectiveURL): + return [self.req.http.lastEffectiveURL] + + post_req = {'key' : re.search(r'name="key" value="(.+?)"', self.html).group(1), + 'submitform': ""} + + if "Please click on continue to see the content" in self.html: + post_req['submitform'] = "Continue" + self.wait(2) + + else: + mstime = int(round(time() * 1000)) + b64time = "_" + urlsafe_b64encode(str(mstime)).replace("=", "%3D") + + post_req.update({'i' : b64time, + 'submitform': "Decrypt+link"}) + + if "Password :" in self.html: + post_req['pwd'] = self.getPassword() + + if "Security Code" in self.html: + captcha_id = re.search(r'/captcha\.php\?uid=(.+?)"', self.html).group(1) + captcha_url = "http://www.dl-protect.com/captcha.php?uid=" + captcha_id + captcha_code = self.decryptCaptcha(captcha_url, imgtype="gif") + + post_req['secure'] = captcha_code + + self.html = self.load(self.pyfile.url, post=post_req) + + for errmsg in ("The password is incorrect", "The security code is incorrect"): + if errmsg in self.html: + self.fail(_(errmsg[1:])) + + return re.findall(r'<a href="([^/].+?)" target="_blank">', self.html) diff --git a/pyload/plugin/crypter/DontKnowMe.py b/pyload/plugin/crypter/DontKnowMe.py new file mode 100644 index 000000000..1e83ab853 --- /dev/null +++ b/pyload/plugin/crypter/DontKnowMe.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.Crypter import Crypter + + +class DontKnowMe(SimpleDereferer): + __name__ = "DontKnowMe" + __type__ = "crypter" + __version__ = "0.11" + + __pattern__ = r'http://(?:www\.)?dontknow\.me/at/\?(?P<LINK>.+)' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """DontKnow.me decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("selaux", "")] diff --git a/module/plugins/crypter/DuckCryptInfo.py b/pyload/plugin/crypter/DuckCryptInfo.py index 55681fd5e..55681fd5e 100644 --- a/module/plugins/crypter/DuckCryptInfo.py +++ b/pyload/plugin/crypter/DuckCryptInfo.py diff --git a/pyload/plugin/crypter/DuploadOrg.py b/pyload/plugin/crypter/DuploadOrg.py new file mode 100644 index 000000000..f92eb2ede --- /dev/null +++ b/pyload/plugin/crypter/DuploadOrg.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class DuploadOrg(DeadCrypter): + __name__ = "DuploadOrg" + __type__ = "crypter" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?dupload\.org/folder/\d+' + __config__ = [] + + __description__ = """Dupload.org folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] diff --git a/pyload/plugin/crypter/EasybytezCom.py b/pyload/plugin/crypter/EasybytezCom.py new file mode 100644 index 000000000..c5c7b0193 --- /dev/null +++ b/pyload/plugin/crypter/EasybytezCom.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSCrypter import XFSCrypter + + +class EasybytezCom(XFSCrypter): + __name__ = "EasybytezCom" + __type__ = "crypter" + __version__ = "0.10" + + __pattern__ = r'http://(?:www\.)?easybytez\.com/users/\d+/\d+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Easybytez.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + LOGIN_ACCOUNT = True diff --git a/module/plugins/crypter/EmbeduploadCom.py b/pyload/plugin/crypter/EmbeduploadCom.py index c94e7e106..c94e7e106 100644 --- a/module/plugins/crypter/EmbeduploadCom.py +++ b/pyload/plugin/crypter/EmbeduploadCom.py diff --git a/pyload/plugin/crypter/FilebeerInfo.py b/pyload/plugin/crypter/FilebeerInfo.py new file mode 100644 index 000000000..e2e0e1e3c --- /dev/null +++ b/pyload/plugin/crypter/FilebeerInfo.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class FilebeerInfo(DeadCrypter): + __name__ = "FilebeerInfo" + __type__ = "crypter" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?filebeer\.info/\d*~f\w+' + __config__ = [] + + __description__ = """Filebeer.info folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/crypter/FilecloudIo.py b/pyload/plugin/crypter/FilecloudIo.py new file mode 100644 index 000000000..f4c967a07 --- /dev/null +++ b/pyload/plugin/crypter/FilecloudIo.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class FilecloudIo(SimpleCrypter): + __name__ = "FilecloudIo" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'https?://(?:www\.)?(filecloud\.io|ifile\.it)/_\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Filecloud.io folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + LINK_PATTERN = r'href="(http://filecloud\.io/\w+)" title' + NAME_PATTERN = r'>(?P<N>.+?) - filecloud\.io<' diff --git a/pyload/plugin/crypter/FilecryptCc.py b/pyload/plugin/crypter/FilecryptCc.py new file mode 100644 index 000000000..816a2d365 --- /dev/null +++ b/pyload/plugin/crypter/FilecryptCc.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# http://filecrypt.cc/Container/64E039F859.html + +import binascii +import re + +from Crypto.Cipher import AES +from urlparse import urljoin + +from pyload.plugin.Crypter import Crypter +from pyload.plugin.internal.CaptchaService import ReCaptcha + + +class FilecryptCc(Crypter): + __name__ = "FilecryptCc" + __type__ = "crypter" + __version__ = "0.11" + + __pattern__ = r'https?://(?:www\.)?filecrypt\.cc/Container/\w+' + + __description__ = """Filecrypt.cc decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] + + + # URL_REPLACEMENTS = [(r'.html$', ""), (r'$', ".html")] #@TODO: Extend SimpleCrypter + + DLC_LINK_PATTERN = r'<button class="dlcdownload" type="button" title="Download \*.dlc" onclick="DownloadDLC\(\'(.+)\'\);"><i></i><span>dlc<' + WEBLINK_PATTERN = r"openLink.?'([\w_-]*)'," + + CAPTCHA_PATTERN = r'<img id="nc" src="(.+?)"' + CIRCLE_CAPTCHA_PATTERN = r'<input type="image" src="(.+?)"' + + MIRROR_PAGE_PATTERN = r'"[\w]*" href="(http://filecrypt.cc/Container/\w+\.html\?mirror=\d+)">' + + + def setup(self): + self.links = [] + + + def decrypt(self, pyfile): + self.html = self.load(pyfile.url, cookies=True) + + if "content notfound" in self.html: #@NOTE: "content notfound" is NOT a typo + self.offline() + + self.handlePasswordProtection() + self.handleCaptcha() + self.handleMirrorPages() + + for handle in (self.handleCNL, self.handleWeblinks, self.handleDlcContainer): + handle() + if self.links: + self.packages = [(pyfile.package().name, self.links, pyfile.package().name)] + return + + + def handleMirrorPages(self): + if "mirror=" not in self.siteWithLinks: + return + + mirror = re.findall(self.MIRROR_PAGE_PATTERN, self.siteWithLinks) + + self.logInfo(_("Found %d mirrors") % len(mirror)) + + for i in mirror[1:]: + self.siteWithLinks = self.siteWithLinks + self.load(i, cookies=True).decode("utf-8", "replace") + + + def handlePasswordProtection(self): + if '<input type="text" name="password"' not in self.html: + return + + self.logInfo(_("Folder is password protected")) + + password = self.getPassword() + + if not password: + self.fail(_("Please enter the password in package section and try again")) + + self.html = self.load(self.pyfile.url, post={"password": password}, cookies=True) + + + def handleCaptcha(self): + m = re.search(self.CAPTCHA_PATTERN, self.html) + m2 = re.search(self.CIRCLE_CAPTCHA_PATTERN, self.html) + + if m: #: normal captcha + self.logDebug("Captcha-URL: %s" % m.group(1)) + + captcha_code = self.decryptCaptcha(urljoin("http://filecrypt.cc", m.group(1)), + forceUser=True, + imgtype="gif") + + self.siteWithLinks = self.load(self.pyfile.url, + post={'recaptcha_response_field': captcha_code}, + cookies=True, + decode=True) + elif m2: #: circle captcha + self.logDebug("Captcha-URL: %s" % m2.group(1)) + + captcha_code = self.decryptCaptcha(urljoin("http://filecrypt.cc", m2.group(1)), + forceUser=True, + imgtype="gif", + result_type='positional') + + self.siteWithLinks = self.load(self.pyfile.url, + post={'button.x': captcha_code[0], 'button.y': captcha_code[1]}, + cookies=True, + decode=True) + + else: + recaptcha = ReCaptcha(self) + captcha_key = recaptcha.detect_key() + + if captcha_key: + response, challenge = recaptcha.challenge(captcha_key) + self.siteWithLinks = self.load(self.pyfile.url, + post={'g-recaptcha-response': response}, + decode=True) + else: + self.logInfo(_("No captcha found")) + self.siteWithLinks = self.html + + if "recaptcha_image" in self.siteWithLinks or "data-sitekey" in self.siteWithLinks: + self.invalidCaptcha() + self.retry() + + + def handleDlcContainer(self): + dlc = re.findall(self.DLC_LINK_PATTERN, self.siteWithLinks) + + if not dlc: + return + + for i in dlc: + self.links.append("http://filecrypt.cc/DLC/%s.dlc" % i) + + + def handleWeblinks(self): + try: + weblinks = re.findall(self.WEBLINK_PATTERN, self.siteWithLinks) + + for link in weblinks: + res = self.load("http://filecrypt.cc/Link/%s.html" % link, cookies=True) + link2 = re.search('<iframe noresize src="(.*)"></iframe>', res) + res2 = self.load(link2.group(1), just_header=True, cookies=True) + self.links.append(res2['location']) + + except Exception, e: + self.logDebug("Error decrypting weblinks: %s" % e) + + + def handleCNL(self): + try: + vjk = re.findall('<input type="hidden" name="jk" value="function f\(\){ return \'(.*)\';}">', self.siteWithLinks) + vcrypted = re.findall('<input type="hidden" name="crypted" value="(.*)">', self.siteWithLinks) + + for i in xrange(len(vcrypted)): + self.links.extend(self._getLinks(vcrypted[i], vjk[i])) + + except Exception, e: + self.logDebug("Error decrypting CNL: %s" % e) + + + def _getLinks(self, crypted, jk): + # Get key + key = binascii.unhexlify(str(jk)) + + # Decrypt + Key = key + IV = key + obj = AES.new(Key, AES.MODE_CBC, IV) + text = obj.decrypt(crypted.decode('base64')) + + # Extract links + text = text.replace("\x00", "").replace("\r", "") + links = filter(bool, text.split('\n')) + + return links diff --git a/pyload/plugin/crypter/FilefactoryCom.py b/pyload/plugin/crypter/FilefactoryCom.py new file mode 100644 index 000000000..40f4c1475 --- /dev/null +++ b/pyload/plugin/crypter/FilefactoryCom.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class FilefactoryCom(SimpleCrypter): + __name__ = "FilefactoryCom" + __type__ = "crypter" + __version__ = "0.32" + + __pattern__ = r'https?://(?:www\.)?filefactory\.com/(?:f|folder)/\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Filefactory.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + COOKIES = [("filefactory.com", "locale", "en_US.utf8")] + + LINK_PATTERN = r'<td>\s*<a href="(.+?)"' + NAME_PATTERN = r'<h1>Files in <span>(?P<N>.+?)<' + PAGES_PATTERN = r'data-paginator-totalPages="(\d+)' + + + def loadPage(self, page_n): + return self.load(self.pyfile.url, get={'page': page_n, 'show': 100}) diff --git a/pyload/plugin/crypter/FilerNet.py b/pyload/plugin/crypter/FilerNet.py new file mode 100644 index 000000000..45d0dd2ab --- /dev/null +++ b/pyload/plugin/crypter/FilerNet.py @@ -0,0 +1,24 @@ +import re + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class FilerNet(SimpleCrypter): + __name__ = "FilerNet" + __type__ = "crypter" + __version__ = "0.42" + + __pattern__ = r'https?://filer\.net/folder/\w{16}' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Filer.net decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("nath_schwarz", "nathan.notwhite@gmail.com"), + ("stickell", "l.stickell@yahoo.it")] + + + LINK_PATTERN = r'href="(/get/\w{16})">(?!<)' + + NAME_PATTERN = r'<h3>(?P<N>.+?) - <small' + OFFLINE_PATTERN = r'Nicht gefunden' diff --git a/module/plugins/crypter/FileserveCom.py b/pyload/plugin/crypter/FileserveCom.py index ab0665fbd..ab0665fbd 100644 --- a/module/plugins/crypter/FileserveCom.py +++ b/pyload/plugin/crypter/FileserveCom.py diff --git a/pyload/plugin/crypter/FilesonicCom.py b/pyload/plugin/crypter/FilesonicCom.py new file mode 100644 index 000000000..1ffaa9c01 --- /dev/null +++ b/pyload/plugin/crypter/FilesonicCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class FilesonicCom(DeadCrypter): + __name__ = "FilesonicCom" + __type__ = "crypter" + __version__ = "0.12" + + __pattern__ = r'http://(?:www\.)?filesonic\.com/folder/\w+' + + __description__ = """Filesonic.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/crypter/FilestubeCom.py b/pyload/plugin/crypter/FilestubeCom.py new file mode 100644 index 000000000..36e4a4caf --- /dev/null +++ b/pyload/plugin/crypter/FilestubeCom.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class FilestubeCom(SimpleCrypter): + __name__ = "FilestubeCom" + __type__ = "crypter" + __version__ = "0.05" + + __pattern__ = r'http://(?:www\.)?filestube\.(?:com|to)/\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Filestube.com decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + LINK_PATTERN = r'<a class=\"file-link-main(?: noref)?\" [^>]* href=\"(http://[^\"]+)' + NAME_PATTERN = r'<h1\s*> (?P<N>.+) download\s*</h1>' diff --git a/pyload/plugin/crypter/FiletramCom.py b/pyload/plugin/crypter/FiletramCom.py new file mode 100644 index 000000000..700050a4b --- /dev/null +++ b/pyload/plugin/crypter/FiletramCom.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class FiletramCom(SimpleCrypter): + __name__ = "FiletramCom" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?filetram\.com/[^/]+/.+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Filetram.com decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("igel", "igelkun@myopera.com"), + ("stickell", "l.stickell@yahoo.it")] + + + LINK_PATTERN = r'\s+(http://.+)' + NAME_PATTERN = r'<title>(?P<N>.+?) - Free Download' diff --git a/pyload/plugin/crypter/FiredriveCom.py b/pyload/plugin/crypter/FiredriveCom.py new file mode 100644 index 000000000..e258ed42f --- /dev/null +++ b/pyload/plugin/crypter/FiredriveCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class FiredriveCom(DeadCrypter): + __name__ = "FiredriveCom" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'https?://(?:www\.)?(firedrive|putlocker)\.com/share/.+' + __config__ = [] + + __description__ = """Firedrive.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] diff --git a/module/plugins/crypter/FourChanOrg.py b/pyload/plugin/crypter/FourChanOrg.py index 62fb9d3fe..62fb9d3fe 100644 --- a/module/plugins/crypter/FourChanOrg.py +++ b/pyload/plugin/crypter/FourChanOrg.py diff --git a/pyload/plugin/crypter/FreakhareCom.py b/pyload/plugin/crypter/FreakhareCom.py new file mode 100644 index 000000000..cb766361c --- /dev/null +++ b/pyload/plugin/crypter/FreakhareCom.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class FreakhareCom(SimpleCrypter): + __name__ = "FreakhareCom" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?freakshare\.com/folder/.+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Freakhare.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + LINK_PATTERN = r'<a href="(http://freakshare\.com/files/[^"]+)" target="_blank">' + NAME_PATTERN = r'Folder:</b> (?P<N>.+)' + PAGES_PATTERN = r'Pages: +(\d+)' + + + def loadPage(self, page_n): + if not hasattr(self, 'f_id') and not hasattr(self, 'f_md5'): + m = re.search(r'http://freakshare.com/\?x=folder&f_id=(\d+)&f_md5=(\w+)', self.html) + if m: + self.f_id = m.group(1) + self.f_md5 = m.group(2) + return self.load('http://freakshare.com/', get={'x': 'folder', + 'f_id': self.f_id, + 'f_md5': self.f_md5, + 'entrys': '20', + 'page': page_n - 1, + 'order': ''}, decode=True) diff --git a/pyload/plugin/crypter/FreetexthostCom.py b/pyload/plugin/crypter/FreetexthostCom.py new file mode 100644 index 000000000..3b082ef7d --- /dev/null +++ b/pyload/plugin/crypter/FreetexthostCom.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class FreetexthostCom(SimpleCrypter): + __name__ = "FreetexthostCom" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?freetexthost\.com/\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Freetexthost.com decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + def getLinks(self): + m = re.search(r'<div id="contentsinner">\s*(.+)<div class="viewcount">', self.html, re.S) + if m is None: + self.error(_("Unable to extract links")) + links = m.group(1) + return links.strip().split("<br />\r\n") diff --git a/pyload/plugin/crypter/FshareVn.py b/pyload/plugin/crypter/FshareVn.py new file mode 100644 index 000000000..700f87ba4 --- /dev/null +++ b/pyload/plugin/crypter/FshareVn.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class FshareVn(SimpleCrypter): + __name__ = "FshareVn" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?fshare\.vn/folder/.+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Fshare.vn folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + LINK_PATTERN = r'<li class="w_80pc"><a href="([^"]+)" target="_blank">' diff --git a/pyload/plugin/crypter/Go4UpCom.py b/pyload/plugin/crypter/Go4UpCom.py new file mode 100644 index 000000000..5bae6e93a --- /dev/null +++ b/pyload/plugin/crypter/Go4UpCom.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urljoin + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class Go4UpCom(SimpleCrypter): + __name__ = "Go4UpCom" + __type__ = "crypter" + __version__ = "0.11" + + __pattern__ = r'http://go4up\.com/(dl/\w{12}|rd/\w{12}/\d+)' + + __description__ = """Go4Up.com decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("rlindner81", "rlindner81@gmail.com"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + LINK_PATTERN = r'(http://go4up\.com/rd/.+?)<' + + NAME_PATTERN = r'<title>Download (.+?)<' + + OFFLINE_PATTERN = r'>\s*(404 Page Not Found|File not Found|Mirror does not exist)' + + + def getLinks(self + links = [] + + m = re.search(r'(/download/gethosts/.+?)"') + if m: + self.html = self.load(urljoin("http://go4up.com/", m.group(1))) + pages = [self.load(url) for url in re.findall(self.LINK_PATTERN, self.html)] + else: + pages = [self.html] + + for html in pages: + try: + links.append(re.search(r'<b><a href="(.+?)"', html).group(1)) + except Exception: + continue + + return links diff --git a/module/plugins/crypter/GooGl.py b/pyload/plugin/crypter/GooGl.py index 13ffce505..13ffce505 100644 --- a/module/plugins/crypter/GooGl.py +++ b/pyload/plugin/crypter/GooGl.py diff --git a/module/plugins/crypter/HoerbuchIn.py b/pyload/plugin/crypter/HoerbuchIn.py index a12d7c02a..a12d7c02a 100644 --- a/module/plugins/crypter/HoerbuchIn.py +++ b/pyload/plugin/crypter/HoerbuchIn.py diff --git a/pyload/plugin/crypter/HotfileCom.py b/pyload/plugin/crypter/HotfileCom.py new file mode 100644 index 000000000..8085aa797 --- /dev/null +++ b/pyload/plugin/crypter/HotfileCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class HotfileCom(DeadCrypter): + __name__ = "HotfileCom" + __type__ = "crypter" + __version__ = "0.30" + + __pattern__ = r'https?://(?:www\.)?hotfile\.com/list/\w+/\w+' + __config__ = [] + + __description__ = """Hotfile.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org")] diff --git a/pyload/plugin/crypter/ILoadTo.py b/pyload/plugin/crypter/ILoadTo.py new file mode 100644 index 000000000..f333e262f --- /dev/null +++ b/pyload/plugin/crypter/ILoadTo.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class ILoadTo(DeadCrypter): + __name__ = "ILoadTo" + __type__ = "crypter" + __version__ = "0.11" + + __pattern__ = r'http://(?:www\.)?iload\.to/go/\d+-[\w.-]+/' + __config__ = [] + + __description__ = """Iload.to decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("hzpz", "")] diff --git a/pyload/plugin/crypter/ImgurComAlbum.py b/pyload/plugin/crypter/ImgurComAlbum.py new file mode 100644 index 000000000..d2ca38d40 --- /dev/null +++ b/pyload/plugin/crypter/ImgurComAlbum.py @@ -0,0 +1,27 @@ +import re + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter +from pyload.utils import uniqify + + +class ImgurComAlbum(SimpleCrypter): + __name__ = "ImgurComAlbum" + __type__ = "crypter" + __version__ = "0.51" + + __pattern__ = r'https?://(?:www\.|m\.)?imgur\.com/(a|gallery|)/?\w{5,7}' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Imgur.com decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("nath_schwarz", "nathan.notwhite@gmail.com")] + + + NAME_PATTERN = r'(?P<N>.+?) - Imgur' + LINK_PATTERN = r'i\.imgur\.com/\w{7}s?\.(?:jpeg|jpg|png|gif|apng)' + + + def getLinks(self): + f = lambda url: "http://" + re.sub(r'(\w{7})s\.', r'\1.', url) + return uniqify(map(f, re.findall(self.LINK_PATTERN, self.html))) diff --git a/module/plugins/crypter/LetitbitNet.py b/pyload/plugin/crypter/LetitbitNet.py index 24bc196b3..24bc196b3 100644 --- a/module/plugins/crypter/LetitbitNet.py +++ b/pyload/plugin/crypter/LetitbitNet.py diff --git a/module/plugins/crypter/LinkCryptWs.py b/pyload/plugin/crypter/LinkCryptWs.py index a3eb4f179..a3eb4f179 100644 --- a/module/plugins/crypter/LinkCryptWs.py +++ b/pyload/plugin/crypter/LinkCryptWs.py diff --git a/pyload/plugin/crypter/LinkSaveIn.py b/pyload/plugin/crypter/LinkSaveIn.py new file mode 100644 index 000000000..b303303a0 --- /dev/null +++ b/pyload/plugin/crypter/LinkSaveIn.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleDereferer import SimpleDereferer + + +class LinkSaveIn(SimpleDereferer): + __name__ = "LinkSaveIn" + __type__ = "crypter" + __version__ = "2.03" + + __pattern__ = r'https?://(?:www\.)?linksave\.in/\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """LinkSave.in decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + COOKIES = [("linksave.in", "Linksave_Language", "english")] + + OFFLINE_PATTERN = r'>(Error )?404 -' diff --git a/module/plugins/crypter/LinkdecrypterCom.py b/pyload/plugin/crypter/LinkdecrypterCom.py index facec37d5..facec37d5 100644 --- a/module/plugins/crypter/LinkdecrypterCom.py +++ b/pyload/plugin/crypter/LinkdecrypterCom.py diff --git a/module/plugins/crypter/LixIn.py b/pyload/plugin/crypter/LixIn.py index 4b978723f..4b978723f 100644 --- a/module/plugins/crypter/LixIn.py +++ b/pyload/plugin/crypter/LixIn.py diff --git a/pyload/plugin/crypter/LofCc.py b/pyload/plugin/crypter/LofCc.py new file mode 100644 index 000000000..076ab59d7 --- /dev/null +++ b/pyload/plugin/crypter/LofCc.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class LofCc(DeadCrypter): + __name__ = "LofCc" + __type__ = "crypter" + __version__ = "0.21" + + __pattern__ = r'http://(?:www\.)?lof\.cc/(.+)' + __config__ = [] + + __description__ = """Lof.cc decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("mkaay", "mkaay@mkaay.de")] diff --git a/pyload/plugin/crypter/MBLinkInfo.py b/pyload/plugin/crypter/MBLinkInfo.py new file mode 100644 index 000000000..7e7be2029 --- /dev/null +++ b/pyload/plugin/crypter/MBLinkInfo.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class MBLinkInfo(DeadCrypter): + __name__ = "MBLinkInfo" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?mblink\.info/?\?id=(\d+)' + __config__ = [] + + __description__ = """MBLink.info decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("Gummibaer", "Gummibaer@wiki-bierkiste.de"), + ("stickell", "l.stickell@yahoo.it")] diff --git a/module/plugins/crypter/MediafireCom.py b/pyload/plugin/crypter/MediafireCom.py index a7360a6db..a7360a6db 100644 --- a/module/plugins/crypter/MediafireCom.py +++ b/pyload/plugin/crypter/MediafireCom.py diff --git a/pyload/plugin/crypter/MegaCoNz.py b/pyload/plugin/crypter/MegaCoNz.py new file mode 100644 index 000000000..3f1d10a5a --- /dev/null +++ b/pyload/plugin/crypter/MegaCoNz.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.Crypter import Crypter + + +class MegaCoNz(Crypter): + __name__ = "MegaCoNz" + __type__ = "crypter" + __version__ = "0.04" + + __pattern__ = r'(?:https?://(?:www\.)?mega\.co\.nz/|mega:|chrome:.+?)#F!(?P<ID>[\w^_]+)!(?P<KEY>[\w,\\-]+)' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Mega.co.nz folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + def setup(self): + self.req.setOption("timeout", 300) + + + def decrypt(self, pyfile): + url = "https://mega.co.nz/#F!%s!%s" % re.match(self.__pattern__, pyfile.url).groups() + self.html = self.load("http://rapidgen.org/linkfinder", post={'linklisturl': url}) + self.urls = re.findall(r'(https://mega.co.nz/#N!.+?)<', self.html) + + if not self.urls: #@TODO: Remove in 0.4.10 + self.fail(_("No link grabbed")) diff --git a/pyload/plugin/crypter/MegaRapidCz.py b/pyload/plugin/crypter/MegaRapidCz.py new file mode 100644 index 000000000..79900c08a --- /dev/null +++ b/pyload/plugin/crypter/MegaRapidCz.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class MegaRapidCz(SimpleCrypter): + __name__ = "MegaRapidCz" + __type__ = "crypter" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?(share|mega)rapid\.cz/slozka/\d+/\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Share-Rapid.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + LINK_PATTERN = r'<td class="soubor"[^>]*><a href="([^"]+)">' diff --git a/pyload/plugin/crypter/MegauploadCom.py b/pyload/plugin/crypter/MegauploadCom.py new file mode 100644 index 000000000..72e0268dd --- /dev/null +++ b/pyload/plugin/crypter/MegauploadCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class MegauploadCom(DeadCrypter): + __name__ = "MegauploadCom" + __type__ = "crypter" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?megaupload\.com/(\?f|xml/folderfiles\.php\?.*&?folderid)=\w+' + + __description__ = """Megaupload.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/crypter/Movie2KTo.py b/pyload/plugin/crypter/Movie2KTo.py new file mode 100644 index 000000000..f8ff4e756 --- /dev/null +++ b/pyload/plugin/crypter/Movie2KTo.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class Movie2KTo(DeadCrypter): + __name__ = "Movie2KTo" + __type__ = "crypter" + __version__ = "0.51" + + __pattern__ = r'http://(?:www\.)?movie2k\.to/(.+)\.html' + __config__ = [] + + __description__ = """Movie2k.to decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("4Christopher", "4Christopher@gmx.de")] diff --git a/pyload/plugin/crypter/MultiUpOrg.py b/pyload/plugin/crypter/MultiUpOrg.py new file mode 100644 index 000000000..1585ac1c8 --- /dev/null +++ b/pyload/plugin/crypter/MultiUpOrg.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- + +import re +from urlparse import urljoin + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class MultiUpOrg(SimpleCrypter): + __name__ = "MultiUpOrg" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?multiup\.org/(en|fr)/(?P<TYPE>project|download|miror)/\w+(/\w+)?' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """MultiUp.org decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + NAME_PATTERN = r'<title>.*(?:Project|Projet|ownload|élécharger) (?P<N>.+?) (\(|- )' + + + def getLinks(self): + m_type = re.match(self.__pattern__, self.pyfile.url).group('TYPE') + + if m_type == "project": + pattern = r'\n(http://www\.multiup\.org/(?:en|fr)/download/.*)' + else: + pattern = r'style="width:97%;text-align:left".*\n.*href="(.*)"' + if m_type == "download": + dl_pattern = r'href="(.*)">.*\n.*<h5>DOWNLOAD</h5>' + miror_page = urljoin("http://www.multiup.org", re.search(dl_pattern, self.html).group(1)) + self.html = self.load(miror_page) + + return re.findall(pattern, self.html) diff --git a/module/plugins/crypter/MultiloadCz.py b/pyload/plugin/crypter/MultiloadCz.py index 856a94a25..856a94a25 100644 --- a/module/plugins/crypter/MultiloadCz.py +++ b/pyload/plugin/crypter/MultiloadCz.py diff --git a/pyload/plugin/crypter/MultiuploadCom.py b/pyload/plugin/crypter/MultiuploadCom.py new file mode 100644 index 000000000..9127140f1 --- /dev/null +++ b/pyload/plugin/crypter/MultiuploadCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class MultiuploadCom(DeadCrypter): + __name__ = "MultiuploadCom" + __type__ = "crypter" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?multiupload\.(com|nl)/\w+' + + __description__ = """MultiUpload.com decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/module/plugins/crypter/NCryptIn.py b/pyload/plugin/crypter/NCryptIn.py index 29b45b11a..29b45b11a 100644 --- a/module/plugins/crypter/NCryptIn.py +++ b/pyload/plugin/crypter/NCryptIn.py diff --git a/pyload/plugin/crypter/NetfolderIn.py b/pyload/plugin/crypter/NetfolderIn.py new file mode 100644 index 000000000..a24a5270f --- /dev/null +++ b/pyload/plugin/crypter/NetfolderIn.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class NetfolderIn(SimpleCrypter): + __name__ = "NetfolderIn" + __type__ = "crypter" + __version__ = "0.72" + + __pattern__ = r'http://(?:www\.)?netfolder\.in/(folder\.php\?folder_id=)?(?P<ID>\w+)(?(1)|/\w+)' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """NetFolder.in decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("fragonib", "fragonib[AT]yahoo[DOT]es")] + + + NAME_PATTERN = r'<div class="Text">Inhalt des Ordners <span.*>(?P<N>.+)</span></div>' + + + def prepare(self): + super(NetfolderIn, self).prepare() + + # Check for password protection + if self.isPasswordProtected(): + self.html = self.submitPassword() + if not self.html: + self.fail(_("Incorrect password, please set right password on Add package form and retry")) + + + def isPasswordProtected(self): + if '<input type="password" name="password"' in self.html: + self.logDebug("Links are password protected") + return True + return False + + + def submitPassword(self): + # Gather data + try: + m = re.match(self.__pattern__, self.pyfile.url) + id = m.group('ID') + except AttributeError: + self.logDebug("Unable to get package id from url [%s]" % self.pyfile.url) + return + url = "http://netfolder.in/folder.php?folder_id=" + id + password = self.getPassword() + + # Submit package password + post = {'password': password, 'save': 'Absenden'} + self.logDebug("Submitting password [%s] for protected links with id [%s]" % (password, id)) + html = self.load(url, {}, post) + + # Check for invalid password + if '<div class="InPage_Error">' in html: + self.logDebug("Incorrect password, please set right password on Edit package form and retry") + return None + + return html + + + def getLinks(self): + links = re.search(r'name="list" value="(.*?)"', self.html).group(1).split(",") + self.logDebug("Package has %d links" % len(links)) + return links diff --git a/pyload/plugin/crypter/NosvideoCom.py b/pyload/plugin/crypter/NosvideoCom.py new file mode 100644 index 000000000..d048ec956 --- /dev/null +++ b/pyload/plugin/crypter/NosvideoCom.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class NosvideoCom(SimpleCrypter): + __name__ = "NosvideoCom" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?nosvideo\.com/\?v=\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Nosvideo.com decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("igel", "igelkun@myopera.com")] + + + LINK_PATTERN = r'href="(http://(?:w{3}\.)?nosupload\.com/\?d=\w+)"' + NAME_PATTERN = r'<[tT]itle>Watch (?P<N>.+?)<' diff --git a/module/plugins/crypter/OneKhDe.py b/pyload/plugin/crypter/OneKhDe.py index 323214df8..323214df8 100644 --- a/module/plugins/crypter/OneKhDe.py +++ b/pyload/plugin/crypter/OneKhDe.py diff --git a/pyload/plugin/crypter/OronCom.py b/pyload/plugin/crypter/OronCom.py new file mode 100644 index 000000000..257e0e046 --- /dev/null +++ b/pyload/plugin/crypter/OronCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class OronCom(DeadCrypter): + __name__ = "OronCom" + __type__ = "crypter" + __version__ = "0.11" + + __pattern__ = r'http://(?:www\.)?oron\.com/folder/\w+' + __config__ = [] + + __description__ = """Oron.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("DHMH", "webmaster@pcProfil.de")] diff --git a/pyload/plugin/crypter/PastebinCom.py b/pyload/plugin/crypter/PastebinCom.py new file mode 100644 index 000000000..43a818cf1 --- /dev/null +++ b/pyload/plugin/crypter/PastebinCom.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class PastebinCom(SimpleCrypter): + __name__ = "PastebinCom" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?pastebin\.com/\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Pastebin.com decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + LINK_PATTERN = r'<div class="de\d+">(https?://[^ <]+)(?:[^<]*)</div>' + NAME_PATTERN = r'<div class="paste_box_line1" title="(?P<N>[^"]+)">' diff --git a/module/plugins/crypter/QuickshareCz.py b/pyload/plugin/crypter/QuickshareCz.py index 8cd4b9c02..8cd4b9c02 100644 --- a/module/plugins/crypter/QuickshareCz.py +++ b/pyload/plugin/crypter/QuickshareCz.py diff --git a/pyload/plugin/crypter/RSLayerCom.py b/pyload/plugin/crypter/RSLayerCom.py new file mode 100644 index 000000000..8ea8a4369 --- /dev/null +++ b/pyload/plugin/crypter/RSLayerCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class RSLayerCom(DeadCrypter): + __name__ = "RSLayerCom" + __type__ = "crypter" + __version__ = "0.21" + + __pattern__ = r'http://(?:www\.)?rs-layer\.com/directory-' + __config__ = [] + + __description__ = """RS-Layer.com decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("hzpz", "")] diff --git a/pyload/plugin/crypter/RelinkUs.py b/pyload/plugin/crypter/RelinkUs.py new file mode 100644 index 000000000..0c27c29b5 --- /dev/null +++ b/pyload/plugin/crypter/RelinkUs.py @@ -0,0 +1,293 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import binascii +import re +import os + +from Crypto.Cipher import AES +from pyload.plugin.Crypter import Crypter +from pyload.utils import safe_join + + +class RelinkUs(Crypter): + __name__ = "RelinkUs" + __type__ = "crypter" + __version__ = "3.12" + + __pattern__ = r'http://(?:www\.)?relink\.us/(f/|((view|go)\.php\?id=))(?P<ID>.+)' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Relink.us decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("fragonib", "fragonib[AT]yahoo[DOT]es"), + ("AndroKev", "neureither.kevin@gmail.com")] + + + PREFERRED_LINK_SOURCES = ["cnl2", "dlc", "web"] + + OFFLINE_TOKEN = r'<title>Tattooside' + + PASSWORD_TOKEN = r'container_password.php' + PASSWORD_ERROR_ROKEN = r'You have entered an incorrect password' + PASSWORD_SUBMIT_URL = r'http://www.relink.us/container_password.php' + + CAPTCHA_TOKEN = r'container_captcha.php' + CAPTCHA_ERROR_ROKEN = r'You have solved the captcha wrong' + CAPTCHA_IMG_URL = r'http://www.relink.us/core/captcha/circlecaptcha.php' + CAPTCHA_SUBMIT_URL = r'http://www.relink.us/container_captcha.php' + + FILE_TITLE_REGEX = r'<th>Title</th><td>(.*)</td></tr>' + FILE_NOTITLE = r'No title' + + CNL2_FORM_REGEX = r'<form id="cnl_form-(.*?)</form>' + CNL2_FORMINPUT_REGEX = r'<input.*?name="%s".*?value="(.*?)"' + CNL2_JK_KEY = "jk" + CNL2_CRYPTED_KEY = "crypted" + + DLC_LINK_REGEX = r'<a href=".*?" class="dlc_button" target="_blank">' + DLC_DOWNLOAD_URL = r'http://www.relink.us/download.php' + + WEB_FORWARD_REGEX = r'getFile\(\'(.+)\'\)' + WEB_FORWARD_URL = r'http://www.relink.us/frame.php' + WEB_LINK_REGEX = r'<iframe name="Container" height="100%" frameborder="no" width="100%" src="(.+)"></iframe>' + + + def setup(self): + self.fileid = None + self.package = None + self.captcha = False + + + def decrypt(self, pyfile): + # Init + self.initPackage(pyfile) + + # Request package + self.requestPackage() + + # Check for online + if not self.isOnline(): + self.offline() + + # Check for protection + if self.isPasswordProtected(): + self.unlockPasswordProtection() + self.handleErrors() + + if self.isCaptchaProtected(): + self.captcha = True + self.unlockCaptchaProtection() + self.handleErrors() + + # Get package name and folder + (package_name, folder_name) = self.getPackageInfo() + + # Extract package links + package_links = [] + for sources in self.PREFERRED_LINK_SOURCES: + package_links.extend(self.handleLinkSource(sources)) + if package_links: # use only first source which provides links + break + package_links = set(package_links) + + # Pack + if package_links: + self.packages = [(package_name, package_links, folder_name)] + + + def initPackage(self, pyfile): + self.fileid = re.match(self.__pattern__, pyfile.url).group('ID') + self.package = pyfile.package() + + + def requestPackage(self): + self.html = self.load(self.pyfile.url, decode=True) + + + def isOnline(self): + if self.OFFLINE_TOKEN in self.html: + self.logDebug("File not found") + return False + return True + + + def isPasswordProtected(self): + if self.PASSWORD_TOKEN in self.html: + self.logDebug("Links are password protected") + return True + + + def isCaptchaProtected(self): + if self.CAPTCHA_TOKEN in self.html: + self.logDebug("Links are captcha protected") + return True + return False + + + def unlockPasswordProtection(self): + password = self.getPassword() + + self.logDebug("Submitting password [%s] for protected links" % password) + + if password: + passwd_url = self.PASSWORD_SUBMIT_URL + "?id=%s" % self.fileid + passwd_data = {'id': self.fileid, 'password': password, 'pw': 'submit'} + self.html = self.load(passwd_url, post=passwd_data, decode=True) + + + def unlockCaptchaProtection(self): + self.logDebug("Request user positional captcha resolving") + captcha_img_url = self.CAPTCHA_IMG_URL + "?id=%s" % self.fileid + coords = self.decryptCaptcha(captcha_img_url, forceUser=True, imgtype="png", result_type='positional') + self.logDebug("Captcha resolved, coords [%s]" % str(coords)) + captcha_post_url = self.CAPTCHA_SUBMIT_URL + "?id=%s" % self.fileid + captcha_post_data = {'button.x': coords[0], 'button.y': coords[1], 'captcha': 'submit'} + self.html = self.load(captcha_post_url, post=captcha_post_data, decode=True) + + + def getPackageInfo(self): + name = folder = None + + # Try to get info from web + m = re.search(self.FILE_TITLE_REGEX, self.html) + if m is not None: + title = m.group(1).strip() + if not self.FILE_NOTITLE in title: + name = folder = title + self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder)) + + # Fallback to defaults + if not name or not folder: + name = self.package.name + folder = self.package.folder + self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder)) + + # Return package info + return name, folder + + + def handleErrors(self): + if self.PASSWORD_ERROR_ROKEN in self.html: + msg = "Incorrect password, please set right password on 'Edit package' form and retry" + self.logDebug(msg) + self.fail(_(msg)) + + if self.captcha: + if self.CAPTCHA_ERROR_ROKEN in self.html: + self.invalidCaptcha() + self.retry() + else: + self.correctCaptcha() + + + def handleLinkSource(self, source): + if source == 'cnl2': + return self.handleCNL2Links() + elif source == 'dlc': + return self.handleDLCLinks() + elif source == 'web': + return self.handleWEBLinks() + else: + self.error(_('Unknown source type "%s"') % source) + + + def handleCNL2Links(self): + self.logDebug("Search for CNL2 links") + package_links = [] + m = re.search(self.CNL2_FORM_REGEX, self.html, re.S) + if m is not None: + cnl2_form = m.group(1) + try: + (vcrypted, vjk) = self._getCipherParams(cnl2_form) + for (crypted, jk) in zip(vcrypted, vjk): + package_links.extend(self._getLinks(crypted, jk)) + except Exception: + self.logDebug("Unable to decrypt CNL2 links") + return package_links + + + def handleDLCLinks(self): + self.logDebug("Search for DLC links") + package_links = [] + m = re.search(self.DLC_LINK_REGEX, self.html) + if m is not None: + container_url = self.DLC_DOWNLOAD_URL + "?id=%s&dlc=1" % self.fileid + self.logDebug("Downloading DLC container link [%s]" % container_url) + try: + dlc = self.load(container_url) + dlc_filename = self.fileid + ".dlc" + dlc_filepath = safe_join(self.config['general']['download_folder'], dlc_filename) + with open(dlc_filepath, "wb") as f: + f.write(dlc) + package_links.append(dlc_filepath) + + except Exception: + self.fail(_("Unable to download DLC container")) + + return package_links + + + def handleWEBLinks(self): + self.logDebug("Search for WEB links") + + package_links = [] + params = re.findall(self.WEB_FORWARD_REGEX, self.html) + + self.logDebug("Decrypting %d Web links" % len(params)) + + for index, param in enumerate(params): + try: + url = self.WEB_FORWARD_URL + "?%s" % param + + self.logDebug("Decrypting Web link %d, %s" % (index + 1, url)) + + res = self.load(url, decode=True) + link = re.search(self.WEB_LINK_REGEX, res).group(1) + + package_links.append(link) + + except Exception, detail: + self.logDebug("Error decrypting Web link %s, %s" % (index, detail)) + + self.setWait(4) + self.wait() + + return package_links + + + def _getCipherParams(self, cnl2_form): + # Get jk + jk_re = self.CNL2_FORMINPUT_REGEX % self.CNL2_JK_KEY + vjk = re.findall(jk_re, cnl2_form, re.I) + + # Get crypted + crypted_re = self.CNL2_FORMINPUT_REGEX % RelinkUs.CNL2_CRYPTED_KEY + vcrypted = re.findall(crypted_re, cnl2_form, re.I) + + # Log and return + self.logDebug("Detected %d crypted blocks" % len(vcrypted)) + return vcrypted, vjk + + + def _getLinks(self, crypted, jk): + # Get key + jreturn = self.js.eval("%s f()" % jk) + self.logDebug("JsEngine returns value [%s]" % jreturn) + key = binascii.unhexlify(jreturn) + + # Decrypt + Key = key + IV = key + obj = AES.new(Key, AES.MODE_CBC, IV) + text = obj.decrypt(crypted.decode('base64')) + + # Extract links + text = text.replace("\x00", "").replace("\r", "") + links = filter(bool, text.split('\n')) + + # Log and return + self.logDebug("Package has %d links" % len(links)) + return links diff --git a/module/plugins/crypter/SafelinkingNet.py b/pyload/plugin/crypter/SafelinkingNet.py index 2d5d273ed..2d5d273ed 100644 --- a/module/plugins/crypter/SafelinkingNet.py +++ b/pyload/plugin/crypter/SafelinkingNet.py diff --git a/pyload/plugin/crypter/SecuredIn.py b/pyload/plugin/crypter/SecuredIn.py new file mode 100644 index 000000000..b0b8eb6d3 --- /dev/null +++ b/pyload/plugin/crypter/SecuredIn.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class SecuredIn(DeadCrypter): + __name__ = "SecuredIn" + __type__ = "crypter" + __version__ = "0.21" + + __pattern__ = r'http://(?:www\.)?secured\.in/download-[\d]+-\w{8}\.html' + __config__ = [] + + __description__ = """Secured.in decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("mkaay", "mkaay@mkaay.de")] diff --git a/module/plugins/crypter/SexuriaCom.py b/pyload/plugin/crypter/SexuriaCom.py index 10101cd7a..10101cd7a 100644 --- a/module/plugins/crypter/SexuriaCom.py +++ b/pyload/plugin/crypter/SexuriaCom.py diff --git a/module/plugins/crypter/ShareLinksBiz.py b/pyload/plugin/crypter/ShareLinksBiz.py index 1328e86aa..1328e86aa 100644 --- a/module/plugins/crypter/ShareLinksBiz.py +++ b/pyload/plugin/crypter/ShareLinksBiz.py diff --git a/pyload/plugin/crypter/SharingmatrixCom.py b/pyload/plugin/crypter/SharingmatrixCom.py new file mode 100644 index 000000000..7db09b246 --- /dev/null +++ b/pyload/plugin/crypter/SharingmatrixCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class SharingmatrixCom(DeadCrypter): + __name__ = "SharingmatrixCom" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?sharingmatrix\.com/folder/\w+' + + __description__ = """Sharingmatrix.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/crypter/SpeedLoadOrg.py b/pyload/plugin/crypter/SpeedLoadOrg.py new file mode 100644 index 000000000..95c8864dc --- /dev/null +++ b/pyload/plugin/crypter/SpeedLoadOrg.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class SpeedLoadOrg(DeadCrypter): + __name__ = "SpeedLoadOrg" + __type__ = "crypter" + __version__ = "0.30" + + __pattern__ = r'http://(?:www\.)?speedload\.org/(\d+~f$|folder/\d+/)' + __config__ = [] + + __description__ = """Speedload decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] diff --git a/pyload/plugin/crypter/StealthTo.py b/pyload/plugin/crypter/StealthTo.py new file mode 100644 index 000000000..23747be1b --- /dev/null +++ b/pyload/plugin/crypter/StealthTo.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class StealthTo(DeadCrypter): + __name__ = "StealthTo" + __type__ = "crypter" + __version__ = "0.20" + + __pattern__ = r'http://(?:www\.)?stealth\.to/folder/.+' + __config__ = [] + + __description__ = """Stealth.to decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("spoob", "spoob@pyload.org")] diff --git a/pyload/plugin/crypter/TnyCz.py b/pyload/plugin/crypter/TnyCz.py new file mode 100644 index 000000000..d73f6de63 --- /dev/null +++ b/pyload/plugin/crypter/TnyCz.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + +import re + + +class TnyCz(SimpleCrypter): + __name__ = "TnyCz" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?tny\.cz/\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Tny.cz decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + NAME_PATTERN = r'<title>(?P<N>.+) - .+</title>' + + + def getLinks(self): + m = re.search(r'<a id=\'save_paste\' href="(.+save\.php\?hash=.+)">', self.html) + return re.findall(".+", self.load(m.group(1), decode=True)) if m else None diff --git a/pyload/plugin/crypter/TrailerzoneInfo.py b/pyload/plugin/crypter/TrailerzoneInfo.py new file mode 100644 index 000000000..06894054b --- /dev/null +++ b/pyload/plugin/crypter/TrailerzoneInfo.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class TrailerzoneInfo(DeadCrypter): + __name__ = "TrailerzoneInfo" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?trailerzone\.info/.+' + __config__ = [] + + __description__ = """TrailerZone.info decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("godofdream", "soilfiction@gmail.com")] diff --git a/pyload/plugin/crypter/TurbobitNet.py b/pyload/plugin/crypter/TurbobitNet.py new file mode 100644 index 000000000..d6b6d7b38 --- /dev/null +++ b/pyload/plugin/crypter/TurbobitNet.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter +from pyload.utils import json_loads + + +class TurbobitNet(SimpleCrypter): + __name__ = "TurbobitNet" + __type__ = "crypter" + __version__ = "0.05" + + __pattern__ = r'http://(?:www\.)?turbobit\.net/download/folder/(?P<ID>\w+)' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Turbobit.net folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + NAME_PATTERN = r'src=\'/js/lib/grid/icon/folder.png\'> <span>(?P<N>.+?)</span>' + + + def _getLinks(self, id, page=1): + gridFile = self.load("http://turbobit.net/downloadfolder/gridFile", + get={"rootId": id, "rows": 200, "page": page}, decode=True) + grid = json_loads(gridFile) + + if grid['rows']: + for i in grid['rows']: + yield i['id'] + for id in self._getLinks(id, page + 1): + yield id + else: + return + + + def getLinks(self): + id = re.match(self.__pattern__, self.pyfile.url).group('ID') + fixurl = lambda id: "http://turbobit.net/%s.html" % id + return map(fixurl, self._getLinks(id)) diff --git a/pyload/plugin/crypter/TusfilesNet.py b/pyload/plugin/crypter/TusfilesNet.py new file mode 100644 index 000000000..39d5dee9d --- /dev/null +++ b/pyload/plugin/crypter/TusfilesNet.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +import math +import re +from urlparse import urljoin + +from pyload.plugin.internal.XFSCrypter import XFSCrypter + + +class TusfilesNet(XFSCrypter): + __name__ = "TusfilesNet" + __type__ = "crypter" + __version__ = "0.08" + + __pattern__ = r'https?://(?:www\.)?tusfiles\.net/go/(?P<ID>\w+)' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Tusfiles.net folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com"), + ("stickell", "l.stickell@yahoo.it")] + + + PAGES_PATTERN = r'>\((\d+) \w+\)<' + + URL_REPLACEMENTS = [(__pattern__ + ".*", r'https://www.tusfiles.net/go/\g<ID>/')] + + + def loadPage(self, page_n): + return self.load(urljoin(self.pyfile.url, str(page_n)), decode=True) + + + def handlePages(self, pyfile): + pages = re.search(self.PAGES_PATTERN, self.html) + if pages: + pages = int(math.ceil(int(pages.group('pages')) / 25.0)) + else: + return + + for p in xrange(2, pages + 1): + self.html = self.loadPage(p) + self.links += self.getLinks() diff --git a/module/plugins/crypter/UlozTo.py b/pyload/plugin/crypter/UlozTo.py index 81fbee172..81fbee172 100644 --- a/module/plugins/crypter/UlozTo.py +++ b/pyload/plugin/crypter/UlozTo.py diff --git a/pyload/plugin/crypter/UploadableCh.py b/pyload/plugin/crypter/UploadableCh.py new file mode 100644 index 000000000..f5fb0c3bc --- /dev/null +++ b/pyload/plugin/crypter/UploadableCh.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class UploadableCh(SimpleCrypter): + __name__ = "UploadableCh" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?uploadable\.ch/list/\w+' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Uploadable.ch folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("guidobelix", "guidobelix@hotmail.it"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + LINK_PATTERN = r'"(.+?)" class="icon_zipfile">' + NAME_PATTERN = r'<div class="folder"><span> </span>(?P<N>.+?)</div>' + OFFLINE_PATTERN = r'We are sorry... The URL you entered cannot be found on the server.' + TEMP_OFFLINE_PATTERN = r'<div class="icon_err">' diff --git a/pyload/plugin/crypter/UploadedTo.py b/pyload/plugin/crypter/UploadedTo.py new file mode 100644 index 000000000..282f82be7 --- /dev/null +++ b/pyload/plugin/crypter/UploadedTo.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urljoin + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class UploadedTo(SimpleCrypter): + __name__ = "UploadedTo" + __type__ = "crypter" + __version__ = "0.42" + + __pattern__ = r'http://(?:www\.)?(uploaded|ul)\.(to|net)/(f|folder|list)/(?P<ID>\w+)' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """UploadedTo decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + PLAIN_PATTERN = r'<small class="date"><a href="([\w/]+)" onclick=' + NAME_PATTERN = r'<title>(?P<N>.+?)<' + + + def getLinks(self): + m = re.search(self.PLAIN_PATTERN, self.html) + if m is None: + self.error(_("PLAIN_PATTERN not found")) + + plain_link = urljoin("http://uploaded.net/", m.group(1)) + return self.load(plain_link).split('\n')[:-1] diff --git a/pyload/plugin/crypter/WiiReloadedOrg.py b/pyload/plugin/crypter/WiiReloadedOrg.py new file mode 100644 index 000000000..4190cb340 --- /dev/null +++ b/pyload/plugin/crypter/WiiReloadedOrg.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class WiiReloadedOrg(DeadCrypter): + __name__ = "WiiReloadedOrg" + __type__ = "crypter" + __version__ = "0.11" + + __pattern__ = r'http://(?:www\.)?wii-reloaded\.org/protect/get\.php\?i=.+' + __config__ = [] + + __description__ = """Wii-Reloaded.org decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("hzpz", "")] diff --git a/pyload/plugin/crypter/WuploadCom.py b/pyload/plugin/crypter/WuploadCom.py new file mode 100644 index 000000000..fb00cb136 --- /dev/null +++ b/pyload/plugin/crypter/WuploadCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadCrypter import DeadCrypter + + +class WuploadCom(DeadCrypter): + __name__ = "WuploadCom" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?wupload\.com/folder/\w+' + + __description__ = """Wupload.com folder decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/crypter/XFileSharingPro.py b/pyload/plugin/crypter/XFileSharingPro.py new file mode 100644 index 000000000..3dc2e8f70 --- /dev/null +++ b/pyload/plugin/crypter/XFileSharingPro.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.XFSCrypter import XFSCrypter + + +class XFileSharingPro(XFSCrypter): + __name__ = "XFileSharingPro" + __type__ = "crypter" + __version__ = "0.04" + + __pattern__ = r'^unmatchable$' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """XFileSharingPro dummy folder decrypter plugin for hook""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + def _log(self, type, args): + msg = " | ".join(str(a).strip() for a in args if a) + logger = getattr(self.log, type) + logger("%s: %s: %s" % (self.__name__, self.HOSTER_NAME, msg or _("%s MARK" % type.upper()))) + + + def init(self): + super(XFileSharingPro, self).init() + + self.__pattern__ = self.core.pluginManager.crypterPlugins[self.__name__]['pattern'] + + self.HOSTER_DOMAIN = re.match(self.__pattern__, self.pyfile.url).group("DOMAIN").lower() + self.HOSTER_NAME = "".join(part.capitalize() for part in re.split(r'(\.|\d+)', self.HOSTER_DOMAIN) if part != '.') + + if self.HOSTER_NAME[0].isdigit(): + self.HOSTER_NAME = 'X' + self.HOSTER_NAME + + account = self.core.accountManager.getAccountPlugin(self.HOSTER_NAME) + + if account and account.canUse(): + self.account = account + + elif self.account: + self.account.HOSTER_DOMAIN = self.HOSTER_DOMAIN + + else: + return + + self.user, data = self.account.selectAccount() + self.req = self.account.getAccountRequest(self.user) + self.premium = self.account.isPremium(self.user) diff --git a/module/plugins/crypter/XupPl.py b/pyload/plugin/crypter/XupPl.py index 9d4d27b61..9d4d27b61 100644 --- a/module/plugins/crypter/XupPl.py +++ b/pyload/plugin/crypter/XupPl.py diff --git a/module/plugins/crypter/YoutubeBatch.py b/pyload/plugin/crypter/YoutubeBatch.py index 5e4269fd2..5e4269fd2 100644 --- a/module/plugins/crypter/YoutubeBatch.py +++ b/pyload/plugin/crypter/YoutubeBatch.py diff --git a/module/plugins/crypter/__init__.py b/pyload/plugin/crypter/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/plugins/crypter/__init__.py +++ b/pyload/plugin/crypter/__init__.py diff --git a/pyload/plugin/extractor/SevenZip.py b/pyload/plugin/extractor/SevenZip.py new file mode 100644 index 000000000..4b23c6ff2 --- /dev/null +++ b/pyload/plugin/extractor/SevenZip.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- + +import os +import re + +from subprocess import Popen, PIPE + +from pyload.plugin.internal.UnRar import ArchiveError, CRCError, PasswordError, UnRar, renice +from pyload.utils import fs_encode, safe_join + + +class SevenZip(UnRar): + __name__ = "SevenZip" + __version__ = "0.08" + + __description__ = """7-Zip extractor plugin""" + __license__ = "GPLv3" + __authors__ = [("Michael Nowak", ""), + ("Walter Purcaro", "vuolter@gmail.com")] + + + CMD = "7z" + VERSION = "" + + EXTENSIONS = [".7z", ".xz", ".zip", ".gz", ".gzip", ".tgz", ".bz2", ".bzip2", + ".tbz2", ".tbz", ".tar", ".wim", ".swm", ".lzma", ".rar", ".cab", + ".arj", ".z", ".taz", ".cpio", ".rpm", ".deb", ".lzh", ".lha", + ".chm", ".chw", ".hxs", ".iso", ".msi", ".doc", ".xls", ".ppt", + ".dmg", ".xar", ".hfs", ".exe", ".ntfs", ".fat", ".vhd", ".mbr", + ".squashfs", ".cramfs", ".scap"] + + + #@NOTE: there are some more uncovered 7z formats + re_filelist = re.compile(r'([\d\:]+)\s+([\d\:]+)\s+([\w\.]+)\s+(\d+)\s+(\d+)\s+(.+)') + re_wrongpwd = re.compile(r'(Can not open encrypted archive|Wrong password)', re.I) + re_wrongcrc = re.compile(r'Encrypted\s+\=\s+\+', re.I) + re_version = re.compile(r'7-Zip\s(?:\[64\]\s)?(\d+\.\d+)', re.I) + + + @classmethod + def isUsable(cls): + if os.name == "nt": + cls.CMD = os.path.join(pypath, "7z.exe") + p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE) + out,err = p.communicate() + else: + p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE) + out, err = p.communicate() + + cls.VERSION = cls.re_version.search(out).group(1) + + return True + + + def check(self): + file = fs_encode(self.filename) + + p = self.call_cmd("t", file) + out, err = p.communicate() + + if p.returncode > 1: + raise CRCError(err) + + p = self.call_cmd("l", "-slt", file) + out, err = p.communicate() + + if p.returncode > 1: + raise ArchiveError(_("Process return code: %d") % p.returncode) + + # check if output or error macthes the 'wrong password'-Regexp + if self.re_wrongpwd.search(out): + raise PasswordError + + # check if output matches 'Encrypted = +' + if self.re_wrongcrc.search(out): + raise CRCError(_("Header protected")) + + + def isPassword(self, password): + p = self.call_cmd("l", fs_encode(self.filename), password=password) + p.communicate() + return p.returncode == 0 + + + def repair(self): + return False + + + def extract(self, password=None): + command = "x" if self.fullpath else "e" + + p = self.call_cmd(command, '-o' + self.out, fs_encode(self.filename), password=password) + + renice(p.pid, self.renice) + + # communicate and retrieve stderr + self._progress(p) + err = p.stderr.read().strip() + + if err: + if self.re_wrongpwd.search(err): + raise PasswordError + + elif self.re_wrongcrc.search(err): + raise CRCError(err) + + else: #: raise error if anything is on stderr + raise ArchiveError(err) + + if p.returncode > 1: + raise ArchiveError(_("Process return code: %d") % p.returncode) + + self.files = self.list(password) + + + def list(self, password=None): + command = "l" if self.fullpath else "l" + + p = self.call_cmd(command, fs_encode(self.filename), password=password) + out, err = p.communicate() + + if "Can not open" in err: + raise ArchiveError(_("Cannot open file")) + + if p.returncode > 1: + raise ArchiveError(_("Process return code: %d") % p.returncode) + + result = set() + for groups in self.re_filelist.findall(out): + f = groups[-1].strip() + result.add(safe_join(self.out, f)) + + return list(result) + + + def call_cmd(self, command, *xargs, **kwargs): + args = [] + + #overwrite flag + if self.overwrite: + args.append("-y") + + #set a password + if "password" in kwargs and kwargs["password"]: + args.append("-p'%s'" % kwargs["password"]) + else: + args.append("-p-") + + #@NOTE: return codes are not reliable, some kind of threading, cleanup whatever issue + call = [self.CMD, command] + args + list(xargs) + + self.manager.logDebug(" ".join(call)) + + p = Popen(call, stdout=PIPE, stderr=PIPE) + return p diff --git a/pyload/plugin/extractor/UnRar.py b/pyload/plugin/extractor/UnRar.py new file mode 100644 index 000000000..8a3985678 --- /dev/null +++ b/pyload/plugin/extractor/UnRar.py @@ -0,0 +1,248 @@ +# -*- coding: utf-8 -*- + +import os +import re + +from glob import glob +from string import digits +from subprocess import Popen, PIPE + +from pyload.plugin.internal.Extractor import Extractor, ArchiveError, CRCError, PasswordError +from pyload.utils import decode, fs_encode, safe_join + + +def renice(pid, value): + if value and os.name != "nt": + try: + Popen(["renice", str(value), str(pid)], stdout=PIPE, stderr=PIPE, bufsize=-1) + + except Exception: + pass + + +class UnRar(Extractor): + __name__ = "UnRar" + __version__ = "1.13" + + __description__ = """Rar extractor plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("Walter Purcaro", "vuolter@gmail.com"), + ("Immenz", "immenz@gmx.net"),] + + + CMD = "unrar" + VERSION = "" + + EXTENSIONS = [".rar"] + + + re_multipart = re.compile(r'\.(part|r)(\d+)(?:\.rar)?',re.I) + + re_filefixed = re.compile(r'Building (.+)') + re_filelist = re.compile(r'^(.)(\s*[\w\.\-]+)\s+(\d+\s+)+(?:\d+\%\s+)?[\d\-]{8}\s+[\d\:]{5}', re.M|re.I) + + re_wrongpwd = re.compile(r'password', re.I) + re_wrongcrc = re.compile(r'encrypted|damaged|CRC failed|checksum error', re.I) + + re_version = re.compile(r'UNRAR\s(\d+\.\d+)', re.I) + + + @classmethod + def isUsable(cls): + if os.name == "nt": + cls.CMD = os.path.join(pypath, "UnRAR.exe") + p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE) + out, err = p.communicate() + else: + try: + p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE) + out, err = p.communicate() + + except OSError: #: fallback to rar + cls.CMD = "rar" + p = Popen([cls.CMD], stdout=PIPE, stderr=PIPE) + out, err = p.communicate() + + cls.VERSION = cls.re_version.search(out).group(1) + + return True + + + @classmethod + def isMultipart(cls,filename): + multipart = cls.re_multipart.search(filename) + if multipart: + # First Multipart file (part1.rar for *.part1-9.rar format or *.rar for .r1-9 format) handled as normal Archive + return False if (multipart.group(1) == "part" and int(multipart.group(2)) == 1) else True + + return False + + + def check(self): + p = self.call_cmd("l", "-v", fs_encode(self.filename)) + out, err = p.communicate() + + if self.re_wrongpwd.search(err): + raise PasswordError + + if self.re_wrongcrc.search(err): + raise CRCError(err) + + # output only used to check if passworded files are present + for attr in self.re_filelist.findall(out): + if attr[0].startswith("*"): + raise PasswordError + + + def isPassword(self, password): + # at this point we can only verify header protected files + p = self.call_cmd("l", "-v", fs_encode(self.filename), password=password) + out, err = p.communicate() + return False if self.re_wrongpwd.search(err) else True + + + def repair(self): + p = self.call_cmd("rc", fs_encode(self.filename)) + + # communicate and retrieve stderr + self._progress(p) + err = p.stderr.read().strip() + + if err or p.returncode: + p = self.call_cmd("r", fs_encode(self.filename)) + + # communicate and retrieve stderr + self._progress(p) + err = p.stderr.read().strip() + + if err or p.returncode: + return False + else: + dir = os.path.dirname(filename) + name = re_filefixed.search(out).group(1) + + self.filename = os.path.join(dir, name) + + return True + + + def _progress(self, process): + s = "" + while True: + c = process.stdout.read(1) + # quit loop on eof + if not c: + break + # reading a percentage sign -> set progress and restart + if c == '%': + self.notifyProgress(int(s)) + s = "" + # not reading a digit -> therefore restart + elif c not in digits: + s = "" + # add digit to progressstring + else: + s += c + + + def extract(self, password=None): + command = "x" if self.fullpath else "e" + + p = self.call_cmd(command, fs_encode(self.filename), self.out, password=password) + + renice(p.pid, self.renice) + + # communicate and retrieve stderr + self._progress(p) + err = p.stderr.read().strip() + + if err: + if self.re_wrongpwd.search(err): + raise PasswordError + + elif self.re_wrongcrc.search(err): + raise CRCError(err) + + else: #: raise error if anything is on stderr + raise ArchiveError(err) + + if p.returncode: + raise ArchiveError(_("Process return code: %d") % p.returncode) + + self.files = self.list(password) + + + def getDeleteFiles(self): + dir, name = os.path.split(self.filename) + + # actually extracted file + files = [self.filename] + + # eventually Multipart Files + files.extend(safe_join(dir, os.path.basename(file)) for file in filter(self.isMultipart, os.listdir(dir)) + if re.sub(self.re_multipart,".rar",name) == re.sub(self.re_multipart,".rar",file)) + + return files + + + def list(self, password=None): + command = "vb" if self.fullpath else "lb" + + p = self.call_cmd(command, "-v", fs_encode(self.filename), password=password) + out, err = p.communicate() + + if "Cannot open" in err: + raise ArchiveError(_("Cannot open file")) + + if err.strip(): #: only log error at this point + self.manager.logError(err.strip()) + + result = set() + if not self.fullpath and self.VERSION.startswith('5'): + # NOTE: Unrar 5 always list full path + for f in decode(out).splitlines(): + f = safe_join(self.out, os.path.basename(f.strip())) + if os.path.isfile(f): + result.add(safe_join(self.out, os.path.basename(f))) + else: + for f in decode(out).splitlines(): + f = f.strip() + result.add(safe_join(self.out, f)) + + return list(result) + + + def call_cmd(self, command, *xargs, **kwargs): + args = [] + + # overwrite flag + if self.overwrite: + args.append("-o+") + else: + args.append("-o-") + if self.delete: + args.append("-or") + + for word in self.excludefiles: + args.append("-x'%s'" % word.strip()) + + # assume yes on all queries + args.append("-y") + + # set a password + if "password" in kwargs and kwargs['password']: + args.append("-p%s" % kwargs['password']) + else: + args.append("-p-") + + if self.keepbroken: + args.append("-kb") + + # NOTE: return codes are not reliable, some kind of threading, cleanup whatever issue + call = [self.CMD, command] + args + list(xargs) + + self.manager.logDebug(" ".join(call)) + + p = Popen(call, stdout=PIPE, stderr=PIPE) + return p diff --git a/pyload/plugin/extractor/UnZip.py b/pyload/plugin/extractor/UnZip.py new file mode 100644 index 000000000..cb6621f99 --- /dev/null +++ b/pyload/plugin/extractor/UnZip.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import os +import sys +import zipfile + +from pyload.plugin.internal.Extractor import Extractor, ArchiveError, CRCError, PasswordError +from pyload.utils import fs_encode + + +class UnZip(Extractor): + __name__ = "UnZip" + __version__ = "1.10" + + __description__ = """Zip extractor plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + EXTENSIONS = [".zip", ".zip64"] + VERSION ="(python %s.%s.%s)" % (sys.version_info[0], sys.version_info[1], sys.version_info[2]) + + + @classmethod + def isUsable(cls): + return sys.version_info[:2] >= (2, 6) + + + def list(self, password=None): + with zipfile.ZipFile(fs_encode(self.filename), 'r', allowZip64=True) as z: + z.setpassword(password) + return z.namelist() + + + def check(self): + with zipfile.ZipFile(fs_encode(self.filename), 'r', allowZip64=True) as z: + badfile = z.testzip() + + if badfile: + raise CRCError(badfile) + else: + raise PasswordError + + + def extract(self, password=None): + try: + with zipfile.ZipFile(fs_encode(self.filename), 'r', allowZip64=True) as z: + z.setpassword(password) + + badfile = z.testzip() + + if badfile: + raise CRCError(badfile) + else: + z.extractall(self.out) + + except (zipfile.BadZipfile, zipfile.LargeZipFile), e: + raise ArchiveError(e) + + except RuntimeError, e: + if "encrypted" in e: + raise PasswordError + else: + raise ArchiveError(e) + else: + self.files = z.namelist() diff --git a/module/plugins/hooks/__init__.py b/pyload/plugin/extractor/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/plugins/hooks/__init__.py +++ b/pyload/plugin/extractor/__init__.py diff --git a/pyload/plugin/hook/AlldebridCom.py b/pyload/plugin/hook/AlldebridCom.py new file mode 100644 index 000000000..6d3e5db48 --- /dev/null +++ b/pyload/plugin/hook/AlldebridCom.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.MultiHook import MultiHook + + +class AlldebridCom(MultiHook): + __name__ = "AlldebridCom" + __type__ = "hook" + __version__ = "0.16" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 ), + ("ssl" , "bool" , "Use HTTPS" , True )] + + __description__ = """Alldebrid.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("Andy Voigt", "spamsales@online.de")] + + + def getHosters(self): + https = "https" if self.getConfig("ssl") else "http" + html = self.getURL(https + "://www.alldebrid.com/api.php", get={'action': "get_host"}).replace("\"", "").strip() + + return [x.strip() for x in html.split(",") if x.strip()] diff --git a/pyload/plugin/hook/BypassCaptcha.py b/pyload/plugin/hook/BypassCaptcha.py new file mode 100644 index 000000000..7b7e156bb --- /dev/null +++ b/pyload/plugin/hook/BypassCaptcha.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- + +from pycurl import FORM_FILE, LOW_SPEED_TIME + +from pyload.network.HTTPRequest import BadHeader +from pyload.network.RequestFactory import getURL, getRequest +from pyload.plugin.Hook import Hook, threaded + + +class BypassCaptchaException(Exception): + + def __init__(self, err): + self.err = err + + + def getCode(self): + return self.err + + + def __str__(self): + return "<BypassCaptchaException %s>" % self.err + + + def __repr__(self): + return "<BypassCaptchaException %s>" % self.err + + +class BypassCaptcha(Hook): + __name__ = "BypassCaptcha" + __type__ = "hook" + __version__ = "0.06" + + __config__ = [("force", "bool", "Force BC even if client is connected", False), + ("passkey", "password", "Passkey", "")] + + __description__ = """Send captchas to BypassCaptcha.com""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("Godofdream", "soilfcition@gmail.com"), + ("zoidberg", "zoidberg@mujmail.cz")] + + + PYLOAD_KEY = "4f771155b640970d5607f919a615bdefc67e7d32" + + SUBMIT_URL = "http://bypasscaptcha.com/upload.php" + RESPOND_URL = "http://bypasscaptcha.com/check_value.php" + GETCREDITS_URL = "http://bypasscaptcha.com/ex_left.php" + + + def getCredits(self): + res = getURL(self.GETCREDITS_URL, post={"key": self.getConfig("passkey")}) + + data = dict(x.split(' ', 1) for x in res.splitlines()) + return int(data['Left']) + + + def submit(self, captcha, captchaType="file", match=None): + req = getRequest() + + #raise timeout threshold + req.c.setopt(LOW_SPEED_TIME, 80) + + try: + res = req.load(self.SUBMIT_URL, + post={'vendor_key': self.PYLOAD_KEY, + 'key': self.getConfig("passkey"), + 'gen_task_id': "1", + 'file': (FORM_FILE, captcha)}, + multipart=True) + finally: + req.close() + + data = dict(x.split(' ', 1) for x in res.splitlines()) + if not data or "Value" not in data: + raise BypassCaptchaException(res) + + result = data['Value'] + ticket = data['TaskId'] + self.logDebug("Result %s : %s" % (ticket, result)) + + return ticket, result + + + def respond(self, ticket, success): + try: + res = getURL(self.RESPOND_URL, post={"task_id": ticket, "key": self.getConfig("passkey"), + "cv": 1 if success else 0}) + except BadHeader, e: + self.logError(_("Could not send response"), e) + + + def captchaTask(self, task): + if "service" in task.data: + return False + + if not task.isTextual(): + return False + + if not self.getConfig("passkey"): + return False + + if self.core.isClientConnected() and not self.getConfig("force"): + return False + + if self.getCredits() > 0: + task.handler.append(self) + task.data['service'] = self.__name__ + task.setWaiting(100) + self._processCaptcha(task) + + else: + self.logInfo(_("Your %s account has not enough credits") % self.__name__) + + + def captchaCorrect(self, task): + if task.data['service'] == self.__name__ and "ticket" in task.data: + self.respond(task.data['ticket'], True) + + + def captchaInvalid(self, task): + if task.data['service'] == self.__name__ and "ticket" in task.data: + self.respond(task.data['ticket'], False) + + + @threaded + def _processCaptcha(self, task): + c = task.captchaFile + try: + ticket, result = self.submit(c) + except BypassCaptchaException, e: + task.error = e.getCode() + return + + task.data['ticket'] = ticket + task.setResult(result) diff --git a/pyload/plugin/hook/Captcha9Kw.py b/pyload/plugin/hook/Captcha9Kw.py new file mode 100644 index 000000000..dd3fb1ba1 --- /dev/null +++ b/pyload/plugin/hook/Captcha9Kw.py @@ -0,0 +1,251 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import re + +from base64 import b64encode +from time import sleep + +from pyload.network.HTTPRequest import BadHeader +from pyload.network.RequestFactory import getURL + +from pyload.plugin.Hook import Hook, threaded + + +class Captcha9kw(Hook): + __name__ = "Captcha9Kw" + __type__ = "hook" + __version__ = "0.28" + + __config__ = [("ssl" , "bool" , "Use HTTPS" , True ), + ("force" , "bool" , "Force captcha resolving even if client is connected" , True ), + ("confirm" , "bool" , "Confirm Captcha (cost +6 credits)" , False ), + ("captchaperhour", "int" , "Captcha per hour" , "9999" ), + ("captchapermin" , "int" , "Captcha per minute" , "9999" ), + ("prio" , "int" , "Priority (max 10)(cost +0 -> +10 credits)" , "0" ), + ("queue" , "int" , "Max. Queue (max 999)" , "50" ), + ("hoster_options", "string" , "Hoster options (format: pluginname:prio=1:selfsolfe=1:confirm=1:timeout=900|...)", "ShareonlineBiz:prio=0:timeout=999 | UploadedTo:prio=0:timeout=999"), + ("selfsolve" , "bool" , "Selfsolve (manually solve your captcha in your 9kw client if active)" , "0" ), + ("passkey" , "password", "API key" , "" ), + ("timeout" , "int" , "Timeout in seconds (min 60, max 3999)" , "900" )] + + __description__ = """Send captchas to 9kw.eu""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + API_URL = "http://www.9kw.eu/index.cgi" + + + def activate(self): + if self.getConfig("ssl"): + self.API_URL = self.API_URL.replace("http://", "https://") + + + def getCredits(self): + res = getURL(self.API_URL, + get={'apikey': self.getConfig("passkey"), + 'pyload': "1", + 'source': "pyload", + 'action': "usercaptchaguthaben"}) + + if res.isdigit(): + self.logInfo(_("%s credits left") % res) + credits = self.info['credits'] = int(res) + return credits + else: + self.logError(res) + return 0 + + + @threaded + def _processCaptcha(self, task): + try: + with open(task.captchaFile, 'rb') as f: + data = f.read() + + except IOError, e: + self.logError(e) + return + + pluginname = re.search(r'_([^_]*)_\d+.\w+', task.captchaFile).group(1) + option = {'min' : 2, + 'max' : 50, + 'phrase' : 0, + 'numeric' : 0, + 'case_sensitive': 0, + 'math' : 0, + 'prio' : min(max(self.getConfig("prio"), 0), 10), + 'confirm' : self.getConfig("confirm"), + 'timeout' : min(max(self.getConfig("timeout"), 300), 3999), + 'selfsolve' : self.getConfig("selfsolve"), + 'cph' : self.getConfig("captchaperhour"), + 'cpm' : self.getConfig("captchapermin")} + + for opt in str(self.getConfig("hoster_options").split('|')): + + details = map(str.strip, opt.split(':')) + + if not details or details[0].lower() != pluginname.lower(): + continue + + for d in details: + hosteroption = d.split("=") + + if len(hosteroption) < 2 or not hosteroption[1].isdigit(): + continue + + o = hosteroption[0].lower() + if o in option: + option[o] = hosteroption[1] + + break + + post_data = {'apikey' : self.getConfig("passkey"), + 'prio' : option['prio'], + 'confirm' : option['confirm'], + 'maxtimeout' : option['timeout'], + 'selfsolve' : option['selfsolve'], + 'captchaperhour': option['cph'], + 'captchapermin' : option['cpm'], + 'case-sensitive': option['case_sensitive'], + 'min_len' : option['min'], + 'max_len' : option['max'], + 'phrase' : option['phrase'], + 'numeric' : option['numeric'], + 'math' : option['math'], + 'oldsource' : pluginname, + 'pyload' : "1", + 'source' : "pyload", + 'base64' : "1", + 'mouse' : 1 if task.isPositional() else 0, + 'file-upload-01': b64encode(data), + 'action' : "usercaptchaupload"} + + for _i in xrange(5): + try: + res = getURL(self.API_URL, post=post_data) + except BadHeader, e: + sleep(3) + else: + if res and res.isdigit(): + break + else: + self.logError(_("Bad upload: %s") % res) + return + + self.logDebug(_("NewCaptchaID ticket: %s") % res, task.captchaFile) + + task.data["ticket"] = res + + for _i in xrange(int(self.getConfig("timeout") / 5)): + result = getURL(self.API_URL, + get={'apikey': self.getConfig("passkey"), + 'id' : res, + 'pyload': "1", + 'info' : "1", + 'source': "pyload", + 'action': "usercaptchacorrectdata"}) + + if not result or result == "NO DATA": + sleep(5) + else: + break + else: + self.logDebug("Could not send request: %s" % res) + result = None + + self.logInfo(_("Captcha result for ticket %s: %s") % (res, result)) + + task.setResult(result) + + + def captchaTask(self, task): + if not task.isTextual() and not task.isPositional(): + return + + if not self.getConfig("passkey"): + return + + if self.core.isClientConnected() and not self.getConfig("force"): + return + + credits = self.getCredits() + + if not credits: + self.logError(_("Your captcha 9kw.eu account has not enough credits")) + return + + queue = min(self.getConfig("queue"), 999) + timeout = min(max(self.getConfig("timeout"), 300), 3999) + pluginname = re.search(r'_([^_]*)_\d+.\w+', task.captchaFile).group(1) + + for _i in xrange(5): + servercheck = getURL("http://www.9kw.eu/grafik/servercheck.txt") + if queue < re.search(r'queue=(\d+)', servercheck).group(1): + break + + sleep(10) + else: + self.fail(_("Too many captchas in queue")) + + for opt in str(self.getConfig("hoster_options").split('|')): + details = map(str.strip, opt.split(':')) + + if not details or details[0].lower() != pluginname.lower(): + continue + + for d in details: + hosteroption = d.split("=") + + if len(hosteroption) > 1 \ + and hosteroption[0].lower() == 'timeout' \ + and hosteroption[1].isdigit(): + timeout = int(hosteroption[1]) + + break + + task.handler.append(self) + + task.setWaiting(timeout) + + self._processCaptcha(task) + + + def _captchaResponse(self, task, correct): + type = "correct" if correct else "refund" + + if 'ticket' not in task.data: + self.logDebug("No CaptchaID for %s request (task: %s)" % (type, task)) + return + + passkey = self.getConfig("passkey") + + for _i in xrange(3): + res = getURL(self.API_URL, + get={'action' : "usercaptchacorrectback", + 'apikey' : passkey, + 'api_key': passkey, + 'correct': "1" if correct else "2", + 'pyload' : "1", + 'source' : "pyload", + 'id' : task.data["ticket"]}) + + self.logDebug("Request %s: %s" % (type, res)) + + if res == "OK": + break + + sleep(5) + else: + self.logDebug("Could not send %s request: %s" % (type, res)) + + + def captchaCorrect(self, task): + self._captchaResponse(task, True) + + + def captchaInvalid(self, task): + self._captchaResponse(task, False) diff --git a/pyload/plugin/hook/CaptchaBrotherhood.py b/pyload/plugin/hook/CaptchaBrotherhood.py new file mode 100644 index 000000000..554d102ec --- /dev/null +++ b/pyload/plugin/hook/CaptchaBrotherhood.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import StringIO +import pycurl + +try: + from PIL import Image +except ImportError: + import Image + +from time import sleep +from urllib import urlencode + +from pyload.network.RequestFactory import getURL, getRequest +from pyload.plugin.Hook import Hook, threaded + + +class CaptchaBrotherhoodException(Exception): + + def __init__(self, err): + self.err = err + + + def getCode(self): + return self.err + + + def __str__(self): + return "<CaptchaBrotherhoodException %s>" % self.err + + + def __repr__(self): + return "<CaptchaBrotherhoodException %s>" % self.err + + +class CaptchaBrotherhood(Hook): + __name__ = "CaptchaBrotherhood" + __type__ = "hook" + __version__ = "0.08" + + __config__ = [("username", "str", "Username", ""), + ("force", "bool", "Force CT even if client is connected", False), + ("passkey", "password", "Password", "")] + + __description__ = """Send captchas to CaptchaBrotherhood.com""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("zoidberg", "zoidberg@mujmail.cz")] + + + API_URL = "http://www.captchabrotherhood.com/" + + + def getCredits(self): + res = getURL(self.API_URL + "askCredits.aspx", + get={"username": self.getConfig("username"), "password": self.getConfig("passkey")}) + if not res.startswith("OK"): + raise CaptchaBrotherhoodException(res) + else: + credits = int(res[3:]) + self.logInfo(_("%d credits left") % credits) + self.info['credits'] = credits + return credits + + + def submit(self, captcha, captchaType="file", match=None): + try: + img = Image.open(captcha) + output = StringIO.StringIO() + self.logDebug("CAPTCHA IMAGE", img, img.format, img.mode) + if img.format in ("GIF", "JPEG"): + img.save(output, img.format) + else: + if img.mode != "RGB": + img = img.convert("RGB") + img.save(output, "JPEG") + data = output.getvalue() + output.close() + except Exception, e: + raise CaptchaBrotherhoodException("Reading or converting captcha image failed: %s" % e) + + req = getRequest() + + url = "%ssendNewCaptcha.aspx?%s" % (self.API_URL, + urlencode({'username' : self.getConfig("username"), + 'password' : self.getConfig("passkey"), + 'captchaSource': "pyLoad", + 'timeout' : "80"})) + + req.c.setopt(pycurl.URL, url) + req.c.setopt(pycurl.POST, 1) + req.c.setopt(pycurl.POSTFIELDS, data) + req.c.setopt(pycurl.HTTPHEADER, ["Content-Type: text/html"]) + + try: + req.c.perform() + res = req.getResponse() + except Exception, e: + raise CaptchaBrotherhoodException("Submit captcha image failed") + + req.close() + + if not res.startswith("OK"): + raise CaptchaBrotherhoodException(res[1]) + + ticket = res[3:] + + for _i in xrange(15): + sleep(5) + res = self.api_response("askCaptchaResult", ticket) + if res.startswith("OK-answered"): + return ticket, res[12:] + + raise CaptchaBrotherhoodException("No solution received in time") + + + def api_response(self, api, ticket): + res = getURL("%s%s.aspx" % (self.API_URL, api), + get={"username": self.getConfig("username"), + "password": self.getConfig("passkey"), + "captchaID": ticket}) + if not res.startswith("OK"): + raise CaptchaBrotherhoodException("Unknown response: %s" % res) + + return res + + + def captchaTask(self, task): + if "service" in task.data: + return False + + if not task.isTextual(): + return False + + if not self.getConfig("username") or not self.getConfig("passkey"): + return False + + if self.core.isClientConnected() and not self.getConfig("force"): + return False + + if self.getCredits() > 10: + task.handler.append(self) + task.data['service'] = self.__name__ + task.setWaiting(100) + self._processCaptcha(task) + else: + self.logInfo(_("Your CaptchaBrotherhood Account has not enough credits")) + + + def captchaInvalid(self, task): + if task.data['service'] == self.__name__ and "ticket" in task.data: + res = self.api_response("complainCaptcha", task.data['ticket']) + + + @threaded + def _processCaptcha(self, task): + c = task.captchaFile + try: + ticket, result = self.submit(c) + except CaptchaBrotherhoodException, e: + task.error = e.getCode() + return + + task.data['ticket'] = ticket + task.setResult(result) diff --git a/pyload/plugin/hook/DeathByCaptcha.py b/pyload/plugin/hook/DeathByCaptcha.py new file mode 100644 index 000000000..e0108963b --- /dev/null +++ b/pyload/plugin/hook/DeathByCaptcha.py @@ -0,0 +1,214 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import re + +from base64 import b64encode +from pycurl import FORM_FILE, HTTPHEADER +from time import sleep + +from pyload.utils import json_loads +from pyload.network.HTTPRequest import BadHeader +from pyload.network.RequestFactory import getRequest +from pyload.plugin.Hook import Hook, threaded + + +class DeathByCaptchaException(Exception): + DBC_ERRORS = {'not-logged-in': 'Access denied, check your credentials', + 'invalid-credentials': 'Access denied, check your credentials', + 'banned': 'Access denied, account is suspended', + 'insufficient-funds': 'Insufficient account balance to decrypt CAPTCHA', + 'invalid-captcha': 'CAPTCHA is not a valid image', + 'service-overload': 'CAPTCHA was rejected due to service overload, try again later', + 'invalid-request': 'Invalid request', + 'timed-out': 'No CAPTCHA solution received in time'} + + + def __init__(self, err): + self.err = err + + + def getCode(self): + return self.err + + + def getDesc(self): + if self.err in self.DBC_ERRORS.keys(): + return self.DBC_ERRORS[self.err] + else: + return self.err + + + def __str__(self): + return "<DeathByCaptchaException %s>" % self.err + + + def __repr__(self): + return "<DeathByCaptchaException %s>" % self.err + + +class DeathByCaptcha(Hook): + __name__ = "DeathByCaptcha" + __type__ = "hook" + __version__ = "0.06" + + __config__ = [("username", "str", "Username", ""), + ("passkey", "password", "Password", ""), + ("force", "bool", "Force DBC even if client is connected", False)] + + __description__ = """Send captchas to DeathByCaptcha.com""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("zoidberg", "zoidberg@mujmail.cz")] + + + API_URL = "http://api.dbcapi.me/api/" + + + def api_response(self, api="captcha", post=False, multipart=False): + req = getRequest() + req.c.setopt(HTTPHEADER, ["Accept: application/json", "User-Agent: pyLoad %s" % self.core.version]) + + if post: + if not isinstance(post, dict): + post = {} + post.update({"username": self.getConfig("username"), + "password": self.getConfig("passkey")}) + + res = None + try: + json = req.load("%s%s" % (self.API_URL, api), + post=post, + multipart=multipart) + self.logDebug(json) + res = json_loads(json) + + if "error" in res: + raise DeathByCaptchaException(res['error']) + elif "status" not in res: + raise DeathByCaptchaException(str(res)) + + except BadHeader, e: + if 403 == e.code: + raise DeathByCaptchaException('not-logged-in') + elif 413 == e.code: + raise DeathByCaptchaException('invalid-captcha') + elif 503 == e.code: + raise DeathByCaptchaException('service-overload') + elif e.code in (400, 405): + raise DeathByCaptchaException('invalid-request') + else: + raise + + finally: + req.close() + + return res + + + def getCredits(self): + res = self.api_response("user", True) + + if 'is_banned' in res and res['is_banned']: + raise DeathByCaptchaException('banned') + elif 'balance' in res and 'rate' in res: + self.info.update(res) + else: + raise DeathByCaptchaException(res) + + + def getStatus(self): + res = self.api_response("status", False) + + if 'is_service_overloaded' in res and res['is_service_overloaded']: + raise DeathByCaptchaException('service-overload') + + + def submit(self, captcha, captchaType="file", match=None): + #@NOTE: Workaround multipart-post bug in HTTPRequest.py + if re.match("^\w*$", self.getConfig("passkey")): + multipart = True + data = (FORM_FILE, captcha) + else: + multipart = False + with open(captcha, 'rb') as f: + data = f.read() + data = "base64:" + b64encode(data) + + res = self.api_response("captcha", {"captchafile": data}, multipart) + + if "captcha" not in res: + raise DeathByCaptchaException(res) + ticket = res['captcha'] + + for _i in xrange(24): + sleep(5) + res = self.api_response("captcha/%d" % ticket, False) + if res['text'] and res['is_correct']: + break + else: + raise DeathByCaptchaException('timed-out') + + result = res['text'] + self.logDebug("Result %s : %s" % (ticket, result)) + + return ticket, result + + + def captchaTask(self, task): + if "service" in task.data: + return False + + if not task.isTextual(): + return False + + if not self.getConfig("username") or not self.getConfig("passkey"): + return False + + if self.core.isClientConnected() and not self.getConfig("force"): + return False + + try: + self.getStatus() + self.getCredits() + except DeathByCaptchaException, e: + self.logError(e.getDesc()) + return False + + balance, rate = self.info['balance'], self.info['rate'] + self.logInfo(_("Account balance"), + _("US$%.3f (%d captchas left at %.2f cents each)") % (balance / 100, + balance // rate, rate)) + + if balance > rate: + task.handler.append(self) + task.data['service'] = self.__name__ + task.setWaiting(180) + self._processCaptcha(task) + + + def captchaInvalid(self, task): + if task.data['service'] == self.__name__ and "ticket" in task.data: + try: + res = self.api_response("captcha/%d/report" % task.data['ticket'], True) + + except DeathByCaptchaException, e: + self.logError(e.getDesc()) + + except Exception, e: + self.logError(e) + + + @threaded + def _processCaptcha(self, task): + c = task.captchaFile + try: + ticket, result = self.submit(c) + except DeathByCaptchaException, e: + task.error = e.getCode() + self.logError(e.getDesc()) + return + + task.data['ticket'] = ticket + task.setResult(result) diff --git a/pyload/plugin/hook/DebridItaliaCom.py b/pyload/plugin/hook/DebridItaliaCom.py new file mode 100644 index 000000000..e2f766d86 --- /dev/null +++ b/pyload/plugin/hook/DebridItaliaCom.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.MultiHook import MultiHook + + +class DebridItaliaCom(MultiHook): + __name__ = "DebridItaliaCom" + __type__ = "hook" + __version__ = "0.12" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Debriditalia.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + def getHosters(self): + return self.getURL("http://debriditalia.com/api.php", get={'hosts': ""}).replace('"', '').split(',') diff --git a/pyload/plugin/hook/EasybytezCom.py b/pyload/plugin/hook/EasybytezCom.py new file mode 100644 index 000000000..1163bbf46 --- /dev/null +++ b/pyload/plugin/hook/EasybytezCom.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.MultiHook import MultiHook + + +class EasybytezCom(MultiHook): + __name__ = "EasybytezCom" + __type__ = "hook" + __version__ = "0.07" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """EasyBytez.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + def getHosters(self): + user, data = self.account.selectAccount() + + req = self.account.getAccountRequest(user) + html = req.load("http://www.easybytez.com") + + return re.search(r'</textarea>\s*Supported sites:(.*)', html).group(1).split(',') diff --git a/pyload/plugin/hook/ExpertDecoders.py b/pyload/plugin/hook/ExpertDecoders.py new file mode 100644 index 000000000..8fbc88c80 --- /dev/null +++ b/pyload/plugin/hook/ExpertDecoders.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +from base64 import b64encode +from pycurl import LOW_SPEED_TIME +from uuid import uuid4 + +from pyload.network.HTTPRequest import BadHeader +from pyload.network.RequestFactory import getURL, getRequest +from pyload.plugin.Hook import Hook, threaded + + +class ExpertDecoders(Hook): + __name__ = "ExpertDecoders" + __type__ = "hook" + __version__ = "0.04" + + __config__ = [("force", "bool", "Force CT even if client is connected", False), + ("passkey", "password", "Access key", "")] + + __description__ = """Send captchas to expertdecoders.com""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("zoidberg", "zoidberg@mujmail.cz")] + + + API_URL = "http://www.fasttypers.org/imagepost.ashx" + + + def getCredits(self): + res = getURL(self.API_URL, post={"key": self.getConfig("passkey"), "action": "balance"}) + + if res.isdigit(): + self.logInfo(_("%s credits left") % res) + self.info['credits'] = credits = int(res) + return credits + else: + self.logError(res) + return 0 + + + @threaded + def _processCaptcha(self, task): + task.data['ticket'] = ticket = uuid4() + result = None + + with open(task.captchaFile, 'rb') as f: + data = f.read() + + req = getRequest() + #raise timeout threshold + req.c.setopt(LOW_SPEED_TIME, 80) + + try: + result = req.load(self.API_URL, + post={'action' : "upload", + 'key' : self.getConfig("passkey"), + 'file' : b64encode(data), + 'gen_task_id': ticket}) + finally: + req.close() + + self.logDebug("Result %s : %s" % (ticket, result)) + task.setResult(result) + + + def captchaTask(self, task): + if not task.isTextual(): + return False + + if not self.getConfig("passkey"): + return False + + if self.core.isClientConnected() and not self.getConfig("force"): + return False + + if self.getCredits() > 0: + task.handler.append(self) + task.setWaiting(100) + self._processCaptcha(task) + + else: + self.logInfo(_("Your ExpertDecoders Account has not enough credits")) + + + def captchaInvalid(self, task): + if "ticket" in task.data: + + try: + res = getURL(self.API_URL, + post={'action': "refund", 'key': self.getConfig("passkey"), 'gen_task_id': task.data['ticket']}) + self.logInfo(_("Request refund"), res) + + except BadHeader, e: + self.logError(_("Could not send refund request"), e) diff --git a/pyload/plugin/hook/FastixRu.py b/pyload/plugin/hook/FastixRu.py new file mode 100644 index 000000000..8bc3b3f16 --- /dev/null +++ b/pyload/plugin/hook/FastixRu.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHook import MultiHook + + +class FastixRu(MultiHook): + __name__ = "FastixRu" + __type__ = "hook" + __version__ = "0.05" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Fastix.ru hook plugin""" + __license__ = "GPLv3" + __authors__ = [("Massimo Rosamilia", "max@spiritix.eu")] + + + def getHosters(self): + html = self.getURL("http://fastix.ru/api_v2", + get={'apikey': "5182964c3f8f9a7f0b00000a_kelmFB4n1IrnCDYuIFn2y", + 'sub' : "allowed_sources"}) + host_list = json_loads(html) + host_list = host_list['allow'] + return host_list diff --git a/pyload/plugin/hook/FreeWayMe.py b/pyload/plugin/hook/FreeWayMe.py new file mode 100644 index 000000000..711be37a8 --- /dev/null +++ b/pyload/plugin/hook/FreeWayMe.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.MultiHook import MultiHook + + +class FreeWayMe(MultiHook): + __name__ = "FreeWayMe" + __type__ = "hook" + __version__ = "0.14" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """FreeWay.me hook plugin""" + __license__ = "GPLv3" + __authors__ = [("Nicolas Giese", "james@free-way.me")] + + + def getHosters(self): + hostis = self.getURL("https://www.free-way.me/ajax/jd.php", get={'id': 3}).replace("\"", "").strip() + self.logDebug("Hosters", hostis) + return [x.strip() for x in hostis.split(",") if x.strip()] diff --git a/pyload/plugin/hook/ImageTyperz.py b/pyload/plugin/hook/ImageTyperz.py new file mode 100644 index 000000000..a9d7326de --- /dev/null +++ b/pyload/plugin/hook/ImageTyperz.py @@ -0,0 +1,153 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import re + +from base64 import b64encode +from pycurl import FORM_FILE, LOW_SPEED_TIME + +from pyload.network.RequestFactory import getURL, getRequest +from pyload.plugin.Hook import Hook, threaded + + +class ImageTyperzException(Exception): + + def __init__(self, err): + self.err = err + + + def getCode(self): + return self.err + + + def __str__(self): + return "<ImageTyperzException %s>" % self.err + + + def __repr__(self): + return "<ImageTyperzException %s>" % self.err + + +class ImageTyperz(Hook): + __name__ = "ImageTyperz" + __type__ = "hook" + __version__ = "0.06" + + __config__ = [("username", "str", "Username", ""), + ("passkey", "password", "Password", ""), + ("force", "bool", "Force IT even if client is connected", False)] + + __description__ = """Send captchas to ImageTyperz.com""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("zoidberg", "zoidberg@mujmail.cz")] + + + SUBMIT_URL = "http://captchatypers.com/Forms/UploadFileAndGetTextNEW.ashx" + RESPOND_URL = "http://captchatypers.com/Forms/SetBadImage.ashx" + GETCREDITS_URL = "http://captchatypers.com/Forms/RequestBalance.ashx" + + + def getCredits(self): + res = getURL(self.GETCREDITS_URL, + post={'action': "REQUESTBALANCE", + 'username': self.getConfig("username"), + 'password': self.getConfig("passkey")}) + + if res.startswith('ERROR'): + raise ImageTyperzException(res) + + try: + balance = float(res) + except Exception: + raise ImageTyperzException("Invalid response") + + self.logInfo(_("Account balance: $%s left") % res) + return balance + + + def submit(self, captcha, captchaType="file", match=None): + req = getRequest() + #raise timeout threshold + req.c.setopt(LOW_SPEED_TIME, 80) + + try: + #@NOTE: Workaround multipart-post bug in HTTPRequest.py + if re.match("^\w*$", self.getConfig("passkey")): + multipart = True + data = (FORM_FILE, captcha) + else: + multipart = False + with open(captcha, 'rb') as f: + data = f.read() + data = b64encode(data) + + res = req.load(self.SUBMIT_URL, + post={'action': "UPLOADCAPTCHA", + 'username': self.getConfig("username"), + 'password': self.getConfig("passkey"), "file": data}, + multipart=multipart) + finally: + req.close() + + if res.startswith("ERROR"): + raise ImageTyperzException(res) + else: + data = res.split('|') + if len(data) == 2: + ticket, result = data + else: + raise ImageTyperzException("Unknown response: %s" % res) + + return ticket, result + + + def captchaTask(self, task): + if "service" in task.data: + return False + + if not task.isTextual(): + return False + + if not self.getConfig("username") or not self.getConfig("passkey"): + return False + + if self.core.isClientConnected() and not self.getConfig("force"): + return False + + if self.getCredits() > 0: + task.handler.append(self) + task.data['service'] = self.__name__ + task.setWaiting(100) + self._processCaptcha(task) + + else: + self.logInfo(_("Your %s account has not enough credits") % self.__name__) + + + def captchaInvalid(self, task): + if task.data['service'] == self.__name__ and "ticket" in task.data: + res = getURL(self.RESPOND_URL, + post={'action': "SETBADIMAGE", + 'username': self.getConfig("username"), + 'password': self.getConfig("passkey"), + 'imageid': task.data['ticket']}) + + if res == "SUCCESS": + self.logInfo(_("Bad captcha solution received, requested refund")) + else: + self.logError(_("Bad captcha solution received, refund request failed"), res) + + + @threaded + def _processCaptcha(self, task): + c = task.captchaFile + try: + ticket, result = self.submit(c) + except ImageTyperzException, e: + task.error = e.getCode() + return + + task.data['ticket'] = ticket + task.setResult(result) diff --git a/pyload/plugin/hook/LinkdecrypterCom.py b/pyload/plugin/hook/LinkdecrypterCom.py new file mode 100644 index 000000000..efdf77065 --- /dev/null +++ b/pyload/plugin/hook/LinkdecrypterCom.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.MultiHook import MultiHook + + +class LinkdecrypterCom(MultiHook): + __name__ = "LinkdecrypterCom" + __type__ = "hook" + __version__ = "1.02" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Linkdecrypter.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + def getCrypters(self): + return re.search(r'>Supported\(\d+\)</b>: <i>(.[\w.\-, ]+)', + self.getURL("http://linkdecrypter.com/").replace("(g)", "")).group(1).split(', ') diff --git a/pyload/plugin/hook/LinksnappyCom.py b/pyload/plugin/hook/LinksnappyCom.py new file mode 100644 index 000000000..dc0c47496 --- /dev/null +++ b/pyload/plugin/hook/LinksnappyCom.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHook import MultiHook + + +class LinksnappyCom(MultiHook): + __name__ = "LinksnappyCom" + __type__ = "hook" + __version__ = "0.04" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Linksnappy.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + def getHosters(self): + json_data = self.getURL("http://gen.linksnappy.com/lseAPI.php", get={'act': "FILEHOSTS"}) + json_data = json_loads(json_data) + + return json_data['return'].keys() diff --git a/pyload/plugin/hook/MegaDebridEu.py b/pyload/plugin/hook/MegaDebridEu.py new file mode 100644 index 000000000..7e86d4d49 --- /dev/null +++ b/pyload/plugin/hook/MegaDebridEu.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHook import MultiHook + + +class MegaDebridEu(MultiHook): + __name__ = "MegaDebridEu" + __type__ = "hook" + __version__ = "0.05" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Mega-debrid.eu hook plugin""" + __license__ = "GPLv3" + __authors__ = [("D.Ducatel", "dducatel@je-geek.fr")] + + + def getHosters(self): + reponse = self.getURL("http://www.mega-debrid.eu/api.php", get={'action': "getHosters"}) + json_data = json_loads(reponse) + + if json_data['response_code'] == "ok": + host_list = [element[0] for element in json_data['hosters']] + else: + self.logError(_("Unable to retrieve hoster list")) + host_list = list() + + return host_list diff --git a/pyload/plugin/hook/MultihostersCom.py b/pyload/plugin/hook/MultihostersCom.py new file mode 100644 index 000000000..7b92089a1 --- /dev/null +++ b/pyload/plugin/hook/MultihostersCom.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.hook.ZeveraCom import ZeveraCom + + +class MultihostersCom(ZeveraCom): + __name__ = "MultihostersCom" + __type__ = "hook" + __version__ = "0.02" + + __config__ = [("mode" , "all;listed;unlisted", "Use for plugins (if supported)" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed", "bool" , "Revert to standard download if download fails", False), + ("interval" , "int" , "Reload interval in hours (0 to disable)" , 12 )] + + __description__ = """Multihosters.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("tjeh", "tjeh@gmx.net")] diff --git a/pyload/plugin/hook/MultishareCz.py b/pyload/plugin/hook/MultishareCz.py new file mode 100644 index 000000000..56f30fb39 --- /dev/null +++ b/pyload/plugin/hook/MultishareCz.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.MultiHook import MultiHook + + +class MultishareCz(MultiHook): + __name__ = "MultishareCz" + __type__ = "hook" + __version__ = "0.07" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """MultiShare.cz hook plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + HOSTER_PATTERN = r'<img class="logo-shareserveru"[^>]*?alt="([^"]+)"></td>\s*<td class="stav">[^>]*?alt="OK"' + + + def getHosters(self): + html = self.getURL("http://www.multishare.cz/monitoring/") + return re.findall(self.HOSTER_PATTERN, html) diff --git a/pyload/plugin/hook/MyfastfileCom.py b/pyload/plugin/hook/MyfastfileCom.py new file mode 100644 index 000000000..097a54b60 --- /dev/null +++ b/pyload/plugin/hook/MyfastfileCom.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.MultiHook import MultiHook +from pyload.utils import json_loads + + +class MyfastfileCom(MultiHook): + __name__ = "MyfastfileCom" + __type__ = "hook" + __version__ = "0.05" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Myfastfile.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + def getHosters(self): + json_data = self.getURL("http://myfastfile.com/api.php", get={'hosts': ""}, decode=True) + self.logDebug("JSON data", json_data) + json_data = json_loads(json_data) + + return json_data['hosts'] diff --git a/pyload/plugin/hook/NoPremiumPl.py b/pyload/plugin/hook/NoPremiumPl.py new file mode 100644 index 000000000..da7967154 --- /dev/null +++ b/pyload/plugin/hook/NoPremiumPl.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHook import MultiHook + + +class NoPremiumPl(MultiHook): + __name__ = "NoPremiumPl" + __type__ = "hook" + __version__ = "0.03" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """NoPremium.pl hook plugin""" + __license__ = "GPLv3" + __authors__ = [("goddie", "dev@nopremium.pl")] + + + def getHosters(self): + hostings = json_loads(self.getURL("https://www.nopremium.pl/clipboard.php?json=3").strip()) + hostings_domains = [domain for row in hostings for domain in row["domains"] if row["sdownload"] == "0"] + + self.logDebug(hostings_domains) + + return hostings_domains diff --git a/pyload/plugin/hook/OverLoadMe.py b/pyload/plugin/hook/OverLoadMe.py new file mode 100644 index 000000000..e4602019f --- /dev/null +++ b/pyload/plugin/hook/OverLoadMe.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.MultiHook import MultiHook + + +class OverLoadMe(MultiHook): + __name__ = "OverLoadMe" + __type__ = "hook" + __version__ = "0.04" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 ), + ("ssl" , "bool" , "Use HTTPS" , True )] + + __description__ = """Over-Load.me hook plugin""" + __license__ = "GPLv3" + __authors__ = [("marley", "marley@over-load.me")] + + + def getHosters(self): + https = "https" if self.getConfig("ssl") else "http" + html = self.getURL(https + "://api.over-load.me/hoster.php", + get={'auth': "0001-cb1f24dadb3aa487bda5afd3b76298935329be7700cd7-5329be77-00cf-1ca0135f"}).replace("\"", "").strip() + self.logDebug("Hosterlist", html) + + return [x.strip() for x in html.split(",") if x.strip()] diff --git a/pyload/plugin/hook/PremiumTo.py b/pyload/plugin/hook/PremiumTo.py new file mode 100644 index 000000000..58d753cec --- /dev/null +++ b/pyload/plugin/hook/PremiumTo.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.MultiHook import MultiHook + + +class PremiumTo(MultiHook): + __name__ = "PremiumTo" + __type__ = "hook" + __version__ = "0.08" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Premium.to hook plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("zoidberg", "zoidberg@mujmail.cz"), + ("stickell", "l.stickell@yahoo.it")] + + + def getHosters(self): + html = self.getURL("http://premium.to/api/hosters.php", + get={'username': self.account.username, 'password': self.account.password}) + return [x.strip() for x in html.replace("\"", "").split(";")] diff --git a/pyload/plugin/hook/PremiumizeMe.py b/pyload/plugin/hook/PremiumizeMe.py new file mode 100644 index 000000000..c5f1588ec --- /dev/null +++ b/pyload/plugin/hook/PremiumizeMe.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHook import MultiHook + + +class PremiumizeMe(MultiHook): + __name__ = "PremiumizeMe" + __type__ = "hook" + __version__ = "0.17" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Premiumize.me hook plugin""" + __license__ = "GPLv3" + __authors__ = [("Florian Franzen", "FlorianFranzen@gmail.com")] + + + def getHosters(self): + # Get account data + user, data = self.account.selectAccount() + + # Get supported hosters list from premiumize.me using the + # json API v1 (see https://secure.premiumize.me/?show=api) + answer = self.getURL("https://api.premiumize.me/pm-api/v1.php", + get={'method': "hosterlist", 'params[login]': user, 'params[pass]': data['password']}) + data = json_loads(answer) + + # If account is not valid thera are no hosters available + if data['status'] != 200: + return [] + + # Extract hosters from json file + return data['result']['hosterlist'] diff --git a/pyload/plugin/hook/PutdriveCom.py b/pyload/plugin/hook/PutdriveCom.py new file mode 100644 index 000000000..85e2f541d --- /dev/null +++ b/pyload/plugin/hook/PutdriveCom.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.hook.ZeveraCom import ZeveraCom + + +class PutdriveCom(ZeveraCom): + __name__ = "PutdriveCom" + __type__ = "hook" + __version__ = "0.01" + + __config__ = [("mode" , "all;listed;unlisted", "Use for plugins (if supported)" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed", "bool" , "Revert to standard download if download fails", False), + ("interval" , "int" , "Reload interval in hours (0 to disable)" , 12 )] + + __description__ = """Putdrive.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] diff --git a/pyload/plugin/hook/RPNetBiz.py b/pyload/plugin/hook/RPNetBiz.py new file mode 100644 index 000000000..75fe0e39b --- /dev/null +++ b/pyload/plugin/hook/RPNetBiz.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHook import MultiHook + + +class RPNetBiz(MultiHook): + __name__ = "RPNetBiz" + __type__ = "hook" + __version__ = "0.14" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """RPNet.biz hook plugin""" + __license__ = "GPLv3" + __authors__ = [("Dman", "dmanugm@gmail.com")] + + + def getHosters(self): + # Get account data + user, data = self.account.selectAccount() + + res = self.getURL("https://premium.rpnet.biz/client_api.php", + get={'username': user, 'password': data['password'], 'action': "showHosterList"}) + hoster_list = json_loads(res) + + # If account is not valid thera are no hosters available + if 'error' in hoster_list: + return [] + + # Extract hosters from json file + return hoster_list['hosters'] diff --git a/pyload/plugin/hook/RapideoPl.py b/pyload/plugin/hook/RapideoPl.py new file mode 100644 index 000000000..12d53830b --- /dev/null +++ b/pyload/plugin/hook/RapideoPl.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHook import MultiHook + + +class RapideoPl(MultiHook): + __name__ = "RapideoPl" + __type__ = "hook" + __version__ = "0.03" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Rapideo.pl hook plugin""" + __license__ = "GPLv3" + __authors__ = [("goddie", "dev@rapideo.pl")] + + + def getHosters(self): + hostings = json_loads(self.getURL("https://www.rapideo.pl/clipboard.php?json=3").strip()) + hostings_domains = [domain for row in hostings for domain in row["domains"] if row["sdownload"] == "0"] + + self.logDebug(hostings_domains) + + return hostings_domains diff --git a/pyload/plugin/hook/RealdebridCom.py b/pyload/plugin/hook/RealdebridCom.py new file mode 100644 index 000000000..a8eb03f83 --- /dev/null +++ b/pyload/plugin/hook/RealdebridCom.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.MultiHook import MultiHook + + +class RealdebridCom(MultiHook): + __name__ = "RealdebridCom" + __type__ = "hook" + __version__ = "0.46" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 ), + ("ssl" , "bool" , "Use HTTPS" , True )] + + __description__ = """Real-Debrid.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("Devirex Hazzard", "naibaf_11@yahoo.de")] + + + def getHosters(self): + https = "https" if self.getConfig("ssl") else "http" + html = self.getURL(https + "://real-debrid.com/api/hosters.php").replace("\"", "").strip() + + return [x.strip() for x in html.split(",") if x.strip()] diff --git a/pyload/plugin/hook/RehostTo.py b/pyload/plugin/hook/RehostTo.py new file mode 100644 index 000000000..cda80417c --- /dev/null +++ b/pyload/plugin/hook/RehostTo.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.MultiHook import MultiHook + + +class RehostTo(MultiHook): + __name__ = "RehostTo" + __type__ = "hook" + __version__ = "0.50" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Rehost.to hook plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org")] + + + def getHosters(self): + user, data = self.account.selectAccount() + html = self.getURL("http://rehost.to/api.php", + get={'cmd' : "get_supported_och_dl", + 'long_ses': self.account.getAccountInfo(user)['session']}) + return [x.strip() for x in html.replace("\"", "").split(",")] diff --git a/pyload/plugin/hook/SimplyPremiumCom.py b/pyload/plugin/hook/SimplyPremiumCom.py new file mode 100644 index 000000000..28d9af41f --- /dev/null +++ b/pyload/plugin/hook/SimplyPremiumCom.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHook import MultiHook + + +class SimplyPremiumCom(MultiHook): + __name__ = "SimplyPremiumCom" + __type__ = "hook" + __version__ = "0.05" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Simply-Premium.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("EvolutionClip", "evolutionclip@live.de")] + + + def getHosters(self): + json_data = self.getURL("http://www.simply-premium.com/api/hosts.php", get={'format': "json", 'online': 1}) + json_data = json_loads(json_data) + + host_list = [element['regex'] for element in json_data['result']] + + return host_list diff --git a/pyload/plugin/hook/SimplydebridCom.py b/pyload/plugin/hook/SimplydebridCom.py new file mode 100644 index 000000000..011b346b8 --- /dev/null +++ b/pyload/plugin/hook/SimplydebridCom.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.MultiHook import MultiHook + + +class SimplydebridCom(MultiHook): + __name__ = "SimplydebridCom" + __type__ = "hook" + __version__ = "0.04" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Simply-Debrid.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("Kagenoshin", "kagenoshin@gmx.ch")] + + + def getHosters(self): + html = self.getURL("http://simply-debrid.com/api.php", get={'list': 1}) + return [x.strip() for x in html.rstrip(';').replace("\"", "").split(";")] diff --git a/pyload/plugin/hook/SmoozedCom.py b/pyload/plugin/hook/SmoozedCom.py new file mode 100644 index 000000000..3f5aab63d --- /dev/null +++ b/pyload/plugin/hook/SmoozedCom.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.MultiHook import MultiHook + + +class SmoozedCom(MultiHook): + __name__ = "SmoozedCom" + __type__ = "hook" + __version__ = "0.03" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Smoozed.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("", "")] + + + def getHosters(self): + user, data = self.account.selectAccount() + return self.account.getAccountInfo(user)["hosters"] diff --git a/pyload/plugin/hook/UnrestrictLi.py b/pyload/plugin/hook/UnrestrictLi.py new file mode 100644 index 000000000..0c4984042 --- /dev/null +++ b/pyload/plugin/hook/UnrestrictLi.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHook import MultiHook + + +class UnrestrictLi(MultiHook): + __name__ = "UnrestrictLi" + __type__ = "hook" + __version__ = "0.05" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 ), + ("history" , "bool" , "Delete History" , False)] + + __description__ = """Unrestrict.li hook plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + def getHosters(self): + json_data = self.getURL("http://unrestrict.li/api/jdownloader/hosts.php", get={'format': "json"}) + json_data = json_loads(json_data) + + return [element['host'] for element in json_data['result']] diff --git a/pyload/plugin/hook/XFileSharingPro.py b/pyload/plugin/hook/XFileSharingPro.py new file mode 100644 index 000000000..e3f816502 --- /dev/null +++ b/pyload/plugin/hook/XFileSharingPro.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.Hook import Hook + + +class XFileSharingPro(Hook): + __name__ = "XFileSharingPro" + __type__ = "hook" + __version__ = "0.31" + + __config__ = [("activated" , "bool", "Activated" , True ), + ("use_hoster_list" , "bool", "Load listed hosters only" , False), + ("use_crypter_list", "bool", "Load listed crypters only" , False), + ("use_builtin_list", "bool", "Load built-in plugin list" , True ), + ("hoster_list" , "str" , "Hoster list (comma separated)" , "" ), + ("crypter_list" , "str" , "Crypter list (comma separated)", "" )] + + __description__ = """Load XFileSharingPro based hosters and crypter which don't need a own plugin to run""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + # event_list = ["pluginConfigChanged"] + regexp = {'hoster' : (r'https?://(?:www\.)?(?P<DOMAIN>[\w.^_]+(?:\.[a-zA-Z]{2,})(?:\:\d+)?)/(?:embed-)?\w{12}(?:\W|$)', + r'https?://(?:[^/]+\.)?(?P<DOMAIN>%s)/(?:embed-)?\w+'), + 'crypter': (r'https?://(?:www\.)?(?P<DOMAIN>[\w.^_]+(?:\.[a-zA-Z]{2,})(?:\:\d+)?)/(?:user|folder)s?/\w+', + r'https?://(?:[^/]+\.)?(?P<DOMAIN>%s)/(?:user|folder)s?/\w+')} + + HOSTER_BUILTIN = [#WORKING HOSTERS: + "180upload.com", "backin.net", "eyesfile.ca", "file4safe.com", "fileband.com", "filedwon.com", + "fileparadox.in", "filevice.com", "hostingbulk.com", "junkyvideo.com", "linestorage.com", "ravishare.com", + "ryushare.com", "salefiles.com", "sendmyway.com", "sharesix.com", "thefile.me", "verzend.be", "xvidstage.com", + #NOT TESTED: + "101shared.com", "4upfiles.com", "filemaze.ws", "filenuke.com", "linkzhost.com", "mightyupload.com", + "rockdizfile.com", "sharebeast.com", "sharerepo.com", "shareswift.com", "uploadbaz.com", "uploadc.com", + "vidbull.com", "zalaa.com", "zomgupload.com", + #NOT WORKING: + "amonshare.com", "banicrazy.info", "boosterking.com", "host4desi.com", "laoupload.com", "rd-fs.com"] + CRYPTER_BUILTIN = ["junocloud.me", "rapidfileshare.net"] + + + # def pluginConfigChanged(self.__name__, plugin, name, value): + # self.loadPattern() + + + def activate(self): + self.loadPattern() + + + def loadPattern(self): + use_builtin_list = self.getConfig('use_builtin_list') + + for type in ("hoster", "crypter"): + every_plugin = not self.getConfig("use_%s_list" % type) + + if every_plugin: + self.logInfo(_("Handling any %s I can!") % type) + pattern = self.regexp[type][0] + else: + plugins = self.getConfig('%s_list' % type) + plugin_set = set(plugins.replace(' ', '').replace('\\', '').replace('|', ',').replace(';', ',').lower().split(',')) + + if use_builtin_list: + plugin_set |= set(x.lower() for x in getattr(self, "%s_BUILTIN" % type.upper())) + + plugin_set -= set(('', u'')) + + if not plugin_set: + self.logInfo(_("No %s to handle") % type) + self._unload(type) + return + + match_list = '|'.join(sorted(plugin_set)) + + len_match_list = len(plugin_set) + self.logInfo(_("Handling %d %s%s: %s") % (len_match_list, + type, + "" if len_match_list == 1 else "s", + match_list.replace('|', ', '))) + + pattern = self.regexp[type][1] % match_list.replace('.', '\.') + + dict = self.core.pluginManager.plugins[type]["XFileSharingPro"] + dict['pattern'] = pattern + dict['re'] = re.compile(pattern) + + self.logDebug("Loaded %s pattern: %s" % (type, pattern)) + + + def _unload(self, type): + dict = self.core.pluginManager.plugins[type]["XFileSharingPro"] + dict['pattern'] = r'^unmatchable$' + dict['re'] = re.compile(dict['pattern']) + + + def deactivate(self): + # self.unloadHoster("BasePlugin") + for type in ("hoster", "crypter"): + self._unload(type, "XFileSharingPro") + + + # def downloadFailed(self, pyfile): + # if pyfile.pluginname == "BasePlugin" \ + # and pyfile.hasStatus("failed") \ + # and not self.getConfig("use_hoster_list") \ + # and self.unloadHoster("BasePlugin"): + # self.logDebug("Unloaded XFileSharingPro from BasePlugin") + # pyfile.setStatus("queued") diff --git a/pyload/plugin/hook/ZeveraCom.py b/pyload/plugin/hook/ZeveraCom.py new file mode 100644 index 000000000..a60c33bd4 --- /dev/null +++ b/pyload/plugin/hook/ZeveraCom.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.MultiHook import MultiHook + + +class ZeveraCom(MultiHook): + __name__ = "ZeveraCom" + __type__ = "hook" + __version__ = "0.05" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Zevera.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + def getHosters(self): + html = self.account.api_response(pyreq.getHTTPRequest(timeout=120), cmd="gethosters") + return [x.strip() for x in html.split(",")] diff --git a/module/plugins/hoster/__init__.py b/pyload/plugin/hook/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/plugins/hoster/__init__.py +++ b/pyload/plugin/hook/__init__.py diff --git a/pyload/plugin/hoster/AlldebridCom.py b/pyload/plugin/hoster/AlldebridCom.py new file mode 100644 index 000000000..8ab98bc6f --- /dev/null +++ b/pyload/plugin/hoster/AlldebridCom.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- + +import re + +from random import randrange +from urllib import unquote + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHoster import MultiHoster +from pyload.utils import parseFileSize + + +class AlldebridCom(MultiHoster): + __name__ = "AlldebridCom" + __type__ = "hoster" + __version__ = "0.44" + + __pattern__ = r'https?://(?:www\.|s\d+\.)?alldebrid\.com/dl/[\w^_]+' + + __description__ = """Alldebrid.com multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Andy Voigt", "spamsales@online.de")] + + + def getFilename(self, url): + try: + name = unquote(url.rsplit("/", 1)[1]) + except IndexError: + name = "Unknown_Filename..." + + if name.endswith("..."): # incomplete filename, append random stuff + name += "%s.tmp" % randrange(100, 999) + + return name + + + def setup(self): + self.chunkLimit = 16 + + + def handlePremium(self, pyfile): + password = self.getPassword() + + data = json_loads(self.load("http://www.alldebrid.com/service.php", + get={'link': pyfile.url, 'json': "true", 'pw': password})) + + self.logDebug("Json data", data) + + if data['error']: + if data['error'] == "This link isn't available on the hoster website.": + self.offline() + else: + self.logWarning(data['error']) + self.tempOffline() + else: + if pyfile.name and not pyfile.name.endswith('.tmp'): + pyfile.name = data['filename'] + pyfile.size = parseFileSize(data['filesize']) + self.link = data['link'] + + if self.getConfig("ssl"): + self.link = self.link.replace("http://", "https://") + else: + self.link = self.link.replace("https://", "http://") + + if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown"): + #only use when name wasnt already set + pyfile.name = self.getFilename(self.link) + + + def checkFile(self): + if self.checkDownload({'error': "<title>An error occured while processing your request</title>"}) == "error": + self.retry(wait_time=60, reason=_("An error occured while generating link")) + + return super(AlldebridCom, self).checkFile() diff --git a/pyload/plugin/hoster/AndroidfilehostCom.py b/pyload/plugin/hoster/AndroidfilehostCom.py new file mode 100644 index 000000000..386df4f2c --- /dev/null +++ b/pyload/plugin/hoster/AndroidfilehostCom.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -* +# +# Test links: +# https://www.androidfilehost.com/?fid=95916177934518197 + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class AndroidfilehostCom(SimpleHoster): + __name__ = "AndroidfilehostCom" + __type__ = "hoster" + __version__ = "0.01" + + __pattern__ = r'https?://(?:www\.)?androidfilehost\.com/\?fid=\d+' + + __description__ = """Androidfilehost.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] + + + NAME_PATTERN = r'<br />(?P<N>.*?)</h1>' + SIZE_PATTERN = r'<h4>size</h4>\s*<p>(?P<S>[\d.,]+)(?P<U>[\w^_]+)</p>' + HASHSUM_PATTERN = r'<h4>(?P<T>.*?)</h4>\s*<p><code>(?P<H>.*?)</code></p>' + + OFFLINE_PATTERN = r'404 not found' + + WAIT_PATTERN = r'users must wait <strong>(\d+) secs' + + + def setup(self): + self.multiDL = True + self.resumeDownload = True + self.chunkLimit = 1 + + + def handleFree(self, pyfile): + wait = re.search(self.WAIT_PATTERN, self.html) + self.logDebug("Waiting time: %s seconds" % wait.group(1)) + + fid = re.search(r'id="fid" value="(\d+)" />', self.html).group(1) + self.logDebug("fid: %s" % fid) + + html = self.load("https://www.androidfilehost.com/libs/otf/mirrors.otf.php", + post={'submit': 'submit', + 'action': 'getdownloadmirrors', + 'fid' : fid}, + decode=True) + + self.link = re.findall('"url":"(.*?)"', html)[0].replace("\\", "") + mirror_host = self.link.split("/")[2] + + self.logDebug("Mirror Host: %s" % mirror_host) + + html = self.load("https://www.androidfilehost.com/libs/otf/stats.otf.php", + get={'fid' : fid, + 'w' : 'download', + 'mirror': mirror_host}, + decode=True) diff --git a/pyload/plugin/hoster/BasketbuildCom.py b/pyload/plugin/hoster/BasketbuildCom.py new file mode 100644 index 000000000..fb34bbc40 --- /dev/null +++ b/pyload/plugin/hoster/BasketbuildCom.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -* +# +# Test links: +# https://s.basketbuild.com/filedl/devs?dev=pacman&dl=pacman/falcon/RC-3/pac_falcon-RC-3-20141103.zip +# https://s.basketbuild.com/filedl/gapps?dl=gapps-gb-20110828-signed.zip + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class BasketbuildCom(SimpleHoster): + __name__ = "BasketbuildCom" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'https?://(?:www\.)?(?:\w\.)?basketbuild\.com/filedl/.+' + + __description__ = """basketbuild.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] + + + NAME_PATTERN = r'File Name:</strong> (?P<N>.+?)<br/>' + SIZE_PATTERN = r'File Size:</strong> (?P<S>[\d.,]+) (?P<U>[\w^_]+)' + OFFLINE_PATTERN = r'404 - Page Not Found' + + + def setup(self): + self.multiDL = True + self.resumeDownload = True + self.chunkLimit = 1 + + + def handleFree(self, pyfile): + try: + link1 = re.search(r'href="(.+dlgate/.+)"', self.html).group(1) + self.html = self.load(link1) + + except AttributeError: + self.error(_("Hop #1 not found")) + + else: + self.logDebug("Next hop: %s" % link1) + + try: + wait = re.search(r'var sec = (\d+)', self.html).group(1) + self.logDebug("Wait %s seconds" % wait) + self.wait(wait) + + except AttributeError: + self.logDebug("No wait time found") + + try: + self.link = re.search(r'id="dlLink">\s*<a href="(.+?)"', self.html).group(1) + + except AttributeError: + self.error(_("DL-Link not found")) diff --git a/pyload/plugin/hoster/BayfilesCom.py b/pyload/plugin/hoster/BayfilesCom.py new file mode 100644 index 000000000..457440bd3 --- /dev/null +++ b/pyload/plugin/hoster/BayfilesCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class BayfilesCom(DeadHoster): + __name__ = "BayfilesCom" + __type__ = "hoster" + __version__ = "0.09" + + __pattern__ = r'https?://(?:www\.)?bayfiles\.(com|net)/file/(?P<ID>\w+/\w+/[^/]+)' + + __description__ = """Bayfiles.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] diff --git a/pyload/plugin/hoster/BezvadataCz.py b/pyload/plugin/hoster/BezvadataCz.py new file mode 100644 index 000000000..cea32dd5c --- /dev/null +++ b/pyload/plugin/hoster/BezvadataCz.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class BezvadataCz(SimpleHoster): + __name__ = "BezvadataCz" + __type__ = "hoster" + __version__ = "0.26" + + __pattern__ = r'http://(?:www\.)?bezvadata\.cz/stahnout/.+' + + __description__ = """BezvaData.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<p><b>Soubor: (?P<N>[^<]+)</b></p>' + SIZE_PATTERN = r'<li><strong>Velikost:</strong> (?P<S>[^<]+)</li>' + OFFLINE_PATTERN = r'<title>BezvaData \| Soubor nenalezen</title>' + + + def setup(self): + self.resumeDownload = True + self.multiDL = True + + + def handleFree(self, pyfile): + #download button + m = re.search(r'<a class="stahnoutSoubor".*?href="(.*?)"', self.html) + if m is None: + self.error(_("Page 1 URL not found")) + url = "http://bezvadata.cz%s" % m.group(1) + + #captcha form + self.html = self.load(url) + self.checkErrors() + for _i in xrange(5): + action, inputs = self.parseHtmlForm('frm-stahnoutFreeForm') + if not inputs: + self.error(_("FreeForm")) + + m = re.search(r'<img src="data:image/png;base64,(.*?)"', self.html) + if m is None: + self.error(_("Wrong captcha image")) + + #captcha image is contained in html page as base64encoded data but decryptCaptcha() expects image url + self.load, proper_load = self.loadcaptcha, self.load + try: + inputs['captcha'] = self.decryptCaptcha(m.group(1), imgtype='png') + finally: + self.load = proper_load + + if '<img src="data:image/png;base64' in self.html: + self.invalidCaptcha() + else: + self.correctCaptcha() + break + else: + self.fail(_("No valid captcha code entered")) + + #download url + self.html = self.load("http://bezvadata.cz%s" % action, post=inputs) + self.checkErrors() + m = re.search(r'<a class="stahnoutSoubor2" href="(.*?)">', self.html) + if m is None: + self.error(_("Page 2 URL not found")) + url = "http://bezvadata.cz%s" % m.group(1) + self.logDebug("DL URL %s" % url) + + #countdown + m = re.search(r'id="countdown">(\d\d):(\d\d)<', self.html) + wait_time = (int(m.group(1)) * 60 + int(m.group(2))) if m else 120 + self.wait(wait_time, False) + + self.download(url) + + + def checkErrors(self): + if 'images/button-download-disable.png' in self.html: + self.longWait(5 * 60, 24) #: parallel dl limit + elif '<div class="infobox' in self.html: + self.tempOffline() + + self.info.pop('error', None) + + + def loadcaptcha(self, data, *args, **kwargs): + return data.decode('base64') diff --git a/pyload/plugin/hoster/BillionuploadsCom.py b/pyload/plugin/hoster/BillionuploadsCom.py new file mode 100644 index 000000000..2dec3e8b8 --- /dev/null +++ b/pyload/plugin/hoster/BillionuploadsCom.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class BillionuploadsCom(XFSHoster): + __name__ = "BillionuploadsCom" + __type__ = "hoster" + __version__ = "0.04" + + __pattern__ = r'http://(?:www\.)?billionuploads\.com/\w{12}' + + __description__ = """Billionuploads.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<td class="dofir" title="(?P<N>.+?)"' + SIZE_PATTERN = r'<td class="dofir">(?P<S>[\d.,]+) (?P<U>[\w^_]+)' diff --git a/pyload/plugin/hoster/BitshareCom.py b/pyload/plugin/hoster/BitshareCom.py new file mode 100644 index 000000000..81bc8dae9 --- /dev/null +++ b/pyload/plugin/hoster/BitshareCom.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import re + +from pyload.plugin.internal.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class BitshareCom(SimpleHoster): + __name__ = "BitshareCom" + __type__ = "hoster" + __version__ = "0.53" + + __pattern__ = r'http://(?:www\.)?bitshare\.com/(files/)?(?(1)|\?f=)(?P<ID>\w+)(?(1)/(?P<NAME>.+?)\.html)' + + __description__ = """Bitshare.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Paul King", ""), + ("fragonib", "fragonib[AT]yahoo[DOT]es")] + + + COOKIES = [("bitshare.com", "language_selection", "EN")] + + INFO_PATTERN = r'Downloading (?P<N>.+) - (?P<S>[\d.,]+) (?P<U>[\w^_]+)</h1>' + OFFLINE_PATTERN = r'[Ff]ile (not available|was deleted|was not found)' + + AJAXID_PATTERN = r'var ajaxdl = "(.*?)";' + TRAFFIC_USED_UP = r'Your Traffic is used up for today' + + + def setup(self): + self.multiDL = self.premium + self.chunkLimit = 1 + + + def process(self, pyfile): + if self.premium: + self.account.relogin(self.user) + + # File id + m = re.match(self.__pattern__, pyfile.url) + self.file_id = max(m.group('ID1'), m.group('ID2')) + self.logDebug("File id is [%s]" % self.file_id) + + # Load main page + self.html = self.load(pyfile.url, ref=False, decode=True) + + # Check offline + if re.search(self.OFFLINE_PATTERN, self.html): + self.offline() + + # Check Traffic used up + if re.search(self.TRAFFIC_USED_UP, self.html): + self.logInfo(_("Your Traffic is used up for today")) + self.wait(30 * 60, True) + self.retry() + + # File name + m = re.match(self.__pattern__, pyfile.url) + name1 = m.group('NAME') if m else None + + m = re.search(self.INFO_PATTERN, self.html) + name2 = m.group('N') if m else None + + pyfile.name = max(name1, name2) + + # Ajax file id + self.ajaxid = re.search(self.AJAXID_PATTERN, self.html).group(1) + self.logDebug("File ajax id is [%s]" % self.ajaxid) + + # This may either download our file or forward us to an error page + self.download(self.getDownloadUrl()) + + if self.checkDownload({"error": ">Error occured<"}): + self.retry(5, 5 * 60, "Bitshare host : Error occured") + + + def getDownloadUrl(self): + # Return location if direct download is active + if self.premium: + header = self.load(self.pyfile.url, cookies=True, just_header=True) + if 'location' in header: + return header['location'] + + # Get download info + self.logDebug("Getting download info") + res = self.load("http://bitshare.com/files-ajax/" + self.file_id + "/request.html", + post={"request": "generateID", "ajaxid": self.ajaxid}) + + self.handleErrors(res, ':') + + parts = res.split(":") + filetype = parts[0] + wait = int(parts[1]) + captcha = int(parts[2]) + + self.logDebug("Download info [type: '%s', waiting: %d, captcha: %d]" % (filetype, wait, captcha)) + + # Waiting + if wait > 0: + self.logDebug("Waiting %d seconds." % wait) + if wait < 120: + self.wait(wait, False) + else: + self.wait(wait - 55, True) + self.retry() + + # Resolve captcha + if captcha == 1: + self.logDebug("File is captcha protected") + recaptcha = ReCaptcha(self) + + # Try up to 3 times + for i in xrange(3): + response, challenge = recaptcha.challenge() + res = self.load("http://bitshare.com/files-ajax/" + self.file_id + "/request.html", + post={"request" : "validateCaptcha", + "ajaxid" : self.ajaxid, + "recaptcha_challenge_field": challenge, + "recaptcha_response_field" : response}) + if self.handleCaptchaErrors(res): + break + + # Get download URL + self.logDebug("Getting download url") + res = self.load("http://bitshare.com/files-ajax/" + self.file_id + "/request.html", + post={"request": "getDownloadURL", "ajaxid": self.ajaxid}) + + self.handleErrors(res, '#') + + url = res.split("#")[-1] + + return url + + + def handleErrors(self, res, separator): + self.logDebug("Checking response [%s]" % res) + if "ERROR:Session timed out" in res: + self.retry() + elif "ERROR" in res: + msg = res.split(separator)[-1] + self.fail(msg) + + + def handleCaptchaErrors(self, res): + self.logDebug("Result of captcha resolving [%s]" % res) + if "SUCCESS" in res: + self.correctCaptcha() + return True + elif "ERROR:SESSION ERROR" in res: + self.retry() + + self.invalidCaptcha() diff --git a/pyload/plugin/hoster/BoltsharingCom.py b/pyload/plugin/hoster/BoltsharingCom.py new file mode 100644 index 000000000..39e84cd7c --- /dev/null +++ b/pyload/plugin/hoster/BoltsharingCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class BoltsharingCom(DeadHoster): + __name__ = "BoltsharingCom" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?boltsharing\.com/\w{12}' + + __description__ = """Boltsharing.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/CatShareNet.py b/pyload/plugin/hoster/CatShareNet.py new file mode 100644 index 000000000..94a963c45 --- /dev/null +++ b/pyload/plugin/hoster/CatShareNet.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class CatShareNet(SimpleHoster): + __name__ = "CatShareNet" + __type__ = "hoster" + __version__ = "0.11" + + __pattern__ = r'http://(?:www\.)?catshare\.net/\w{16}' + + __description__ = """CatShare.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("z00nx", "z00nx0@gmail.com"), + ("prOq", ""), + ("Walter Purcaro", "vuolter@gmail.com")] + + + TEXT_ENCODING = True + + INFO_PATTERN = r'<title>(?P<N>.+) \((?P<S>[\d.,]+) (?P<U>[\w^_]+)\)<' + OFFLINE_PATTERN = ur'Podany plik zostaÅ usuniÄty\s*</div>' + + IP_BLOCKED_PATTERN = ur'>Nasz serwis wykryÅ ÅŒe Twój adres IP nie pochodzi z Polski.<' + WAIT_PATTERN = r'var\scount\s=\s(\d+);' + + LINK_FREE_PATTERN = LINK_PREMIUM_PATTERN = r'<form action="(.+?)" method="GET">' + + + def setup(self): + self.multiDL = self.premium + self.resumeDownload = True + + + def getFileInfo(self): + m = re.search(self.IP_BLOCKED_PATTERN, self.html) + if m: + self.fail(_("Only connections from Polish IP address are allowed")) + return super(CatShareNet, self).getFileInfo() + + + def handleFree(self, pyfile): + recaptcha = ReCaptcha(self) + + response, challenge = recaptcha.challenge() + self.html = self.load(pyfile.url, + post={'recaptcha_challenge_field': challenge, + 'recaptcha_response_field' : response}) + + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.invalidCaptcha() + self.retry(reason=_("Wrong captcha entered")) + + self.link = m.group(1) diff --git a/pyload/plugin/hoster/CloudzerNet.py b/pyload/plugin/hoster/CloudzerNet.py new file mode 100644 index 000000000..c3154e9f1 --- /dev/null +++ b/pyload/plugin/hoster/CloudzerNet.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class CloudzerNet(DeadHoster): + __name__ = "CloudzerNet" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'https?://(?:www\.)?(cloudzer\.net/file/|clz\.to/(file/)?)\w+' + + __description__ = """Cloudzer.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("gs", "I-_-I-_-I@web.de"), + ("z00nx", "z00nx0@gmail.com"), + ("stickell", "l.stickell@yahoo.it")] diff --git a/pyload/plugin/hoster/CloudzillaTo.py b/pyload/plugin/hoster/CloudzillaTo.py new file mode 100644 index 000000000..e33e2ebe4 --- /dev/null +++ b/pyload/plugin/hoster/CloudzillaTo.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class CloudzillaTo(SimpleHoster): + __name__ = "CloudzillaTo" + __type__ = "hoster" + __version__ = "0.06" + + __pattern__ = r'http://(?:www\.)?cloudzilla\.to/share/file/(?P<ID>[\w^_]+)' + + __description__ = """Cloudzilla.to hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + INFO_PATTERN = r'title="(?P<N>.+?)">\1</span> <span class="size">\((?P<S>[\d.]+) (?P<U>[\w^_]+)' + OFFLINE_PATTERN = r'>File not found...<' + + PASSWORD_PATTERN = r'<div id="pwd_protected">' + + + def checkErrors(self): + m = re.search(self.PASSWORD_PATTERN, self.html) + if m: + self.html = self.load(self.pyfile.url, get={'key': self.getPassword()}) + + if re.search(self.PASSWORD_PATTERN, self.html): + self.retry(reason="Wrong password") + + + def handleFree(self, pyfile): + self.html = self.load("http://www.cloudzilla.to/generateticket/", + post={'file_id': self.info['pattern']['ID'], 'key': self.getPassword()}) + + ticket = dict(re.findall(r'<(.+?)>([^<>]+?)</', self.html)) + + self.logDebug(ticket) + + if 'error' in ticket: + if "File is password protected" in ticket['error']: + self.retry(reason="Wrong password") + else: + self.fail(ticket['error']) + + if 'wait' in ticket: + self.wait(ticket['wait'], int(ticket['wait']) > 5) + + self.link = "http://%(server)s/download/%(file_id)s/%(ticket_id)s" % {'server' : ticket['server'], + 'file_id' : self.info['pattern']['ID'], + 'ticket_id': ticket['ticket_id']} + + + def handlePremium(self, pyfile): + return self.handleFree(pyfile) diff --git a/pyload/plugin/hoster/CramitIn.py b/pyload/plugin/hoster/CramitIn.py new file mode 100644 index 000000000..3ccb3cfc6 --- /dev/null +++ b/pyload/plugin/hoster/CramitIn.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class CramitIn(XFSHoster): + __name__ = "CramitIn" + __type__ = "hoster" + __version__ = "0.07" + + __pattern__ = r'http://(?:www\.)?cramit\.in/\w{12}' + + __description__ = """Cramit.in hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + INFO_PATTERN = r'<span class=t2>\s*(?P<N>.*?)</span>.*?<small>\s*\((?P<S>.*?)\)' + + LINK_PATTERN = r'href="(http://cramit\.in/file_download/.*?)"' diff --git a/pyload/plugin/hoster/CrockoCom.py b/pyload/plugin/hoster/CrockoCom.py new file mode 100644 index 000000000..bcbbc84a1 --- /dev/null +++ b/pyload/plugin/hoster/CrockoCom.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class CrockoCom(SimpleHoster): + __name__ = "CrockoCom" + __type__ = "hoster" + __version__ = "0.19" + + __pattern__ = r'http://(?:www\.)?(crocko|easy-share)\.com/\w+' + + __description__ = """Crocko hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<span class="fz24">Download:\s*<strong>(?P<N>.*)' + SIZE_PATTERN = r'<span class="tip1"><span class="inner">(?P<S>[^<]+)</span></span>' + OFFLINE_PATTERN = r'<h1>Sorry,<br />the page you\'re looking for <br />isn\'t here.</h1>|File not found' + + CAPTCHA_PATTERN = re.compile(r"u='(/file_contents/captcha/\w+)';\s*w='(\d+)';") + + FORM_PATTERN = r'<form method="post" action="([^"]+)">(.*?)</form>' + FORM_INPUT_PATTERN = r'<input[^>]* name="?([^" ]+)"? value="?([^" ]+)"?[^>]*>' + + NAME_REPLACEMENTS = [(r'<[^>]*>', '')] + + + def handleFree(self, pyfile): + if "You need Premium membership to download this file." in self.html: + self.fail(_("You need Premium membership to download this file")) + + for _i in xrange(5): + m = re.search(self.CAPTCHA_PATTERN, self.html) + if m: + url, wait_time = 'http://crocko.com' + m.group(1), int(m.group(2)) + self.wait(wait_time) + self.html = self.load(url) + else: + break + + m = re.search(self.FORM_PATTERN, self.html, re.S) + if m is None: + self.error(_("FORM_PATTERN not found")) + + action, form = m.groups() + inputs = dict(re.findall(self.FORM_INPUT_PATTERN, form)) + recaptcha = ReCaptcha(self) + + for _i in xrange(5): + inputs['recaptcha_response_field'], inputs['recaptcha_challenge_field'] = recaptcha.challenge() + self.download(action, post=inputs) + + if self.checkDownload({"captcha": recaptcha.KEY_AJAX_PATTERN}): + self.invalidCaptcha() + else: + break + else: + self.fail(_("No valid captcha solution received")) diff --git a/pyload/plugin/hoster/CyberlockerCh.py b/pyload/plugin/hoster/CyberlockerCh.py new file mode 100644 index 000000000..c4e1d41b1 --- /dev/null +++ b/pyload/plugin/hoster/CyberlockerCh.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class CyberlockerCh(DeadHoster): + __name__ = "CyberlockerCh" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?cyberlocker\.ch/\w+' + + __description__ = """Cyberlocker.ch hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] diff --git a/pyload/plugin/hoster/CzshareCom.py b/pyload/plugin/hoster/CzshareCom.py new file mode 100644 index 000000000..3bf371508 --- /dev/null +++ b/pyload/plugin/hoster/CzshareCom.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# http://czshare.com/5278880/random.bin + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster +from pyload.utils import parseFileSize + + +class CzshareCom(SimpleHoster): + __name__ = "CzshareCom" + __type__ = "hoster" + __version__ = "0.98" + + __pattern__ = r'http://(?:www\.)?(czshare|sdilej)\.(com|cz)/(\d+/|download\.php\?).+' + + __description__ = """CZshare.com hoster plugin, now Sdilej.cz""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<div class="tab" id="parameters">\s*<p>\s*Cel. n.zev: <a href=[^>]*>(?P<N>[^<]+)</a>' + SIZE_PATTERN = r'<div class="tab" id="category">(?:\s*<p>[^\n]*</p>)*\s*Velikost:\s*(?P<S>[\d .,]+)(?P<U>[\w^_]+)\s*</div>' + OFFLINE_PATTERN = r'<div class="header clearfix">\s*<h2 class="red">' + + SIZE_REPLACEMENTS = [(' ', '')] + URL_REPLACEMENTS = [(r'http://[^/]*/download.php\?.*?id=(\w+).*', r'http://sdilej.cz/\1/x/')] + + CHECK_TRAFFIC = True + + FREE_URL_PATTERN = r'<a href="([^"]+)" class="page-download">[^>]*alt="([^"]+)" /></a>' + FREE_FORM_PATTERN = r'<form action="download\.php" method="post">\s*<img src="captcha\.php" id="captcha" />(.*?)</form>' + PREMIUM_FORM_PATTERN = r'<form action="/profi_down\.php" method="post">(.*?)</form>' + FORM_INPUT_PATTERN = r'<input[^>]* name="([^"]+)" value="([^"]+)"[^>]*/>' + MULTIDL_PATTERN = r'<p><font color=\'red\'>Z[^<]*PROFI.</font></p>' + USER_CREDIT_PATTERN = r'<div class="credit">\s*kredit: <strong>([\d .,]+)(\w+)</strong>\s*</div><!-- .credit -->' + + + def checkTrafficLeft(self): + # check if user logged in + m = re.search(self.USER_CREDIT_PATTERN, self.html) + if m is None: + self.account.relogin(self.user) + self.html = self.load(self.pyfile.url, cookies=True, decode=True) + m = re.search(self.USER_CREDIT_PATTERN, self.html) + if m is None: + return False + + # check user credit + try: + credit = parseFileSize(m.group(1).replace(' ', ''), m.group(2)) + self.logInfo(_("Premium download for %i KiB of Credit") % (self.pyfile.size / 1024)) + self.logInfo(_("User %s has %i KiB left") % (self.user, credit / 1024)) + if credit < self.pyfile.size: + self.logInfo(_("Not enough credit to download file: %s") % self.pyfile.name) + return False + except Exception, e: + # let's continue and see what happens... + self.logError(e) + + return True + + + def handlePremium(self, pyfile): + # parse download link + try: + form = re.search(self.PREMIUM_FORM_PATTERN, self.html, re.S).group(1) + inputs = dict(re.findall(self.FORM_INPUT_PATTERN, form)) + except Exception, e: + self.logError(e) + self.resetAccount() + + # download the file, destination is determined by pyLoad + self.download("http://sdilej.cz/profi_down.php", post=inputs, disposition=True) + + + def handleFree(self, pyfile): + # get free url + m = re.search(self.FREE_URL_PATTERN, self.html) + if m is None: + self.error(_("FREE_URL_PATTERN not found")) + + parsed_url = "http://sdilej.cz" + m.group(1) + + self.logDebug("PARSED_URL:" + parsed_url) + + # get download ticket and parse html + self.html = self.load(parsed_url, cookies=True, decode=True) + if re.search(self.MULTIDL_PATTERN, self.html): + self.longWait(5 * 60, 12) + + try: + form = re.search(self.FREE_FORM_PATTERN, self.html, re.S).group(1) + inputs = dict(re.findall(self.FORM_INPUT_PATTERN, form)) + pyfile.size = int(inputs['size']) + + except Exception, e: + self.logError(e) + self.error(_("Form")) + + # get and decrypt captcha + captcha_url = 'http://sdilej.cz/captcha.php' + for _i in xrange(5): + inputs['captchastring2'] = self.decryptCaptcha(captcha_url) + self.html = self.load(parsed_url, cookies=True, post=inputs, decode=True) + + if u"<li>ZadanÃœ ovÄÅovacà kód nesouhlasÃ!</li>" in self.html: + self.invalidCaptcha() + + elif re.search(self.MULTIDL_PATTERN, self.html): + self.longWait(5 * 60, 12) + + else: + self.correctCaptcha() + break + else: + self.fail(_("No valid captcha code entered")) + + m = re.search("countdown_number = (\d+);", self.html) + self.setWait(int(m.group(1)) if m else 50) + + # download the file, destination is determined by pyLoad + self.logDebug("WAIT URL", self.req.lastEffectiveURL) + + m = re.search("free_wait.php\?server=(.*?)&(.*)", self.req.lastEffectiveURL) + if m is None: + self.error(_("Download URL not found")) + + self.link = "http://%s/download.php?%s" % (m.group(1), m.group(2)) + + self.wait() + + + def checkFile(self): + # check download + check = self.checkDownload({ + "temp offline" : re.compile(r"^Soubor je do.*asn.* nedostupn.*$"), + "credit" : re.compile(r"^Nem.*te dostate.*n.* kredit.$"), + "multi-dl" : re.compile(self.MULTIDL_PATTERN), + "captcha" : "<li>ZadanÃœ ovÄÅovacà kód nesouhlasÃ!</li>" + }) + + if check == "temp offline": + self.fail(_("File not available - try later")) + + elif check == "credit": + self.resetAccount() + + elif check == "multi-dl": + self.longWait(5 * 60, 12) + + elif check == "captcha": + self.invalidCaptcha() + self.retry() + + return super(CzshareCom, self).checkFile() diff --git a/module/plugins/hoster/DailymotionCom.py b/pyload/plugin/hoster/DailymotionCom.py index c212fa872..c212fa872 100644 --- a/module/plugins/hoster/DailymotionCom.py +++ b/pyload/plugin/hoster/DailymotionCom.py diff --git a/pyload/plugin/hoster/DataHu.py b/pyload/plugin/hoster/DataHu.py new file mode 100644 index 000000000..219e73441 --- /dev/null +++ b/pyload/plugin/hoster/DataHu.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# http://data.hu/get/6381232/random.bin + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class DataHu(SimpleHoster): + __name__ = "DataHu" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?data\.hu/get/\w+' + + __description__ = """Data.hu hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("crash", ""), + ("stickell", "l.stickell@yahoo.it")] + + + INFO_PATTERN = ur'<title>(?P<N>.*) \((?P<S>[^)]+)\) let\xf6lt\xe9se</title>' + OFFLINE_PATTERN = ur'Az adott f\xe1jl nem l\xe9tezik' + LINK_FREE_PATTERN = r'<div class="download_box_button"><a href="([^"]+)">' + + + def setup(self): + self.resumeDownload = True + self.multiDL = self.premium diff --git a/pyload/plugin/hoster/DataportCz.py b/pyload/plugin/hoster/DataportCz.py new file mode 100644 index 000000000..8a32400ec --- /dev/null +++ b/pyload/plugin/hoster/DataportCz.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class DataportCz(SimpleHoster): + __name__ = "DataportCz" + __type__ = "hoster" + __version__ = "0.41" + + __pattern__ = r'http://(?:www\.)?dataport\.cz/file/(.+)' + + __description__ = """Dataport.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<span itemprop="name">(?P<N>[^<]+)</span>' + SIZE_PATTERN = r'<td class="fil">Velikost</td>\s*<td>(?P<S>[^<]+)</td>' + OFFLINE_PATTERN = r'<h2>Soubor nebyl nalezen</h2>' + + CAPTCHA_PATTERN = r'<section id="captcha_bg">\s*<img src="(.*?)"' + FREE_SLOTS_PATTERN = ur'PoÄet volnÃœch slotů: <span class="darkblue">(\d+)</span><br />' + + + def handleFree(self, pyfile): + captchas = {"1": "jkeG", "2": "hMJQ", "3": "vmEK", "4": "ePQM", "5": "blBd"} + + for _i in xrange(60): + action, inputs = self.parseHtmlForm('free_download_form') + self.logDebug(action, inputs) + if not action or not inputs: + self.error(_("free_download_form")) + + if "captchaId" in inputs and inputs['captchaId'] in captchas: + inputs['captchaCode'] = captchas[inputs['captchaId']] + else: + self.error(_("captcha")) + + self.html = self.download("http://www.dataport.cz%s" % action, post=inputs) + + check = self.checkDownload({"captcha": 'alert("\u0160patn\u011b opsan\u00fd k\u00f3d z obr\u00e1zu");', + "slot" : 'alert("Je n\u00e1m l\u00edto, ale moment\u00e1ln\u011b nejsou'}) + if check == "captcha": + self.error(_("invalid captcha")) + + elif check == "slot": + self.logDebug("No free slots - wait 60s and retry") + self.wait(60, False) + self.html = self.load(pyfile.url, decode=True) + continue + + else: + break diff --git a/pyload/plugin/hoster/DateiTo.py b/pyload/plugin/hoster/DateiTo.py new file mode 100644 index 000000000..216a758c8 --- /dev/null +++ b/pyload/plugin/hoster/DateiTo.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class DateiTo(SimpleHoster): + __name__ = "DateiTo" + __type__ = "hoster" + __version__ = "0.07" + + __pattern__ = r'http://(?:www\.)?datei\.to/datei/(?P<ID>\w+)\.html' + + __description__ = """Datei.to hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'Dateiname:</td>\s*<td colspan="2"><strong>(?P<N>.*?)</' + SIZE_PATTERN = r'Dateigröße:</td>\s*<td colspan="2">(?P<S>.*?)</' + OFFLINE_PATTERN = r'>Datei wurde nicht gefunden<|>Bitte wÀhle deine Datei aus... <' + + WAIT_PATTERN = r'countdown\({seconds: (\d+)' + MULTIDL_PATTERN = r'>Du lÀdst bereits eine Datei herunter<' + + DATA_PATTERN = r'url: "(.*?)", data: "(.*?)",' + + + def handleFree(self, pyfile): + url = 'http://datei.to/ajax/download.php' + data = {'P': 'I', 'ID': self.info['pattern']['ID']} + recaptcha = ReCaptcha(self) + + for _i in xrange(10): + self.logDebug("URL", url, "POST", data) + self.html = self.load(url, post=data) + self.checkErrors() + + if url.endswith('download.php') and 'P' in data: + if data['P'] == 'I': + self.doWait() + + elif data['P'] == 'IV': + break + + m = re.search(self.DATA_PATTERN, self.html) + if m is None: + self.error(_("data")) + url = 'http://datei.to/' + m.group(1) + data = dict(x.split('=') for x in m.group(2).split('&')) + + if url.endswith('recaptcha.php'): + data['recaptcha_response_field'], data['recaptcha_challenge_field'] = recaptcha.challenge() + else: + self.fail(_("Too bad...")) + + self.download(self.html) + + + def checkErrors(self): + m = re.search(self.MULTIDL_PATTERN, self.html) + if m: + m = re.search(self.WAIT_PATTERN, self.html) + wait_time = int(m.group(1)) if m else 30 + + errmsg = self.info['error'] = _("Parallel downloads") + self.retry(wait_time=wait_time, reason=errmsg) + + self.info.pop('error', None) + + + def doWait(self): + m = re.search(self.WAIT_PATTERN, self.html) + wait_time = int(m.group(1)) if m else 30 + + self.load('http://datei.to/ajax/download.php', post={'P': 'Ads'}) + self.wait(wait_time, False) diff --git a/pyload/plugin/hoster/DdlstorageCom.py b/pyload/plugin/hoster/DdlstorageCom.py new file mode 100644 index 000000000..cfde84ad0 --- /dev/null +++ b/pyload/plugin/hoster/DdlstorageCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class DdlstorageCom(DeadHoster): + __name__ = "DdlstorageCom" + __type__ = "hoster" + __version__ = "1.02" + + __pattern__ = r'https?://(?:www\.)?ddlstorage\.com/\w+' + + __description__ = """DDLStorage.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), + ("stickell", "l.stickell@yahoo.it")] diff --git a/pyload/plugin/hoster/DebridItaliaCom.py b/pyload/plugin/hoster/DebridItaliaCom.py new file mode 100644 index 000000000..1e7e1a338 --- /dev/null +++ b/pyload/plugin/hoster/DebridItaliaCom.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.MultiHoster import MultiHoster + + +class DebridItaliaCom(MultiHoster): + __name__ = "DebridItaliaCom" + __type__ = "hoster" + __version__ = "0.17" + + __pattern__ = r'https?://(?:www\.|s\d+\.)?debriditalia\.com/dl/\d+' + + __description__ = """Debriditalia.com multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + URL_REPLACEMENTS = [("https://", "http://")] + + + def handlePremium(self, pyfile): + self.html = self.load("http://www.debriditalia.com/api.php", + get={'generate': "on", 'link': pyfile.url, 'p': self.getPassword()}) + + if "ERROR:" not in self.html: + self.link = self.html.strip() + else: + self.info['error'] = re.search(r'ERROR:(.*)', self.html).group(1).strip() + + self.html = self.load("http://debriditalia.com/linkgen2.php", + post={'xjxfun' : "convertiLink", + 'xjxargs[]': "S<![CDATA[%s]]>" % pyfile.url, + 'xjxargs[]': "S%s" % self.getPassword()}) + try: + self.link = re.search(r'<a href="(.+?)"', self.html).group(1) + except AttributeError: + pass diff --git a/pyload/plugin/hoster/DepositfilesCom.py b/pyload/plugin/hoster/DepositfilesCom.py new file mode 100644 index 000000000..67cfe4bdc --- /dev/null +++ b/pyload/plugin/hoster/DepositfilesCom.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- + +import re + +from urllib import unquote + +from pyload.plugin.internal.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class DepositfilesCom(SimpleHoster): + __name__ = "DepositfilesCom" + __type__ = "hoster" + __version__ = "0.53" + + __pattern__ = r'https?://(?:www\.)?(depositfiles\.com|dfiles\.(eu|ru))(/\w{1,3})?/files/(?P<ID>\w+)' + + __description__ = """Depositfiles.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("spoob", "spoob@pyload.org"), + ("zoidberg", "zoidberg@mujmail.cz"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + NAME_PATTERN = r'<script type="text/javascript">eval\( unescape\(\'(?P<N>.*?)\'' + SIZE_PATTERN = r': <b>(?P<S>[\d.,]+) (?P<U>[\w^_]+)</b>' + OFFLINE_PATTERN = r'<span class="html_download_api-not_exists"></span>' + + NAME_REPLACEMENTS = [(r'\%u([0-9A-Fa-f]{4})', lambda m: unichr(int(m.group(1), 16))), + (r'.*<b title="(?P<N>[^"]+).*', "\g<N>")] + URL_REPLACEMENTS = [(__pattern__ + ".*", "https://dfiles.eu/files/\g<ID>")] + + COOKIES = [("dfiles.eu", "lang_current", "en")] + + LINK_FREE_PATTERN = r'<form id="downloader_file_form" action="(http://.+?\.(dfiles\.eu|depositfiles\.com)/.+?)" method="post"' + LINK_PREMIUM_PATTERN = r'class="repeat"><a href="(.+?)"' + LINK_MIRROR_PATTERN = r'class="repeat_mirror"><a href="(.+?)"' + + + def handleFree(self, pyfile): + if re.search(r'File is checked, please try again in a minute.', self.html) is not None: + self.logInfo(_("The file is being checked. Waiting 1 minute")) + self.retry(wait_time=60) + + wait = re.search(r'html_download_api-limit_interval\">(\d+)</span>', self.html) + if wait: + wait_time = int(wait.group(1)) + self.logInfo(_("Traffic used up. Waiting %d seconds") % wait_time) + self.wait(wait_time, True) + self.retry() + + wait = re.search(r'>Try in (\d+) minutes or use GOLD account', self.html) + if wait: + wait_time = int(wait.group(1)) + self.logInfo(_("All free slots occupied. Waiting %d minutes") % wait_time) + self.setWait(wait_time * 60, False) + + wait = re.search(r'Please wait (\d+) sec', self.html) + if wait: + self.setWait(int(wait.group(1))) + + m = re.search(r"var fid = '(\w+)';", self.html) + if m is None: + self.retry(wait_time=5) + params = {'fid': m.group(1)} + self.logDebug("FID: %s" % params['fid']) + + self.wait() + recaptcha = ReCaptcha(self) + captcha_key = recaptcha.detect_key() + if captcha_key is None: + self.error(_("ReCaptcha key not found")) + + for _i in xrange(5): + self.html = self.load("https://dfiles.eu/get_file.php", get=params) + + if '<input type=button value="Continue" onclick="check_recaptcha' in self.html: + if 'response' in params: + self.invalidCaptcha() + params['response'], params['challenge'] = recaptcha.challenge(captcha_key) + self.logDebug(params) + continue + + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m: + if 'response' in params: + self.correctCaptcha() + + self.link = unquote(m.group(1)) + break + else: + self.error(_("Download link")) + else: + self.fail(_("No valid captcha response received")) + + + def handlePremium(self, pyfile): + if '<span class="html_download_api-gold_traffic_limit">' in self.html: + self.logWarning(_("Download limit reached")) + self.retry(25, 60 * 60, "Download limit reached") + elif 'onClick="show_gold_offer' in self.html: + self.account.relogin(self.user) + self.retry() + else: + link = re.search(self.LINK_PREMIUM_PATTERN, self.html) + mirror = re.search(self.LINK_MIRROR_PATTERN, self.html) + + if link: + self.link = link.group(1) + + elif mirror: + self.link = mirror.group(1) diff --git a/pyload/plugin/hoster/DevhostSt.py b/pyload/plugin/hoster/DevhostSt.py new file mode 100644 index 000000000..e4c6f819b --- /dev/null +++ b/pyload/plugin/hoster/DevhostSt.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# http://d-h.st/mM8 + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class DevhostSt(SimpleHoster): + __name__ = "DevhostSt" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'http://(?:www\.)?d-h\.st/(?!users/)\w{3}' + + __description__ = """d-h.st hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] + + + NAME_PATTERN = r'<span title="(?P<N>.*?)"' + SIZE_PATTERN = r'</span> \((?P<S>[\d.,]+) (?P<U>[\w^_]+)\)<br' + HASHSUM_PATTERN = r'>(?P<T>.*?) Sum</span>: (?P<H>.*?)<br' + + OFFLINE_PATTERN = r'>File Not Found' + LINK_FREE_PATTERN = r'var product_download_url= \'(.+?)\'' + + + def setup(self): + self.multiDL = True + self.chunkLimit = 1 diff --git a/pyload/plugin/hoster/DlFreeFr.py b/pyload/plugin/hoster/DlFreeFr.py new file mode 100644 index 000000000..b0f9e7b7f --- /dev/null +++ b/pyload/plugin/hoster/DlFreeFr.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- + +import pycurl +import re + +from pyload.network.Browser import Browser +from pyload.network.CookieJar import CookieJar +from pyload.plugin.internal.captcha import AdYouLike +from pyload.plugin.internal.SimpleHoster import SimpleHoster, replace_patterns +from pyload.utils import json_loads + + +class CustomBrowser(Browser): + + def __init__(self, bucket=None, options={}): + Browser.__init__(self, bucket, options) + + + def load(self, *args, **kwargs): + post = kwargs.get("post") + + if post is None and len(args) > 2: + post = args[2] + + if post: + self.http.c.setopt(pycurl.FOLLOWLOCATION, 0) + self.http.c.setopt(pycurl.POST, 1) + self.http.c.setopt(pycurl.CUSTOMREQUEST, "POST") + else: + self.http.c.setopt(pycurl.FOLLOWLOCATION, 1) + self.http.c.setopt(pycurl.POST, 0) + self.http.c.setopt(pycurl.CUSTOMREQUEST, "GET") + + return Browser.load(self, *args, **kwargs) + + +class DlFreeFr(SimpleHoster): + __name__ = "DlFreeFr" + __type__ = "hoster" + __version__ = "0.28" + + __pattern__ = r'http://(?:www\.)?dl\.free\.fr/(\w+|getfile\.pl\?file=/\w+)' + + __description__ = """Dl.free.fr hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("the-razer", "daniel_ AT gmx DOT net"), + ("zoidberg", "zoidberg@mujmail.cz"), + ("Toilal", "toilal.dev@gmail.com")] + + + NAME_PATTERN = r'Fichier:</td>\s*<td[^>]*>(?P<N>[^>]*)</td>' + SIZE_PATTERN = r'Taille:</td>\s*<td[^>]*>(?P<S>[\d.,]+\w)o' + OFFLINE_PATTERN = r'Erreur 404 - Document non trouv|Fichier inexistant|Le fichier demandé n\'a pas été trouvé' + + + def setup(self): + self.resumeDownload = True + self.multiDL = True + self.limitDL = 5 + self.chunkLimit = 1 + + + def init(self): + factory = self.core.requestFactory + self.req = CustomBrowser(factory.bucket, factory.getOptions()) + + + def process(self, pyfile): + pyfile.url = replace_patterns(pyfile.url, self.URL_REPLACEMENTS) + valid_url = pyfile.url + headers = self.load(valid_url, just_header=True) + + if headers.get('code') == 302: + valid_url = headers.get('location') + headers = self.load(valid_url, just_header=True) + + if headers.get('code') == 200: + content_type = headers.get('content-type') + if content_type and content_type.startswith("text/html"): + # Undirect acces to requested file, with a web page providing it (captcha) + self.html = self.load(valid_url) + self.handleFree(pyfile) + else: + # Direct access to requested file for users using free.fr as Internet Service Provider. + self.link = valid_url + + elif headers.get('code') == 404: + self.offline() + + else: + self.fail(_("Invalid return code: ") + str(headers.get('code'))) + + + def handleFree(self, pyfile): + action, inputs = self.parseHtmlForm('action="getfile.pl"') + + adyoulike = AdYouLike(self) + response, challenge = adyoulike.challenge() + inputs.update(response) + + self.load("http://dl.free.fr/getfile.pl", post=inputs) + headers = self.getLastHeaders() + if headers.get("code") == 302 and "set-cookie" in headers and "location" in headers: + m = re.search("(.*?)=(.*?); path=(.*?); domain=(.*?)", headers.get("set-cookie")) + cj = CookieJar(__name__) + if m: + cj.setCookie(m.group(4), m.group(1), m.group(2), m.group(3)) + else: + self.fail(_("Cookie error")) + + self.link = headers.get("location") + + self.req.setCookieJar(cj) + else: + self.fail(_("Invalid response")) + + + def getLastHeaders(self): + #parse header + header = {"code": self.req.code} + for line in self.req.http.header.splitlines(): + line = line.strip() + if not line or ":" not in line: + continue + + key, none, value = line.partition(":") + key = key.lower().strip() + value = value.strip() + + if key in header: + if type(header[key]) == list: + header[key].append(value) + else: + header[key] = [header[key], value] + else: + header[key] = value + return header diff --git a/pyload/plugin/hoster/DodanePl.py b/pyload/plugin/hoster/DodanePl.py new file mode 100644 index 000000000..35fa1ecab --- /dev/null +++ b/pyload/plugin/hoster/DodanePl.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class DodanePl(DeadHoster): + __name__ = "DodanePl" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?dodane\.pl/file/\d+' + + __description__ = """Dodane.pl hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("z00nx", "z00nx0@gmail.com")] diff --git a/pyload/plugin/hoster/DuploadOrg.py b/pyload/plugin/hoster/DuploadOrg.py new file mode 100644 index 000000000..db00c46e9 --- /dev/null +++ b/pyload/plugin/hoster/DuploadOrg.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class DuploadOrg(DeadHoster): + __name__ = "DuploadOrg" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?dupload\.org/\w{12}' + + __description__ = """Dupload.grg hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] diff --git a/pyload/plugin/hoster/EasybytezCom.py b/pyload/plugin/hoster/EasybytezCom.py new file mode 100644 index 000000000..07e75714d --- /dev/null +++ b/pyload/plugin/hoster/EasybytezCom.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class EasybytezCom(XFSHoster): + __name__ = "EasybytezCom" + __type__ = "hoster" + __version__ = "0.23" + + __pattern__ = r'http://(?:www\.)?easybytez\.com/\w{12}' + + __description__ = """Easybytez.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), + ("stickell", "l.stickell@yahoo.it")] + + + OFFLINE_PATTERN = r'>File not available' + + LINK_PATTERN = r'(http://(\w+\.(easybytez|easyload|ezbytez|zingload)\.(com|to)|\d+\.\d+\.\d+\.\d+)/files/\d+/\w+/.+?)["\'<]' diff --git a/pyload/plugin/hoster/EdiskCz.py b/pyload/plugin/hoster/EdiskCz.py new file mode 100644 index 000000000..7aaef10ae --- /dev/null +++ b/pyload/plugin/hoster/EdiskCz.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class EdiskCz(SimpleHoster): + __name__ = "EdiskCz" + __type__ = "hoster" + __version__ = "0.23" + + __pattern__ = r'http://(?:www\.)?edisk\.(cz|sk|eu)/(stahni|sk/stahni|en/download)/.+' + + __description__ = """Edisk.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + INFO_PATTERN = r'<span class="fl" title="(?P<N>[^"]+)">\s*.*?\((?P<S>[\d.,]+) (?P<U>[\w^_]+)\)</h1></span>' + OFFLINE_PATTERN = r'<h3>This file does not exist due to one of the following:</h3><ul><li>' + + ACTION_PATTERN = r'/en/download/(\d+/.*\.html)' + LINK_FREE_PATTERN = r'http://.*edisk\.cz.*\.html' + + + def setup(self): + self.multiDL = False + + + def process(self, pyfile): + url = re.sub("/(stahni|sk/stahni)/", "/en/download/", pyfile.url) + + self.logDebug("URL:" + url) + + m = re.search(self.ACTION_PATTERN, url) + if m is None: + self.error(_("ACTION_PATTERN not found")) + action = m.group(1) + + self.html = self.load(url, decode=True) + self.getFileInfo() + + self.html = self.load(re.sub("/en/download/", "/en/download-slow/", url)) + + url = self.load(re.sub("/en/download/", "/x-download/", url), post={ + "action": action + }) + + if not re.match(self.LINK_FREE_PATTERN, url): + self.fail(_("Unexpected server response")) + + self.download(url) diff --git a/pyload/plugin/hoster/EgoFilesCom.py b/pyload/plugin/hoster/EgoFilesCom.py new file mode 100644 index 000000000..a843f5051 --- /dev/null +++ b/pyload/plugin/hoster/EgoFilesCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class EgoFilesCom(DeadHoster): + __name__ = "EgoFilesCom" + __type__ = "hoster" + __version__ = "0.16" + + __pattern__ = r'https?://(?:www\.)?egofiles\.com/\w+' + + __description__ = """Egofiles.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] diff --git a/pyload/plugin/hoster/EnteruploadCom.py b/pyload/plugin/hoster/EnteruploadCom.py new file mode 100644 index 000000000..efec5b37c --- /dev/null +++ b/pyload/plugin/hoster/EnteruploadCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class EnteruploadCom(DeadHoster): + __name__ = "EnteruploadCom" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?enterupload\.com/\w+' + + __description__ = """EnterUpload.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/EpicShareNet.py b/pyload/plugin/hoster/EpicShareNet.py new file mode 100644 index 000000000..16685088a --- /dev/null +++ b/pyload/plugin/hoster/EpicShareNet.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class EpicShareNet(DeadHoster): + __name__ = "EpicShareNet" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'https?://(?:www\.)?epicshare\.net/\w{12}' + + __description__ = """EpicShare.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("t4skforce", "t4skforce1337[AT]gmail[DOT]com")] diff --git a/pyload/plugin/hoster/EuroshareEu.py b/pyload/plugin/hoster/EuroshareEu.py new file mode 100644 index 000000000..84fbcda08 --- /dev/null +++ b/pyload/plugin/hoster/EuroshareEu.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class EuroshareEu(SimpleHoster): + __name__ = "EuroshareEu" + __type__ = "hoster" + __version__ = "0.27" + + __pattern__ = r'http://(?:www\.)?euroshare\.(eu|sk|cz|hu|pl)/file/.+' + + __description__ = """Euroshare.eu hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + INFO_PATTERN = r'<span style="float: left;"><strong>(?P<N>.+?)</strong> \((?P<S>.+?)\)</span>' + OFFLINE_PATTERN = ur'<h2>S.bor sa nena.iel</h2>|PoÅŸadovaná stránka neexistuje!' + + LINK_FREE_PATTERN = r'<a href="(/file/\d+/[^/]*/download/)"><div class="downloadButton"' + + ERR_PARDL_PATTERN = r'<h2>Prebieha s.ahovanie</h2>|<p>Naraz je z jednej IP adresy mo.n. s.ahova. iba jeden s.bor' + ERR_NOT_LOGGED_IN_PATTERN = r'href="/customer-zone/login/"' + + URL_REPLACEMENTS = [(r"(http://[^/]*\.)(sk|cz|hu|pl)/", r"\1eu/")] + + + def handlePremium(self, pyfile): + if self.ERR_NOT_LOGGED_IN_PATTERN in self.html: + self.account.relogin(self.user) + self.retry(reason=_("User not logged in")) + + self.download(pyfile.url.rstrip('/') + "/download/") + + check = self.checkDownload({"login": re.compile(self.ERR_NOT_LOGGED_IN_PATTERN), + "json" : re.compile(r'\{"status":"error".*?"message":"(.*?)"')}) + + if check == "login" or (check == "json" and self.lastCheck.group(1) == "Access token expired"): + self.account.relogin(self.user) + self.retry(reason=_("Access token expired")) + + elif check == "json": + self.fail(self.lastCheck.group(1)) + + + def handleFree(self, pyfile): + if re.search(self.ERR_PARDL_PATTERN, self.html) is not None: + self.longWait(5 * 60, 12) + + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("LINK_FREE_PATTERN not found")) + + self.link = "http://euroshare.eu%s" % m.group(1) + + + def checkFile(self): + if self.checkDownload({"multi-dl": re.compile(self.ERR_PARDL_PATTERN)}) + self.longWait(5 * 60, 12) + + return super(EuroshareEu, self).checkFile() diff --git a/pyload/plugin/hoster/ExashareCom.py b/pyload/plugin/hoster/ExashareCom.py new file mode 100644 index 000000000..504eef334 --- /dev/null +++ b/pyload/plugin/hoster/ExashareCom.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class ExashareCom(XFSHoster): + __name__ = "ExashareCom" + __type__ = "hoster" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?exashare\.com/\w{12}' + + __description__ = """Exashare.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + INFO_PATTERN = r'>(?P<NAME>.+?)<small>\( (?P<S>[\d.,]+) (?P<U>[\w^_]+)' + LINK_FREE_PATTERN = r'file: "(.+?)"' + + + def setup(self): + self.multiDL = True + self.chunkLimit = 1 + self.resumeDownload = self.premium + + + def handleFree(self, pyfile): + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("Free download link not found")) + else: + self.link = m.group(1) diff --git a/pyload/plugin/hoster/ExtabitCom.py b/pyload/plugin/hoster/ExtabitCom.py new file mode 100644 index 000000000..d5c1f0ba4 --- /dev/null +++ b/pyload/plugin/hoster/ExtabitCom.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.utils import json_loads + +from pyload.plugin.internal.CaptchaService import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster, secondsToMidnight + + +class ExtabitCom(SimpleHoster): + __name__ = "ExtabitCom" + __type__ = "hoster" + __version__ = "0.65" + + __pattern__ = r'http://(?:www\.)?extabit\.com/(file|go|fid)/(?P<ID>\w+)' + + __description__ = """Extabit.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<th>File:</th>\s*<td class="col-fileinfo">\s*<div title="(?P<N>[^"]+)">' + SIZE_PATTERN = r'<th>Size:</th>\s*<td class="col-fileinfo">(?P<S>[^<]+)</td>' + OFFLINE_PATTERN = r'>File not found<' + TEMP_OFFLINE_PATTERN = r'>(File is temporary unavailable|No download mirror)<' + + LINK_FREE_PATTERN = r'[\'"](http://guest\d+\.extabit\.com/\w+/.*?)[\'"]' + + + def handleFree(self, pyfile): + if r">Only premium users can download this file" in self.html: + self.fail(_("Only premium users can download this file")) + + m = re.search(r"Next free download from your ip will be available in <b>(\d+)\s*minutes", self.html) + if m: + self.wait(int(m.group(1)) * 60, True) + elif "The daily downloads limit from your IP is exceeded" in self.html: + self.logWarning(_("You have reached your daily downloads limit for today")) + self.wait(secondsToMidnight(gmt=2), True) + + self.logDebug("URL: " + self.req.http.lastEffectiveURL) + m = re.match(self.__pattern__, self.req.http.lastEffectiveURL) + fileID = m.group('ID') if m else self.info['pattern']['ID'] + + m = re.search(r'recaptcha/api/challenge\?k=(\w+)', self.html) + if m: + recaptcha = ReCaptcha(self) + captcha_key = m.group(1) + + for _i in xrange(5): + get_data = {"type": "recaptcha"} + get_data['capture'], get_data['challenge'] = recaptcha.challenge(captcha_key) + res = json_loads(self.load("http://extabit.com/file/%s/" % fileID, get=get_data)) + if "ok" in res: + self.correctCaptcha() + break + else: + self.invalidCaptcha() + else: + self.fail(_("Invalid captcha")) + else: + self.error(_("Captcha")) + + if not "href" in res: + self.error(_("Bad JSON response")) + + self.html = self.load("http://extabit.com/file/%s%s" % (fileID, res['href'])) + + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("LINK_FREE_PATTERN not found")) + + url = m.group(1) + self.download(url) diff --git a/pyload/plugin/hoster/FastixRu.py b/pyload/plugin/hoster/FastixRu.py new file mode 100644 index 000000000..129259304 --- /dev/null +++ b/pyload/plugin/hoster/FastixRu.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +import re + +from random import randrange +from urllib import unquote + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHoster import MultiHoster + + +class FastixRu(MultiHoster): + __name__ = "FastixRu" + __type__ = "hoster" + __version__ = "0.09" + + __pattern__ = r'http://(?:www\.)?fastix\.(ru|it)/file/\w{24}' + + __description__ = """Fastix multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Massimo Rosamilia", "max@spiritix.eu")] + + + def getFilename(self, url): + try: + name = unquote(url.rsplit("/", 1)[1]) + except IndexError: + name = "Unknown_Filename..." + if name.endswith("..."): # incomplete filename, append random stuff + name += "%s.tmp" % randrange(100, 999) + return name + + + def setup(self): + self.chunkLimit = 3 + + + def handlePremium(self, pyfile): + api_key = self.account.getAccountData(self.user) + api_key = api_key['api'] + + self.html = self.load("http://fastix.ru/api_v2/", + get={'apikey': api_key, 'sub': "getdirectlink", 'link': pyfile.url}) + + data = json_loads(self.html) + + self.logDebug("Json data", data) + + if "error\":true" in self.html: + self.offline() + else: + self.link = data['downloadlink'] + + if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown"): + #only use when name wasnt already set + pyfile.name = self.getFilename(self.link) + + + def checkFile(self): + if self.checkDownload({"error": "<title>An error occurred while processing your request</title>"}): + self.retry(wait_time=60, reason=_("An error occurred while generating link")) + + return super(FastixRu, self).checkFile() diff --git a/pyload/plugin/hoster/FastshareCz.py b/pyload/plugin/hoster/FastshareCz.py new file mode 100644 index 000000000..4baa362c3 --- /dev/null +++ b/pyload/plugin/hoster/FastshareCz.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urljoin + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class FastshareCz(SimpleHoster): + __name__ = "FastshareCz" + __type__ = "hoster" + __version__ = "0.27" + + __pattern__ = r'http://(?:www\.)?fastshare\.cz/\d+/.+' + + __description__ = """FastShare.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + URL_REPLACEMENTS = [("#.*", "")] + + COOKIES = [("fastshare.cz", "lang", "en")] + + INFO_PATTERN = r'<h1 class="dwp">(?P<N>[^<]+)</h1>\s*<div class="fileinfo">\s*Size\s*: (?P<S>\d+) (?P<U>[\w^_]+),' + OFFLINE_PATTERN = r'>(The file has been deleted|Requested page not found)' + + LINK_FREE_PATTERN = r'action=(/free/.*?)>\s*<img src="([^"]*)"><br' + LINK_PREMIUM_PATTERN = r'(http://data\d+\.fastshare\.cz/download\.php\?id=\d+&)' + + SLOT_ERROR = "> 100% of FREE slots are full" + CREDIT_ERROR = " credit for " + + + def checkErrors(self): + if self.SLOT_ERROR in self.html: + errmsg = self.info['error'] = _("No free slots") + self.retry(12, 60, errmsg) + + if self.CREDIT_ERROR in self.html: + errmsg = self.info['error'] = _("Not enough traffic left") + self.logWarning(errmsg) + self.resetAccount() + + self.info.pop('error', None) + + + def handleFree(self, pyfile): + m = re.search(self.FREE_URL_PATTERN, self.html) + if m: + action, captcha_src = m.groups() + else: + self.error(_("FREE_URL_PATTERN not found")) + + baseurl = "http://www.fastshare.cz" + captcha = self.decryptCaptcha(urljoin(baseurl, captcha_src)) + self.download(urljoin(baseurl, action), post={'code': captcha, 'btn.x': 77, 'btn.y': 18}) + + + def checkFile(self): + check = self.checkDownload({ + 'paralell-dl' : re.compile(r"<title>FastShare.cz</title>|<script>alert\('Pres FREE muzete stahovat jen jeden soubor najednou.'\)"), + 'wrong captcha': re.compile(r'Download for FREE'), + 'credit' : re.compile(self.CREDIT_ERROR) + }) + + if check == "paralell-dl": + self.retry(6, 10 * 60, _("Paralell download")) + + elif check == "wrong captcha": + self.retry(max_tries=5, reason=_("Wrong captcha")) + + elif check == "credit": + self.resetAccount() + + return super(FastshareCz, self).checkFile() diff --git a/pyload/plugin/hoster/FileApeCom.py b/pyload/plugin/hoster/FileApeCom.py new file mode 100644 index 000000000..2c39e314c --- /dev/null +++ b/pyload/plugin/hoster/FileApeCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class FileApeCom(DeadHoster): + __name__ = "FileApeCom" + __type__ = "hoster" + __version__ = "0.12" + + __pattern__ = r'http://(?:www\.)?fileape\.com/(index\.php\?act=download\&id=|dl/)\w+' + + __description__ = """FileApe.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("espes", "")] diff --git a/pyload/plugin/hoster/FileSharkPl.py b/pyload/plugin/hoster/FileSharkPl.py new file mode 100644 index 000000000..24b1db6de --- /dev/null +++ b/pyload/plugin/hoster/FileSharkPl.py @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urljoin + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class FileSharkPl(SimpleHoster): + __name__ = "FileSharkPl" + __type__ = "hoster" + __version__ = "0.07" + + __pattern__ = r'http://(?:www\.)?fileshark\.pl/pobierz/\d+/\w+' + + __description__ = """FileShark.pl hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("prOq", ""), + ("Walter Purcaro", "vuolter@gmail.com")] + + + NAME_PATTERN = r'<h2 class="name-file">(?P<N>.+)</h2>' + SIZE_PATTERN = r'<p class="size-file">(.*?)<strong>(?P<S>\d+\.?\d*)\s(?P<U>\w+)</strong></p>' + + OFFLINE_PATTERN = '(P|p)lik zosta. (usuni.ty|przeniesiony)' + + LINK_FREE_PATTERN = r'<a href="(.*?)" class="btn-upload-free">' + LINK_PREMIUM_PATTERN = r'<a href="(.*?)" class="btn-upload-premium">' + + WAIT_PATTERN = r'var timeToDownload = (\d+);' + ERROR_PATTERN = r'<p class="lead text-center alert alert-warning">(.*?)</p>' + IP_ERROR_PATTERN = r'Strona jest dost.pna wy..cznie dla u.ytkownik.w znajduj.cych si. na terenie Polski' + SLOT_ERROR_PATTERN = r'Osi.gni.to maksymaln. liczb. .ci.ganych jednocze.nie plik.w\.' + + CAPTCHA_PATTERN = '<img src="data:image/jpeg;base64,(.*?)" title="captcha"' + TOKEN_PATTERN = r'name="form\[_token\]" value="(.*?)" />' + + + def setup(self): + self.resumeDownload = True + + if self.premium: + self.multiDL = True + self.limitDL = 20 + else: + self.multiDL = False + + + def checkErrors(self): + # check if file is now available for download (-> file name can be found in html body) + m = re.search(self.WAIT_PATTERN, self.html) + if m: + errmsg = self.info['error'] = _("Another download already run") + self.retry(15, int(m.group(1)), errmsg) + + m = re.search(self.ERROR_PATTERN, self.html) + if m: + alert = m.group(1) + + if re.match(self.IP_ERROR_PATTERN, alert): + self.fail(_("Only connections from Polish IP are allowed")) + + elif re.match(self.SLOT_ERROR_PATTERN, alert): + errmsg = self.info['error'] = _("No free download slots available") + self.logWarning(errmsg) + self.retry(10, 30 * 60, _("Still no free download slots available")) + + else: + self.info['error'] = alert + self.retry(10, 10 * 60, _("Try again later")) + + self.info.pop('error', None) + + + def handleFree(self, pyfile): + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("Download url not found")) + + link = urljoin("http://fileshark.pl", m.group(1)) + + m = re.search(self.WAIT_PATTERN, self.html) + if m: + seconds = int(m.group(1)) + self.logDebug("Wait %s seconds" % seconds) + self.wait(seconds) + + action, inputs = self.parseHtmlForm('action=""') + + m = re.search(self.TOKEN_PATTERN, self.html) + if m is None: + self.retry(reason=_("Captcha form not found")) + + inputs['form[_token]'] = m.group(1) + + m = re.search(self.CAPTCHA_PATTERN, self.html) + if m is None: + self.retry(reason=_("Captcha image not found")) + + tmp_load = self.load + self.load = self._decode64 #: work-around: injects decode64 inside decryptCaptcha + + inputs['form[captcha]'] = self.decryptCaptcha(m.group(1), imgtype='jpeg') + inputs['form[start]'] = "" + + self.load = tmp_load + + self.download(link, post=inputs, cookies=True, disposition=True) + + + def checkFile(self): + check = self.checkDownload({'wrong_captcha': re.compile(r'<label for="form_captcha" generated="true" class="error">(.*?)</label>'), + 'wait_pattern' : re.compile(self.SECONDS_PATTERN), + 'DL-found' : re.compile('<a href="(.*)">')}) + if check == "DL-found": + self.correctCaptcha() + + elif check == "wrong_captcha": + self.invalidCaptcha() + self.retry(10, 1, _("Wrong captcha solution")) + + elif check == "wait_pattern": + self.retry() + + return super(FileSharkPl, self).checkFile() + + + def _decode64(self, data, *args, **kwargs): + return data.decode('base64') diff --git a/pyload/plugin/hoster/FileStoreTo.py b/pyload/plugin/hoster/FileStoreTo.py new file mode 100644 index 000000000..8998c0b1c --- /dev/null +++ b/pyload/plugin/hoster/FileStoreTo.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class FileStoreTo(SimpleHoster): + __name__ = "FileStoreTo" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'http://(?:www\.)?filestore\.to/\?d=(?P<ID>\w+)' + + __description__ = """FileStore.to hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com"), + ("stickell", "l.stickell@yahoo.it")] + + + INFO_PATTERN = r'File: <span.*?>(?P<N>.+?)<.*>Size: (?P<S>[\d.,]+) (?P<U>[\w^_]+)' + OFFLINE_PATTERN = r'>Download-Datei wurde nicht gefunden<' + TEMP_OFFLINE_PATTERN = r'>Der Download ist nicht bereit !<' + + + def setup(self): + self.resumeDownload = True + self.multiDL = True + + + def handleFree(self, pyfile): + self.wait(10) + self.link = self.load("http://filestore.to/ajax/download.php", + get={'D': re.search(r'"D=(\w+)', self.html).group(1)}) diff --git a/pyload/plugin/hoster/FilebeerInfo.py b/pyload/plugin/hoster/FilebeerInfo.py new file mode 100644 index 000000000..83fc6dbfc --- /dev/null +++ b/pyload/plugin/hoster/FilebeerInfo.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class FilebeerInfo(DeadHoster): + __name__ = "FilebeerInfo" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?filebeer\.info/(?!\d*~f)(?P<ID>\w+)' + + __description__ = """Filebeer.info plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/FilecloudIo.py b/pyload/plugin/hoster/FilecloudIo.py new file mode 100644 index 000000000..ae50f95bb --- /dev/null +++ b/pyload/plugin/hoster/FilecloudIo.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.utils import json_loads +from pyload.plugin.internal.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class FilecloudIo(SimpleHoster): + __name__ = "FilecloudIo" + __type__ = "hoster" + __version__ = "0.08" + + __pattern__ = r'http://(?:www\.)?(?:filecloud\.io|ifile\.it|mihd\.net)/(?P<ID>\w+)' + + __description__ = """Filecloud.io hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), + ("stickell", "l.stickell@yahoo.it")] + + + LOGIN_ACCOUNT = True + + NAME_PATTERN = r'id="aliasSpan">(?P<N>.*?) <' + SIZE_PATTERN = r'{var __ab1 = (?P<S>\d+);}' + OFFLINE_PATTERN = r'l10n\.(FILES__DOESNT_EXIST|REMOVED)' + TEMP_OFFLINE_PATTERN = r'l10n\.FILES__WARNING' + + UKEY_PATTERN = r'\'ukey\'\s*:\'(\w+)' + AB1_PATTERN = r'if\( __ab1 == \'(\w+)\' \)' + + ERROR_MSG_PATTERN = r'var __error_msg\s*=\s*l10n\.(.*?);' + + RECAPTCHA_PATTERN = r'var __recaptcha_public\s*=\s*\'(.+?)\';' + + LINK_FREE_PATTERN = r'"(http://s\d+\.filecloud\.io/%s/\d+/.*?)"' + + + def setup(self): + self.resumeDownload = True + self.multiDL = True + self.chunkLimit = 1 + + + def handleFree(self, pyfile): + data = {"ukey": self.info['pattern']['ID']} + + m = re.search(self.AB1_PATTERN, self.html) + if m is None: + self.error(_("__AB1")) + data['__ab1'] = m.group(1) + + recaptcha = ReCaptcha(self) + + m = re.search(self.RECAPTCHA_PATTERN, self.html) + captcha_key = m.group(1) if m else recaptcha.detect_key() + + if captcha_key is None: + self.error(_("ReCaptcha key not found")) + + response, challenge = recaptcha.challenge(captcha_key) + self.account.form_data = {"recaptcha_challenge_field": challenge, + "recaptcha_response_field" : response} + self.account.relogin(self.user) + self.retry(2) + + json_url = "http://filecloud.io/download-request.json" + res = self.load(json_url, post=data) + self.logDebug(res) + res = json_loads(res) + + if "error" in res and res['error']: + self.fail(res) + + self.logDebug(res) + if res['captcha']: + data['ctype'] = "recaptcha" + + for _i in xrange(5): + data['recaptcha_response'], data['recaptcha_challenge'] = recaptcha.challenge(captcha_key) + + json_url = "http://filecloud.io/download-request.json" + res = self.load(json_url, post=data) + self.logDebug(res) + res = json_loads(res) + + if "retry" in res and res['retry']: + self.invalidCaptcha() + else: + self.correctCaptcha() + break + else: + self.fail(_("Incorrect captcha")) + + if res['dl']: + self.html = self.load('http://filecloud.io/download.html') + + m = re.search(self.LINK_FREE_PATTERN % self.info['pattern']['ID'], self.html) + if m is None: + self.error(_("LINK_FREE_PATTERN not found")) + + if "size" in self.info and self.info['size']: + self.check_data = {"size": int(self.info['size'])} + + download_url = m.group(1) + self.download(download_url) + else: + self.fail(_("Unexpected server response")) + + + def handlePremium(self, pyfile): + akey = self.account.getAccountData(self.user)['akey'] + ukey = self.info['pattern']['ID'] + self.logDebug("Akey: %s | Ukey: %s" % (akey, ukey)) + rep = self.load("http://api.filecloud.io/api-fetch_download_url.api", + post={"akey": akey, "ukey": ukey}) + self.logDebug("FetchDownloadUrl: " + rep) + rep = json_loads(rep) + if rep['status'] == 'ok': + self.link = rep['download_url'] + else: + self.fail(rep['message']) diff --git a/module/plugins/hoster/FilefactoryCom.py b/pyload/plugin/hoster/FilefactoryCom.py index 95d61cd6a..95d61cd6a 100644 --- a/module/plugins/hoster/FilefactoryCom.py +++ b/pyload/plugin/hoster/FilefactoryCom.py diff --git a/module/plugins/hoster/FilejungleCom.py b/pyload/plugin/hoster/FilejungleCom.py index cd890778b..cd890778b 100644 --- a/module/plugins/hoster/FilejungleCom.py +++ b/pyload/plugin/hoster/FilejungleCom.py diff --git a/pyload/plugin/hoster/FileomCom.py b/pyload/plugin/hoster/FileomCom.py new file mode 100644 index 000000000..cdfc15dd9 --- /dev/null +++ b/pyload/plugin/hoster/FileomCom.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# http://fileom.com/gycaytyzdw3g/random.bin.html + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class FileomCom(XFSHoster): + __name__ = "FileomCom" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'https?://(?:www\.)?fileom\.com/\w{12}' + + __description__ = """Fileom.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + NAME_PATTERN = r'Filename: <span>(?P<N>.+?)<' + SIZE_PATTERN = r'File Size: <span class="size">(?P<S>[\d.,]+) (?P<U>[\w^_]+)' + + LINK_PATTERN = r'var url2 = \'(.+?)\';' + + + def setup(self): + self.multiDL = True + self.chunkLimit = 1 + self.resumeDownload = self.premium diff --git a/pyload/plugin/hoster/FilepostCom.py b/pyload/plugin/hoster/FilepostCom.py new file mode 100644 index 000000000..8c462b5d6 --- /dev/null +++ b/pyload/plugin/hoster/FilepostCom.py @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- + +import re + +from time import time + +from pyload.utils import json_loads +from pyload.plugin.internal.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class FilepostCom(SimpleHoster): + __name__ = "FilepostCom" + __type__ = "hoster" + __version__ = "0.33" + + __pattern__ = r'https?://(?:www\.)?(?:filepost\.com/files|fp\.io)/(?P<ID>[^/]+)' + + __description__ = """Filepost.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + INFO_PATTERN = r'<input type="text" id="url" value=\'<a href[^>]*>(?P<N>[^>]+?) - (?P<S>[\d.,]+) (?P<U>[\w^_]+)</a>\' class="inp_text"/>' + OFFLINE_PATTERN = r'class="error_msg_title"> Invalid or Deleted File. </div>|<div class="file_info file_info_deleted">' + + PREMIUM_ONLY_PATTERN = r'members only. Please upgrade to premium|a premium membership is required to download this file' + RECAPTCHA_PATTERN = r'Captcha.init\({\s*key:\s*\'(.+?)\'' + FLP_TOKEN_PATTERN = r'set_store_options\({token: \'(.+?)\'' + + + def handleFree(self, pyfile): + m = re.search(self.FLP_TOKEN_PATTERN, self.html) + if m is None: + self.error(_("Token")) + flp_token = m.group(1) + + m = re.search(self.RECAPTCHA_PATTERN, self.html) + if m is None: + self.error(_("Captcha key")) + captcha_key = m.group(1) + + # Get wait time + get_dict = {'SID': self.req.cj.getCookie('SID'), 'JsHttpRequest': str(int(time() * 10000)) + '-xml'} + post_dict = {'action': 'set_download', 'token': flp_token, 'code': self.info['pattern']['ID']} + wait_time = int(self.getJsonResponse(get_dict, post_dict, 'wait_time')) + + if wait_time > 0: + self.wait(wait_time) + + post_dict = {"token": flp_token, "code": self.info['pattern']['ID'], "file_pass": ''} + + if 'var is_pass_exists = true;' in self.html: + # Solve password + password = self.getPassword() + + if password: + self.logInfo(_("Password protected link, trying ") + file_pass) + + get_dict['JsHttpRequest'] = str(int(time() * 10000)) + '-xml' + post_dict['file_pass'] = file_pass + + self.link = self.getJsonResponse(get_dict, post_dict, 'link') + + if not self.link: + self.fail(_("Incorrect password")) + else: + self.fail(_("No password found")) + + else: + # Solve recaptcha + recaptcha = ReCaptcha(self) + + for i in xrange(5): + get_dict['JsHttpRequest'] = str(int(time() * 10000)) + '-xml' + if i: + post_dict['recaptcha_response_field'], post_dict['recaptcha_challenge_field'] = recaptcha.challenge( + captcha_key) + self.logDebug(u"RECAPTCHA: %s : %s : %s" % ( + captcha_key, post_dict['recaptcha_challenge_field'], post_dict['recaptcha_response_field'])) + + download_url = self.getJsonResponse(get_dict, post_dict, 'link') + if download_url: + if i: + self.correctCaptcha() + break + elif i: + self.invalidCaptcha() + + else: + self.fail(_("Invalid captcha")) + + # Download + self.download(download_url) + + + def getJsonResponse(self, get_dict, post_dict, field): + res = json_loads(self.load('https://filepost.com/files/get/', get=get_dict, post=post_dict)) + + self.logDebug(res) + + if not 'js' in res: + self.error(_("JSON %s 1") % field) + + # i changed js_answer to res['js'] since js_answer is nowhere set. + # i don't know the JSON-HTTP specs in detail, but the previous author + # accessed res['js']['error'] as well as js_answer['error']. + # see the two lines commented out with "# ~?". + if 'error' in res['js']: + + if res['js']['error'] == 'download_delay': + self.retry(wait_time=res['js']['params']['next_download']) + # ~? self.retry(wait_time=js_answer['params']['next_download']) + + elif 'Wrong file password' in res['js']['error'] \ + or 'You entered a wrong CAPTCHA code' in res['js']['error'] \ + or 'CAPTCHA Code nicht korrekt' in res['js']['error']: + return None + + elif 'CAPTCHA' in res['js']['error']: + self.logDebug("Error response is unknown, but mentions CAPTCHA") + return None + + else: + self.fail(res['js']['error']) + + if not 'answer' in res['js'] or not field in res['js']['answer']: + self.error(_("JSON %s 2") % field) + + return res['js']['answer'][field] diff --git a/pyload/plugin/hoster/FilepupNet.py b/pyload/plugin/hoster/FilepupNet.py new file mode 100644 index 000000000..b19f40106 --- /dev/null +++ b/pyload/plugin/hoster/FilepupNet.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# http://www.filepup.net/files/k5w4ZVoF1410184283.html +# http://www.filepup.net/files/R4GBq9XH1410186553.html + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class FilepupNet(SimpleHoster): + __name__ = "FilepupNet" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?filepup\.net/files/\w+' + + __description__ = """Filepup.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + NAME_PATTERN = r'>(?P<N>.+?)</h1>' + SIZE_PATTERN = r'class="fa fa-archive"></i> \((?P<S>[\d.,]+) (?P<U>[\w^_]+)' + + OFFLINE_PATTERN = r'>This file has been deleted' + + LINK_FREE_PATTERN = r'(http://www\.filepup\.net/get/.+?)\'' + + + def setup(self): + self.multiDL = False + self.chunkLimit = 1 + + + def handleFree(self, pyfile): + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("Download link not found")) + + dl_link = m.group(1) + self.download(dl_link, post={'task': "download"}) diff --git a/pyload/plugin/hoster/FilerNet.py b/pyload/plugin/hoster/FilerNet.py new file mode 100644 index 000000000..3cf4bec36 --- /dev/null +++ b/pyload/plugin/hoster/FilerNet.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# http://filer.net/get/ivgf5ztw53et3ogd +# http://filer.net/get/hgo14gzcng3scbvv + +import pycurl +import re + +from urlparse import urljoin + +from pyload.plugin.internal.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class FilerNet(SimpleHoster): + __name__ = "FilerNet" + __type__ = "hoster" + __version__ = "0.16" + + __pattern__ = r'https?://(?:www\.)?filer\.net/get/\w+' + + __description__ = """Filer.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + INFO_PATTERN = r'<h1 class="page-header">Free Download (?P<N>\S+) <small>(?P<S>[\w.]+) (?P<U>[\w^_]+)</small></h1>' + OFFLINE_PATTERN = r'Nicht gefunden' + + LINK_FREE_PATTERN = LINK_PREMIUM_PATTERN = r'href="([^"]+)">Get download</a>' + + + def checkErrors(self): + # Wait between downloads + m = re.search(r'musst du <span id="time">(\d+)</span> Sekunden warten', self.html) + if m: + errmsg = self.info['error'] = _("Wait between free downloads") + self.retry(wait_time=int(m.group(1)), reason=errmsg) + + self.info.pop('error', None) + + + def handleFree(self, pyfile): + inputs = self.parseHtmlForm(input_names={'token': re.compile(r'.+')})[1] + if 'token' not in inputs: + self.error(_("Unable to detect token")) + + self.html = self.load(pyfile.url, post={'token': inputs['token']}, decode=True) + + inputs = self.parseHtmlForm(input_names={'hash': re.compile(r'.+')})[1] + if 'hash' not in inputs: + self.error(_("Unable to detect hash")) + + recaptcha = ReCaptcha(self) + response, challenge = recaptcha.challenge() + + #@NOTE: Work-around for v0.4.9 just_header issue + #@TODO: Check for v0.4.10 + self.req.http.c.setopt(pycurl.FOLLOWLOCATION, 0) + self.load(pyfile.url, post={'recaptcha_challenge_field': challenge, + 'recaptcha_response_field' : response, + 'hash' : inputs['hash']}) + self.req.http.c.setopt(pycurl.FOLLOWLOCATION, 1) + + if 'location' in self.req.http.header.lower(): + self.link = re.search(r'location: (\S+)', self.req.http.header, re.I).group(1) + self.correctCaptcha() + else: + self.invalidCaptcha() diff --git a/pyload/plugin/hoster/FilerioCom.py b/pyload/plugin/hoster/FilerioCom.py new file mode 100644 index 000000000..9290bee84 --- /dev/null +++ b/pyload/plugin/hoster/FilerioCom.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class FilerioCom(XFSHoster): + __name__ = "FilerioCom" + __type__ = "hoster" + __version__ = "0.07" + + __pattern__ = r'http://(?:www\.)?(filerio\.(in|com)|filekeen\.com)/\w{12}' + + __description__ = """FileRio.in hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + URL_REPLACEMENTS = [(r'filekeen\.com', "filerio.in")] + + OFFLINE_PATTERN = r'>"File Not Found|File has been removed' diff --git a/module/plugins/hoster/FilesMailRu.py b/pyload/plugin/hoster/FilesMailRu.py index 09da46b01..09da46b01 100644 --- a/module/plugins/hoster/FilesMailRu.py +++ b/pyload/plugin/hoster/FilesMailRu.py diff --git a/pyload/plugin/hoster/FileserveCom.py b/pyload/plugin/hoster/FileserveCom.py new file mode 100644 index 000000000..18322fa00 --- /dev/null +++ b/pyload/plugin/hoster/FileserveCom.py @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.utils import json_loads +from pyload.network.RequestFactory import getURL +from pyload.plugin.Hoster import Hoster +from pyload.plugin.Plugin import chunks +from pyload.plugin.internal.CaptchaService import ReCaptcha +from pyload.plugin.internal.SimpleHoster import secondsToMidnight +from pyload.utils import parseFileSize + + +def checkFile(plugin, urls): + html = getURL(plugin.URLS[1], post={"urls": "\n".join(urls)}, decode=True) + + file_info = [] + for li in re.finditer(plugin.LINKCHECK_TR, html, re.S): + try: + cols = re.findall(plugin.LINKCHECK_TD, li.group(1)) + if cols: + file_info.append(( + cols[1] if cols[1] != '--' else cols[0], + parseFileSize(cols[2]) if cols[2] != '--' else 0, + 2 if cols[3].startswith('Available') else 1, + cols[0])) + except Exception, e: + continue + + return file_info + + +class FileserveCom(Hoster): + __name__ = "FileserveCom" + __type__ = "hoster" + __version__ = "0.54" + + __pattern__ = r'http://(?:www\.)?fileserve\.com/file/(?P<ID>[^/]+)' + + __description__ = """Fileserve.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("jeix", "jeix@hasnomail.de"), + ("mkaay", "mkaay@mkaay.de"), + ("Paul King", ""), + ("zoidberg", "zoidberg@mujmail.cz")] + + + URLS = ["http://www.fileserve.com/file/", "http://www.fileserve.com/link-checker.php", + "http://www.fileserve.com/checkReCaptcha.php"] + LINKCHECK_TR = r'<tr>\s*(<td>http://www\.fileserve\.com/file/.*?)</tr>' + LINKCHECK_TD = r'<td>(?:<[^>]*>| )*([^<]*)' + + CAPTCHA_KEY_PATTERN = r'var reCAPTCHA_publickey=\'(.+?)\'' + LONG_WAIT_PATTERN = r'<li class="title">You need to wait (\d+) (\w+) to start another download\.</li>' + LINK_EXPIRED_PATTERN = r'Your download link has expired' + DAILY_LIMIT_PATTERN = r'Your daily download limit has been reached' + NOT_LOGGED_IN_PATTERN = r'<form (name="loginDialogBoxForm"|id="login_form")|<li><a href="/login\.php">Login</a></li>' + + + def setup(self): + self.resumeDownload = self.multiDL = self.premium + self.file_id = re.match(self.__pattern__, self.pyfile.url).group('ID') + self.url = "%s%s" % (self.URLS[0], self.file_id) + + self.logDebug("File ID: %s URL: %s" % (self.file_id, self.url)) + + + def process(self, pyfile): + pyfile.name, pyfile.size, status, self.url = checkFile(self, [self.url])[0] + if status != 2: + self.offline() + self.logDebug("File Name: %s Size: %d" % (pyfile.name, pyfile.size)) + + if self.premium: + self.handlePremium(pyfile) + else: + self.handleFree(pyfile) + + + def handleFree(self, pyfile): + self.html = self.load(self.url) + action = self.load(self.url, post={"checkDownload": "check"}, decode=True) + action = json_loads(action) + self.logDebug(action) + + if "fail" in action: + if action['fail'] == "timeLimit": + self.html = self.load(self.url, post={"checkDownload": "showError", "errorType": "timeLimit"}, + decode=True) + + self.doLongWait(re.search(self.LONG_WAIT_PATTERN, self.html)) + + elif action['fail'] == "parallelDownload": + self.logWarning(_("Parallel download error, now waiting 60s")) + self.retry(wait_time=60, reason=_("parallelDownload")) + + else: + self.fail(_("Download check returned: %s") % action['fail']) + + elif "success" in action: + if action['success'] == "showCaptcha": + self.doCaptcha() + self.doTimmer() + elif action['success'] == "showTimmer": + self.doTimmer() + + else: + self.error(_("Unknown server response")) + + # show download link + res = self.load(self.url, post={"downloadLink": "show"}, decode=True) + self.logDebug("Show downloadLink response: %s" % res) + if "fail" in res: + self.error(_("Couldn't retrieve download url")) + + # this may either download our file or forward us to an error page + self.download(self.url, post={"download": "normal"}) + self.logDebug(self.req.http.lastEffectiveURL) + + check = self.checkDownload({"expired": self.LINK_EXPIRED_PATTERN, + "wait" : re.compile(self.LONG_WAIT_PATTERN), + "limit" : self.DAILY_LIMIT_PATTERN}) + + if check == "expired": + self.logDebug("Download link was expired") + self.retry() + + elif check == "wait": + self.doLongWait(self.lastCheck) + + elif check == "limit": + self.logWarning(_("Download limited reached for today")) + self.setWait(secondsToMidnight(gmt=2), True) + self.wait() + self.retry() + + self.thread.m.reconnecting.wait(3) # Ease issue with later downloads appearing to be in parallel + + + def doTimmer(self): + res = self.load(self.url, post={"downloadLink": "wait"}, decode=True) + self.logDebug("Wait response: %s" % res[:80]) + + if "fail" in res: + self.fail(_("Failed getting wait time")) + + if self.__name__ == "FilejungleCom": + m = re.search(r'"waitTime":(\d+)', res) + if m is None: + self.fail(_("Cannot get wait time")) + wait_time = int(m.group(1)) + else: + wait_time = int(res) + 3 + + self.setWait(wait_time) + self.wait() + + + def doCaptcha(self): + captcha_key = re.search(self.CAPTCHA_KEY_PATTERN, self.html).group(1) + recaptcha = ReCaptcha(self) + + for _i in xrange(5): + response, challenge = recaptcha.challenge(captcha_key) + res = json_loads(self.load(self.URLS[2], + post={'recaptcha_challenge_field' : challenge, + 'recaptcha_response_field' : response, + 'recaptcha_shortencode_field': self.file_id})) + if not res['success']: + self.invalidCaptcha() + else: + self.correctCaptcha() + break + else: + self.fail(_("Invalid captcha")) + + + def doLongWait(self, m): + wait_time = (int(m.group(1)) * {'seconds': 1, 'minutes': 60, 'hours': 3600}[m.group(2)]) if m else 12 * 60 + self.setWait(wait_time, True) + self.wait() + self.retry() + + + def handlePremium(self, pyfile): + premium_url = None + if self.__name__ == "FileserveCom": + #try api download + res = self.load("http://app.fileserve.com/api/download/premium/", + post={"username": self.user, + "password": self.account.getAccountData(self.user)['password'], + "shorten": self.file_id}, + decode=True) + if res: + res = json_loads(res) + if res['error_code'] == "302": + premium_url = res['next'] + elif res['error_code'] in ["305", "500"]: + self.tempOffline() + elif res['error_code'] in ["403", "605"]: + self.resetAccount() + elif res['error_code'] in ["606", "607", "608"]: + self.offline() + else: + self.logError(res['error_code'], res['error_message']) + + self.download(premium_url or pyfile.url) + + if not premium_url and self.checkDownload({"login": re.compile(self.NOT_LOGGED_IN_PATTERN)}): + self.account.relogin(self.user) + self.retry(reason=_("Not logged in")) + + +def getInfo(urls): + for chunk in chunks(urls, 100): + yield checkFile(FileserveCom, chunk) diff --git a/pyload/plugin/hoster/FileshareInUa.py b/pyload/plugin/hoster/FileshareInUa.py new file mode 100644 index 000000000..f7855378a --- /dev/null +++ b/pyload/plugin/hoster/FileshareInUa.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class FileshareInUa(DeadHoster): + __name__ = "FileshareInUa" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'https?://(?:www\.)?fileshare\.in\.ua/\w{7}' + + __description__ = """Fileshare.in.ua hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("fwannmacher", "felipe@warhammerproject.com")] diff --git a/pyload/plugin/hoster/FilesonicCom.py b/pyload/plugin/hoster/FilesonicCom.py new file mode 100644 index 000000000..1dee6eefd --- /dev/null +++ b/pyload/plugin/hoster/FilesonicCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class FilesonicCom(DeadHoster): + __name__ = "FilesonicCom" + __type__ = "hoster" + __version__ = "0.35" + + __pattern__ = r'http://(?:www\.)?filesonic\.com/file/\w+' + + __description__ = """Filesonic.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("jeix", "jeix@hasnomail.de"), + ("paulking", "")] diff --git a/pyload/plugin/hoster/FilezyNet.py b/pyload/plugin/hoster/FilezyNet.py new file mode 100644 index 000000000..deab69101 --- /dev/null +++ b/pyload/plugin/hoster/FilezyNet.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class FilezyNet(DeadHoster): + __name__ = "FilezyNet" + __type__ = "hoster" + __version__ = "0.20" + + __pattern__ = r'http://(?:www\.)?filezy\.net/\w{12}' + + __description__ = """Filezy.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [] diff --git a/pyload/plugin/hoster/FiredriveCom.py b/pyload/plugin/hoster/FiredriveCom.py new file mode 100644 index 000000000..4ce47e692 --- /dev/null +++ b/pyload/plugin/hoster/FiredriveCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class FiredriveCom(DeadHoster): + __name__ = "FiredriveCom" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'https?://(?:www\.)?(firedrive|putlocker)\.com/(mobile/)?(file|embed)/(?P<ID>\w+)' + + __description__ = """Firedrive.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] diff --git a/module/plugins/hoster/FlyFilesNet.py b/pyload/plugin/hoster/FlyFilesNet.py index 5aff3e811..5aff3e811 100644 --- a/module/plugins/hoster/FlyFilesNet.py +++ b/pyload/plugin/hoster/FlyFilesNet.py diff --git a/pyload/plugin/hoster/FourSharedCom.py b/pyload/plugin/hoster/FourSharedCom.py new file mode 100644 index 000000000..00209f4f1 --- /dev/null +++ b/pyload/plugin/hoster/FourSharedCom.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class FourSharedCom(SimpleHoster): + __name__ = "FourSharedCom" + __type__ = "hoster" + __version__ = "0.31" + + __pattern__ = r'https?://(?:www\.)?4shared(\-china)?\.com/(account/)?(download|get|file|document|photo|video|audio|mp3|office|rar|zip|archive|music)/.+' + + __description__ = """4Shared.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("jeix", "jeix@hasnomail.de"), + ("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<meta name="title" content="(?P<N>.+?)"' + SIZE_PATTERN = r'<span title="Size: (?P<S>[\d.,]+) (?P<U>[\w^_]+)">' + OFFLINE_PATTERN = r'The file link that you requested is not valid\.|This file was deleted.' + + NAME_REPLACEMENTS = [(r"&#(\d+).", lambda m: unichr(int(m.group(1))))] + SIZE_REPLACEMENTS = [(",", "")] + + DIRECT_LINK = False + LOGIN_ACCOUNT = True + + LINK_FREE_PATTERN = r'name="d3link" value="(.*?)"' + LINK_BTN_PATTERN = r'id="btnLink" href="(.*?)"' + + ID_PATTERN = r'name="d3fid" value="(.*?)"' + + + def handleFree(self, pyfile): + m = re.search(self.LINK_BTN_PATTERN, self.html) + if m: + link = m.group(1) + else: + link = re.sub(r'/(download|get|file|document|photo|video|audio)/', r'/get/', pyfile.url) + + self.html = self.load(link) + + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("Download link")) + + self.link = m.group(1) + + try: + m = re.search(self.ID_PATTERN, self.html) + res = self.load('http://www.4shared.com/web/d2/getFreeDownloadLimitInfo?fileId=%s' % m.group(1)) + self.logDebug(res) + except Exception: + pass + + self.wait(20) diff --git a/pyload/plugin/hoster/FreakshareCom.py b/pyload/plugin/hoster/FreakshareCom.py new file mode 100644 index 000000000..331d7f2a3 --- /dev/null +++ b/pyload/plugin/hoster/FreakshareCom.py @@ -0,0 +1,180 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.Hoster import Hoster +from pyload.plugin.internal.CaptchaService import ReCaptcha +from pyload.plugin.internal.SimpleHoster import secondsToMidnight + + +class FreakshareCom(Hoster): + __name__ = "FreakshareCom" + __type__ = "hoster" + __version__ = "0.40" + + __pattern__ = r'http://(?:www\.)?freakshare\.(net|com)/files/\S*?/' + + __description__ = """Freakshare.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("sitacuisses", "sitacuisses@yahoo.de"), + ("spoob", "spoob@pyload.org"), + ("mkaay", "mkaay@mkaay.de"), + ("Toilal", "toilal.dev@gmail.com")] + + + def setup(self): + self.multiDL = False + self.req_opts = [] + + + def process(self, pyfile): + self.pyfile = pyfile + + pyfile.url = pyfile.url.replace("freakshare.net/", "freakshare.com/") + + if self.account: + self.html = self.load(pyfile.url, cookies=False) + pyfile.name = self.get_file_name() + self.download(pyfile.url) + + else: + self.prepare() + self.get_file_url() + + self.download(pyfile.url, post=self.req_opts) + + check = self.checkDownload({"bad" : "bad try", + "paralell" : "> Sorry, you cant download more then 1 files at time. <", + "empty" : "Warning: Unknown: Filename cannot be empty", + "wrong_captcha" : "Wrong Captcha!", + "downloadserver": "No Downloadserver. Please try again later!"}) + + if check == "bad": + self.fail(_("Bad Try")) + + elif check == "paralell": + self.setWait(300, True) + self.wait() + self.retry() + + elif check == "empty": + self.fail(_("File not downloadable")) + + elif check == "wrong_captcha": + self.invalidCaptcha() + self.retry() + + elif check == "downloadserver": + self.retry(5, 15 * 60, _("No Download server")) + + + def prepare(self): + pyfile = self.pyfile + + self.download_html() + + if not self.file_exists(): + self.offline() + + self.setWait(self.get_waiting_time()) + + pyfile.name = self.get_file_name() + pyfile.size = self.get_file_size() + + self.wait() + + return True + + + def download_html(self): + self.load("http://freakshare.com/index.php", {"language": "EN"}) # Set english language in server session + self.html = self.load(self.pyfile.url) + + + def get_file_url(self): + """ returns the absolute downloadable filepath + """ + if not self.html: + self.download_html() + if not self.wantReconnect: + self.req_opts = self.get_download_options() # get the Post options for the Request + #file_url = self.pyfile.url + #return file_url + else: + self.offline() + + + def get_file_name(self): + if not self.html: + self.download_html() + if not self.wantReconnect: + file_name = re.search(r"<h1\sclass=\"box_heading\"\sstyle=\"text-align:center;\">([^ ]+)", self.html) + if file_name is not None: + file_name = file_name.group(1) + else: + file_name = self.pyfile.url + return file_name + else: + return self.pyfile.url + + + def get_file_size(self): + size = 0 + if not self.html: + self.download_html() + if not self.wantReconnect: + file_size_check = re.search( + r"<h1\sclass=\"box_heading\"\sstyle=\"text-align:center;\">[^ ]+ - ([^ ]+) (\w\w)yte", self.html) + if file_size_check is not None: + units = float(file_size_check.group(1).replace(",", "")) + pow = {'KB': 1, 'MB': 2, 'GB': 3}[file_size_check.group(2)] + size = int(units * 1024 ** pow) + + return size + + + def get_waiting_time(self): + if not self.html: + self.download_html() + + if "Your Traffic is used up for today" in self.html: + self.wantReconnect = True + return secondsToMidnight(gmt=2) + + timestring = re.search('\s*var\s(?:downloadWait|time)\s=\s(\d*)[\d.]*;', self.html) + if timestring: + return int(timestring.group(1)) + else: + return 60 + + + def file_exists(self): + """ returns True or False + """ + if not self.html: + self.download_html() + if re.search(r"This file does not exist!", self.html) is not None: + return False + else: + return True + + + def get_download_options(self): + re_envelope = re.search(r".*?value=\"Free\sDownload\".*?\n*?(.*?<.*?>\n*)*?\n*\s*?</form>", + self.html).group(0) # get the whole request + to_sort = re.findall(r"<input\stype=\"hidden\"\svalue=\"(.*?)\"\sname=\"(.*?)\"\s\/>", re_envelope) + request_options = dict((n, v) for (v, n) in to_sort) + + herewego = self.load(self.pyfile.url, None, request_options) # the actual download-Page + + to_sort = re.findall(r"<input\stype=\".*?\"\svalue=\"(\S*?)\".*?name=\"(\S*?)\"\s.*?\/>", herewego) + request_options = dict((n, v) for (v, n) in to_sort) + + challenge = re.search(r"http://api\.recaptcha\.net/challenge\?k=(\w+)", herewego) + + if challenge: + re_captcha = ReCaptcha(self) + (request_options['recaptcha_challenge_field'], + request_options['recaptcha_response_field']) = re_captcha.challenge(challenge.group(1)) + + return request_options diff --git a/pyload/plugin/hoster/FreeWayMe.py b/pyload/plugin/hoster/FreeWayMe.py new file mode 100644 index 000000000..21f99c19e --- /dev/null +++ b/pyload/plugin/hoster/FreeWayMe.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.MultiHoster import MultiHoster + + +class FreeWayMe(MultiHoster): + __name__ = "FreeWayMe" + __type__ = "hoster" + __version__ = "0.16" + + __pattern__ = r'https://(?:www\.)?free-way\.me/.+' + + __description__ = """FreeWayMe multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Nicolas Giese", "james@free-way.me")] + + + def setup(self): + self.resumeDownload = False + self.multiDL = self.premium + self.chunkLimit = 1 + + + def handlePremium(self, pyfile): + user, data = self.account.selectAccount() + + for _i in xrange(5): + # try it five times + header = self.load("https://www.free-way.me/load.php", + get={'multiget': 7, + 'url' : pyfile.url, + 'user' : user, + 'pw' : self.account.getAccountData(user)['password'], + 'json' : ""}, + just_header=True) + + if 'location' in header: + headers = self.load(header['location'], just_header=True) + if headers['code'] == 500: + # error on 2nd stage + self.logError(_("Error [stage2]")) + else: + # seems to work.. + self.download(header['location']) + break + else: + # error page first stage + self.logError(_("Error [stage1]")) + + #@TODO: handle errors diff --git a/pyload/plugin/hoster/FreevideoCz.py b/pyload/plugin/hoster/FreevideoCz.py new file mode 100644 index 000000000..3c9b94ea8 --- /dev/null +++ b/pyload/plugin/hoster/FreevideoCz.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class FreevideoCz(DeadHoster): + __name__ = "FreevideoCz" + __type__ = "hoster" + __version__ = "0.30" + + __pattern__ = r'http://(?:www\.)?freevideo\.cz/vase-videa/.+' + + __description__ = """Freevideo.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/module/plugins/hoster/FshareVn.py b/pyload/plugin/hoster/FshareVn.py index 186cb2f87..186cb2f87 100644 --- a/module/plugins/hoster/FshareVn.py +++ b/pyload/plugin/hoster/FshareVn.py diff --git a/module/plugins/hoster/Ftp.py b/pyload/plugin/hoster/Ftp.py index 6924c5910..6924c5910 100644 --- a/module/plugins/hoster/Ftp.py +++ b/pyload/plugin/hoster/Ftp.py diff --git a/module/plugins/hoster/GamefrontCom.py b/pyload/plugin/hoster/GamefrontCom.py index 89e188010..89e188010 100644 --- a/module/plugins/hoster/GamefrontCom.py +++ b/pyload/plugin/hoster/GamefrontCom.py diff --git a/pyload/plugin/hoster/GigapetaCom.py b/pyload/plugin/hoster/GigapetaCom.py new file mode 100644 index 000000000..9aa842e21 --- /dev/null +++ b/pyload/plugin/hoster/GigapetaCom.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +import re + +from random import randint + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class GigapetaCom(SimpleHoster): + __name__ = "GigapetaCom" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?gigapeta\.com/dl/\w+' + + __description__ = """GigaPeta.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<img src=".*" alt="file" />-->\s*(?P<N>.*?)\s*</td>' + SIZE_PATTERN = r'<th>\s*Size\s*</th>\s*<td>\s*(?P<S>.*?)\s*</td>' + OFFLINE_PATTERN = r'<div id="page_error">' + + COOKIES = [("gigapeta.com", "lang", "us")] + + + def handleFree(self, pyfile): + captcha_key = str(randint(1, 100000000)) + captcha_url = "http://gigapeta.com/img/captcha.gif?x=%s" % captcha_key + + for _i in xrange(5): + self.checkErrors() + + captcha = self.decryptCaptcha(captcha_url) + self.html = self.load(pyfile.url, + post={'captcha_key': captcha_key, + 'captcha' : captcha, + 'download' : "Download"}, + follow_location=False) + + m = re.search(r'Location\s*:\s*(.+)', self.req.http.header, re.I) + if m: + download_url = m.group(1) + break + elif "Entered figures don`t coincide with the picture" in self.html: + self.invalidCaptcha() + else: + self.fail(_("No valid captcha code entered")) + + self.download(download_url) + + + def checkErrors(self): + if "All threads for IP" in self.html: + self.logDebug("Your IP is already downloading a file") + self.wait(5 * 60, True) + self.retry() + + self.info.pop('error', None) diff --git a/pyload/plugin/hoster/GooIm.py b/pyload/plugin/hoster/GooIm.py new file mode 100644 index 000000000..2090141ca --- /dev/null +++ b/pyload/plugin/hoster/GooIm.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# https://goo.im/devs/liquidsmooth/3.x/codina/Nightly/LS-KK-v3.2-2014-08-01-codina.zip + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class GooIm(SimpleHoster): + __name__ = "GooIm" + __type__ = "hoster" + __version__ = "0.04" + + __pattern__ = r'https?://(?:www\.)?goo\.im/.+' + + __description__ = """Goo.im hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] + + + NAME_PATTERN = r'You will be redirected to .*(?P<N>[^/ ]+) in' + OFFLINE_PATTERN = r'The file you requested was not found' + + + def setup(self): + self.resumeDownload = True + self.multiDL = True + + + def handleFree(self, pyfile): + self.wait(10) + self.download(pyfile.url, cookies=True) diff --git a/pyload/plugin/hoster/GoogledriveCom.py b/pyload/plugin/hoster/GoogledriveCom.py new file mode 100644 index 000000000..14a9d058d --- /dev/null +++ b/pyload/plugin/hoster/GoogledriveCom.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -* +# +# Test links: +# https://drive.google.com/file/d/0B6RNTe4ygItBQm15RnJiTmMyckU/view?pli=1 + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster +from pyload.utils import html_unescape + + +class GoogledriveCom(SimpleHoster): + __name__ = "GoogledriveCom" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'https?://(?:www\.)?drive\.google\.com/file/.+' + + __description__ = """Drive.google.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] + + + DISPOSITION = False + + NAME_PATTERN = r'"og:title" content="(?P<N>.*?)">' + OFFLINE_PATTERN = r'align="center"><p class="errorMessage"' + + + def setup(self): + self.multiDL = True + self.resumeDownload = True + self.chunkLimit = 1 + + + def handleFree(self, pyfile): + try: + link1 = re.search(r'"(https://docs.google.com/uc\?id.*?export=download)",', + self.html.decode('unicode-escape')).group(1) + + except AttributeError: + self.error(_("Hop #1 not found")) + + else: + self.logDebug("Next hop: %s" % link1) + + self.html = self.load(link1).decode('unicode-escape') + + try: + link2 = html_unescape(re.search(r'href="(/uc\?export=download.*?)">', + self.html).group(1)) + + except AttributeError: + self.error(_("Hop #2 not found")) + + else: + self.logDebug("Next hop: %s" % link2) + + link3 = self.load("https://docs.google.com" + link2, just_header=True) + self.logDebug("DL-Link: %s" % link3['location']) + + self.link = link3['location'] diff --git a/pyload/plugin/hoster/HellshareCz.py b/pyload/plugin/hoster/HellshareCz.py new file mode 100644 index 000000000..2caaeb143 --- /dev/null +++ b/pyload/plugin/hoster/HellshareCz.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +from urlparse import urljoin + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class HellshareCz(SimpleHoster): + __name__ = "HellshareCz" + __type__ = "hoster" + __version__ = "0.85" + + __pattern__ = r'http://(?:www\.)?hellshare\.(?:cz|com|sk|hu|pl)/[^?]*/\d+' + + __description__ = """Hellshare.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + CHECK_TRAFFIC = True + LOGIN_ACCOUNT = True + + NAME_PATTERN = r'<h1 id="filename"[^>]*>(?P<N>[^<]+)</h1>' + SIZE_PATTERN = r'<strong id="FileSize_master">(?P<S>[\d.,]+) (?P<U>[\w^_]+)</strong>' + OFFLINE_PATTERN = r'<h1>File not found.</h1>' + + LINK_FREE_PATTERN = LINK_PREMIUM_PATTERN = r'<a href="([^?]+/(\d+)/\?do=(fileDownloadButton|relatedFileDownloadButton-\2)-showDownloadWindow)"' + + + def setup(self): + self.resumeDownload = self.multiDL = bool(self.account) + self.chunkLimit = 1 diff --git a/pyload/plugin/hoster/HellspyCz.py b/pyload/plugin/hoster/HellspyCz.py new file mode 100644 index 000000000..049dd8df3 --- /dev/null +++ b/pyload/plugin/hoster/HellspyCz.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class HellspyCz(DeadHoster): + __name__ = "HellspyCz" + __type__ = "hoster" + __version__ = "0.28" + + __pattern__ = r'http://(?:www\.)?(?:hellspy\.(?:cz|com|sk|hu|pl)|sciagaj\.pl)(/\S+/\d+)' + + __description__ = """HellSpy.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/HotfileCom.py b/pyload/plugin/hoster/HotfileCom.py new file mode 100644 index 000000000..a9b1aa099 --- /dev/null +++ b/pyload/plugin/hoster/HotfileCom.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class HotfileCom(DeadHoster): + __name__ = "HotfileCom" + __type__ = "hoster" + __version__ = "0.37" + + __pattern__ = r'https?://(?:www\.)?hotfile\.com/dl/\d+/\w+' + + __description__ = """Hotfile.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("sitacuisses", "sitacuisses@yhoo.de"), + ("spoob", "spoob@pyload.org"), + ("mkaay", "mkaay@mkaay.de"), + ("JoKoT3", "jokot3@gmail.com")] diff --git a/pyload/plugin/hoster/HugefilesNet.py b/pyload/plugin/hoster/HugefilesNet.py new file mode 100644 index 000000000..413191c52 --- /dev/null +++ b/pyload/plugin/hoster/HugefilesNet.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class HugefilesNet(XFSHoster): + __name__ = "HugefilesNet" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'http://(?:www\.)?hugefiles\.net/\w{12}' + + __description__ = """Hugefiles.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + SIZE_PATTERN = r'File Size:</span>\s*<span[^>]*>(?P<S>[^<]+)</span></div>' + + FORM_INPUTS_MAP = {'ctype': re.compile(r'\d+')} diff --git a/pyload/plugin/hoster/HundredEightyUploadCom.py b/pyload/plugin/hoster/HundredEightyUploadCom.py new file mode 100644 index 000000000..14fe6db68 --- /dev/null +++ b/pyload/plugin/hoster/HundredEightyUploadCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class HundredEightyUploadCom(XFSHoster): + __name__ = "HundredEightyUploadCom" + __type__ = "hoster" + __version__ = "0.04" + + __pattern__ = r'http://(?:www\.)?180upload\.com/\w{12}' + + __description__ = """180upload.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] diff --git a/pyload/plugin/hoster/IFileWs.py b/pyload/plugin/hoster/IFileWs.py new file mode 100644 index 000000000..8effe015a --- /dev/null +++ b/pyload/plugin/hoster/IFileWs.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class IFileWs(DeadHoster): + __name__ = "IFileWs" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?ifile\.ws/\w{12}' + + __description__ = """Ifile.ws hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("z00nx", "z00nx0@gmail.com")] diff --git a/pyload/plugin/hoster/IcyFilesCom.py b/pyload/plugin/hoster/IcyFilesCom.py new file mode 100644 index 000000000..2a5b1d55a --- /dev/null +++ b/pyload/plugin/hoster/IcyFilesCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class IcyFilesCom(DeadHoster): + __name__ = "IcyFilesCom" + __type__ = "hoster" + __version__ = "0.06" + + __pattern__ = r'http://(?:www\.)?icyfiles\.com/(.+)' + + __description__ = """IcyFiles.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("godofdream", "soilfiction@gmail.com")] diff --git a/pyload/plugin/hoster/IfileIt.py b/pyload/plugin/hoster/IfileIt.py new file mode 100644 index 000000000..58e64aff1 --- /dev/null +++ b/pyload/plugin/hoster/IfileIt.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class IfileIt(DeadHoster): + __name__ = "IfileIt" + __type__ = "hoster" + __version__ = "0.29" + + __pattern__ = r'^unmatchable$' + + __description__ = """Ifile.it""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/IfolderRu.py b/pyload/plugin/hoster/IfolderRu.py new file mode 100644 index 000000000..b6e98674f --- /dev/null +++ b/pyload/plugin/hoster/IfolderRu.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class IfolderRu(SimpleHoster): + __name__ = "IfolderRu" + __type__ = "hoster" + __version__ = "0.39" + + __pattern__ = r'http://(?:www\.)?(?:ifolder\.ru|rusfolder\.(?:com|net|ru))/(?:files/)?(?P<ID>\d+)' + + __description__ = """Ifolder.ru hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + SIZE_REPLACEMENTS = [(u'Ðб', 'KB'), (u'Ðб', 'MB'), (u'Ðб', 'GB')] + + NAME_PATTERN = ur'(?:<div><span>)?ÐазваМОе:(?:</span>)? <b>(?P<N>[^<]+)</b><(?:/div|br)>' + SIZE_PATTERN = ur'(?:<div><span>)?РазЌеÑ:(?:</span>)? <b>(?P<S>[^<]+)</b><(?:/div|br)>' + OFFLINE_PATTERN = ur'<p>Ѐайл ÐœÐŸÐŒÐµÑ <b>[^<]*</b> (Ме МайЎеМ|ÑЎалеМ) !!!</p>' + + SESSION_ID_PATTERN = r'<a href=(http://ints\.(?:rusfolder\.com|ifolder\.ru)/ints/sponsor/\?bi=\d*&session=([^&]+)&u=[^>]+)>' + INTS_SESSION_PATTERN = r'\(\'ints_session\'\);\s*if\(tag\)\{tag\.value = "([^"]+)";\}' + HIDDEN_INPUT_PATTERN = r'var v = .*?name=\'(.+?)\' value=\'1\'' + + LINK_FREE_PATTERN = r'<a id="download_file_href" href="([^"]+)"' + + WRONG_CAPTCHA_PATTERN = ur'<font color=Red>МевеÑÐœÑй кПЎ,<br>ввеЎОÑе еÑе Ñаз</font><br>' + + + def setup(self): + self.resumeDownload = self.multiDL = bool(self.account) + self.chunkLimit = 1 + + + def handleFree(self, pyfile): + self.html = self.load("http://rusfolder.com/%s" % self.info['pattern']['ID'], cookies=True, decode=True) + self.getFileInfo() + + url = re.search(r"location\.href = '(http://ints\..*?=)'", self.html).group(1) + self.html = self.load(url, cookies=True, decode=True) + + url, session_id = re.search(self.SESSION_ID_PATTERN, self.html).groups() + self.html = self.load(url, cookies=True, decode=True) + + url = "http://ints.rusfolder.com/ints/frame/?session=%s" % session_id + self.html = self.load(url, cookies=True) + + self.wait(31, False) + + captcha_url = "http://ints.rusfolder.com/random/images/?session=%s" % session_id + for _i in xrange(5): + self.html = self.load(url, cookies=True) + action, inputs = self.parseHtmlForm('ID="Form1"') + inputs['ints_session'] = re.search(self.INTS_SESSION_PATTERN, self.html).group(1) + inputs[re.search(self.HIDDEN_INPUT_PATTERN, self.html).group(1)] = '1' + inputs['confirmed_number'] = self.decryptCaptcha(captcha_url, cookies=True) + inputs['action'] = '1' + self.logDebug(inputs) + + self.html = self.load(url, decode=True, cookies=True, post=inputs) + if self.WRONG_CAPTCHA_PATTERN in self.html: + self.invalidCaptcha() + else: + break + else: + self.fail(_("Invalid captcha")) + + self.link = re.search(self.LINK_PATTERN, self.html).group(1) diff --git a/pyload/plugin/hoster/JumbofilesCom.py b/pyload/plugin/hoster/JumbofilesCom.py new file mode 100644 index 000000000..fa2ffdbff --- /dev/null +++ b/pyload/plugin/hoster/JumbofilesCom.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class JumbofilesCom(SimpleHoster): + __name__ = "JumbofilesCom" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?jumbofiles\.com/(?P<ID>\w{12})' + + __description__ = """JumboFiles.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("godofdream", "soilfiction@gmail.com")] + + + INFO_PATTERN = r'<TR><TD>(?P<N>[^<]+?)\s*<small>\((?P<S>[\d.,]+)\s*(?P<U>[\w^_]+)' + OFFLINE_PATTERN = r'Not Found or Deleted / Disabled due to inactivity or DMCA' + LINK_FREE_PATTERN = r'<meta http-equiv="refresh" content="10;url=(.+)">' + + + def setup(self): + self.resumeDownload = True + self.multiDL = True + + + def handleFree(self, pyfile): + post_data = {"id": self.info['pattern']['ID'], "op": "download3", "rand": ""} + html = self.load(self.pyfile.url, post=post_data, decode=True) + self.link = re.search(self.LINK_FREE_PATTERN, html).group(1) diff --git a/pyload/plugin/hoster/JunocloudMe.py b/pyload/plugin/hoster/JunocloudMe.py new file mode 100644 index 000000000..4fc6457d7 --- /dev/null +++ b/pyload/plugin/hoster/JunocloudMe.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class JunocloudMe(XFSHoster): + __name__ = "JunocloudMe" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'http://(?:\w+\.)?junocloud\.me/\w{12}' + + __description__ = """Junocloud.me hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("guidobelix", "guidobelix@hotmail.it")] + + + URL_REPLACEMENTS = [(r'//(www\.)?junocloud', "//dl3.junocloud")] + + OFFLINE_PATTERN = r'>No such file with this filename<' + TEMP_OFFLINE_PATTERN = r'The page may have been renamed, removed or be temporarily unavailable.<' diff --git a/pyload/plugin/hoster/Keep2ShareCc.py b/pyload/plugin/hoster/Keep2ShareCc.py new file mode 100644 index 000000000..d655cf6ba --- /dev/null +++ b/pyload/plugin/hoster/Keep2ShareCc.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urljoin + +from pyload.plugin.internal.CaptchaService import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class Keep2ShareCc(SimpleHoster): + __name__ = "Keep2ShareCc" + __type__ = "hoster" + __version__ = "0.21" + + __pattern__ = r'https?://(?:www\.)?(keep2share|k2s|keep2s)\.cc/file/(?P<ID>\w+)' + + __description__ = """Keep2Share.cc hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + URL_REPLACEMENTS = [(__pattern__ + ".*", "http://k2s.cc/file/\g<ID>")] + + NAME_PATTERN = r'File: <span>(?P<N>.+)</span>' + SIZE_PATTERN = r'Size: (?P<S>[^<]+)</div>' + + OFFLINE_PATTERN = r'File not found or deleted|Sorry, this file is blocked or deleted|Error 404' + TEMP_OFFLINE_PATTERN = r'Downloading blocked due to' + + LINK_FREE_PATTERN = r'"([^"]+url.html?file=.+?)"|window\.location\.href = \'(.+?)\';' + LINK_PREMIUM_PATTERN = r'window\.location\.href = \'(.+?)\';' + + CAPTCHA_PATTERN = r'src="(/file/captcha\.html.+?)"' + + WAIT_PATTERN = r'Please wait ([\d:]+) to download this file' + TEMP_ERROR_PATTERN = r'>\s*(Download count files exceed|Traffic limit exceed|Free account does not allow to download more than one file at the same time)' + ERROR_PATTERN = r'>\s*(Free user can\'t download large files|You no can access to this file|This download available only for premium users|This is private file)' + + + def checkErrors(self): + m = re.search(self.TEMP_ERROR_PATTERN, self.html) + if m: + self.info['error'] = m.group(1) + self.wantReconnect = True + self.retry(wait_time=30 * 60, reason=m.group(0)) + + m = re.search(self.ERROR_PATTERN, self.html) + if m: + errmsg = self.info['error'] = m.group(1) + self.error(errmsg) + + m = re.search(self.WAIT_PATTERN, self.html) + if m: + self.logDebug("Hoster told us to wait for %s" % m.group(1)) + + # string to time convert courtesy of https://stackoverflow.com/questions/10663720 + ftr = [3600, 60, 1] + wait_time = sum(a * b for a, b in zip(ftr, map(int, m.group(1).split(':')))) + + self.wantReconnect = True + self.retry(wait_time=wait_time, reason="Please wait to download this file") + + self.info.pop('error', None) + + + def handleFree(self, pyfile): + self.fid = re.search(r'<input type="hidden" name="slow_id" value="([^"]+)">', self.html).group(1) + self.html = self.load(pyfile.url, post={'yt0': '', 'slow_id': self.fid}) + + self.checkErrors() + + m = re.search(self.LINK_FREE_PATTERN, self.html) + + if m is None: + self.handleCaptcha() + + self.wait(30) + + self.html = self.load(pyfile.url) + + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("Free download link not found")) + + self.link = m.group(1) + def handleCaptcha(self): + recaptcha = ReCaptcha(self) + post_data = {'free' : 1, + 'freeDownloadRequest': 1, + 'uniqueId' : self.fid, + 'yt0' : ''} + + m = re.search(self.CAPTCHA_PATTERN, self.html) + if m: + captcha_url = urljoin("http://k2s.cc/", m.group(1)) + post_data['CaptchaForm[code]'] = self.decryptCaptcha(captcha_url) + else: + response, challenge = recaptcha.challenge() + post_data.update({'recaptcha_challenge_field': challenge, + 'recaptcha_response_field' : response}) + + self.html = self.load(self.pyfile.url, post=post_data) + + if 'verification code is incorrect' not in self.html: + self.correctCaptcha() + else: + self.invalidCaptcha() diff --git a/pyload/plugin/hoster/KickloadCom.py b/pyload/plugin/hoster/KickloadCom.py new file mode 100644 index 000000000..5079570af --- /dev/null +++ b/pyload/plugin/hoster/KickloadCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class KickloadCom(DeadHoster): + __name__ = "KickloadCom" + __type__ = "hoster" + __version__ = "0.21" + + __pattern__ = r'http://(?:www\.)?kickload\.com/get/.+' + + __description__ = """Kickload.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("mkaay", "mkaay@mkaay.de")] diff --git a/pyload/plugin/hoster/KingfilesNet.py b/pyload/plugin/hoster/KingfilesNet.py new file mode 100644 index 000000000..ad856dfb6 --- /dev/null +++ b/pyload/plugin/hoster/KingfilesNet.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.captcha import SolveMedia +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class KingfilesNet(SimpleHoster): + __name__ = "KingfilesNet" + __type__ = "hoster" + __version__ = "0.07" + + __pattern__ = r'http://(?:www\.)?kingfiles\.net/(?P<ID>\w{12})' + + __description__ = """Kingfiles.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + NAME_PATTERN = r'name="fname" value="(?P<N>.+?)">' + SIZE_PATTERN = r'>Size: .+?">(?P<S>[\d.,]+) (?P<U>[\w^_]+)' + + OFFLINE_PATTERN = r'>(File Not Found</b><br><br>|File Not Found</h2>)' + + RAND_ID_PATTERN = r'type=\"hidden\" name=\"rand\" value=\"(.+)\">' + + LINK_FREE_PATTERN = r'var download_url = \'(.+)\';' + + + def setup(self): + self.resumeDownload = True + self.multiDL = True + + + def handleFree(self, pyfile): + # Click the free user button + post_data = {'op' : "download1", + 'usr_login' : "", + 'id' : self.info['pattern']['ID'], + 'fname' : pyfile.name, + 'referer' : "", + 'method_free': "+"} + + self.html = self.load(pyfile.url, post=post_data, cookies=True, decode=True) + + solvemedia = SolveMedia(self) + response, challenge = solvemedia.challenge() + + # Make the downloadlink appear and load the file + m = re.search(self.RAND_ID_PATTERN, self.html) + if m is None: + self.error(_("Random key not found")) + + rand = m.group(1) + self.logDebug("rand = ", rand) + + post_data = {'op' : "download2", + 'id' : self.info['pattern']['ID'], + 'rand' : rand, + 'referer' : pyfile.url, + 'method_free' : "+", + 'method_premium' : "", + 'adcopy_response' : response, + 'adcopy_challenge': challenge, + 'down_direct' : "1"} + + self.html = self.load(pyfile.url, post=post_data, cookies=True, decode=True) + + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("Download url not found")) + + self.link = m.group(1) diff --git a/pyload/plugin/hoster/LemUploadsCom.py b/pyload/plugin/hoster/LemUploadsCom.py new file mode 100644 index 000000000..deb0d374f --- /dev/null +++ b/pyload/plugin/hoster/LemUploadsCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class LemUploadsCom(DeadHoster): + __name__ = "LemUploadsCom" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'https?://(?:www\.)?lemuploads\.com/\w{12}' + + __description__ = """LemUploads.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("t4skforce", "t4skforce1337[AT]gmail[DOT]com")] diff --git a/pyload/plugin/hoster/LetitbitNet.py b/pyload/plugin/hoster/LetitbitNet.py new file mode 100644 index 000000000..dfdae5784 --- /dev/null +++ b/pyload/plugin/hoster/LetitbitNet.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +# +# API Documentation: +# http://api.letitbit.net/reg/static/api.pdf +# +# Test links: +# http://letitbit.net/download/07874.0b5709a7d3beee2408bb1f2eefce/random.bin.html + +import re + +from urlparse import urljoin + +from pyload.utils import json_loads, json_dumps +from pyload.network.RequestFactory import getURL +from pyload.plugin.internal.CaptchaService import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster, secondsToMidnight + + +def api_response(url): + json_data = ["yw7XQy2v9", ["download/info", {"link": url}]] + api_rep = getURL("http://api.letitbit.net/json", + post={'r': json_dumps(json_data)}) + return json_loads(api_rep) + + +def getInfo(urls): + for url in urls: + api_rep = api_response(url) + if api_rep['status'] == 'OK': + info = api_rep['data'][0] + yield (info['name'], info['size'], 2, url) + else: + yield (url, 0, 1, url) + + +class LetitbitNet(SimpleHoster): + __name__ = "LetitbitNet" + __type__ = "hoster" + __version__ = "0.30" + + __pattern__ = r'https?://(?:www\.)?(letitbit|shareflare)\.net/download/.+' + + __description__ = """Letitbit.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), + ("z00nx", "z00nx0@gmail.com")] + + + URL_REPLACEMENTS = [(r"(?<=http://)([^/]+)", "letitbit.net")] + + SECONDS_PATTERN = r'seconds\s*=\s*(\d+);' + CAPTCHA_CONTROL_FIELD = r'recaptcha_control_field\s=\s\'(.+?)\'' + + + def setup(self): + self.resumeDownload = True + + + def getFileInfo(self): + api_rep = api_response(self.pyfile.url) + if api_rep['status'] == 'OK': + self.api_data = api_rep['data'][0] + self.pyfile.name = self.api_data['name'] + self.pyfile.size = self.api_data['size'] + else: + self.offline() + + + def handleFree(self, pyfile): + action, inputs = self.parseHtmlForm('id="ifree_form"') + if not action: + self.error(_("ifree_form")) + + pyfile.size = float(inputs['sssize']) + self.logDebug(action, inputs) + inputs['desc'] = "" + + self.html = self.load(urljoin("http://letitbit.net/", action), post=inputs, cookies=True) + + m = re.search(self.SECONDS_PATTERN, self.html) + seconds = int(m.group(1)) if m else 60 + + self.logDebug("Seconds found", seconds) + + m = re.search(self.CAPTCHA_CONTROL_FIELD, self.html) + recaptcha_control_field = m.group(1) + + self.logDebug("ReCaptcha control field found", recaptcha_control_field) + + self.wait(seconds) + + res = self.load("http://letitbit.net/ajax/download3.php", post=" ", cookies=True) + if res != '1': + self.error(_("Unknown response - ajax_check_url")) + + self.logDebug(res) + + recaptcha = ReCaptcha(self) + response, challenge = recaptcha.challenge() + + post_data = {"recaptcha_challenge_field": challenge, + "recaptcha_response_field": response, + "recaptcha_control_field": recaptcha_control_field} + + self.logDebug("Post data to send", post_data) + + res = self.load("http://letitbit.net/ajax/check_recaptcha.php", post=post_data, cookies=True) + + self.logDebug(res) + + if not res: + self.invalidCaptcha() + + if res == "error_free_download_blocked": + self.logWarning(_("Daily limit reached")) + self.wait(secondsToMidnight(gmt=2), True) + + if res == "error_wrong_captcha": + self.invalidCaptcha() + self.retry() + + elif res.startswith('['): + urls = json_loads(res) + + elif res.startswith('http://'): + urls = [res] + + else: + self.error(_("Unknown response - captcha check")) + + self.correctCaptcha() + + for download_url in urls: + try: + self.download(download_url) + break + except Exception, e: + self.logError(e) + else: + self.fail(_("Download did not finish correctly")) + + + def handlePremium(self, pyfile): + api_key = self.user + premium_key = self.account.getAccountData(self.user)['password'] + + json_data = [api_key, ["download/direct_links", {"pass": premium_key, "link": pyfile.url}]] + api_rep = self.load('http://api.letitbit.net/json', post={'r': json_dumps(json_data)}) + self.logDebug("API Data: " + api_rep) + api_rep = json_loads(api_rep) + + if api_rep['status'] == 'FAIL': + self.fail(api_rep['data']) + + self.link = api_rep['data'][0][0] diff --git a/pyload/plugin/hoster/LinksnappyCom.py b/pyload/plugin/hoster/LinksnappyCom.py new file mode 100644 index 000000000..fe3104579 --- /dev/null +++ b/pyload/plugin/hoster/LinksnappyCom.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urlsplit + +from pyload.utils import json_loads, json_dumps +from pyload.plugin.internal.MultiHoster import MultiHoster + + +class LinksnappyCom(MultiHoster): + __name__ = "LinksnappyCom" + __type__ = "hoster" + __version__ = "0.08" + + __pattern__ = r'https?://(?:[^/]+\.)?linksnappy\.com' + + __description__ = """Linksnappy.com multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + SINGLE_CHUNK_HOSTERS = ["easybytez.com"] + + + def handlePremium(self, pyfile): + host = self._get_host(pyfile.url) + json_params = json_dumps({'link' : pyfile.url, + 'type' : host, + 'username': self.user, + 'password': self.account.getAccountData(self.user)['password']}) + + r = self.load("http://gen.linksnappy.com/genAPI.php", + post={'genLinks': json_params}) + + self.logDebug("JSON data: " + r) + + j = json_loads(r)['links'][0] + + if j['error']: + self.error(_("Error converting the link")) + + pyfile.name = j['filename'] + self.link = j['generated'] + + if host in self.SINGLE_CHUNK_HOSTERS: + self.chunkLimit = 1 + else: + self.setup() + + + @staticmethod + def _get_host(url): + host = urlsplit(url).netloc + return re.search(r'[\w-]+\.\w+$', host).group(0) diff --git a/pyload/plugin/hoster/LoadTo.py b/pyload/plugin/hoster/LoadTo.py new file mode 100644 index 000000000..42d76b4fa --- /dev/null +++ b/pyload/plugin/hoster/LoadTo.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# http://www.load.to/JWydcofUY6/random.bin +# http://www.load.to/oeSmrfkXE/random100.bin + +import re + +from pyload.plugin.internal.captcha import SolveMedia +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class LoadTo(SimpleHoster): + __name__ = "LoadTo" + __type__ = "hoster" + __version__ = "0.22" + + __pattern__ = r'http://(?:www\.)?load\.to/\w+' + + __description__ = """Load.to hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("halfman", "Pulpan3@gmail.com"), + ("stickell", "l.stickell@yahoo.it")] + + + NAME_PATTERN = r'<h1>(?P<N>.+)</h1>' + SIZE_PATTERN = r'Size: (?P<S>[\d.,]+) (?P<U>[\w^_]+)' + OFFLINE_PATTERN = r'>Can\'t find file' + + LINK_FREE_PATTERN = r'<form method="post" action="(.+?)"' + WAIT_PATTERN = r'type="submit" value="Download \((\d+)\)"' + + URL_REPLACEMENTS = [(r'(\w)$', r'\1/')] + + + def setup(self): + self.multiDL = True + self.chunkLimit = 1 + + + def handleFree(self, pyfile): + # Search for Download URL + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("LINK_FREE_PATTERN not found")) + + download_url = m.group(1) + + # Set Timer - may be obsolete + m = re.search(self.WAIT_PATTERN, self.html) + if m: + self.wait(m.group(1)) + + # Load.to is using solvemedia captchas since ~july 2014: + solvemedia = SolveMedia(self) + captcha_key = solvemedia.detect_key() + + if captcha_key is None: + self.download(download_url) + else: + response, challenge = solvemedia.challenge(captcha_key) + self.download(download_url, + post={'adcopy_challenge': challenge, + 'adcopy_response' : response, + 'returnUrl' : pyfile.url}) diff --git a/pyload/plugin/hoster/LomafileCom.py b/pyload/plugin/hoster/LomafileCom.py new file mode 100644 index 000000000..18f315bd6 --- /dev/null +++ b/pyload/plugin/hoster/LomafileCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class LomafileCom(DeadHoster): + __name__ = "LomafileCom" + __type__ = "hoster" + __version__ = "0.52" + + __pattern__ = r'http://lomafile\.com/\w{12}' + + __description__ = """Lomafile.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("nath_schwarz", "nathan.notwhite@gmail.com"), + ("guidobelix", "guidobelix@hotmail.it")] diff --git a/pyload/plugin/hoster/LuckyShareNet.py b/pyload/plugin/hoster/LuckyShareNet.py new file mode 100644 index 000000000..d9cc5fe88 --- /dev/null +++ b/pyload/plugin/hoster/LuckyShareNet.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- + +import re + +from bottle import json_loads + +from pyload.plugin.internal.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class LuckyShareNet(SimpleHoster): + __name__ = "LuckyShareNet" + __type__ = "hoster" + __version__ = "0.06" + + __pattern__ = r'https?://(?:www\.)?luckyshare\.net/(?P<ID>\d{10,})' + + __description__ = """LuckyShare.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + INFO_PATTERN = r'<h1 class=\'file_name\'>(?P<N>\S+)</h1>\s*<span class=\'file_size\'>Filesize: (?P<S>[\d.,]+)(?P<U>[\w^_]+)</span>' + OFFLINE_PATTERN = r'There is no such file available' + + + def parseJson(self, rep): + if 'AJAX Error' in rep: + html = self.load(self.pyfile.url, decode=True) + m = re.search(r"waitingtime = (\d+);", html) + if m: + seconds = int(m.group(1)) + self.logDebug("You have to wait %d seconds between free downloads" % seconds) + self.retry(wait_time=seconds) + else: + self.error(_("Unable to detect wait time between free downloads")) + elif 'Hash expired' in rep: + self.retry(reason=_("Hash expired")) + return json_loads(rep) + + + # TODO: There should be a filesize limit for free downloads + # TODO: Some files could not be downloaded in free mode + def handleFree(self, pyfile): + rep = self.load(r"http://luckyshare.net/download/request/type/time/file/" + self.info['pattern']['ID'], decode=True) + + self.logDebug("JSON: " + rep) + + json = self.parseJson(rep) + self.wait(json['time']) + + recaptcha = ReCaptcha(self) + + for _i in xrange(5): + response, challenge = recaptcha.challenge() + rep = self.load(r"http://luckyshare.net/download/verify/challenge/%s/response/%s/hash/%s" % + (challenge, response, json['hash']), decode=True) + self.logDebug("JSON: " + rep) + if 'link' in rep: + json.update(self.parseJson(rep)) + self.correctCaptcha() + break + elif 'Verification failed' in rep: + self.invalidCaptcha() + else: + self.error(_("Unable to get downlaod link")) + + if not json['link']: + self.fail(_("No Download url retrieved/all captcha attempts failed")) + + self.download(json['link']) diff --git a/module/plugins/hoster/MediafireCom.py b/pyload/plugin/hoster/MediafireCom.py index 5adf004d0..5adf004d0 100644 --- a/module/plugins/hoster/MediafireCom.py +++ b/pyload/plugin/hoster/MediafireCom.py diff --git a/pyload/plugin/hoster/MegaCoNz.py b/pyload/plugin/hoster/MegaCoNz.py new file mode 100644 index 000000000..9648e8316 --- /dev/null +++ b/pyload/plugin/hoster/MegaCoNz.py @@ -0,0 +1,217 @@ +# -*- coding: utf-8 -*- + +import os +import random +import re + +from array import array +from base64 import standard_b64decode + +from Crypto.Cipher import AES +from Crypto.Util import Counter +# from pycurl import SSL_CIPHER_LIST + +from pyload.utils import json_loads, json_dumps +from pyload.plugin.Hoster import Hoster +from pyload.utils import decode, fs_decode, fs_encode + + +############################ General errors ################################### +# EINTERNAL (-1): An internal error has occurred. Please submit a bug report, detailing the exact circumstances in which this error occurred +# EARGS (-2): You have passed invalid arguments to this command +# EAGAIN (-3): (always at the request level) A temporary congestion or server malfunction prevented your request from being processed. No data was altered. Retry. Retries must be spaced with exponential backoff +# ERATELIMIT (-4): You have exceeded your command weight per time quota. Please wait a few seconds, then try again (this should never happen in sane real-life applications) +# +############################ Upload errors #################################### +# EFAILED (-5): The upload failed. Please restart it from scratch +# ETOOMANY (-6): Too many concurrent IP addresses are accessing this upload target URL +# ERANGE (-7): The upload file packet is out of range or not starting and ending on a chunk boundary +# EEXPIRED (-8): The upload target URL you are trying to access has expired. Please request a fresh one +# +############################ Stream/System errors ############################# +# ENOENT (-9): Object (typically, node or user) not found +# ECIRCULAR (-10): Circular linkage attempted +# EACCESS (-11): Access violation (e.g., trying to write to a read-only share) +# EEXIST (-12): Trying to create an object that already exists +# EINCOMPLETE (-13): Trying to access an incomplete resource +# EKEY (-14): A decryption operation failed (never returned by the API) +# ESID (-15): Invalid or expired user session, please relogin +# EBLOCKED (-16): User blocked +# EOVERQUOTA (-17): Request over quota +# ETEMPUNAVAIL (-18): Resource temporarily not available, please try again later +# ETOOMANYCONNECTIONS (-19): Too many connections on this resource +# EWRITE (-20): Write failed +# EREAD (-21): Read failed +# EAPPKEY (-22): Invalid application key; request not processed + + +class MegaCoNz(Hoster): + __name__ = "MegaCoNz" + __type__ = "hoster" + __version__ = "0.26" + + __pattern__ = r'(?:https?://(?:www\.)?mega\.co\.nz/|mega:|chrome:.+?)#(?P<TYPE>N|)!(?P<ID>[\w^_]+)!(?P<KEY>[\w,\\-]+)' + + __description__ = """Mega.co.nz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "ranan@pyload.org"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + API_URL = "https://eu.api.mega.co.nz/cs" + FILE_SUFFIX = ".crypted" + + + def b64_decode(self, data): + data = data.replace("-", "+").replace("_", "/") + return standard_b64decode(data + '=' * (-len(data) % 4)) + + + def getCipherKey(self, key): + """ Construct the cipher key from the given data """ + a = array("I", self.b64_decode(key)) + + k = array("I", (a[0] ^ a[4], a[1] ^ a[5], a[2] ^ a[6], a[3] ^ a[7])) + iv = a[4:6] + array("I", (0, 0)) + meta_mac = a[6:8] + + return k, iv, meta_mac + + + def api_response(self, **kwargs): + """ Dispatch a call to the api, see https://mega.co.nz/#developers """ + + # generate a session id, no idea where to obtain elsewhere + uid = random.randint(10 << 9, 10 ** 10) + + res = self.load(self.API_URL, get={'id': uid}, post=json_dumps([kwargs])) + self.logDebug("Api Response: " + res) + return json_loads(res) + + + def decryptAttr(self, data, key): + k, iv, meta_mac = self.getCipherKey(key) + cbc = AES.new(k, AES.MODE_CBC, "\0" * 16) + attr = decode(cbc.decrypt(self.b64_decode(data))) + + self.logDebug("Decrypted Attr: %s" % attr) + if not attr.startswith("MEGA"): + self.fail(_("Decryption failed")) + + # Data is padded, 0-bytes must be stripped + return json_loads(re.search(r'{.+?}', attr).group(0)) + + + def decryptFile(self, key): + """ Decrypts the file at lastDownload` """ + + # upper 64 bit of counter start + n = self.b64_decode(key)[16:24] + + # convert counter to long and shift bytes + k, iv, meta_mac = self.getCipherKey(key) + ctr = Counter.new(128, initial_value=long(n.encode("hex"), 16) << 64) + cipher = AES.new(k, AES.MODE_CTR, counter=ctr) + + self.pyfile.setStatus("decrypting") + self.pyfile.setProgress(0) + + file_crypted = fs_encode(self.lastDownload) + file_decrypted = file_crypted.rsplit(self.FILE_SUFFIX)[0] + + try: + f = open(file_crypted, "rb") + df = open(file_decrypted, "wb") + + except IOError, e: + self.fail(e) + + chunk_size = 2 ** 15 # buffer size, 32k + # file_mac = [0, 0, 0, 0] # calculate CBC-MAC for checksum + + chunks = os.path.getsize(file_crypted) / chunk_size + 1 + for i in xrange(chunks): + buf = f.read(chunk_size) + if not buf: + break + + chunk = cipher.decrypt(buf) + df.write(chunk) + + self.pyfile.setProgress(int((100.0 / chunks) * i)) + + # chunk_mac = [iv[0], iv[1], iv[0], iv[1]] + # for i in xrange(0, chunk_size, 16): + # block = chunk[i:i+16] + # if len(block) % 16: + # block += '=' * (16 - (len(block) % 16)) + # block = array("I", block) + + # chunk_mac = [chunk_mac[0] ^ a_[0], chunk_mac[1] ^ block[1], chunk_mac[2] ^ block[2], chunk_mac[3] ^ block[3]] + # chunk_mac = aes_cbc_encrypt_a32(chunk_mac, k) + + # file_mac = [file_mac[0] ^ chunk_mac[0], file_mac[1] ^ chunk_mac[1], file_mac[2] ^ chunk_mac[2], file_mac[3] ^ chunk_mac[3]] + # file_mac = aes_cbc_encrypt_a32(file_mac, k) + + self.pyfile.setProgress(100) + + f.close() + df.close() + + # if file_mac[0] ^ file_mac[1], file_mac[2] ^ file_mac[3] != meta_mac: + # os.remove(file_decrypted) + # self.fail(_("Checksum mismatch")) + + os.remove(file_crypted) + self.lastDownload = fs_decode(file_decrypted) + + + def checkError(self, code): + ecode = abs(code) + + if ecode in (9, 16, 21): + self.offline() + + elif ecode in (3, 13, 17, 18, 19): + self.tempOffline() + + elif ecode in (1, 4, 6, 10, 15, 21): + self.retry(5, 30, _("Error code: [%s]") % -ecode) + + else: + self.fail(_("Error code: [%s]") % -ecode) + + + def process(self, pyfile): + pattern = re.match(self.__pattern__, pyfile.url).groupdict() + id = pattern['ID'] + key = pattern['KEY'] + public = pattern['TYPE'] == '' + + self.logDebug("ID: %s" % id, "Key: %s" % key, "Type: %s" % ("public" if public else "node")) + + # g is for requesting a download url + # this is similar to the calls in the mega js app, documentation is very bad + if public: + mega = self.api_response(a="g", g=1, p=id, ssl=1)[0] + else: + mega = self.api_response(a="g", g=1, n=id, ssl=1)[0] + + if isinstance(mega, int): + self.checkError(mega) + elif "e" in mega: + self.checkError(mega['e']) + + attr = self.decryptAttr(mega['at'], key) + + pyfile.name = attr['n'] + self.FILE_SUFFIX + pyfile.size = mega['s'] + + # self.req.http.c.setopt(SSL_CIPHER_LIST, "RC4-MD5:DEFAULT") + + self.download(mega['g']) + + self.decryptFile(key) + + # Everything is finished and final name can be set + pyfile.name = attr['n'] diff --git a/pyload/plugin/hoster/MegaDebridEu.py b/pyload/plugin/hoster/MegaDebridEu.py new file mode 100644 index 000000000..842ad4de9 --- /dev/null +++ b/pyload/plugin/hoster/MegaDebridEu.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- + +import re + +from urllib import unquote_plus + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHoster import MultiHoster + + +class MegaDebridEu(MultiHoster): + __name__ = "MegaDebridEu" + __type__ = "hoster" + __version__ = "0.46" + + __pattern__ = r'http://((?:www\d+\.|s\d+\.)?mega-debrid\.eu|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/download/file/[\w^_]+' + + __description__ = """mega-debrid.eu multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("D.Ducatel", "dducatel@je-geek.fr")] + + + API_URL = "https://www.mega-debrid.eu/api.php" + + + def getFilename(self, url): + try: + return unquote_plus(url.rsplit("/", 1)[1]) + except IndexError: + return "" + + + def handlePremium(self, pyfile): + if not self.api_load(): + self.exitOnFail("Unable to connect to Mega-debrid.eu") + + self.link = self.debridLink(pyfile.url) + + filename = self.getFilename(self.link) + if filename: + pyfile.name = filename + + + def api_load(self): + """ + Connexion to the mega-debrid API + Return True if succeed + """ + user, data = self.account.selectAccount() + jsonResponse = self.load(self.API_URL, + get={'action': 'connectUser', 'login': user, 'password': data['password']}) + res = json_loads(jsonResponse) + + if res['response_code'] == "ok": + self.token = res['token'] + return True + else: + return False + + + def debridLink(self, linkToDebrid): + """ + Debrid a link + Return The debrided link if succeed or original link if fail + """ + jsonResponse = self.load(self.API_URL, get={'action': 'getLink', 'token': self.token}, + post={"link": linkToDebrid}) + res = json_loads(jsonResponse) + + if res['response_code'] == "ok": + debridedLink = res['debridLink'][1:-1] + return debridedLink + else: + self.exitOnFail("Unable to debrid %s" % linkToDebrid) + + + def exitOnFail(self, msg): + """ + exit the plugin on fail case + And display the reason of this failure + """ + if self.getConfig("unloadFailing"): + self.logError(_(msg)) + self.resetAccount() + else: + self.fail(_(msg)) diff --git a/pyload/plugin/hoster/MegaFilesSe.py b/pyload/plugin/hoster/MegaFilesSe.py new file mode 100644 index 000000000..3cfd41da4 --- /dev/null +++ b/pyload/plugin/hoster/MegaFilesSe.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class MegaFilesSe(DeadHoster): + __name__ = "MegaFilesSe" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?megafiles\.se/\w{12}' + + __description__ = """MegaFiles.se hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("t4skforce", "t4skforce1337[AT]gmail[DOT]com")] diff --git a/pyload/plugin/hoster/MegaRapidCz.py b/pyload/plugin/hoster/MegaRapidCz.py new file mode 100644 index 000000000..b7b9e3ffe --- /dev/null +++ b/pyload/plugin/hoster/MegaRapidCz.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- + +import re + +from pycurl import HTTPHEADER + +from pyload.network.HTTPRequest import BadHeader +from pyload.network.RequestFactory import getRequest +from pyload.plugin.internal.SimpleHoster import SimpleHoster, parseFileInfo + + +def getInfo(urls): + h = getRequest() + h.c.setopt(HTTPHEADER, + ["Accept: text/html", + "User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0"]) + + for url in urls: + html = h.load(url, decode=True) + yield parseFileInfo(MegaRapidCz, url, html) + + +class MegaRapidCz(SimpleHoster): + __name__ = "MegaRapidCz" + __type__ = "hoster" + __version__ = "0.56" + + __pattern__ = r'http://(?:www\.)?(share|mega)rapid\.cz/soubor/\d+/.+' + + __description__ = """MegaRapid.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("MikyWoW", "mikywow@seznam.cz"), + ("zoidberg", "zoidberg@mujmail.cz"), + ("stickell", "l.stickell@yahoo.it"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + NAME_PATTERN = r'<h1[^>]*><span[^>]*>(?:<a[^>]*>)?(?P<N>[^<]+)' + SIZE_PATTERN = r'<td class="i">Velikost:</td>\s*<td class="h"><strong>\s*(?P<S>[\d.,]+) (?P<U>[\w^_]+)</strong></td>' + OFFLINE_PATTERN = ur'Nastala chyba 404|Soubor byl smazán' + + CHECK_TRAFFIC = True + + LINK_PREMIUM_PATTERN = r'<a href="([^"]+)" title="Stahnout">([^<]+)</a>' + + ERR_LOGIN_PATTERN = ur'<div class="error_div"><strong>Stahovánà je pÅÃstupné pouze pÅihlášenÃœm uÅŸivatelům' + ERR_CREDIT_PATTERN = ur'<div class="error_div"><strong>Stahovánà zdarma je moÅŸné jen pÅes náš' + + + def setup(self): + self.chunkLimit = 1 + + + def handlePremium(self, pyfile): + m = re.search(self.LINK_PREMIUM_PATTERN, self.html) + if m: + self.link = m.group(1) + else: + if re.search(self.ERR_LOGIN_PATTERN, self.html): + self.relogin(self.user) + self.retry(wait_time=60, reason=_("User login failed")) + elif re.search(self.ERR_CREDIT_PATTERN, self.html): + self.fail(_("Not enough credit left")) + else: + self.fail(_("Download link not found")) diff --git a/module/plugins/hoster/MegacrypterCom.py b/pyload/plugin/hoster/MegacrypterCom.py index f8fcb97fe..f8fcb97fe 100644 --- a/module/plugins/hoster/MegacrypterCom.py +++ b/pyload/plugin/hoster/MegacrypterCom.py diff --git a/pyload/plugin/hoster/MegareleaseOrg.py b/pyload/plugin/hoster/MegareleaseOrg.py new file mode 100644 index 000000000..c2c7fe357 --- /dev/null +++ b/pyload/plugin/hoster/MegareleaseOrg.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class MegareleaseOrg(DeadHoster): + __name__ = "MegareleaseOrg" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'https?://(?:www\.)?megarelease\.org/\w{12}' + + __description__ = """Megarelease.org hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("derek3x", "derek3x@vmail.me"), + ("stickell", "l.stickell@yahoo.it")] diff --git a/pyload/plugin/hoster/MegasharesCom.py b/pyload/plugin/hoster/MegasharesCom.py new file mode 100644 index 000000000..483969e2e --- /dev/null +++ b/pyload/plugin/hoster/MegasharesCom.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- + +import re + +from time import time + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class MegasharesCom(SimpleHoster): + __name__ = "MegasharesCom" + __type__ = "hoster" + __version__ = "0.28" + + __pattern__ = r'http://(?:www\.)?(d\d{2}\.)?megashares\.com/((index\.php)?\?d\d{2}=|dl/)\w+' + + __description__ = """Megashares.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + NAME_PATTERN = r'<h1 class="black xxl"[^>]*title="(?P<N>[^"]+)">' + SIZE_PATTERN = r'<strong><span class="black">Filesize:</span></strong> (?P<S>[\d.,]+) (?P<U>[\w^_]+)' + OFFLINE_PATTERN = r'<dd class="red">(Invalid Link Request|Link has been deleted|Invalid link)' + + LINK_PATTERN = r'<div id="show_download_button_%d"[^>]*>\s*<a href="([^"]+)">' + + PASSPORT_LEFT_PATTERN = r'Your Download Passport is: <[^>]*>(\w+).*?You have.*?<[^>]*>.*?([\d.]+) (\w+)' + PASSPORT_RENEW_PATTERN = r'(\d+):<strong>(\d+)</strong>:<strong>(\d+)</strong>' + REACTIVATE_NUM_PATTERN = r'<input[^>]*id="random_num" value="(\d+)" />' + REACTIVATE_PASSPORT_PATTERN = r'<input[^>]*id="passport_num" value="(\w+)" />' + REQUEST_URI_PATTERN = r'var request_uri = "([^"]+)";' + NO_SLOTS_PATTERN = r'<dd class="red">All download slots for this link are currently filled' + + + def setup(self): + self.resumeDownload = True + self.multiDL = self.premium + + + def handlePremium(self, pyfile): + self.handleDownload(True) + + + def handleFree(self, pyfile): + if self.NO_SLOTS_PATTERN in self.html: + self.retry(wait_time=5 * 60) + + m = re.search(self.REACTIVATE_PASSPORT_PATTERN, self.html) + if m: + passport_num = m.group(1) + request_uri = re.search(self.REQUEST_URI_PATTERN, self.html).group(1) + + for _i in xrange(5): + random_num = re.search(self.REACTIVATE_NUM_PATTERN, self.html).group(1) + + verifyinput = self.decryptCaptcha("http://d01.megashares.com/index.php", + get={'secgfx': "gfx", 'random_num': random_num}) + + self.logInfo(_("Reactivating passport %s: %s %s") % (passport_num, random_num, verifyinput)) + + res = self.load("http://d01.megashares.com%s" % request_uri, + get={'rs' : "check_passport_renewal", + 'rsargs[]': verifyinput, + 'rsargs[]': random_num, + 'rsargs[]': passport_num, + 'rsargs[]': "replace_sec_pprenewal", + 'rsrnd[]' : str(int(time() * 1000))}) + + if 'Thank you for reactivating your passport.' in res: + self.correctCaptcha() + self.retry() + else: + self.invalidCaptcha() + else: + self.fail(_("Failed to reactivate passport")) + + m = re.search(self.PASSPORT_RENEW_PATTERN, self.html) + if m: + time = [int(x) for x in m.groups()] + renew = time[0] + (time[1] * 60) + (time[2] * 60) + self.logDebug("Waiting %d seconds for a new passport" % renew) + self.retry(wait_time=renew, reason=_("Passport renewal")) + + # Check traffic left on passport + m = re.search(self.PASSPORT_LEFT_PATTERN, self.html, re.M | re.S) + if m is None: + self.fail(_("Passport not found")) + + self.logInfo(_("Download passport: %s") % m.group(1)) + data_left = float(m.group(2)) * 1024 ** {'B': 0, 'KB': 1, 'MB': 2, 'GB': 3}[m.group(3)] + self.logInfo(_("Data left: %s %s (%d MB needed)") % (m.group(2), m.group(3), self.pyfile.size / 1048576)) + + if not data_left: + self.retry(wait_time=600, reason=_("Passport renewal")) + + self.handleDownload(False) + + + def handleDownload(self, premium=False): + # Find download link; + m = re.search(self.LINK_PATTERN % (1 if premium else 2), self.html) + msg = _('%s download URL' % ('Premium' if premium else 'Free')) + if m is None: + self.error(msg) + + download_url = m.group(1) + self.logDebug("%s: %s" % (msg, download_url)) + self.download(download_url) diff --git a/pyload/plugin/hoster/MegauploadCom.py b/pyload/plugin/hoster/MegauploadCom.py new file mode 100644 index 000000000..c1d5b4524 --- /dev/null +++ b/pyload/plugin/hoster/MegauploadCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class MegauploadCom(DeadHoster): + __name__ = "MegauploadCom" + __type__ = "hoster" + __version__ = "0.31" + + __pattern__ = r'http://(?:www\.)?megaupload\.com/\?.*&?(d|v)=\w+' + + __description__ = """Megaupload.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("spoob", "spoob@pyload.org")] diff --git a/pyload/plugin/hoster/MegavideoCom.py b/pyload/plugin/hoster/MegavideoCom.py new file mode 100644 index 000000000..442b0f292 --- /dev/null +++ b/pyload/plugin/hoster/MegavideoCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class MegavideoCom(DeadHoster): + __name__ = "MegavideoCom" + __type__ = "hoster" + __version__ = "0.21" + + __pattern__ = r'http://(?:www\.)?megavideo\.com/\?.*&?(d|v)=\w+' + + __description__ = """Megavideo.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("jeix", "jeix@hasnomail.de"), + ("mkaay", "mkaay@mkaay.de")] diff --git a/pyload/plugin/hoster/MovReelCom.py b/pyload/plugin/hoster/MovReelCom.py new file mode 100644 index 000000000..f273d623a --- /dev/null +++ b/pyload/plugin/hoster/MovReelCom.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class MovReelCom(XFSHoster): + __name__ = "MovReelCom" + __type__ = "hoster" + __version__ = "1.24" + + __pattern__ = r'http://(?:www\.)?movreel\.com/\w{12}' + + __description__ = """MovReel.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("JorisV83", "jorisv83-pyload@yahoo.com")] + + + LINK_PATTERN = r'<a href="([^"]+)">Download Link' diff --git a/pyload/plugin/hoster/MultihostersCom.py b/pyload/plugin/hoster/MultihostersCom.py new file mode 100644 index 000000000..3c9e81242 --- /dev/null +++ b/pyload/plugin/hoster/MultihostersCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.hoster.ZeveraCom import ZeveraCom + + +class MultihostersCom(ZeveraCom): + __name__ = "MultihostersCom" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'https?://(?:www\.)multihosters\.com/(getFiles\.ashx|Members/download\.ashx)\?.*ourl=.+' + + __description__ = """Multihosters.com multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("tjeh", "tjeh@gmx.net")] diff --git a/pyload/plugin/hoster/MultishareCz.py b/pyload/plugin/hoster/MultishareCz.py new file mode 100644 index 000000000..252e9cdb5 --- /dev/null +++ b/pyload/plugin/hoster/MultishareCz.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +import re + +from random import random + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class MultishareCz(SimpleHoster): + __name__ = "MultishareCz" + __type__ = "hoster" + __version__ = "0.40" + + __pattern__ = r'http://(?:www\.)?multishare\.cz/stahnout/(?P<ID>\d+)' + + __description__ = """MultiShare.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + SIZE_REPLACEMENTS = [(' ', '')] + + CHECK_TRAFFIC = True + MULTI_HOSTER = True + + INFO_PATTERN = ur'(?:<li>Název|Soubor): <strong>(?P<N>[^<]+)</strong><(?:/li><li|br)>Velikost: <strong>(?P<S>[^<]+)</strong>' + OFFLINE_PATTERN = ur'<h1>Stáhnout soubor</h1><p><strong>PoÅŸadovanÃœ soubor neexistuje.</strong></p>' + + + def handleFree(self, pyfile): + self.download("http://www.multishare.cz/html/download_free.php", get={'ID': self.info['pattern']['ID']}) + + + def handlePremium(self, pyfile): + self.download("http://www.multishare.cz/html/download_premium.php", get={'ID': self.info['pattern']['ID']}) + + + def handleMulti(self, pyfile): + self.html = self.load('http://www.multishare.cz/html/mms_ajax.php', post={"link": pyfile.url}, decode=True) + + self.checkInfo() + + if not self.checkTrafficLeft(): + self.fail(_("Not enough credit left to download file")) + + self.download("http://dl%d.mms.multishare.cz/html/mms_process.php" % round(random() * 10000 * random()), + get={'u_ID' : self.acc_info['u_ID'], + 'u_hash': self.acc_info['u_hash'], + 'link' : pyfile.url}, + disposition=True) diff --git a/pyload/plugin/hoster/MyfastfileCom.py b/pyload/plugin/hoster/MyfastfileCom.py new file mode 100644 index 000000000..c065c2331 --- /dev/null +++ b/pyload/plugin/hoster/MyfastfileCom.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHoster import MultiHoster + + +class MyfastfileCom(MultiHoster): + __name__ = "MyfastfileCom" + __type__ = "hoster" + __version__ = "0.08" + + __pattern__ = r'http://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/dl/' + + __description__ = """Myfastfile.com multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + + def setup(self): + self.chunkLimit = -1 + + + def handlePremium(self, pyfile): + self.html = self.load('http://myfastfile.com/api.php', + get={'user': self.user, 'pass': self.account.getAccountData(self.user)['password'], + 'link': pyfile.url}) + self.logDebug("JSON data: " + self.html) + + self.html = json_loads(self.html) + if self.html['status'] != 'ok': + self.fail(_("Unable to unrestrict link")) + + self.link = self.html['link'] diff --git a/pyload/plugin/hoster/MystoreTo.py b/pyload/plugin/hoster/MystoreTo.py new file mode 100644 index 000000000..e2288e344 --- /dev/null +++ b/pyload/plugin/hoster/MystoreTo.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# +# Test link: +# http://mystore.to/dl/mxcA50jKfP + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class MystoreTo(SimpleHoster): + __name__ = "MystoreTo" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'https?://(?:www\.)?mystore\.to/dl/.+' + + __description__ = """Mystore.to hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "")] + + + NAME_PATTERN = r'<h1>(?P<N>.+?)<' + SIZE_PATTERN = r'FILESIZE: (?P<S>[\d\.,]+) (?P<U>[\w^_]+)' + OFFLINE_PATTERN = r'>file not found<' + + + def setup(self): + self.chunkLimit = 1 + self.resumeDownload = True + self.multiDL = True + + + def handleFree(self, pyfile): + try: + fid = re.search(r'wert="(.+?)"', self.html).group(1) + + except AttributeError: + self.error(_("File-ID not found")) + + self.link = self.load("http://mystore.to/api/download", + post={'FID': fid}) diff --git a/module/plugins/hoster/MyvideoDe.py b/pyload/plugin/hoster/MyvideoDe.py index 4b5fa99ca..4b5fa99ca 100644 --- a/module/plugins/hoster/MyvideoDe.py +++ b/pyload/plugin/hoster/MyvideoDe.py diff --git a/pyload/plugin/hoster/NahrajCz.py b/pyload/plugin/hoster/NahrajCz.py new file mode 100644 index 000000000..6aa87a520 --- /dev/null +++ b/pyload/plugin/hoster/NahrajCz.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class NahrajCz(DeadHoster): + __name__ = "NahrajCz" + __type__ = "hoster" + __version__ = "0.21" + + __pattern__ = r'http://(?:www\.)?nahraj\.cz/content/download/.+' + + __description__ = """Nahraj.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/NarodRu.py b/pyload/plugin/hoster/NarodRu.py new file mode 100644 index 000000000..7b9da6e4e --- /dev/null +++ b/pyload/plugin/hoster/NarodRu.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +import re + +from random import random + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class NarodRu(SimpleHoster): + __name__ = "NarodRu" + __type__ = "hoster" + __version__ = "0.12" + + __pattern__ = r'http://(?:www\.)?narod(\.yandex)?\.ru/(disk|start/\d+\.\w+-narod\.yandex\.ru)/(?P<ID>\d+)/.+' + + __description__ = """Narod.ru hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<dt class="name">(?:<[^<]*>)*(?P<N>[^<]+)</dt>' + SIZE_PATTERN = r'<dd class="size">(?P<S>\d[^<]*)</dd>' + OFFLINE_PATTERN = r'<title>404</title>|Ѐайл ÑЎалеМ Ñ ÑеÑвОÑа|ÐакПМÑОлÑÑ ÑÑПк Ñ
ÑÐ°ÐœÐµÐœÐžÑ Ñайла\.' + + SIZE_REPLACEMENTS = [(u'ÐÐ', 'KB'), (u'ÐÐ', 'MB'), (u'ÐÐ', 'GB')] + URL_REPLACEMENTS = [("narod.yandex.ru/", "narod.ru/"), + (r"/start/\d+\.\w+-narod\.yandex\.ru/(\d{6,15})/\w+/(\w+)", r"/disk/\1/\2")] + + CAPTCHA_PATTERN = r'<number url="(.*?)">(\w+)</number>' + LINK_FREE_PATTERN = r'<a class="h-link" rel="yandex_bar" href="(.+?)">' + + + def handleFree(self, pyfile): + for _i in xrange(5): + self.html = self.load('http://narod.ru/disk/getcapchaxml/?rnd=%d' % int(random() * 777)) + + m = re.search(self.CAPTCHA_PATTERN, self.html) + if m is None: + self.error(_("Captcha")) + + post_data = {"action": "sendcapcha"} + captcha_url, post_data['key'] = m.groups() + post_data['rep'] = self.decryptCaptcha(captcha_url) + + self.html = self.load(pyfile.url, post=post_data, decode=True) + + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m: + url = 'http://narod.ru' + m.group(1) + self.correctCaptcha() + break + + elif u'<b class="error-msg"><strong>ÐÑОблОÑÑ?</strong>' in self.html: + self.invalidCaptcha() + + else: + self.error(_("Download link")) + + else: + self.fail(_("No valid captcha code entered")) + + self.download(url) diff --git a/module/plugins/hoster/NetloadIn.py b/pyload/plugin/hoster/NetloadIn.py index 2ed298ffa..2ed298ffa 100644 --- a/module/plugins/hoster/NetloadIn.py +++ b/pyload/plugin/hoster/NetloadIn.py diff --git a/pyload/plugin/hoster/NitroflareCom.py b/pyload/plugin/hoster/NitroflareCom.py new file mode 100644 index 000000000..85630a148 --- /dev/null +++ b/pyload/plugin/hoster/NitroflareCom.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +# +# Note: +# Right now premium support is not added +# Thus, any file that require premium support +# cannot be downloaded. Only the file that is free to +# download can be downloaded. + +import re + +from pyload.utils import json_loads +from pyload.plugin.internal.CaptchaService import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class NitroflareCom(SimpleHoster): + __name__ = "NitroflareCom" + __type__ = "hoster" + __version__ = "0.08" + + __pattern__ = r'https?://(?:www\.)?nitroflare\.com/view/(?P<ID>[\w^_]+)' + + __description__ = """Nitroflare.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("sahil", "sahilshekhawat01@gmail.com"), + ("Walter Purcaro", "vuolter@gmail.com"), + ("Stickell", "l.stickell@yahoo.it")] + + # URL_REPLACEMENTS = [("http://", "https://")] + + INFO_PATTERN = r'title="(?P<N>.+?)".+>(?P<S>[\d.,]+) (?P<U>[\w^_]+)' + OFFLINE_PATTERN = r'>File doesn\'t exist' + + LINK_FREE_PATTERN = r'(https?://[\w\-]+\.nitroflare\.com/.+?)"' + + RECAPTCHA_KEY = "6Lenx_USAAAAAF5L1pmTWvWcH73dipAEzNnmNLgy" + + PREMIUM_ONLY_PATTERN = r'This file is available with Premium only' + WAIT_PATTERN = r'You have to wait .+' + ERROR_PATTERN = r'downloading is not possible' + + + def checkErrors(self): + if not self.html: + return + + if not self.premium and re.search(self.PREMIUM_ONLY_PATTERN, self.html): + self.fail(_("Link require a premium account to be handled")) + + elif hasattr(self, 'WAIT_PATTERN'): + m = re.search(self.WAIT_PATTERN, self.html) + if m: + wait_time = sum(int(v) * {"hr": 3600, "hour": 3600, "min": 60, "sec": 1}[u.lower()] for v, u in + re.findall(r'(\d+)\s*(hr|hour|min|sec)', m.group(0), re.I)) + self.wait(wait_time, wait_time > 300) + return + + elif hasattr(self, 'ERROR_PATTERN'): + m = re.search(self.ERROR_PATTERN, self.html) + if m: + errmsg = self.info['error'] = m.group(1) + self.error(errmsg) + + self.info.pop('error', None) + + + def handleFree(self, pyfile): + # used here to load the cookies which will be required later + self.load(pyfile.url, post={'goToFreePage': ""}) + + self.load("https://www.nitroflare.com/ajax/setCookie.php", post={'fileId': self.info['pattern']['ID']}) + self.html = self.load("https://www.nitroflare.com/ajax/freeDownload.php", + post={'method': "startTimer", 'fileId': self.info['pattern']['ID']}) + + self.checkErrors() + + try: + js_file = self.load("http://nitroflare.com/js/downloadFree.js?v=1.0.1") + var_time = re.search("var time = (\\d+);", js_file) + wait_time = int(var_time.groups()[0]) + + except Exception: + wait_time = 60 + + self.wait(wait_time) + + recaptcha = ReCaptcha(self) + response, challenge = recaptcha.challenge(self.RECAPTCHA_KEY) + + self.html = self.load("https://www.nitroflare.com/ajax/freeDownload.php", + post={'method' : "fetchDownload", + 'recaptcha_challenge_field': challenge, + 'recaptcha_response_field' : response}) + + if "The captcha wasn't entered correctly" in self.html: + self.logWarning("The captcha wasn't entered correctly") + return + + if "You have to fill the captcha" in self.html: + self.logWarning("Captcha unfilled") + return + + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m: + self.link = m.group(1) + else: + self.logError("Unable to detect direct link") diff --git a/pyload/plugin/hoster/NoPremiumPl.py b/pyload/plugin/hoster/NoPremiumPl.py new file mode 100644 index 000000000..ddb9d78f8 --- /dev/null +++ b/pyload/plugin/hoster/NoPremiumPl.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHoster import MultiHoster + + +class NoPremiumPl(MultiHoster): + __name__ = "NoPremiumPl" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'https?://direct\.nopremium\.pl.+' + + __description__ = """NoPremium.pl multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("goddie", "dev@nopremium.pl")] + + + API_URL = "http://crypt.nopremium.pl" + + API_QUERY = {'site' : "nopremium", + 'output' : "json", + 'username': "", + 'password': "", + 'url' : ""} + + ERROR_CODES = {0 : "[%s] Incorrect login credentials", + 1 : "[%s] Not enough transfer to download - top-up your account", + 2 : "[%s] Incorrect / dead link", + 3 : "[%s] Error connecting to hosting, try again later", + 9 : "[%s] Premium account has expired", + 15: "[%s] Hosting no longer supported", + 80: "[%s] Too many incorrect login attempts, account blocked for 24h"} + + + def prepare(self): + super(NoPremiumPl, self).prepare() + + data = self.account.getAccountData(self.user) + + self.usr = data['usr'] + self.pwd = data['pwd'] + + + def runFileQuery(self, url, mode=None): + query = self.API_QUERY.copy() + + query["username"] = self.usr + query["password"] = self.pwd + query["url"] = url + + if mode == "fileinfo": + query['check'] = 2 + query['loc'] = 1 + + self.logDebug(query) + + return self.load(self.API_URL, post=query) + + + def handleFree(self, pyfile): + try: + data = self.runFileQuery(pyfile.url, 'fileinfo') + + except Exception: + self.logDebug("runFileQuery error") + self.tempOffline() + + try: + parsed = json_loads(data) + + except Exception: + self.logDebug("loads error") + self.tempOffline() + + self.logDebug(parsed) + + if "errno" in parsed.keys(): + if parsed["errno"] in self.ERROR_CODES: + # error code in known + self.fail(self.ERROR_CODES[parsed["errno"]] % self.__name__) + else: + # error code isn't yet added to plugin + self.fail( + parsed["errstring"] + or _("Unknown error (code: %s)") % parsed["errno"] + ) + + if "sdownload" in parsed: + if parsed["sdownload"] == "1": + self.fail( + _("Download from %s is possible only using NoPremium.pl website \ + directly") % parsed["hosting"]) + + pyfile.name = parsed["filename"] + pyfile.size = parsed["filesize"] + + try: + self.link = self.runFileQuery(pyfile.url, 'filedownload') + + except Exception: + self.logDebug("runFileQuery error #2") + self.tempOffline() diff --git a/pyload/plugin/hoster/NosuploadCom.py b/pyload/plugin/hoster/NosuploadCom.py new file mode 100644 index 000000000..edb8c6508 --- /dev/null +++ b/pyload/plugin/hoster/NosuploadCom.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class NosuploadCom(XFSHoster): + __name__ = "NosuploadCom" + __type__ = "hoster" + __version__ = "0.31" + + __pattern__ = r'http://(?:www\.)?nosupload\.com/\?d=\w{12}' + + __description__ = """Nosupload.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("igel", "igelkun@myopera.com")] + + + SIZE_PATTERN = r'<p><strong>Size:</strong> (?P<S>[\d.,]+) (?P<U>[\w^_]+)</p>' + LINK_PATTERN = r'<a class="select" href="(http://.+?)">Download</a>' + + WAIT_PATTERN = r'Please wait.*?>(\d+)</span>' + + + def getDownloadLink(self): + # stage1: press the "Free Download" button + data = self.getPostParameters() + self.html = self.load(self.pyfile.url, post=data, ref=True, decode=True) + + # stage2: wait some time and press the "Download File" button + data = self.getPostParameters() + wait_time = re.search(self.WAIT_PATTERN, self.html, re.M | re.S).group(1) + self.logDebug("Hoster told us to wait %s seconds" % wait_time) + self.wait(wait_time) + self.html = self.load(self.pyfile.url, post=data, ref=True, decode=True) + + # stage3: get the download link + return re.search(self.LINK_PATTERN, self.html, re.S).group(1) diff --git a/pyload/plugin/hoster/NovafileCom.py b/pyload/plugin/hoster/NovafileCom.py new file mode 100644 index 000000000..e79ba5980 --- /dev/null +++ b/pyload/plugin/hoster/NovafileCom.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# http://novafile.com/vfun4z6o2cit +# http://novafile.com/s6zrr5wemuz4 + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class NovafileCom(XFSHoster): + __name__ = "NovafileCom" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'http://(?:www\.)?novafile\.com/\w{12}' + + __description__ = """Novafile.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), + ("stickell", "l.stickell@yahoo.it")] + + + ERROR_PATTERN = r'class="alert[^"]*alert-separate"[^>]*>\s*(?:<p>)?(.*?)\s*</' + WAIT_PATTERN = r'<p>Please wait <span id="count"[^>]*>(\d+)</span> seconds</p>' + + LINK_PATTERN = r'<a href="(http://s\d+\.novafile\.com/.*?)" class="btn btn-green">Download File</a>' diff --git a/pyload/plugin/hoster/NowDownloadSx.py b/pyload/plugin/hoster/NowDownloadSx.py new file mode 100644 index 000000000..00101a379 --- /dev/null +++ b/pyload/plugin/hoster/NowDownloadSx.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster +from pyload.utils import fixup + + +class NowDownloadSx(SimpleHoster): + __name__ = "NowDownloadSx" + __type__ = "hoster" + __version__ = "0.07" + + __pattern__ = r'http://(?:www\.)?(nowdownload\.(at|ch|co|eu|sx)/(dl/|download\.php\?id=)|likeupload\.org/)\w+' + + __description__ = """NowDownload.sx hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("godofdream", "soilfiction@gmail.com"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + INFO_PATTERN = r'Downloading</span> <br> (?P<N>.*) (?P<S>[\d.,]+) (?P<U>[\w^_]+) </h4>' + OFFLINE_PATTERN = r'>This file does not exist' + + TOKEN_PATTERN = r'"(/api/token\.php\?token=\w+)"' + CONTINUE_PATTERN = r'"(/dl2/\w+/\w+)"' + WAIT_PATTERN = r'\.countdown\(\{until: \+(\d+),' + LINK_FREE_PATTERN = r'(http://s\d+\.coolcdn\.info/nowdownload/.+?)["\']' + + NAME_REPLACEMENTS = [("&#?\w+;", fixup), (r'<[^>]*>', '')] + + + def setup(self): + self.resumeDownload = True + self.multiDL = True + self.chunkLimit = -1 + + + def handleFree(self, pyfile): + tokenlink = re.search(self.TOKEN_PATTERN, self.html) + continuelink = re.search(self.CONTINUE_PATTERN, self.html) + if tokenlink is None or continuelink is None: + self.error() + + m = re.search(self.WAIT_PATTERN, self.html) + if m: + wait = int(m.group(1)) + else: + wait = 60 + + baseurl = "http://www.nowdownload.at" + self.html = self.load(baseurl + str(tokenlink.group(1))) + self.wait(wait) + + self.html = self.load(baseurl + str(continuelink.group(1))) + + url = re.search(self.LINK_FREE_PATTERN, self.html) + if url is None: + self.error(_("Download link not found")) + + self.download(str(url.group(1))) diff --git a/pyload/plugin/hoster/NowVideoSx.py b/pyload/plugin/hoster/NowVideoSx.py new file mode 100644 index 000000000..3c747c253 --- /dev/null +++ b/pyload/plugin/hoster/NowVideoSx.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class NowVideoSx(SimpleHoster): + __name__ = "NowVideoSx" + __type__ = "hoster" + __version__ = "0.10" + + __pattern__ = r'http://(?:www\.)?nowvideo\.(at|ch|co|eu|li|sx)/(video|mobile/#/videos)/(?P<ID>\w+)' + + __description__ = """NowVideo.sx hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + URL_REPLACEMENTS = [(__pattern__ + ".*", r'http://www.nowvideo.sx/video/\g<ID>')] + + NAME_PATTERN = r'<h4>(?P<N>.+?)<' + OFFLINE_PATTERN = r'>This file no longer exists' + + LINK_FREE_PATTERN = r'<source src="(.+?)"' + LINK_PREMIUM_PATTERN = r'<div id="content_player" >\s*<a href="(.+?)"' + + + def setup(self): + self.resumeDownload = True + self.multiDL = True + + + def handleFree(self, pyfile): + self.html = self.load("http://www.nowvideo.sx/mobile/video.php", get={'id': self.info['pattern']['ID']}) + + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("Free download link not found")) + + self.download(m.group(1)) diff --git a/module/plugins/hoster/OboomCom.py b/pyload/plugin/hoster/OboomCom.py index 43d41c538..43d41c538 100644 --- a/module/plugins/hoster/OboomCom.py +++ b/pyload/plugin/hoster/OboomCom.py diff --git a/pyload/plugin/hoster/OneFichierCom.py b/pyload/plugin/hoster/OneFichierCom.py new file mode 100644 index 000000000..b9756e7ff --- /dev/null +++ b/pyload/plugin/hoster/OneFichierCom.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class OneFichierCom(SimpleHoster): + __name__ = "OneFichierCom" + __type__ = "hoster" + __version__ = "0.78" + + __pattern__ = r'https?://(?:www\.)?(?:(?P<ID1>\w+)\.)?(?P<HOST>1fichier\.com|alterupload\.com|cjoint\.net|d(es)?fichiers\.com|dl4free\.com|megadl\.fr|mesfichiers\.org|piecejointe\.net|pjointe\.com|tenvoi\.com)(?:/\?(?P<ID2>\w+))?' + + __description__ = """1fichier.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("fragonib", "fragonib[AT]yahoo[DOT]es"), + ("the-razer", "daniel_ AT gmx DOT net"), + ("zoidberg", "zoidberg@mujmail.cz"), + ("imclem", ""), + ("stickell", "l.stickell@yahoo.it"), + ("Elrick69", "elrick69[AT]rocketmail[DOT]com"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + NAME_PATTERN = r'>FileName :</td>\s*<td.*>(?P<N>.+?)<' + SIZE_PATTERN = r'>Size :</td>\s*<td.*>(?P<S>[\d.,]+) (?P<U>[\w^_]+)' + + OFFLINE_PATTERN = r'File not found !\s*<' + + COOKIES = [("1fichier.com", "LG", "en")] + DISPOSITION = False #: Remove in 0.4.10 + + WAIT_PATTERN = r'>You must wait (\d+) minutes' + + + def setup(self): + self.multiDL = self.premium + self.resumeDownload = True + + + def handleFree(self, pyfile): + id = self.info['pattern']['ID1'] or self.info['pattern']['ID2'] + url, inputs = self.parseHtmlForm('action="https://1fichier.com/\?%s' % id) + + if not url: + self.fail(_("Download link not found")) + + if "pass" in inputs: + inputs['pass'] = self.getPassword() + + inputs['submit'] = "Download" + + self.download(url, post=inputs) + + + def handlePremium(self, pyfile): + self.download(pyfile.url, post={'dl': "Download", 'did': 0}) diff --git a/pyload/plugin/hoster/OronCom.py b/pyload/plugin/hoster/OronCom.py new file mode 100644 index 000000000..f28d34391 --- /dev/null +++ b/pyload/plugin/hoster/OronCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class OronCom(DeadHoster): + __name__ = "OronCom" + __type__ = "hoster" + __version__ = "0.14" + + __pattern__ = r'https?://(?:www\.)?oron\.com/\w{12}' + + __description__ = """Oron.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("chrox", "chrox@pyload.org"), + ("DHMH", "DHMH@pyload.org")] diff --git a/pyload/plugin/hoster/OverLoadMe.py b/pyload/plugin/hoster/OverLoadMe.py new file mode 100644 index 000000000..8c0436d78 --- /dev/null +++ b/pyload/plugin/hoster/OverLoadMe.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +import re + +from random import randrange +from urllib import unquote + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHoster import MultiHoster +from pyload.utils import parseFileSize + + +class OverLoadMe(MultiHoster): + __name__ = "OverLoadMe" + __type__ = "hoster" + __version__ = "0.09" + + __pattern__ = r'https?://.*overload\.me/.+' + + __description__ = """Over-Load.me multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("marley", "marley@over-load.me")] + + + def getFilename(self, url): + try: + name = unquote(url.rsplit("/", 1)[1]) + except IndexError: + name = "Unknown_Filename..." + + if name.endswith("..."): #: incomplete filename, append random stuff + name += "%s.tmp" % randrange(100, 999) + + return name + + + def setup(self): + self.chunkLimit = 5 + + + def handlePremium(self, pyfile): + https = "https" if self.getConfig("ssl") else "http" + data = self.account.getAccountData(self.user) + page = self.load(https + "://api.over-load.me/getdownload.php", + get={'auth': data['password'], + 'link': pyfile.url}) + + data = json_loads(page) + + self.logDebug(data) + + if data['error'] == 1: + self.logWarning(data['msg']) + self.tempOffline() + else: + if pyfile.name is not None and pyfile.name.endswith('.tmp') and data['filename']: + pyfile.name = data['filename'] + pyfile.size = parseFileSize(data['filesize']) + + http_repl = ["http://", "https://"] + self.link = data['downloadlink'].replace(*http_repl if self.getConfig("ssl") else *http_repl[::-1]) + + if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown") or pyfile.name.endswith('..'): + # only use when name wasn't already set + pyfile.name = self.getFilename(self.link) + + + def checkFile(self): + if self.checkDownload({"error": "<title>An error occured while processing your request</title>"}) + # usual this download can safely be retried + self.retry(wait_time=60, reason=_("An error occured while generating link.")) + + return super(OverLoadMe, self).checkFile() diff --git a/pyload/plugin/hoster/PandaplaNet.py b/pyload/plugin/hoster/PandaplaNet.py new file mode 100644 index 000000000..b9d5b6e5a --- /dev/null +++ b/pyload/plugin/hoster/PandaplaNet.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class PandaplaNet(DeadHoster): + __name__ = "PandaplaNet" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?pandapla\.net/\w{12}' + + __description__ = """Pandapla.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("t4skforce", "t4skforce1337[AT]gmail[DOT]com")] diff --git a/module/plugins/hoster/PornhostCom.py b/pyload/plugin/hoster/PornhostCom.py index 70ce4f32e..70ce4f32e 100644 --- a/module/plugins/hoster/PornhostCom.py +++ b/pyload/plugin/hoster/PornhostCom.py diff --git a/module/plugins/hoster/PornhubCom.py b/pyload/plugin/hoster/PornhubCom.py index 9f8a5eec2..9f8a5eec2 100644 --- a/module/plugins/hoster/PornhubCom.py +++ b/pyload/plugin/hoster/PornhubCom.py diff --git a/pyload/plugin/hoster/PotloadCom.py b/pyload/plugin/hoster/PotloadCom.py new file mode 100644 index 000000000..4845299a5 --- /dev/null +++ b/pyload/plugin/hoster/PotloadCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class PotloadCom(DeadHoster): + __name__ = "PotloadCom" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?potload\.com/\w{12}' + + __description__ = """Potload.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] diff --git a/pyload/plugin/hoster/PremiumTo.py b/pyload/plugin/hoster/PremiumTo.py new file mode 100644 index 000000000..07945f873 --- /dev/null +++ b/pyload/plugin/hoster/PremiumTo.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +from os import remove + +from pyload.plugin.internal.MultiHoster import MultiHoster +from pyload.utils import fs_encode + + +class PremiumTo(MultiHoster): + __name__ = "PremiumTo" + __type__ = "hoster" + __version__ = "0.21" + + __pattern__ = r'^unmatchable$' + + __description__ = """Premium.to multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("zoidberg", "zoidberg@mujmail.cz"), + ("stickell", "l.stickell@yahoo.it")] + + + CHECK_TRAFFIC = True + + + def handlePremium(self, pyfile): + #raise timeout to 2min + self.download("http://premium.to/api/getfile.php", + get={'username': self.account.username, + 'password': self.account.password, + 'link' : pyfile.url}, + disposition=True) + + + def checkFile(self): + if self.checkDownload({'nopremium': "No premium account available"}): + self.retry(60, 5 * 60, "No premium account available") + + err = '' + if self.req.http.code == '420': + # Custom error code send - fail + file = fs_encode(self.lastDownload) + with open(file, "rb") as f: + err = f.read(256).strip() + remove(file) + + if err: + self.fail(err) + + return super(PremiumTo, self).checkFile() diff --git a/pyload/plugin/hoster/PremiumizeMe.py b/pyload/plugin/hoster/PremiumizeMe.py new file mode 100644 index 000000000..c1153280b --- /dev/null +++ b/pyload/plugin/hoster/PremiumizeMe.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHoster import MultiHoster + + +class PremiumizeMe(MultiHoster): + __name__ = "PremiumizeMe" + __type__ = "hoster" + __version__ = "0.16" + + __pattern__ = r'^unmatchable$' #: Since we want to allow the user to specify the list of hoster to use we let MultiHoster.activate + + __description__ = """Premiumize.me multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Florian Franzen", "FlorianFranzen@gmail.com")] + + + def handlePremium(self, pyfile): + # In some cases hostsers do not supply us with a filename at download, so we + # are going to set a fall back filename (e.g. for freakshare or xfileshare) + pyfile.name = pyfile.name.split('/').pop() # Remove everthing before last slash + + # Correction for automatic assigned filename: Removing html at end if needed + suffix_to_remove = ["html", "htm", "php", "php3", "asp", "shtm", "shtml", "cfml", "cfm"] + temp = pyfile.name.split('.') + if temp.pop() in suffix_to_remove: + pyfile.name = ".".join(temp) + + # Get account data + user, data = self.account.selectAccount() + + # Get rewritten link using the premiumize.me api v1 (see https://secure.premiumize.me/?show=api) + data = json_loads(self.load("https://api.premiumize.me/pm-api/v1.php", + get={'method' : "directdownloadlink", + 'params[login]': user, + 'params[pass]' : data['password'], + 'params[link]' : pyfile.url})) + + # Check status and decide what to do + status = data['status'] + + if status == 200: + self.link = data['result']['location'] + return + + elif status == 400: + self.fail(_("Invalid link")) + + elif status == 404: + self.offline() + + elif status >= 500: + self.tempOffline() + + else: + self.fail(data['statusmessage']) diff --git a/pyload/plugin/hoster/PromptfileCom.py b/pyload/plugin/hoster/PromptfileCom.py new file mode 100644 index 000000000..fb8c907e5 --- /dev/null +++ b/pyload/plugin/hoster/PromptfileCom.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class PromptfileCom(SimpleHoster): + __name__ = "PromptfileCom" + __type__ = "hoster" + __version__ = "0.13" + + __pattern__ = r'https?://(?:www\.)?promptfile\.com/' + + __description__ = """Promptfile.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("igel", "igelkun@myopera.com")] + + + INFO_PATTERN = r'<span style="[^"]*" title="[^"]*">(?P<N>.*?) \((?P<S>[\d.,]+) (?P<U>[\w^_]+)\)</span>' + OFFLINE_PATTERN = r'<span style="[^"]*" title="File Not Found">File Not Found</span>' + + CHASH_PATTERN = r'<input type="hidden" name="chash" value="([^"]*)" />' + LINK_FREE_PATTERN = r'<a href=\"(.+)\" target=\"_blank\" class=\"view_dl_link\">Download File</a>' + + + def handleFree(self, pyfile): + # STAGE 1: get link to continue + m = re.search(self.CHASH_PATTERN, self.html) + if m is None: + self.error(_("CHASH_PATTERN not found")) + chash = m.group(1) + self.logDebug("Read chash %s" % chash) + # continue to stage2 + self.html = self.load(pyfile.url, decode=True, post={'chash': chash}) + + # STAGE 2: get the direct link + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("LINK_FREE_PATTERN not found")) + + self.link = m.group(1) diff --git a/pyload/plugin/hoster/PrzeklejPl.py b/pyload/plugin/hoster/PrzeklejPl.py new file mode 100644 index 000000000..bfb27834a --- /dev/null +++ b/pyload/plugin/hoster/PrzeklejPl.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class PrzeklejPl(DeadHoster): + __name__ = "PrzeklejPl" + __type__ = "hoster" + __version__ = "0.11" + + __pattern__ = r'http://(?:www\.)?przeklej\.pl/plik/.+' + + __description__ = """Przeklej.pl hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/PutdriveCom.py b/pyload/plugin/hoster/PutdriveCom.py new file mode 100644 index 000000000..562951e81 --- /dev/null +++ b/pyload/plugin/hoster/PutdriveCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.hoster.ZeveraCom import ZeveraCom + + +class PutdriveCom(ZeveraCom): + __name__ = "PutdriveCom" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'https?://(?:www\.)putdrive\.com/(getFiles\.ashx|Members/download\.ashx)\?.*ourl=.+' + + __description__ = """Multihosters.com multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] diff --git a/pyload/plugin/hoster/QuickshareCz.py b/pyload/plugin/hoster/QuickshareCz.py new file mode 100644 index 000000000..9300d230b --- /dev/null +++ b/pyload/plugin/hoster/QuickshareCz.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class QuickshareCz(SimpleHoster): + __name__ = "QuickshareCz" + __type__ = "hoster" + __version__ = "0.56" + + __pattern__ = r'http://(?:[^/]*\.)?quickshare\.cz/stahnout-soubor/.+' + + __description__ = """Quickshare.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<th width="145px">Název:</th>\s*<td style="word-wrap:break-word;">(?P<N>[^<]+)</td>' + SIZE_PATTERN = r'<th>Velikost:</th>\s*<td>(?P<S>[\d.,]+) (?P<U>[\w^_]+)</td>' + OFFLINE_PATTERN = r'<script type="text/javascript">location\.href=\'/chyba\';</script>' + + + def process(self, pyfile): + self.html = self.load(pyfile.url, decode=True) + self.getFileInfo() + + # parse js variables + self.jsvars = dict((x, y.strip("'")) for x, y in re.findall(r"var (\w+) = ([\d.]+|'[^']*')", self.html)) + self.logDebug(self.jsvars) + pyfile.name = self.jsvars['ID3'] + + # determine download type - free or premium + if self.premium: + if 'UU_prihlasen' in self.jsvars: + if self.jsvars['UU_prihlasen'] == '0': + self.logWarning(_("User not logged in")) + self.relogin(self.user) + self.retry() + elif float(self.jsvars['UU_kredit']) < float(self.jsvars['kredit_odecet']): + self.logWarning(_("Not enough credit left")) + self.premium = False + + if self.premium: + self.handlePremium(pyfile) + else: + self.handleFree(pyfile) + + if self.checkDownload({"error": re.compile(r"\AChyba!")}, max_size=100): + self.fail(_("File not m or plugin defect")) + + + def handleFree(self, pyfile): + # get download url + download_url = '%s/download.php' % self.jsvars['server'] + data = dict((x, self.jsvars[x]) for x in self.jsvars if x in ("ID1", "ID2", "ID3", "ID4")) + self.logDebug("FREE URL1:" + download_url, data) + + self.load(download_url, post=data, follow_location=False) + self.header = self.req.http.header + + m = re.search(r'Location\s*:\s*(.+)', self.header, re.I) + if m is None: + self.fail(_("File not found")) + download_url = m.group(1) + self.logDebug("FREE URL2:" + download_url) + + # check errors + m = re.search(r'/chyba/(\d+)', download_url) + if m: + if m.group(1) == '1': + self.retry(60, 2 * 60, "This IP is already downloading") + elif m.group(1) == '2': + self.retry(60, 60, "No free slots available") + else: + self.fail(_("Error %d") % m.group(1)) + + # download file + self.download(download_url) + + + def handlePremium(self, pyfile): + download_url = '%s/download_premium.php' % self.jsvars['server'] + data = dict((x, self.jsvars[x]) for x in self.jsvars if x in ("ID1", "ID2", "ID4", "ID5")) + self.download(download_url, get=data) diff --git a/pyload/plugin/hoster/RPNetBiz.py b/pyload/plugin/hoster/RPNetBiz.py new file mode 100644 index 000000000..af56d8162 --- /dev/null +++ b/pyload/plugin/hoster/RPNetBiz.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.MultiHoster import MultiHoster +from pyload.utils import json_loads + + +class RPNetBiz(MultiHoster): + __name__ = "RPNetBiz" + __type__ = "hoster" + __version__ = "0.14" + + __description__ = """RPNet.biz multi-hoster plugin""" + __license__ = "GPLv3" + + __pattern__ = r'https?://.+rpnet\.biz' + __authors__ = [("Dman", "dmanugm@gmail.com")] + + + def setup(self): + self.chunkLimit = -1 + + + def handlePremium(self, pyfile): + user, data = self.account.selectAccount() + + # Get the download link + res = self.load("https://premium.rpnet.biz/client_api.php", + get={"username": user, + "password": data['password'], + "action" : "generate", + "links" : pyfile.url}) + + self.logDebug("JSON data: %s" % res) + link_status = json_loads(res)['links'][0] # get the first link... since we only queried one + + # Check if we only have an id as a HDD link + if 'id' in link_status: + self.logDebug("Need to wait at least 30 seconds before requery") + self.setWait(30) # wait for 30 seconds + self.wait() + # Lets query the server again asking for the status on the link, + # we need to keep doing this until we reach 100 + max_tries = 30 + my_try = 0 + while (my_try <= max_tries): + self.logDebug("Try: %d ; Max Tries: %d" % (my_try, max_tries)) + res = self.load("https://premium.rpnet.biz/client_api.php", + get={"username": user, + "password": data['password'], + "action": "downloadInformation", + "id": link_status['id']}) + self.logDebug("JSON data hdd query: %s" % res) + download_status = json_loads(res)['download'] + + if download_status['status'] == '100': + link_status['generated'] = download_status['rpnet_link'] + self.logDebug("Successfully downloaded to rpnet HDD: %s" % link_status['generated']) + break + else: + self.logDebug("At %s%% for the file download" % download_status['status']) + + self.setWait(30) + self.wait() + my_try += 1 + + if my_try > max_tries: # We went over the limit! + self.fail(_("Waited for about 15 minutes for download to finish but failed")) + + if 'generated' in link_status: + self.link = link_status['generated'] + return + elif 'error' in link_status: + self.fail(link_status['error']) + else: + self.fail(_("Something went wrong, not supposed to enter here")) diff --git a/pyload/plugin/hoster/RapideoPl.py b/pyload/plugin/hoster/RapideoPl.py new file mode 100644 index 000000000..9e9bbf58b --- /dev/null +++ b/pyload/plugin/hoster/RapideoPl.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHoster import MultiHoster + + +class RapideoPl(MultiHoster): + __name__ = "RapideoPl" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'^unmatchable$' + + __description__ = """Rapideo.pl multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("goddie", "dev@rapideo.pl")] + + + API_URL = "http://enc.rapideo.pl" + + API_QUERY = {'site' : "newrd", + 'output' : "json", + 'username': "", + 'password': "", + 'url' : ""} + + ERROR_CODES = {0 : "[%s] Incorrect login credentials", + 1 : "[%s] Not enough transfer to download - top-up your account", + 2 : "[%s] Incorrect / dead link", + 3 : "[%s] Error connecting to hosting, try again later", + 9 : "[%s] Premium account has expired", + 15: "[%s] Hosting no longer supported", + 80: "[%s] Too many incorrect login attempts, account blocked for 24h"} + + + def prepare(self): + super(RapideoPl, self).prepare() + + data = self.account.getAccountData(self.user) + + self.usr = data['usr'] + self.pwd = data['pwd'] + + + def runFileQuery(self, url, mode=None): + query = self.API_QUERY.copy() + + query["username"] = self.usr + query["password"] = self.pwd + query["url"] = url + + if mode == "fileinfo": + query['check'] = 2 + query['loc'] = 1 + + self.logDebug(query) + + return self.load(self.API_URL, post=query) + + + def handleFree(self, pyfile): + try: + data = self.runFileQuery(pyfile.url, 'fileinfo') + + except Exception: + self.logDebug("RunFileQuery error") + self.tempOffline() + + try: + parsed = json_loads(data) + + except Exception: + self.logDebug("Loads error") + self.tempOffline() + + self.logDebug(parsed) + + if "errno" in parsed.keys(): + if parsed["errno"] in self.ERROR_CODES: + # error code in known + self.fail(self.ERROR_CODES[parsed["errno"]] % self.__name__) + else: + # error code isn't yet added to plugin + self.fail( + parsed["errstring"] + or _("Unknown error (code: %s)") % parsed["errno"] + ) + + if "sdownload" in parsed: + if parsed["sdownload"] == "1": + self.fail( + _("Download from %s is possible only using Rapideo.pl website \ + directly") % parsed["hosting"]) + + pyfile.name = parsed["filename"] + pyfile.size = parsed["filesize"] + + try: + self.link = self.runFileQuery(pyfile.url, 'filedownload') + + except Exception: + self.logDebug("runFileQuery error #2") + self.tempOffline() diff --git a/pyload/plugin/hoster/RapidfileshareNet.py b/pyload/plugin/hoster/RapidfileshareNet.py new file mode 100644 index 000000000..1b1895b39 --- /dev/null +++ b/pyload/plugin/hoster/RapidfileshareNet.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class RapidfileshareNet(XFSHoster): + __name__ = "RapidfileshareNet" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?rapidfileshare\.net/\w{12}' + + __description__ = """Rapidfileshare.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("guidobelix", "guidobelix@hotmail.it")] + + + NAME_PATTERN = r'<input type="hidden" name="fname" value="(?P<N>.+?)">' + SIZE_PATTERN = r'>http://www.rapidfileshare.net/\w+?</font> \((?P<S>[\d.,]+) (?P<U>[\w^_]+)\)</font>' + + OFFLINE_PATTERN = r'>No such file with this filename' + TEMP_OFFLINE_PATTERN = r'The page may have been renamed, removed or be temporarily unavailable.<' diff --git a/pyload/plugin/hoster/RapidgatorNet.py b/pyload/plugin/hoster/RapidgatorNet.py new file mode 100644 index 000000000..8cd883537 --- /dev/null +++ b/pyload/plugin/hoster/RapidgatorNet.py @@ -0,0 +1,169 @@ +# -*- coding: utf-8 -*- + +import re + +from pycurl import HTTPHEADER + +from pyload.utils import json_loads +from pyload.network.HTTPRequest import BadHeader +from pyload.plugin.internal.CaptchaService import AdsCaptcha, ReCaptcha, SolveMedia +from pyload.plugin.internal.SimpleHoster import SimpleHoster, secondsToMidnight + + +class RapidgatorNet(SimpleHoster): + __name__ = "RapidgatorNet" + __type__ = "hoster" + __version__ = "0.32" + + __pattern__ = r'http://(?:www\.)?(rapidgator\.net|rg\.to)/file/\w+' + + __description__ = """Rapidgator.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), + ("chrox", ""), + ("stickell", "l.stickell@yahoo.it"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + API_URL = "http://rapidgator.net/api/file" + + COOKIES = [("rapidgator.net", "lang", "en")] + + NAME_PATTERN = r'<title>Download file (?P<N>.*)</title>' + SIZE_PATTERN = r'File size:\s*<strong>(?P<S>[\d.,]+) (?P<U>[\w^_]+)</strong>' + OFFLINE_PATTERN = r'>(File not found|Error 404)' + + JSVARS_PATTERN = r'\s+var\s*(startTimerUrl|getDownloadUrl|captchaUrl|fid|secs)\s*=\s*\'?(.*?)\'?;' + + PREMIUM_ONLY_PATTERN = r'You can download files up to|This file can be downloaded by premium only<' + ERROR_PATTERN = r'You have reached your (daily|hourly) downloads limit' + WAIT_PATTERN = r'(Delay between downloads must be not less than|Try again in).+' + + LINK_FREE_PATTERN = r'return \'(http://\w+.rapidgator.net/.*)\';' + + RECAPTCHA_PATTERN = r'"http://api\.recaptcha\.net/challenge\?k=(.*?)"' + ADSCAPTCHA_PATTERN = r'(http://api\.adscaptcha\.com/Get\.aspx[^"\']*)' + SOLVEMEDIA_PATTERN = r'http://api\.solvemedia\.com/papi/challenge\.script\?k=(.*?)"' + + + def setup(self): + if self.account: + self.sid = self.account.getAccountInfo(self.user).get('sid', None) + else: + self.sid = None + + if self.sid: + self.premium = True + + self.resumeDownload = self.multiDL = self.premium + self.chunkLimit = 1 + + + def api_response(self, cmd): + try: + json = self.load('%s/%s' % (self.API_URL, cmd), + get={'sid': self.sid, + 'url': self.pyfile.url}, decode=True) + self.logDebug("API:%s" % cmd, json, "SID: %s" % self.sid) + json = json_loads(json) + status = json['response_status'] + msg = json['response_details'] + + except BadHeader, e: + self.logError("API: %s" % cmd, e, "SID: %s" % self.sid) + status = e.code + msg = e + + if status == 200: + return json['response'] + + elif status == 423: + self.account.empty(self.user) + self.retry() + + else: + self.account.relogin(self.user) + self.retry(wait_time=60) + + + def handlePremium(self, pyfile): + self.api_data = self.api_response('info') + self.api_data['md5'] = self.api_data['hash'] + + pyfile.name = self.api_data['filename'] + pyfile.size = self.api_data['size'] + + self.link = self.api_response('download')['url'] + + + def handleFree(self, pyfile): + jsvars = dict(re.findall(self.JSVARS_PATTERN, self.html)) + self.logDebug(jsvars) + + self.req.http.lastURL = pyfile.url + self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) + + url = "http://rapidgator.net%s?fid=%s" % ( + jsvars.get('startTimerUrl', '/download/AjaxStartTimer'), jsvars['fid']) + jsvars.update(self.getJsonResponse(url)) + + self.wait(jsvars.get('secs', 45), False) + + url = "http://rapidgator.net%s?sid=%s" % ( + jsvars.get('getDownloadUrl', '/download/AjaxGetDownload'), jsvars['sid']) + jsvars.update(self.getJsonResponse(url)) + + self.req.http.lastURL = pyfile.url + self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With:"]) + + url = "http://rapidgator.net%s" % jsvars.get('captchaUrl', '/download/captcha') + self.html = self.load(url) + + for _i in xrange(5): + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m: + self.link = m.group(1) + break + else: + captcha, captcha_key = self.handleCaptcha() + response, challenge = captcha.challenge(captcha_key) + + self.html = self.load(url, post={'DownloadCaptchaForm[captcha]': "", + 'adcopy_challenge' : challenge, + 'adcopy_response' : response}) + + if "The verification code is incorrect" in self.html: + self.invalidCaptcha() + else: + self.correctCaptcha() + else: + self.error(_("Download link")) + + + def handleCaptcha(self): + m = re.search(self.ADSCAPTCHA_PATTERN, self.html) + if m: + captcha_key = m.group(1) + captcha = AdsCaptcha(self) + else: + m = re.search(self.RECAPTCHA_PATTERN, self.html) + if m: + captcha_key = m.group(1) + captcha = ReCaptcha(self) + else: + m = re.search(self.SOLVEMEDIA_PATTERN, self.html) + if m: + captcha_key = m.group(1) + captcha = SolveMedia(self) + else: + self.error(_("Captcha")) + + return captcha, captcha_key + + + def getJsonResponse(self, url): + res = self.load(url, decode=True) + if not res.startswith('{'): + self.retry() + self.logDebug(url, res) + return json_loads(res) diff --git a/pyload/plugin/hoster/RapiduNet.py b/pyload/plugin/hoster/RapiduNet.py new file mode 100644 index 000000000..1e12ab776 --- /dev/null +++ b/pyload/plugin/hoster/RapiduNet.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- + +import re + +from pycurl import HTTPHEADER +from time import time, altzone + +from pyload.utils import json_loads +from pyload.plugin.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class RapiduNet(SimpleHoster): + __name__ = "RapiduNet" + __type__ = "hoster" + __version__ = "0.07" + + __pattern__ = r'https?://(?:www\.)?rapidu\.net/(?P<ID>\d{10})' + + __description__ = """Rapidu.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("prOq", "")] + + + COOKIES = [("rapidu.net", "rapidu_lang", "en")] + + INFO_PATTERN = r'<h1 title="(?P<N>.*)">.*</h1>\s*<small>(?P<S>\d+(\.\d+)?)\s(?P<U>\w+)</small>' + OFFLINE_PATTERN = r'404 - File not found' + + ERROR_PATTERN = r'<div class="error">' + + RECAPTCHA_KEY = r'6Ld12ewSAAAAAHoE6WVP_pSfCdJcBQScVweQh8Io' + + + def setup(self): + self.resumeDownload = True + self.multiDL = self.premium + + + def handleFree(self, pyfile): + self.req.http.lastURL = pyfile.url + self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) + + jsvars = self.getJsonResponse("https://rapidu.net/ajax.php", + get={'a': "getLoadTimeToDownload"}, + post={'_go': ""}, + decode=True) + + if str(jsvars['timeToDownload']) is "stop": + t = (24 * 60 * 60) - (int(time()) % (24 * 60 * 60)) + altzone + + self.logInfo("You've reach your daily download transfer") + + self.retry(10, 10 if t < 1 else None, _("Try tomorrow again")) #@NOTE: check t in case of not synchronised clock + + else: + self.wait(int(jsvars['timeToDownload']) - int(time())) + + recaptcha = ReCaptcha(self) + + for _i in xrange(10): + response, challenge = recaptcha.challenge(self.RECAPTCHA_KEY) + + jsvars = self.getJsonResponse("https://rapidu.net/ajax.php", + get={'a': "getCheckCaptcha"}, + post={'_go' : "", + 'captcha1': challenge, + 'captcha2': response, + 'fileId' : self.info['pattern']['ID']}, + decode=True) + if jsvars['message'] == 'success': + self.download(jsvars['url']) + break + + + def getJsonResponse(self, *args, **kwargs): + res = self.load(*args, **kwargs) + if not res.startswith('{'): + self.retry() + + self.logDebug(res) + + return json_loads(res) diff --git a/pyload/plugin/hoster/RarefileNet.py b/pyload/plugin/hoster/RarefileNet.py new file mode 100644 index 000000000..1010c92ca --- /dev/null +++ b/pyload/plugin/hoster/RarefileNet.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class RarefileNet(XFSHoster): + __name__ = "RarefileNet" + __type__ = "hoster" + __version__ = "0.09" + + __pattern__ = r'http://(?:www\.)?rarefile\.net/\w{12}' + + __description__ = """Rarefile.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + LINK_PATTERN = r'<a href="(.+?)">\1</a>' diff --git a/pyload/plugin/hoster/RealdebridCom.py b/pyload/plugin/hoster/RealdebridCom.py new file mode 100644 index 000000000..ae6f69d7c --- /dev/null +++ b/pyload/plugin/hoster/RealdebridCom.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +import re + +from random import randrange +from urllib import unquote +from time import time + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHoster import MultiHoster +from pyload.utils import parseFileSize + + +class RealdebridCom(MultiHoster): + __name__ = "RealdebridCom" + __type__ = "hoster" + __version__ = "0.64" + + __pattern__ = r'https?://((?:www\.|s\d+\.)?real-debrid\.com/dl/|[\w^_]\.rdb\.so/d/)[\w^_]+' + + __description__ = """Real-Debrid.com multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Devirex Hazzard", "naibaf_11@yahoo.de")] + + + def getFilename(self, url): + try: + name = unquote(url.rsplit("/", 1)[1]) + except IndexError: + name = "Unknown_Filename..." + if not name or name.endswith(".."): #: incomplete filename, append random stuff + name += "%s.tmp" % randrange(100, 999) + return name + + + def setup(self): + self.chunkLimit = 3 + + + def handlePremium(self, pyfile): + data = json_loads(self.load("https://real-debrid.com/ajax/unrestrict.php", + get={'lang' : "en", + 'link' : pyfile.url, + 'password': self.getPassword(), + 'time' : int(time() * 1000)})) + + self.logDebug("Returned Data: %s" % data) + + if data['error'] != 0: + if data['message'] == "Your file is unavailable on the hoster.": + self.offline() + else: + self.logWarning(data['message']) + self.tempOffline() + else: + if pyfile.name is not None and pyfile.name.endswith('.tmp') and data['file_name']: + pyfile.name = data['file_name'] + pyfile.size = parseFileSize(data['file_size']) + self.link = data['generated_links'][0][-1] + + if self.getConfig("ssl"): + self.link = self.link.replace("http://", "https://") + else: + self.link = self.link.replace("https://", "http://") + + if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown") or pyfile.name.endswith('..'): + #only use when name wasnt already set + pyfile.name = self.getFilename(self.link) + + + def checkFile(self): + if self.checkDownload({"error": "<title>An error occured while processing your request</title>"}): + #usual this download can safely be retried + self.retry(wait_time=60, reason=_("An error occured while generating link")) + + return super(RealdebridCom, self).checkFile() diff --git a/module/plugins/hoster/RedtubeCom.py b/pyload/plugin/hoster/RedtubeCom.py index 1f18d09c7..1f18d09c7 100644 --- a/module/plugins/hoster/RedtubeCom.py +++ b/pyload/plugin/hoster/RedtubeCom.py diff --git a/pyload/plugin/hoster/RehostTo.py b/pyload/plugin/hoster/RehostTo.py new file mode 100644 index 000000000..3e3e88c6c --- /dev/null +++ b/pyload/plugin/hoster/RehostTo.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +from urllib import unquote + +from pyload.plugin.internal.MultiHoster import MultiHoster + + +class RehostTo(MultiHoster): + __name__ = "RehostTo" + __type__ = "hoster" + __version__ = "0.21" + + __pattern__ = r'https?://.*rehost\.to\..+' + + __description__ = """Rehost.com multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org")] + + + def handlePremium(self, pyfile): + self.download("http://rehost.to/process_download.php", + get={'user': "cookie", + 'pass': self.account.getAccountInfo(self.user)['session'], + 'dl' : pyfile.url}, + disposition=True) diff --git a/pyload/plugin/hoster/RemixshareCom.py b/pyload/plugin/hoster/RemixshareCom.py new file mode 100644 index 000000000..a1cd2a37e --- /dev/null +++ b/pyload/plugin/hoster/RemixshareCom.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# http://remixshare.com/download/p946u +# +# Note: +# The remixshare.com website is very very slow, so +# if your download not starts because of pycurl timeouts: +# Adjust timeouts in /usr/share/pyload/pyload/network/HTTPRequest.py + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class RemixshareCom(SimpleHoster): + __name__ = "RemixshareCom" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'https?://remixshare\.com/(download|dl)/\w+' + + __description__ = """Remixshare.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + INFO_PATTERN = r'title=\'.+?\'>(?P<N>.+?)</span><span class=\'light2\'> \((?P<S>\d+) (?P<U>[\w^_]+)\)<' + OFFLINE_PATTERN = r'<h1>Ooops!<' + + LINK_FREE_PATTERN = r'(http://remixshare\.com/downloadfinal/.+?)"' + TOKEN_PATTERN = r'var acc = (\d+)' + WAIT_PATTERN = r'var XYZ = r"(\d+)"' + + + def setup(self): + self.multiDL = True + self.chunkLimit = 1 + + + def handleFree(self, pyfile): + b = re.search(self.LINK_FREE_PATTERN, self.html) + if not b: + self.error(_("Cannot parse download url")) + + c = re.search(self.TOKEN_PATTERN, self.html) + if not c: + self.error(_("Cannot parse file token")) + + self.link = b.group(1) + c.group(1) + + #Check if we have to wait + seconds = re.search(self.WAIT_PATTERN, self.html) + if seconds: + self.logDebug("Wait " + seconds.group(1)) + self.wait(seconds.group(1)) diff --git a/pyload/plugin/hoster/RgHostNet.py b/pyload/plugin/hoster/RgHostNet.py new file mode 100644 index 000000000..d9e548721 --- /dev/null +++ b/pyload/plugin/hoster/RgHostNet.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class RgHostNet(SimpleHoster): + __name__ = "RgHostNet" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?rghost\.net/\d+(?:r=\d+)?' + + __description__ = """RgHost.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("z00nx", "z00nx0@gmail.com")] + + + INFO_PATTERN = r'<h1>\s+(<a[^>]+>)?(?P<N>[^<]+)(</a>)?\s+<small[^>]+>\s+\((?P<S>[^)]+)\)\s+</small>\s+</h1>' + OFFLINE_PATTERN = r'File is deleted|this page is not found' + + LINK_FREE_PATTERN = r'<a\s+href="([^"]+)"\s+class="btn\s+large\s+download"[^>]+>Download</a>' diff --git a/pyload/plugin/hoster/SafesharingEu.py b/pyload/plugin/hoster/SafesharingEu.py new file mode 100644 index 000000000..af046af62 --- /dev/null +++ b/pyload/plugin/hoster/SafesharingEu.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class SafesharingEu(XFSHoster): + __name__ = "SafesharingEu" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'https?://(?:www\.)?safesharing\.eu/\w{12}' + + __description__ = """Safesharing.eu hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] + + + ERROR_PATTERN = r'(?:<div class="alert alert-danger">)(.+?)(?:</div>)' diff --git a/pyload/plugin/hoster/SecureUploadEu.py b/pyload/plugin/hoster/SecureUploadEu.py new file mode 100644 index 000000000..4db413c90 --- /dev/null +++ b/pyload/plugin/hoster/SecureUploadEu.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class SecureUploadEu(XFSHoster): + __name__ = "SecureUploadEu" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'https?://(?:www\.)?secureupload\.eu/\w{12}' + + __description__ = """SecureUpload.eu hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("z00nx", "z00nx0@gmail.com")] + + + INFO_PATTERN = r'<h3>Downloading (?P<N>[^<]+) \((?P<S>[^<]+)\)</h3>' diff --git a/pyload/plugin/hoster/SendspaceCom.py b/pyload/plugin/hoster/SendspaceCom.py new file mode 100644 index 000000000..4d477579d --- /dev/null +++ b/pyload/plugin/hoster/SendspaceCom.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class SendspaceCom(SimpleHoster): + __name__ = "SendspaceCom" + __type__ = "hoster" + __version__ = "0.17" + + __pattern__ = r'https?://(?:www\.)?sendspace\.com/file/\w+' + + __description__ = """Sendspace.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<h2 class="bgray">\s*<(?:b|strong)>(?P<N>[^<]+)</' + SIZE_PATTERN = r'<div class="file_description reverse margin_center">\s*<b>File Size:</b>\s*(?P<S>[\d.,]+)(?P<U>[\w^_]+)\s*</div>' + OFFLINE_PATTERN = r'<div class="msg error" style="cursor: default">Sorry, the file you requested is not available.</div>' + + LINK_FREE_PATTERN = r'<a id="download_button" href="([^"]+)"' + + CAPTCHA_PATTERN = r'<td><img src="(/captchas/captcha\.php?captcha=([^"]+))"></td>' + USER_CAPTCHA_PATTERN = r'<td><img src="/captchas/captcha\.php?user=([^"]+))"></td>' + + + def handleFree(self, pyfile): + params = {} + for _i in xrange(3): + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m: + if 'captcha_hash' in params: + self.correctCaptcha() + download_url = m.group(1) + break + + m = re.search(self.CAPTCHA_PATTERN, self.html) + if m: + if 'captcha_hash' in params: + self.invalidCaptcha() + captcha_url1 = "http://www.sendspace.com/" + m.group(1) + m = re.search(self.USER_CAPTCHA_PATTERN, self.html) + captcha_url2 = "http://www.sendspace.com/" + m.group(1) + params = {'captcha_hash': m.group(2), + 'captcha_submit': 'Verify', + 'captcha_answer': self.decryptCaptcha(captcha_url1) + " " + self.decryptCaptcha(captcha_url2)} + else: + params = {'download': "Regular Download"} + + self.logDebug(params) + self.html = self.load(pyfile.url, post=params) + else: + self.fail(_("Download link not found")) + + self.download(download_url) diff --git a/pyload/plugin/hoster/Share4WebCom.py b/pyload/plugin/hoster/Share4WebCom.py new file mode 100644 index 000000000..f2b4e49e9 --- /dev/null +++ b/pyload/plugin/hoster/Share4WebCom.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.hoster.UnibytesCom import UnibytesCom + + +class Share4WebCom(UnibytesCom): + __name__ = "Share4WebCom" + __type__ = "hoster" + __version__ = "0.11" + + __pattern__ = r'https?://(?:www\.)?share4web\.com/get/\w+' + + __description__ = """Share4web.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + HOSTER_DOMAIN = "share4web.com" diff --git a/pyload/plugin/hoster/Share76Com.py b/pyload/plugin/hoster/Share76Com.py new file mode 100644 index 000000000..d460726f2 --- /dev/null +++ b/pyload/plugin/hoster/Share76Com.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class Share76Com(DeadHoster): + __name__ = "Share76Com" + __type__ = "hoster" + __version__ = "0.04" + + __pattern__ = r'http://(?:www\.)?share76\.com/\w{12}' + + __description__ = """Share76.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [] diff --git a/pyload/plugin/hoster/ShareFilesCo.py b/pyload/plugin/hoster/ShareFilesCo.py new file mode 100644 index 000000000..edd56572e --- /dev/null +++ b/pyload/plugin/hoster/ShareFilesCo.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class ShareFilesCo(DeadHoster): + __name__ = "ShareFilesCo" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?sharefiles\.co/\w{12}' + + __description__ = """Sharefiles.co hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] diff --git a/pyload/plugin/hoster/SharebeesCom.py b/pyload/plugin/hoster/SharebeesCom.py new file mode 100644 index 000000000..54de21095 --- /dev/null +++ b/pyload/plugin/hoster/SharebeesCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class SharebeesCom(DeadHoster): + __name__ = "SharebeesCom" + __type__ = "hoster" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?sharebees\.com/\w{12}' + + __description__ = """ShareBees hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/ShareonlineBiz.py b/pyload/plugin/hoster/ShareonlineBiz.py new file mode 100644 index 000000000..f3be1aeb2 --- /dev/null +++ b/pyload/plugin/hoster/ShareonlineBiz.py @@ -0,0 +1,184 @@ +# -*- coding: utf-8 -*- + +import re + +from time import time +from urllib import unquote +from urlparse import urlparse + +from pyload.network.RequestFactory import getURL +from pyload.plugin.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class ShareonlineBiz(SimpleHoster): + __name__ = "ShareonlineBiz" + __type__ = "hoster" + __version__ = "0.48" + + __pattern__ = r'https?://(?:www\.)?(share-online\.biz|egoshare\.com)/(download\.php\?id=|dl/)(?P<ID>\w+)' + + __description__ = """Shareonline.biz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("spoob", "spoob@pyload.org"), + ("mkaay", "mkaay@mkaay.de"), + ("zoidberg", "zoidberg@mujmail.cz"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + URL_REPLACEMENTS = [(__pattern__ + ".*", "http://www.share-online.biz/dl/\g<ID>")] + + CHECK_TRAFFIC = True + + RECAPTCHA_KEY = "6LdatrsSAAAAAHZrB70txiV5p-8Iv8BtVxlTtjKX" + + ERROR_PATTERN = r'<p class="b">Information:</p>\s*<div>\s*<strong>(.*?)</strong>' + + + @classmethod + def getInfo(cls, url="", html=""): + info = {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 3 if url else 1, 'url': url} + + if url: + info['pattern'] = re.match(cls.__pattern__, url).groupdict() + + field = getURL("http://api.share-online.biz/linkcheck.php", + get={'md5': "1"}, + post={'links': info['pattern']['ID']}, + decode=True).split(";") + + if field[1] == "OK": + info['fileid'] = field[0] + info['status'] = 2 + info['name'] = field[2] + info['size'] = field[3] #: in bytes + info['md5'] = field[4].strip().lower().replace("\n\n", "") #: md5 + + elif field[1] in ("DELETED", "NOT FOUND"): + info['status'] = 1 + + return info + + + def setup(self): + self.resumeDownload = self.premium + self.multiDL = False + + + def handleCaptcha(self): + recaptcha = ReCaptcha(self) + + for _i in xrange(5): + response, challenge = recaptcha.challenge(self.RECAPTCHA_KEY) + + m = re.search(r'var wait=(\d+);', self.html) + self.setWait(int(m.group(1)) if m else 30) + + res = self.load("%s/free/captcha/%d" % (self.pyfile.url, int(time() * 1000)), + post={'dl_free' : "1", + 'recaptcha_challenge_field': challenge, + 'recaptcha_response_field' : response}) + if not res == '0': + self.correctCaptcha() + return res + else: + self.invalidCaptcha() + else: + self.invalidCaptcha() + self.fail(_("No valid captcha solution received")) + + + def handleFree(self, pyfile): + self.wait(3) + + self.html = self.load("%s/free/" % pyfile.url, + post={'dl_free': "1", 'choice': "free"}, + decode=True) + + self.checkErrors() + + res = self.handleCaptcha() + download_url = res.decode('base64') + + if not download_url.startswith("http://"): + self.error(_("Wrong download url")) + + self.wait() + + self.download(download_url) + + + def checkFile(self): + check = self.checkDownload({'cookie': re.compile(r'<div id="dl_failure"'), + 'fail' : re.compile(r"<title>Share-Online")}) + + if check == "cookie": + self.invalidCaptcha() + self.retry(5, 60, _("Cookie failure")) + + elif check == "fail": + self.invalidCaptcha() + self.retry(5, 5 * 60, _("Download failed")) + + return super(ShareonlineBiz, self).checkFile() + + + def handlePremium(self, pyfile): #: should be working better loading (account) api internally + html = self.load("http://api.share-online.biz/account.php", + get={'username': self.user, + 'password': self.account.getAccountData(self.user)['password'], + 'act' : "download", + 'lid' : self.info['fileid']}) + + self.api_data = dlinfo = {} + + for line in html.splitlines(): + key, value = line.split(": ") + dlinfo[key.lower()] = value + + self.logDebug(dlinfo) + + if not dlinfo['status'] == "online": + self.offline() + else: + pyfile.name = dlinfo['name'] + pyfile.size = int(dlinfo['size']) + + dlLink = dlinfo['url'] + + if dlLink == "server_under_maintenance": + self.tempOffline() + else: + self.multiDL = True + self.download(dlLink) + + + def checkErrors(self): + m = re.search(r"/failure/(.*?)/1", self.req.lastEffectiveURL) + if m is None: + self.info.pop('error', None) + return + + errmsg = m.group(1).lower() + + try: + self.logError(errmsg, re.search(self.ERROR_PATTERN, self.html).group(1)) + except Exception: + self.logError("Unknown error occurred", errmsg) + + if errmsg is "invalid": + self.fail(_("File not available")) + + elif errmsg in ("freelimit", "size", "proxy"): + self.fail(_("Premium account needed")) + + elif errmsg in ("expired", "server"): + self.retry(wait_time=600, reason=errmsg) + + elif 'slot' in errmsg: + self.wantReconnect = True + self.retry(24, 3600, errmsg) + + else: + self.wantReconnect = True + self.retry(wait_time=60, reason=errmsg) diff --git a/module/plugins/hoster/ShareplaceCom.py b/pyload/plugin/hoster/ShareplaceCom.py index 61e0f8723..61e0f8723 100644 --- a/module/plugins/hoster/ShareplaceCom.py +++ b/pyload/plugin/hoster/ShareplaceCom.py diff --git a/pyload/plugin/hoster/SharingmatrixCom.py b/pyload/plugin/hoster/SharingmatrixCom.py new file mode 100644 index 000000000..d1892be14 --- /dev/null +++ b/pyload/plugin/hoster/SharingmatrixCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class SharingmatrixCom(DeadHoster): + __name__ = "SharingmatrixCom" + __type__ = "hoster" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?sharingmatrix\.com/file/\w+' + + __description__ = """Sharingmatrix.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("jeix", "jeix@hasnomail.de"), + ("paulking", "")] diff --git a/pyload/plugin/hoster/ShragleCom.py b/pyload/plugin/hoster/ShragleCom.py new file mode 100644 index 000000000..628537108 --- /dev/null +++ b/pyload/plugin/hoster/ShragleCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class ShragleCom(DeadHoster): + __name__ = "ShragleCom" + __type__ = "hoster" + __version__ = "0.22" + + __pattern__ = r'http://(?:www\.)?(cloudnator|shragle)\.com/files/(?P<ID>.+?)/' + + __description__ = """Cloudnator.com (Shragle.com) hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/SimplyPremiumCom.py b/pyload/plugin/hoster/SimplyPremiumCom.py new file mode 100644 index 000000000..50b278985 --- /dev/null +++ b/pyload/plugin/hoster/SimplyPremiumCom.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- + +import re + +from datetime import datetime, timedelta + +from pyload.plugin.internal.MultiHoster import MultiHoster +from pyload.plugin.internal.SimpleHoster import secondsToMidnight + + +class SimplyPremiumCom(MultiHoster): + __name__ = "SimplyPremiumCom" + __type__ = "hoster" + __version__ = "0.08" + + __pattern__ = r'https?://.+simply-premium\.com' + + __description__ = """Simply-Premium.com multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("EvolutionClip", "evolutionclip@live.de")] + + + def setup(self): + self.chunkLimit = 16 + + + def checkErrors(self): + if '<valid>0</valid>' in self.html or ( + "You are not allowed to download from this host" in self.html and self.premium): + self.account.relogin(self.user) + self.retry() + + elif "NOTFOUND" in self.html: + self.offline() + + elif "downloadlimit" in self.html: + self.logWarning(_("Reached maximum connctions")) + self.retry(5, 60, _("Reached maximum connctions")) + + elif "trafficlimit" in self.html: + self.logWarning(_("Reached daily limit for this host")) + self.retry(wait_time=secondsToMidnight(gmt=2), reason="Daily limit for this host reached") + + elif "hostererror" in self.html: + self.logWarning(_("Hoster temporarily unavailable, waiting 1 minute and retry")) + self.retry(5, 60, _("Hoster is temporarily unavailable")) + + + def handlePremium(self, pyfile): + for i in xrange(5): + self.html = self.load("http://www.simply-premium.com/premium.php", get={'info': "", 'link': self.pyfile.url}) + + if self.html: + self.logDebug("JSON data: " + self.html) + break + else: + self.logInfo(_("Unable to get API data, waiting 1 minute and retry")) + self.retry(5, 60, _("Unable to get API data")) + + self.checkErrors() + + try: + self.pyfile.name = re.search(r'<name>([^<]+)</name>', self.html).group(1) + + except AttributeError: + self.pyfile.name = "" + + try: + self.pyfile.size = re.search(r'<size>(\d+)</size>', self.html).group(1) + + except AttributeError: + self.pyfile.size = 0 + + try: + self.link = re.search(r'<download>([^<]+)</download>', self.html).group(1) + + except AttributeError: + self.link = 'http://www.simply-premium.com/premium.php?link=' + self.pyfile.url diff --git a/pyload/plugin/hoster/SimplydebridCom.py b/pyload/plugin/hoster/SimplydebridCom.py new file mode 100644 index 000000000..4b740ff20 --- /dev/null +++ b/pyload/plugin/hoster/SimplydebridCom.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.MultiHoster import MultiHoster, replace_patterns + + +class SimplydebridCom(MultiHoster): + __name__ = "SimplydebridCom" + __type__ = "hoster" + __version__ = "0.15" + + __pattern__ = r'http://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/sd\.php' + + __description__ = """Simply-debrid.com multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Kagenoshin", "kagenoshin@gmx.ch")] + + + def handlePremium(self, pyfile): + #fix the links for simply-debrid.com! + self.link = replace_patterns(pyfile.url, [("clz.to", "cloudzer.net/file") + ("http://share-online", "http://www.share-online") + ("ul.to", "uploaded.net/file") + ("uploaded.com", "uploaded.net") + ("filerio.com", "filerio.in") + ("lumfile.com", "lumfile.se")] + + if 'fileparadox' in self.link: + self.link = self.link.replace("http://", "https://") + + self.html = self.load("http://simply-debrid.com/api.php", get={'dl': self.link}) + if 'tiger Link' in self.html or 'Invalid Link' in self.html or ('API' in self.html and 'ERROR' in self.html): + self.error(_("Unable to unrestrict link")) + + self.link = self.html + + self.wait(5) + + + def checkFile(self): + if self.checkDownload({"error": "No address associated with hostname"}): + self.retry(24, 3 * 60, _("Bad file downloaded")) + + return super(SimplydebridCom, self).checkFile() diff --git a/pyload/plugin/hoster/SmoozedCom.py b/pyload/plugin/hoster/SmoozedCom.py new file mode 100644 index 000000000..715d99b40 --- /dev/null +++ b/pyload/plugin/hoster/SmoozedCom.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHoster import MultiHoster + + +class SmoozedCom(MultiHoster): + __name__ = "SmoozedCom" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'^unmatchable$' #: Since we want to allow the user to specify the list of hoster to use we let MultiHoster.activate + + __description__ = """Smoozed.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("", "")] + + + def handlePremium(self, pyfile): + # In some cases hostsers do not supply us with a filename at download, so we + # are going to set a fall back filename (e.g. for freakshare or xfileshare) + pyfile.name = pyfile.name.split('/').pop() # Remove everthing before last slash + + # Correction for automatic assigned filename: Removing html at end if needed + suffix_to_remove = ["html", "htm", "php", "php3", "asp", "shtm", "shtml", "cfml", "cfm"] + temp = pyfile.name.split('.') + + if temp.pop() in suffix_to_remove: + pyfile.name = ".".join(temp) + + # Check the link + get_data = {'session_key': self.account.getAccountInfo(self.user)['session'], + 'url' : pyfile.url} + + data = json_loads(self.load("http://www2.smoozed.com/api/check", get=get_data)) + + if data["state"] != "ok": + self.fail(data["message"]) + + if data["data"].get("state", "ok") != "ok": + if data["data"] == "Offline": + self.offline() + else: + self.fail(data["data"]["message"]) + + pyfile.name = data["data"]["name"] + pyfile.size = int(data["data"]["size"]) + + # Start the download + header = self.load("http://www2.smoozed.com/api/download", get=get_data, just_header=True) + + if not "location" in header: + self.fail(_("Unable to initialize download")) + else: + self.link = header["location"][-1] if isinstance(header["location"], list) else header["location"] + + + def checkFile(self): + if self.checkDownload({'error': '{"state":"error"}', + 'retry': '{"state":"retry"}'}): + self.fail(_("Error response received")) + + return super(SmoozedCom, self).checkFile() diff --git a/pyload/plugin/hoster/SockshareCom.py b/pyload/plugin/hoster/SockshareCom.py new file mode 100644 index 000000000..e903e3daf --- /dev/null +++ b/pyload/plugin/hoster/SockshareCom.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class SockshareCom(DeadHoster): + __name__ = "SockshareCom" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'http://(?:www\.)?sockshare\.com/(mobile/)?(file|embed)/(?P<ID>\w+)' + + __description__ = """Sockshare.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("jeix", "jeix@hasnomail.de"), + ("stickell", "l.stickell@yahoo.it"), + ("Walter Purcaro", "vuolter@gmail.com")] diff --git a/module/plugins/hoster/SoundcloudCom.py b/pyload/plugin/hoster/SoundcloudCom.py index fd5d1ea6c..fd5d1ea6c 100644 --- a/module/plugins/hoster/SoundcloudCom.py +++ b/pyload/plugin/hoster/SoundcloudCom.py diff --git a/pyload/plugin/hoster/SpeedLoadOrg.py b/pyload/plugin/hoster/SpeedLoadOrg.py new file mode 100644 index 000000000..a20f87902 --- /dev/null +++ b/pyload/plugin/hoster/SpeedLoadOrg.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class SpeedLoadOrg(DeadHoster): + __name__ = "SpeedLoadOrg" + __type__ = "hoster" + __version__ = "1.02" + + __pattern__ = r'http://(?:www\.)?speedload\.org/(?P<ID>\w+)' + + __description__ = """Speedload.org hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] diff --git a/pyload/plugin/hoster/SpeedfileCz.py b/pyload/plugin/hoster/SpeedfileCz.py new file mode 100644 index 000000000..981ba861d --- /dev/null +++ b/pyload/plugin/hoster/SpeedfileCz.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class SpeedfileCz(DeadHoster): + __name__ = "SpeedFileCz" + __type__ = "hoster" + __version__ = "0.32" + + __pattern__ = r'http://(?:www\.)?speedfile\.cz/.+' + + __description__ = """Speedfile.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/SpeedyshareCom.py b/pyload/plugin/hoster/SpeedyshareCom.py new file mode 100644 index 000000000..c92522d70 --- /dev/null +++ b/pyload/plugin/hoster/SpeedyshareCom.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# http://speedy.sh/ep2qY/Zapp-Brannigan.jpg + +import re + +from urlparse import urljoin + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class SpeedyshareCom(SimpleHoster): + __name__ = "SpeedyshareCom" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'https?://(?:www\.)?(speedyshare\.com|speedy\.sh)/\w+' + + __description__ = """Speedyshare.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] + + + NAME_PATTERN = r'class=downloadfilename>(?P<N>.*)</span></td>' + SIZE_PATTERN = r'class=sizetagtext>(?P<S>.*) (?P<U>[kKmM]?[iI]?[bB]?)</div>' + + OFFLINE_PATTERN = r'class=downloadfilenamenotfound>.*</span>' + + LINK_FREE_PATTERN = r'<a href=\'(.*)\'><img src=/gf/slowdownload\.png alt=\'Slow Download\' border=0' + + + def setup(self): + self.multiDL = False + self.chunkLimit = 1 + + + def handleFree(self, pyfile): + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.link = m.group(1) diff --git a/pyload/plugin/hoster/StorageTo.py b/pyload/plugin/hoster/StorageTo.py new file mode 100644 index 000000000..78b9a60bb --- /dev/null +++ b/pyload/plugin/hoster/StorageTo.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class StorageTo(DeadHoster): + __name__ = "StorageTo" + __type__ = "hoster" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?storage\.to/get/.+' + + __description__ = """Storage.to hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("mkaay", "mkaay@mkaay.de")] diff --git a/module/plugins/hoster/StreamCz.py b/pyload/plugin/hoster/StreamCz.py index 95e69abf4..95e69abf4 100644 --- a/module/plugins/hoster/StreamCz.py +++ b/pyload/plugin/hoster/StreamCz.py diff --git a/pyload/plugin/hoster/StreamcloudEu.py b/pyload/plugin/hoster/StreamcloudEu.py new file mode 100644 index 000000000..01e334491 --- /dev/null +++ b/pyload/plugin/hoster/StreamcloudEu.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class StreamcloudEu(XFSHoster): + __name__ = "StreamcloudEu" + __type__ = "hoster" + __version__ = "0.10" + + __pattern__ = r'http://(?:www\.)?streamcloud\.eu/\w{12}' + + __description__ = """Streamcloud.eu hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("seoester", "seoester@googlemail.com")] + + + WAIT_PATTERN = r'var count = (\d+)' + + LINK_PATTERN = r'file: "(http://(stor|cdn)\d+\.streamcloud\.eu:?\d*/.*/video\.(mp4|flv))",' + + + def setup(self): + self.multiDL = True + self.chunkLimit = 1 + self.resumeDownload = self.premium diff --git a/pyload/plugin/hoster/TurbobitNet.py b/pyload/plugin/hoster/TurbobitNet.py new file mode 100644 index 000000000..c69158c39 --- /dev/null +++ b/pyload/plugin/hoster/TurbobitNet.py @@ -0,0 +1,164 @@ +# -*- coding: utf-8 -*- + +import random +import re +import time + +from Crypto.Cipher import ARC4 +from binascii import hexlify, unhexlify +from pycurl import HTTPHEADER +from urllib import quote + +from pyload.network.RequestFactory import getURL +from pyload.plugin.internal.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster, timestamp + + +class TurbobitNet(SimpleHoster): + __name__ = "TurbobitNet" + __type__ = "hoster" + __version__ = "0.19" + + __pattern__ = r'http://(?:www\.)?turbobit\.net/(?:download/free/)?(?P<ID>\w+)' + + __description__ = """Turbobit.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), + ("prOq", "")] + + + URL_REPLACEMENTS = [(__pattern__ + ".*", "http://turbobit.net/\g<ID>.html")] + + COOKIES = [("turbobit.net", "user_lang", "en")] + + NAME_PATTERN = r'id="file-title">(?P<N>.+?)<' + SIZE_PATTERN = r'class="file-size">(?P<S>[\d.,]+) (?P<U>[\w^_]+)' + OFFLINE_PATTERN = r'<h2>File Not Found</h2>|html\(\'File (?:was )?not found' + + LINK_FREE_PATTERN = LINK_PREMIUM_PATTERN = r'(/download/redirect/[^"\']+)' + + LIMIT_WAIT_PATTERN = r'<div id=\'timeout\'>(\d+)<' + CAPTCHA_PATTERN = r'<img alt="Captcha" src="(.+?)"' + + + def handleFree(self, pyfile): + self.html = self.load("http://turbobit.net/download/free/%s" % self.info['pattern']['ID'], + decode=True) + + rtUpdate = self.getRtUpdate() + + self.solveCaptcha() + + self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) + + self.html = self.load(self.getDownloadUrl(rtUpdate)) + + self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With:"]) + + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m: + self.link = m.group(1) + + + def solveCaptcha(self): + for _i in xrange(5): + m = re.search(self.LIMIT_WAIT_PATTERN, self.html) + if m: + wait_time = int(m.group(1)) + self.wait(wait_time, wait_time > 60) + self.retry() + + action, inputs = self.parseHtmlForm("action='#'") + if not inputs: + self.error(_("Captcha form not found")) + self.logDebug(inputs) + + if inputs['captcha_type'] == 'recaptcha': + recaptcha = ReCaptcha(self) + inputs['recaptcha_response_field'], inputs['recaptcha_challenge_field'] = recaptcha.challenge() + else: + m = re.search(self.CAPTCHA_PATTERN, self.html) + if m is None: + self.error(_("captcha")) + captcha_url = m.group(1) + inputs['captcha_response'] = self.decryptCaptcha(captcha_url) + + self.logDebug(inputs) + self.html = self.load(self.url, post=inputs) + + if '<div class="captcha-error">Incorrect, try again!<' in self.html: + self.invalidCaptcha() + else: + self.correctCaptcha() + break + else: + self.fail(_("Invalid captcha")) + + + def getRtUpdate(self): + rtUpdate = self.getStorage("rtUpdate") + if not rtUpdate: + if self.getStorage("version") != self.__version__ \ + or int(self.getStorage("timestamp", 0)) + 86400000 < timestamp(): + # that's right, we are even using jdownloader updates + rtUpdate = getURL("http://update0.jdownloader.org/pluginstuff/tbupdate.js") + rtUpdate = self.decrypt(rtUpdate.splitlines()[1]) + # but we still need to fix the syntax to work with other engines than rhino + rtUpdate = re.sub(r'for each\(var (\w+) in(\[[^\]]+\])\)\{', + r'zza=\2;for(var zzi=0;zzi<zza.length;zzi++){\1=zza[zzi];', rtUpdate) + rtUpdate = re.sub(r"for\((\w+)=", r"for(var \1=", rtUpdate) + + self.setStorage("rtUpdate", rtUpdate) + self.setStorage("timestamp", timestamp()) + self.setStorage("version", self.__version__) + else: + self.logError(_("Unable to download, wait for update...")) + self.tempOffline() + + return rtUpdate + + + def getDownloadUrl(self, rtUpdate): + self.req.http.lastURL = self.url + + m = re.search("(/\w+/timeout\.js\?\w+=)([^\"\'<>]+)", self.html) + if m: + url = "http://turbobit.net%s%s" % m.groups() + else: + url = "http://turbobit.net/files/timeout.js?ver=%s" % "".join(random.choice('0123456789ABCDEF') for _i in xrange(32)) + + fun = self.load(url) + + self.setWait(65, False) + + for b in [1, 3]: + self.jscode = "var id = \'%s\';var b = %d;var inn = \'%s\';%sout" % ( + self.info['pattern']['ID'], b, quote(fun), rtUpdate) + + try: + out = self.js.eval(self.jscode) + self.logDebug("URL", self.js.engine, out) + if out.startswith('/download/'): + return "http://turbobit.net%s" % out.strip() + + except Exception, e: + self.logError(e) + else: + if self.retries >= 2: + # retry with updated js + self.delStorage("rtUpdate") + else: + self.retry() + + self.wait() + + + def decrypt(self, data): + cipher = ARC4.new(hexlify('E\x15\xa1\x9e\xa3M\xa0\xc6\xa0\x84\xb6H\x83\xa8o\xa0')) + return unhexlify(cipher.encrypt(unhexlify(data))) + + + def getLocalTimeString(self): + lt = time.localtime() + tz = time.altzone if lt.tm_isdst else time.timezone + return "%s GMT%+03d%02d" % (time.strftime("%a %b %d %Y %H:%M:%S", lt), -tz // 3600, tz % 3600) diff --git a/pyload/plugin/hoster/TurbouploadCom.py b/pyload/plugin/hoster/TurbouploadCom.py new file mode 100644 index 000000000..e964d1365 --- /dev/null +++ b/pyload/plugin/hoster/TurbouploadCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class TurbouploadCom(DeadHoster): + __name__ = "TurbouploadCom" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?turboupload\.com/(\w+)' + + __description__ = """Turboupload.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/TusfilesNet.py b/pyload/plugin/hoster/TusfilesNet.py new file mode 100644 index 000000000..20a948925 --- /dev/null +++ b/pyload/plugin/hoster/TusfilesNet.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +from pyload.network.HTTPRequest import BadHeader +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class TusfilesNet(XFSHoster): + __name__ = "TusfilesNet" + __type__ = "hoster" + __version__ = "0.09" + + __pattern__ = r'https?://(?:www\.)?tusfiles\.net/\w{12}' + + __description__ = """Tusfiles.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com"), + ("guidobelix", "guidobelix@hotmail.it")] + + + INFO_PATTERN = r'\](?P<N>.+) - (?P<S>[\d.,]+) (?P<U>[\w^_]+)\[' + OFFLINE_PATTERN = r'>File Not Found|<Title>TusFiles - Fast Sharing Files!|The file you are trying to download is no longer available' + + + def setup(self): + self.chunkLimit = -1 + self.multiDL = True + self.resumeDownload = True + + + def downloadLink(self, link): + try: + return super(TusfilesNet, self).downloadLink(link) + + except BadHeader, e: + if e.code is 503: + self.multiDL = False + raise Retry("503") diff --git a/pyload/plugin/hoster/TwoSharedCom.py b/pyload/plugin/hoster/TwoSharedCom.py new file mode 100644 index 000000000..8c6864414 --- /dev/null +++ b/pyload/plugin/hoster/TwoSharedCom.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class TwoSharedCom(SimpleHoster): + __name__ = "TwoSharedCom" + __type__ = "hoster" + __version__ = "0.13" + + __pattern__ = r'http://(?:www\.)?2shared\.com/(account/)?(download|get|file|document|photo|video|audio)/.+' + + __description__ = """2Shared.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<h1>(?P<N>.*)</h1>' + SIZE_PATTERN = r'<span class="dtitle">File size:</span>\s*(?P<S>[\d.,]+) (?P<U>[\w^_]+)' + OFFLINE_PATTERN = r'The file link that you requested is not valid\.|This file was deleted\.' + + LINK_FREE_PATTERN = r'window.location =\'(.+?)\';' + + + def setup(self): + self.resumeDownload = True + self.multiDL = True diff --git a/pyload/plugin/hoster/UlozTo.py b/pyload/plugin/hoster/UlozTo.py new file mode 100644 index 000000000..0e4156ad0 --- /dev/null +++ b/pyload/plugin/hoster/UlozTo.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- + +import re +import time + +from pyload.utils import json_loads +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +def convertDecimalPrefix(m): + # decimal prefixes used in filesize and traffic + return ("%%.%df" % {'k': 3, 'M': 6, 'G': 9}[m.group(2)] % float(m.group(1))).replace('.', '') + + +class UlozTo(SimpleHoster): + __name__ = "UlozTo" + __type__ = "hoster" + __version__ = "1.04" + + __pattern__ = r'http://(?:www\.)?(uloz\.to|ulozto\.(cz|sk|net)|bagruj\.cz|zachowajto\.pl)/(?:live/)?(?P<ID>\w+/[^/?]*)' + + __description__ = """Uloz.to hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + INFO_PATTERN = r'<p>File <strong>(?P<N>[^<]+)</strong> is password protected</p>' + NAME_PATTERN = r'<title>(?P<N>[^<]+) \| Uloz\.to</title>' + SIZE_PATTERN = r'<span id="fileSize">.*?(?P<S>[\d.,]+\s[kMG]?B)</span>' + OFFLINE_PATTERN = r'<title>404 - Page not found</title>|<h1 class="h1">File (has been deleted|was banned)</h1>' + + URL_REPLACEMENTS = [(r"(?<=http://)([^/]+)", "www.ulozto.net")] + SIZE_REPLACEMENTS = [('([\d.]+)\s([kMG])B', convertDecimalPrefix)] + + ADULT_PATTERN = r'<form action="([^\"]*)" method="post" id="frm-askAgeForm">' + PASSWD_PATTERN = r'<div class="passwordProtectedFile">' + VIPLINK_PATTERN = r'<a href="[^"]*\?disclaimer=1" class="linkVip">' + TOKEN_PATTERN = r'<input type="hidden" name="_token_" .*?value="(.+?)"' + + + def setup(self): + self.chunkLimit = 16 if self.premium else 1 + self.multiDL = self.premium + self.resumeDownload = True + + + def process(self, pyfile): + pyfile.url = re.sub(r"(?<=http://)([^/]+)", "www.ulozto.net", pyfile.url) + self.html = self.load(pyfile.url, decode=True, cookies=True) + + if re.search(self.ADULT_PATTERN, self.html): + self.logInfo(_("Adult content confirmation needed")) + + m = re.search(self.TOKEN_PATTERN, self.html) + if m is None: + self.error(_("TOKEN_PATTERN not found")) + token = m.group(1) + + self.html = self.load(pyfile.url, get={'do': "askAgeForm-submit"}, + post={"agree": "Confirm", "_token_": token}, cookies=True) + + if self.PASSWD_PATTERN in self.html: + password = self.getPassword() + + if password: + self.logInfo(_("Password protected link, trying ") + password) + self.html = self.load(pyfile.url, get={'do': "passwordProtectedForm-submit"}, + post={"password": password, "password_send": 'Send'}, cookies=True) + + if self.PASSWD_PATTERN in self.html: + self.fail(_("Incorrect password")) + else: + self.fail(_("No password found")) + + if re.search(self.VIPLINK_PATTERN, self.html): + self.html = self.load(pyfile.url, get={'disclaimer': "1"}) + + self.getFileInfo() + + if self.premium and self.checkTrafficLeft(): + self.handlePremium(pyfile) + else: + self.handleFree(pyfile) + + self.doCheckDownload() + + + def handleFree(self, pyfile): + action, inputs = self.parseHtmlForm('id="frm-downloadDialog-freeDownloadForm"') + if not action or not inputs: + self.error(_("Free download form not found")) + + self.logDebug("inputs.keys = " + str(inputs.keys())) + # get and decrypt captcha + if all(key in inputs for key in ("captcha_value", "captcha_id", "captcha_key")): + # Old version - last seen 9.12.2013 + self.logDebug('Using "old" version') + + captcha_value = self.decryptCaptcha("http://img.uloz.to/captcha/%s.png" % inputs['captcha_id']) + self.logDebug("CAPTCHA ID: " + inputs['captcha_id'] + ", CAPTCHA VALUE: " + captcha_value) + + inputs.update({'captcha_id': inputs['captcha_id'], 'captcha_key': inputs['captcha_key'], 'captcha_value': captcha_value}) + + elif all(key in inputs for key in ("captcha_value", "timestamp", "salt", "hash")): + # New version - better to get new parameters (like captcha reload) because of image url - since 6.12.2013 + self.logDebug('Using "new" version') + + xapca = self.load("http://www.ulozto.net/reloadXapca.php", get={'rnd': str(int(time.time()))}) + self.logDebug("xapca = " + str(xapca)) + + data = json_loads(xapca) + captcha_value = self.decryptCaptcha(str(data['image'])) + self.logDebug("CAPTCHA HASH: " + data['hash'], "CAPTCHA SALT: " + str(data['salt']), "CAPTCHA VALUE: " + captcha_value) + + inputs.update({'timestamp': data['timestamp'], 'salt': data['salt'], 'hash': data['hash'], 'captcha_value': captcha_value}) + else: + self.error(_("CAPTCHA form changed")) + + self.multiDL = True + self.download("http://www.ulozto.net" + action, post=inputs, cookies=True, disposition=True) + + + def handlePremium(self, pyfile): + self.download(pyfile.url, get={'do': "directDownload"}, disposition=True) + + + def doCheckDownload(self): + check = self.checkDownload({ + "wrong_captcha": re.compile(r'<ul class="error">\s*<li>Error rewriting the text.</li>'), + "offline" : re.compile(self.OFFLINE_PATTERN), + "passwd" : self.PASSWD_PATTERN, + "server_error" : 'src="http://img.ulozto.cz/error403/vykricnik.jpg"', # paralell dl, server overload etc. + "not_found" : "<title>UloÅŸ.to</title>" + }) + + if check == "wrong_captcha": + #self.delStorage("captcha_id") + #self.delStorage("captcha_text") + self.invalidCaptcha() + self.retry(reason=_("Wrong captcha code")) + + elif check == "offline": + self.offline() + + elif check == "passwd": + self.fail(_("Wrong password")) + + elif check == "server_error": + self.logError(_("Server error, try downloading later")) + self.multiDL = False + self.wait(1 * 60 * 60, True) + self.retry() + + elif check == "not_found": + self.fail(_("Server error - file not downloadable")) diff --git a/pyload/plugin/hoster/UloziskoSk.py b/pyload/plugin/hoster/UloziskoSk.py new file mode 100644 index 000000000..ce40c9f7a --- /dev/null +++ b/pyload/plugin/hoster/UloziskoSk.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class UloziskoSk(SimpleHoster): + __name__ = "UloziskoSk" + __type__ = "hoster" + __version__ = "0.25" + + __pattern__ = r'http://(?:www\.)?ulozisko\.sk/.+' + + __description__ = """Ulozisko.sk hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<div class="down1">(?P<N>[^<]+)</div>' + SIZE_PATTERN = ur'VeÄŸkosÅ¥ súboru: <strong>(?P<S>[\d.,]+) (?P<U>[\w^_]+)</strong><br />' + OFFLINE_PATTERN = ur'<span class = "red">ZadanÃœ súbor neexistuje z jedného z nasledujúcich dÃŽvodov:</span>' + + LINK_FREE_PATTERN = r'<form name = "formular" action = "([^"]+)" method = "post">' + ID_PATTERN = r'<input type = "hidden" name = "id" value = "([^"]+)" />' + CAPTCHA_PATTERN = r'<img src="(/obrazky/obrazky\.php\?fid=[^"]+)" alt="" />' + IMG_PATTERN = ur'<strong>PRE ZVÃÄÅ ENIE KLIKNITE NA OBRÃZOK</strong><br /><a href = "([^"]+)">' + + + def process(self, pyfile): + self.html = self.load(pyfile.url, decode=True) + self.getFileInfo() + + m = re.search(self.IMG_PATTERN, self.html) + if m: + url = "http://ulozisko.sk" + m.group(1) + self.download(url) + else: + self.handleFree(pyfile) + + + def handleFree(self, pyfile): + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("LINK_FREE_PATTERN not found")) + parsed_url = 'http://www.ulozisko.sk' + m.group(1) + + m = re.search(self.ID_PATTERN, self.html) + if m is None: + self.error(_("ID_PATTERN not found")) + id = m.group(1) + + self.logDebug("URL:" + parsed_url + ' ID:' + id) + + m = re.search(self.CAPTCHA_PATTERN, self.html) + if m is None: + self.error(_("CAPTCHA_PATTERN not found")) + captcha_url = 'http://www.ulozisko.sk' + m.group(1) + + captcha = self.decryptCaptcha(captcha_url, cookies=True) + + self.logDebug("CAPTCHA_URL:" + captcha_url + ' CAPTCHA:' + captcha) + + self.download(parsed_url, + post={"antispam": captcha, + "id" : id, + "name" : pyfile.name, + "but" : "++++STIAHNI+S%DABOR++++"}) diff --git a/pyload/plugin/hoster/UnibytesCom.py b/pyload/plugin/hoster/UnibytesCom.py new file mode 100644 index 000000000..2c9b9ca5f --- /dev/null +++ b/pyload/plugin/hoster/UnibytesCom.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urljoin + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class UnibytesCom(SimpleHoster): + __name__ = "UnibytesCom" + __type__ = "hoster" + __version__ = "0.12" + + __pattern__ = r'https?://(?:www\.)?unibytes\.com/[\w .-]{11}B' + + __description__ = """UniBytes.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + HOSTER_DOMAIN = "unibytes.com" + + INFO_PATTERN = r'<span[^>]*?id="fileName"[^>]*>(?P<N>[^>]+)</span>\s*\((?P<S>\d.*?)\)' + + WAIT_PATTERN = r'Wait for <span id="slowRest">(\d+)</span> sec' + LINK_FREE_PATTERN = r'<a href="([^"]+)">Download</a>' + + + def handleFree(self, pyfile): + domain = "http://www.%s/" % self.HOSTER_DOMAIN + action, post_data = self.parseHtmlForm('id="startForm"') + + + for _i in xrange(8): + self.logDebug(action, post_data) + self.html = self.load(urljoin(domain, action), post=post_data, follow_location=False) + + m = re.search(r'location:\s*(\S+)', self.req.http.header, re.I) + if m: + url = m.group(1) + break + + if '>Somebody else is already downloading using your IP-address<' in self.html: + self.wait(10 * 60, True) + self.retry() + + if post_data['step'] == 'last': + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m: + url = m.group(1) + self.correctCaptcha() + break + else: + self.invalidCaptcha() + + last_step = post_data['step'] + action, post_data = self.parseHtmlForm('id="stepForm"') + + if last_step == 'timer': + m = re.search(self.WAIT_PATTERN, self.html) + self.wait(m.group(1) if m else 60, False) + + elif last_step in ("captcha", "last"): + post_data['captcha'] = self.decryptCaptcha(urljoin(domain, "/captcha.jpg")) + + else: + self.fail(_("No valid captcha code entered")) + + self.download(url) diff --git a/pyload/plugin/hoster/UnrestrictLi.py b/pyload/plugin/hoster/UnrestrictLi.py new file mode 100644 index 000000000..c81bb0554 --- /dev/null +++ b/pyload/plugin/hoster/UnrestrictLi.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.utils import json_loads +from pyload.plugin.internal.MultiHoster import MultiHoster +from pyload.plugin.internal.SimpleHoster import secondsToMidnight + + +class UnrestrictLi(MultiHoster): + __name__ = "UnrestrictLi" + __type__ = "hoster" + __version__ = "0.21" + + __pattern__ = r'https?://(?:www\.)?(unrestrict|unr)\.li/dl/[\w^_]+' + + __description__ = """Unrestrict.li multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + LOGIN_ACCOUNT = False + + + def setup(self): + self.chunkLimit = 16 + self.resumeDownload = True + + + def handleFree(self, pyfile): + for _i in xrange(5): + self.html = self.load('https://unrestrict.li/unrestrict.php', + post={'link': pyfile.url, 'domain': 'long'}) + + self.logDebug("JSON data: " + self.html) + + if self.html: + break + else: + self.logInfo(_("Unable to get API data, waiting 1 minute and retry")) + self.retry(5, 60, "Unable to get API data") + + if 'Expired session' in self.html \ + or ("You are not allowed to download from this host" in self.html and self.premium): + self.account.relogin(self.user) + self.retry() + + elif "File offline" in self.html: + self.offline() + + elif "You are not allowed to download from this host" in self.html: + self.fail(_("You are not allowed to download from this host")) + + elif "You have reached your daily limit for this host" in self.html: + self.logWarning(_("Reached daily limit for this host")) + self.retry(5, secondsToMidnight(gmt=2), "Daily limit for this host reached") + + elif "ERROR_HOSTER_TEMPORARILY_UNAVAILABLE" in self.html: + self.logInfo(_("Hoster temporarily unavailable, waiting 1 minute and retry")) + self.retry(5, 60, "Hoster is temporarily unavailable") + + self.html = json_loads(self.html) + self.link = self.html.keys()[0] + self.api_data = self.html[self.link] + + if hasattr(self, 'api_data'): + self.setNameSize() + + + def checkFile(self): + super(UnrestrictLi, self).checkFile() + + if self.getConfig("history"): + self.load("https://unrestrict.li/history/", get={'delete': "all"}) + self.logInfo(_("Download history deleted")) + + + def setNameSize(self): + if 'name' in self.api_data: + self.pyfile.name = self.api_data['name'] + if 'size' in self.api_data: + self.pyfile.size = self.api_data['size'] diff --git a/pyload/plugin/hoster/UpleaCom.py b/pyload/plugin/hoster/UpleaCom.py new file mode 100644 index 000000000..855d9ed65 --- /dev/null +++ b/pyload/plugin/hoster/UpleaCom.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urljoin + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class UpleaCom(XFSHoster): + __name__ = "UpleaCom" + __type__ = "hoster" + __version__ = "0.06" + + __pattern__ = r'https?://(?:www\.)?uplea\.com/dl/\w{15}' + + __description__ = """Uplea.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Redleon", "")] + + + NAME_PATTERN = r'class="agmd size18">(?P<N>.+?)<' + SIZE_PATTERN = r'size14">(?P<S>[\d.,]+) (?P<U>[\w^_])</span>' + + OFFLINE_PATTERN = r'>You followed an invalid or expired link' + + LINK_PATTERN = r'"(http?://\w+\.uplea\.com/anonym/.*?)"' + + WAIT_PATTERN = r'timeText:([\d.]+),' + STEP_PATTERN = r'<a href="(/step/.+)">' + + + def setup(self): + self.multiDL = False + self.chunkLimit = 1 + self.resumeDownload = True + + + def handleFree(self, pyfile): + m = re.search(self.STEP_PATTERN, self.html) + if m is None: + self.error(_("STEP_PATTERN not found")) + + self.html = self.load(urljoin("http://uplea.com/", m.group(1))) + + m = re.search(self.WAIT_PATTERN, self.html) + if m: + self.wait(m.group(1), True) + self.retry() + + m = re.search(self.LINK_PATTERN, self.html) + if m is None: + self.error(_("LINK_PATTERN not found")) + + self.link = m.group(1) + self.wait(15) diff --git a/pyload/plugin/hoster/UploadStationCom.py b/pyload/plugin/hoster/UploadStationCom.py new file mode 100644 index 000000000..d77bdb760 --- /dev/null +++ b/pyload/plugin/hoster/UploadStationCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class UploadStationCom(DeadHoster): + __name__ = "UploadStationCom" + __type__ = "hoster" + __version__ = "0.52" + + __pattern__ = r'http://(?:www\.)?uploadstation\.com/file/(?P<ID>\w+)' + + __description__ = """UploadStation.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("fragonib", "fragonib[AT]yahoo[DOT]es"), + ("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/UploadableCh.py b/pyload/plugin/hoster/UploadableCh.py new file mode 100644 index 000000000..c54ecb495 --- /dev/null +++ b/pyload/plugin/hoster/UploadableCh.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +import re + +from time import sleep + +from pyload.plugin.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class UploadableCh(SimpleHoster): + __name__ = "UploadableCh" + __type__ = "hoster" + __version__ = "0.08" + + __pattern__ = r'http://(?:www\.)?uploadable\.ch/file/(?P<ID>\w+)' + + __description__ = """Uploadable.ch hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + URL_REPLACEMENTS = [(__pattern__ + ".*", r'http://www.uploadable.ch/file/\g<ID>')] + + INFO_PATTERN = r'div id=\"file_name\" title=.*>(?P<N>.+)<span class=\"filename_normal\">\((?P<S>[\d.]+) (?P<U>\w+)\)</span><' + + OFFLINE_PATTERN = r'>(File not available|This file is no longer available)' + TEMP_OFFLINE_PATTERN = r'<div class="icon_err">' + + WAIT_PATTERN = r'>Please wait.+?<' + + RECAPTCHA_KEY = "6LdlJuwSAAAAAPJbPIoUhyqOJd7-yrah5Nhim5S3" + + + def handleFree(self, pyfile): + # Click the "free user" button and wait + a = self.load(pyfile.url, cookies=True, post={'downloadLink': "wait"}, decode=True) + self.logDebug(a) + + self.wait(30) + + # Make the recaptcha appear and show it the pyload interface + b = self.load(pyfile.url, cookies=True, post={'checkDownload': "check"}, decode=True) + self.logDebug(b) #: Expected output: {"success":"showCaptcha"} + + recaptcha = ReCaptcha(self) + + response, challenge = recaptcha.challenge(self.RECAPTCHA_KEY) + + # Submit the captcha solution + self.load("http://www.uploadable.ch/checkReCaptcha.php", + cookies=True, + post={'recaptcha_challenge_field' : challenge, + 'recaptcha_response_field' : response, + 'recaptcha_shortencode_field': self.info['pattern']['ID']}, + decode=True) + + self.wait(3) + + # Get ready for downloading + self.load(pyfile.url, cookies=True, post={'downloadLink': "show"}, decode=True) + + self.wait(3) + + # Download the file + self.download(pyfile.url, cookies=True, post={'download': "normal"}, disposition=True) + + + def checkFile(self): + if self.checkDownload({'wait': re.compile("Please wait for")}): + self.logInfo("Downloadlimit reached, please wait or reconnect") + self.wait(60 * 60, True) + self.retry() + + return super(UploadableCh, self).checkFile() diff --git a/pyload/plugin/hoster/UploadboxCom.py b/pyload/plugin/hoster/UploadboxCom.py new file mode 100644 index 000000000..01e4c6854 --- /dev/null +++ b/pyload/plugin/hoster/UploadboxCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class UploadboxCom(DeadHoster): + __name__ = "Uploadbox" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'http://(?:www\.)?uploadbox\.com/files/.+' + + __description__ = """UploadBox.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/UploadedTo.py b/pyload/plugin/hoster/UploadedTo.py new file mode 100644 index 000000000..f9b121bfe --- /dev/null +++ b/pyload/plugin/hoster/UploadedTo.py @@ -0,0 +1,117 @@ +# -*- coding: utf-8 -*- + +import re + +from time import sleep + +from pyload.network.RequestFactory import getURL +from pyload.plugin.internal.CaptchaService import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class UploadedTo(SimpleHoster): + __name__ = "UploadedTo" + __type__ = "hoster" + __version__ = "0.84" + + __pattern__ = r'https?://(?:www\.)?(uploaded\.(to|net)|ul\.to)(/file/|/?\?id=|.*?&id=|/)(?P<ID>\w+)' + + __description__ = """Uploaded.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + API_KEY = "lhF2IeeprweDfu9ccWlxXVVypA5nA3EL" + + URL_REPLACEMENTS = [(__pattern__ + ".*", r'http://uploaded.net/file/\g<ID>')] + + LINK_PREMIUM_PATTERN = r'<div class="tfree".*\s*<form method="post" action="(.+?)"' + + WAIT_PATTERN = r'Current waiting period: <span>(\d+)' + DL_LIMIT_ERROR = r'You have reached the max. number of possible free downloads for this hour' + + + @classmethod + def apiInfo(cls, url="", get={}, post={}): + info = super(UploadedTo, cls).apiInfo(url) + + for _i in xrange(5): + html = getURL("http://uploaded.net/api/filemultiple", + get={"apikey": cls.API_KEY, 'id_0': re.match(cls.__pattern__, url).group('ID')}, + decode=True) + + if html != "can't find request": + api = html.split(",", 4) + if api[0] == "online": + info.update({'name': api[4].strip(), 'size': api[2], 'status': 2}) + else: + info['status'] = 1 + break + else: + sleep(3) + + return info + + + def setup(self): + self.multiDL = self.resumeDownload = self.premium + self.chunkLimit = 1 # critical problems with more chunks + + + def checkErrors(self): + if 'var free_enabled = false;' in self.html: + self.logError(_("Free-download capacities exhausted")) + self.retry(24, 5 * 60) + + elif "limit-size" in self.html: + self.fail(_("File too big for free download")) + + elif "limit-slot" in self.html: # Temporary restriction so just wait a bit + self.wait(30 * 60, True) + self.retry() + + elif "limit-parallel" in self.html: + self.fail(_("Cannot download in parallel")) + + elif "limit-dl" in self.html or self.DL_LIMIT_ERROR in self.html: # limit-dl + self.wait(3 * 60 * 60, True) + self.retry() + + elif '"err":"captcha"' in self.html: + self.invalidCaptcha() + + else: + m = re.search(self.WAIT_PATTERN, self.html) + if m: + self.wait(m.group(1)) + + + def handleFree(self, pyfile): + self.load("http://uploaded.net/language/en", just_header=True) + + self.html = self.load("http://uploaded.net/js/download.js", decode=True) + + recaptcha = ReCaptcha(self) + response, challenge = recaptcha.challenge() + + self.html = self.load("http://uploaded.net/io/ticket/captcha/%s" % self.info['pattern']['ID'], + post={'recaptcha_challenge_field': challenge, + 'recaptcha_response_field' : response}) + + if "type:'download'" in self.html: + self.correctCaptcha() + try: + self.link = re.search("url:'([^']+)", self.html).group(1) + + except Exception: + pass + + self.checkErrors() + + + def checkFile(self): + if self.checkDownload({'limit-dl': self.DL_LIMIT_ERROR}): + self.wait(3 * 60 * 60, True) + self.retry() + + return super(UploadedTo, self).checkFile() diff --git a/pyload/plugin/hoster/UploadhereCom.py b/pyload/plugin/hoster/UploadhereCom.py new file mode 100644 index 000000000..77970a97b --- /dev/null +++ b/pyload/plugin/hoster/UploadhereCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class UploadhereCom(DeadHoster): + __name__ = "UploadhereCom" + __type__ = "hoster" + __version__ = "0.12" + + __pattern__ = r'http://(?:www\.)?uploadhere\.com/\w{10}' + + __description__ = """Uploadhere.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/UploadheroCom.py b/pyload/plugin/hoster/UploadheroCom.py new file mode 100644 index 000000000..917053f18 --- /dev/null +++ b/pyload/plugin/hoster/UploadheroCom.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# http://uploadhero.co/dl/wQBRAVSM + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class UploadheroCom(SimpleHoster): + __name__ = "UploadheroCom" + __type__ = "hoster" + __version__ = "0.17" + + __pattern__ = r'http://(?:www\.)?uploadhero\.com?/dl/\w+' + + __description__ = """UploadHero.co plugin""" + __license__ = "GPLv3" + __authors__ = [("mcmyst", "mcmyst@hotmail.fr"), + ("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'<div class="nom_de_fichier">(?P<N>.*?)</div>' + SIZE_PATTERN = r'Taille du fichier : </span><strong>(?P<S>.*?)</strong>' + OFFLINE_PATTERN = r'<p class="titre_dl_2">|<div class="raison"><strong>Le lien du fichier ci-dessus n\'existe plus.' + + COOKIES = [("uploadhero.co", "lang", "en")] + + IP_BLOCKED_PATTERN = r'href="(/lightbox_block_download\.php\?min=.*?)"' + IP_WAIT_PATTERN = r'<span id="minutes">(\d+)</span>.*\s*<span id="seconds">(\d+)</span>' + + CAPTCHA_PATTERN = r'"(/captchadl\.php\?\w+)"' + + LINK_FREE_PATTERN = r'var magicomfg = \'<a href="(http://[^<>"]*?)"|"(http://storage\d+\.uploadhero\.co/\?d=\w+/[^<>"/]+)"' + LINK_PREMIUM_PATTERN = r'<a href="([^"]+)" id="downloadnow"' + + + def handleFree(self, pyfile): + self.checkErrors() + + m = re.search(self.CAPTCHA_PATTERN, self.html) + if m is None: + self.error(_("CAPTCHA_PATTERN not found")) + captcha_url = "http://uploadhero.co" + m.group(1) + + for _i in xrange(5): + captcha = self.decryptCaptcha(captcha_url) + self.html = self.load(pyfile.url, get={"code": captcha}) + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m: + self.correctCaptcha() + download_url = m.group(1) or m.group(2) + break + else: + self.invalidCaptcha() + else: + self.fail(_("No valid captcha code entered")) + + self.download(download_url) + + + def checkErrors(self): + m = re.search(self.IP_BLOCKED_PATTERN, self.html) + if m: + self.html = self.load("http://uploadhero.co%s" % m.group(1)) + + m = re.search(self.IP_WAIT_PATTERN, self.html) + wait_time = (int(m.group(1)) * 60 + int(m.group(2))) if m else 5 * 60 + self.wait(wait_time, True) + self.retry() + + self.info.pop('error', None) diff --git a/pyload/plugin/hoster/UploadingCom.py b/pyload/plugin/hoster/UploadingCom.py new file mode 100644 index 000000000..461b0113a --- /dev/null +++ b/pyload/plugin/hoster/UploadingCom.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- + +import re + +from pycurl import HTTPHEADER + +from pyload.utils import json_loads +from pyload.plugin.internal.SimpleHoster import SimpleHoster, timestamp + + +class UploadingCom(SimpleHoster): + __name__ = "UploadingCom" + __type__ = "hoster" + __version__ = "0.40" + + __pattern__ = r'http://(?:www\.)?uploading\.com/files/(?:get/)?(?P<ID>\w+)' + + __description__ = """Uploading.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("jeix", "jeix@hasnomail.de"), + ("mkaay", "mkaay@mkaay.de"), + ("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'id="file_title">(?P<N>.+)</' + SIZE_PATTERN = r'size tip_container">(?P<S>[\d.,]+) (?P<U>[\w^_]+)<' + OFFLINE_PATTERN = r'(Page|file) not found' + + COOKIES = [("uploading.com", "lang", "1"), + (".uploading.com", "language", "1"), + (".uploading.com", "setlang", "en"), + (".uploading.com", "_lang", "en")] + + + def process(self, pyfile): + if not "/get/" in pyfile.url: + pyfile.url = pyfile.url.replace("/files", "/files/get") + + self.html = self.load(pyfile.url, decode=True) + self.getFileInfo() + + if self.premium: + self.handlePremium(pyfile) + else: + self.handleFree(pyfile) + + + def handlePremium(self, pyfile): + postData = {'action': 'get_link', + 'code' : self.info['pattern']['ID'], + 'pass' : 'undefined'} + + self.html = self.load('http://uploading.com/files/get/?JsHttpRequest=%d-xml' % timestamp(), post=postData) + url = re.search(r'"link"\s*:\s*"(.*?)"', self.html) + if url: + url = url.group(1).replace("\\/", "/") + self.download(url) + + raise Exception("Plugin defect") + + + def handleFree(self, pyfile): + m = re.search('<h2>((Daily )?Download Limit)</h2>', self.html) + if m: + pyfile.error = m.group(1) + self.logWarning(pyfile.error) + self.retry(6, (6 * 60 if m.group(2) else 15) * 60, pyfile.error) + + ajax_url = "http://uploading.com/files/get/?ajax" + self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) + self.req.http.lastURL = pyfile.url + + res = json_loads(self.load(ajax_url, post={'action': 'second_page', 'code': self.info['pattern']['ID']})) + + if 'answer' in res and 'wait_time' in res['answer']: + wait_time = int(res['answer']['wait_time']) + self.logInfo(_("Waiting %d seconds") % wait_time) + self.wait(wait_time) + else: + self.error(_("No AJAX/WAIT")) + + res = json_loads(self.load(ajax_url, post={'action': 'get_link', 'code': self.info['pattern']['ID'], 'pass': 'false'})) + + if 'answer' in res and 'link' in res['answer']: + url = res['answer']['link'] + else: + self.error(_("No AJAX/URL")) + + self.html = self.load(url) + m = re.search(r'<form id="file_form" action="(.*?)"', self.html) + if m: + url = m.group(1) + else: + self.error(_("No URL")) + + self.download(url) diff --git a/pyload/plugin/hoster/UploadkingCom.py b/pyload/plugin/hoster/UploadkingCom.py new file mode 100644 index 000000000..6f4374096 --- /dev/null +++ b/pyload/plugin/hoster/UploadkingCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class UploadkingCom(DeadHoster): + __name__ = "UploadkingCom" + __type__ = "hoster" + __version__ = "0.14" + + __pattern__ = r'http://(?:www\.)?uploadking\.com/\w{10}' + + __description__ = """UploadKing.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] diff --git a/pyload/plugin/hoster/UpstoreNet.py b/pyload/plugin/hoster/UpstoreNet.py new file mode 100644 index 000000000..98e5c0d64 --- /dev/null +++ b/pyload/plugin/hoster/UpstoreNet.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.captcha import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class UpstoreNet(SimpleHoster): + __name__ = "UpstoreNet" + __type__ = "hoster" + __version__ = "0.05" + + __pattern__ = r'https?://(?:www\.)?upstore\.net/' + + __description__ = """Upstore.Net File Download Hoster""" + __license__ = "GPLv3" + __authors__ = [("igel", "igelkun@myopera.com")] + + + INFO_PATTERN = r'<div class="comment">.*?</div>\s*\n<h2 style="margin:0">(?P<N>.*?)</h2>\s*\n<div class="comment">\s*\n\s*(?P<S>[\d.,]+) (?P<U>[\w^_]+)' + OFFLINE_PATTERN = r'<span class="error">File not found</span>' + + WAIT_PATTERN = r'var sec = (\d+)' + CHASH_PATTERN = r'<input type="hidden" name="hash" value="([^"]*)">' + LINK_FREE_PATTERN = r'<a href="(https?://.*?)" target="_blank"><b>' + + + def handleFree(self, pyfile): + # STAGE 1: get link to continue + m = re.search(self.CHASH_PATTERN, self.html) + if m is None: + self.error(_("CHASH_PATTERN not found")) + chash = m.group(1) + self.logDebug("Read hash " + chash) + # continue to stage2 + post_data = {'hash': chash, 'free': 'Slow download'} + self.html = self.load(pyfile.url, post=post_data, decode=True) + + # STAGE 2: solv captcha and wait + # first get the infos we need: recaptcha key and wait time + recaptcha = ReCaptcha(self) + + # try the captcha 5 times + for i in xrange(5): + m = re.search(self.WAIT_PATTERN, self.html) + if m is None: + self.error(_("Wait pattern not found")) + wait_time = int(m.group(1)) + + # then, do the waiting + self.wait(wait_time) + + # then, handle the captcha + response, challenge = recaptcha.challenge() + post_data.update({'recaptcha_challenge_field': challenge, + 'recaptcha_response_field' : response}) + + self.html = self.load(pyfile.url, post=post_data, decode=True) + + # STAGE 3: get direct link + m = re.search(self.LINK_FREE_PATTERN, self.html, re.S) + if m: + break + + if m is None: + self.error(_("Download link not found")) + + self.link = m.group(1) diff --git a/pyload/plugin/hoster/UptoboxCom.py b/pyload/plugin/hoster/UptoboxCom.py new file mode 100644 index 000000000..da93b3c6b --- /dev/null +++ b/pyload/plugin/hoster/UptoboxCom.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class UptoboxCom(XFSHoster): + __name__ = "UptoboxCom" + __type__ = "hoster" + __version__ = "0.17" + + __pattern__ = r'https?://(?:www\.)?(uptobox|uptostream)\.com/\w{12}' + + __description__ = """Uptobox.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + INFO_PATTERN = r'"para_title">(?P<N>.+) \((?P<S>[\d.,]+) (?P<U>[\w^_]+)\)' + OFFLINE_PATTERN = r'>(File not found|Access Denied|404 Not Found)' + + LINK_PATTERN = r'"(https?://\w+\.uptobox\.com/d/.*?)"' + + ERROR_PATTERN = r'>(You have to wait.+till next download.)<' #@TODO: Check XFSHoster ERROR_PATTERN + + + def setup(self): + self.multiDL = True + self.chunkLimit = 1 + self.resumeDownload = True diff --git a/module/plugins/hoster/VeehdCom.py b/pyload/plugin/hoster/VeehdCom.py index 91d7cc443..91d7cc443 100644 --- a/module/plugins/hoster/VeehdCom.py +++ b/pyload/plugin/hoster/VeehdCom.py diff --git a/pyload/plugin/hoster/VeohCom.py b/pyload/plugin/hoster/VeohCom.py new file mode 100644 index 000000000..a4394736d --- /dev/null +++ b/pyload/plugin/hoster/VeohCom.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class VeohCom(SimpleHoster): + __name__ = "VeohCom" + __type__ = "hoster" + __version__ = "0.22" + + __pattern__ = r'http://(?:www\.)?veoh\.com/(tv/)?(watch|videos)/(?P<ID>v\w+)' + __config__ = [("quality", "Low;High;Auto", "Quality", "Auto")] + + __description__ = """Veoh.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + NAME_PATTERN = r'<meta name="title" content="(?P<N>.*?)"' + OFFLINE_PATTERN = r'>Sorry, we couldn\'t find the video you were looking for' + + URL_REPLACEMENTS = [(__pattern__ + ".*", r'http://www.veoh.com/watch/\g<ID>')] + + COOKIES = [("veoh.com", "lassieLocale", "en")] + + + def setup(self): + self.resumeDownload = True + self.multiDL = True + self.chunkLimit = -1 + + + def handleFree(self, pyfile): + quality = self.getConfig("quality") + if quality == "Auto": + quality = ("High", "Low") + + for q in quality: + pattern = r'"fullPreviewHash%sPath":"(.+?)"' % q + m = re.search(pattern, self.html) + if m: + pyfile.name += ".mp4" + link = m.group(1).replace("\\", "") + self.download(link) + return + else: + self.logInfo(_("No %s quality video found") % q.upper()) + else: + self.fail(_("No video found!")) diff --git a/pyload/plugin/hoster/VidPlayNet.py b/pyload/plugin/hoster/VidPlayNet.py new file mode 100644 index 000000000..094da09bd --- /dev/null +++ b/pyload/plugin/hoster/VidPlayNet.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# +# Test links: +# BigBuckBunny_320x180.mp4 - 61.7 Mb - http://vidplay.net/38lkev0h3jv0 + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class VidPlayNet(XFSHoster): + __name__ = "VidPlayNet" + __type__ = "hoster" + __version__ = "0.04" + + __pattern__ = r'https?://(?:www\.)?vidplay\.net/\w{12}' + + __description__ = """VidPlay.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("t4skforce", "t4skforce1337[AT]gmail[DOT]com")] + + + NAME_PATTERN = r'<b>Password:</b></div>\s*<h[1-6]>(?P<N>[^<]+)</h[1-6]>' diff --git a/pyload/plugin/hoster/VimeoCom.py b/pyload/plugin/hoster/VimeoCom.py new file mode 100644 index 000000000..c48ad3414 --- /dev/null +++ b/pyload/plugin/hoster/VimeoCom.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class VimeoCom(SimpleHoster): + __name__ = "VimeoCom" + __type__ = "hoster" + __version__ = "0.04" + + __pattern__ = r'https?://(?:www\.)?(player\.)?vimeo\.com/(video/)?(?P<ID>\d+)' + __config__ = [("quality", "Lowest;Mobile;SD;HD;Highest", "Quality", "Highest"), + ("original", "bool", "Try to download the original file first", True)] + + __description__ = """Vimeo.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + NAME_PATTERN = r'<title>(?P<N>.+) on Vimeo<' + OFFLINE_PATTERN = r'class="exception_header"' + TEMP_OFFLINE_PATTERN = r'Please try again in a few minutes.<' + + URL_REPLACEMENTS = [(__pattern__ + ".*", r'https://www.vimeo.com/\g<ID>')] + + COOKIES = [("vimeo.com", "language", "en")] + + + def setup(self): + self.resumeDownload = True + self.multiDL = True + self.chunkLimit = -1 + + + def handleFree(self, pyfile): + password = self.getPassword() + + if self.js and 'class="btn iconify_down_b"' in self.html: + html = self.js.eval(self.load(pyfile.url, get={'action': "download", 'password': password}, decode=True)) + pattern = r'href="(?P<URL>http://vimeo\.com.+?)".*?\>(?P<QL>.+?) ' + else: + html = self.load("https://player.vimeo.com/video/" + self.info['pattern']['ID'], get={'password': password}) + pattern = r'"(?P<QL>\w+)":{"profile".*?"(?P<URL>http://pdl\.vimeocdn\.com.+?)"' + + link = dict((l.group('QL').lower(), l.group('URL')) for l in re.finditer(pattern, html)) + + if self.getConfig("original"): + if "original" in link: + self.download(link[q]) + return + else: + self.logInfo(_("Original file not downloadable")) + + quality = self.getConfig("quality") + if quality == "Highest": + qlevel = ("hd", "sd", "mobile") + elif quality == "Lowest": + qlevel = ("mobile", "sd", "hd") + else: + qlevel = quality.lower() + + for q in qlevel: + if q in link: + self.download(link[q]) + return + else: + self.logInfo(_("No %s quality video found") % q.upper()) + else: + self.fail(_("No video found!")) diff --git a/pyload/plugin/hoster/Vipleech4UCom.py b/pyload/plugin/hoster/Vipleech4UCom.py new file mode 100644 index 000000000..100def197 --- /dev/null +++ b/pyload/plugin/hoster/Vipleech4UCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class Vipleech4UCom(DeadHoster): + __name__ = "Vipleech4UCom" + __type__ = "hoster" + __version__ = "0.20" + + __pattern__ = r'http://(?:www\.)?vipleech4u\.com/manager\.php' + + __description__ = """Vipleech4u.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Kagenoshin", "kagenoshin@gmx.ch")] diff --git a/pyload/plugin/hoster/WarserverCz.py b/pyload/plugin/hoster/WarserverCz.py new file mode 100644 index 000000000..d44b751f9 --- /dev/null +++ b/pyload/plugin/hoster/WarserverCz.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class WarserverCz(DeadHoster): + __name__ = "WarserverCz" + __type__ = "hoster" + __version__ = "0.13" + + __pattern__ = r'http://(?:www\.)?warserver\.cz/stahnout/\d+' + + __description__ = """Warserver.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] diff --git a/pyload/plugin/hoster/WebshareCz.py b/pyload/plugin/hoster/WebshareCz.py new file mode 100644 index 000000000..58c9c6a44 --- /dev/null +++ b/pyload/plugin/hoster/WebshareCz.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.network.RequestFactory import getURL +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class WebshareCz(SimpleHoster): + __name__ = "WebshareCz" + __type__ = "hoster" + __version__ = "0.16" + + __pattern__ = r'https?://(?:www\.)?webshare\.cz/(?:#/)?file/(?P<ID>\w+)' + + __description__ = """WebShare.cz hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it"), + ("rush", "radek.senfeld@gmail.com")] + + + @classmethod + def getInfo(cls, url="", html=""): + info = super(WebshareCz, cls).getInfo(url, html) + + if url: + info['pattern'] = re.match(cls.__pattern__, url).groupdict() + + api_data = getURL("https://webshare.cz/api/file_info/", + post={'ident': info['pattern']['ID']}, + decode=True) + + if 'File not found' in api_data: + info['status'] = 1 + else: + info["status"] = 2 + info['name'] = re.search('<name>(.+)</name>', api_data).group(1) or info['name'] + info['size'] = re.search('<size>(.+)</size>', api_data).group(1) or info['size'] + + return info + + + def handleFree(self, pyfile): + wst = self.account.infos['wst'] if self.account and 'wst' in self.account.infos else "" + + api_data = getURL('https://webshare.cz/api/file_link/', + post={'ident': self.info['pattern']['ID'], 'wst': wst}, + decode=True) + + self.logDebug("API data: " + api_data) + + m = re.search('<link>(.+)</link>', api_data) + if m is None: + self.error(_("Unable to detect direct link")) + + self.link = m.group(1) + + + def handlePremium(self, pyfile): + return self.handleFree(pyfile) diff --git a/pyload/plugin/hoster/WrzucTo.py b/pyload/plugin/hoster/WrzucTo.py new file mode 100644 index 000000000..de78d7af2 --- /dev/null +++ b/pyload/plugin/hoster/WrzucTo.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +import re + +from pycurl import HTTPHEADER + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class WrzucTo(SimpleHoster): + __name__ = "WrzucTo" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?wrzuc\.to/(\w+(\.wt|\.html)|(\w+/?linki/\w+))' + + __description__ = """Wrzuc.to hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'id="file_info">\s*<strong>(?P<N>.*?)</strong>' + SIZE_PATTERN = r'class="info">\s*<tr>\s*<td>(?P<S>.*?)</td>' + + COOKIES = [("wrzuc.to", "language", "en")] + + + def setup(self): + self.multiDL = True + + + def handleFree(self, pyfile): + data = dict(re.findall(r'(md5|file): "(.*?)"', self.html)) + if len(data) != 2: + self.error(_("No file ID")) + + self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) + self.req.http.lastURL = pyfile.url + self.load("http://www.wrzuc.to/ajax/server/prepair", post={"md5": data['md5']}) + + self.req.http.lastURL = pyfile.url + self.html = self.load("http://www.wrzuc.to/ajax/server/download_link", post={"file": data['file']}) + + data.update(re.findall(r'"(download_link|server_id)":"(.*?)"', self.html)) + if len(data) != 4: + self.error(_("No download URL")) + + download_url = "http://%s.wrzuc.to/pobierz/%s" % (data['server_id'], data['download_link']) + self.download(download_url) diff --git a/pyload/plugin/hoster/WuploadCom.py b/pyload/plugin/hoster/WuploadCom.py new file mode 100644 index 000000000..729db1d4d --- /dev/null +++ b/pyload/plugin/hoster/WuploadCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class WuploadCom(DeadHoster): + __name__ = "WuploadCom" + __type__ = "hoster" + __version__ = "0.23" + + __pattern__ = r'http://(?:www\.)?wupload\..+?/file/((\w+/)?\d+)(/.*)?' + + __description__ = """Wupload.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("jeix", "jeix@hasnomail.de"), + ("Paul King", "")] diff --git a/pyload/plugin/hoster/X7To.py b/pyload/plugin/hoster/X7To.py new file mode 100644 index 000000000..ac01bc5ff --- /dev/null +++ b/pyload/plugin/hoster/X7To.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class X7To(DeadHoster): + __name__ = "X7To" + __type__ = "hoster" + __version__ = "0.41" + + __pattern__ = r'http://(?:www\.)?x7\.to/' + + __description__ = """X7.to hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("ernieb", "ernieb")] diff --git a/pyload/plugin/hoster/XFileSharingPro.py b/pyload/plugin/hoster/XFileSharingPro.py new file mode 100644 index 000000000..8b9f7fcfa --- /dev/null +++ b/pyload/plugin/hoster/XFileSharingPro.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.XFSHoster import XFSHoster + + +class XFileSharingPro(XFSHoster): + __name__ = "XFileSharingPro" + __type__ = "hoster" + __version__ = "0.44" + + __pattern__ = r'^unmatchable$' + + __description__ = """XFileSharingPro dummy hoster plugin for hook""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + URL_REPLACEMENTS = [("/embed-", "/")] + + + def _log(self, type, args): + msg = " | ".join(str(a).strip() for a in args if a) + logger = getattr(self.log, type) + logger("%s: %s: %s" % (self.__name__, self.HOSTER_NAME, msg or _("%s MARK" % type.upper()))) + + + def init(self): + super(XFileSharingPro, self).init() + + self.__pattern__ = self.core.pluginManager.hosterPlugins[self.__name__]['pattern'] + + self.HOSTER_DOMAIN = re.match(self.__pattern__, self.pyfile.url).group("DOMAIN").lower() + self.HOSTER_NAME = "".join(part.capitalize() for part in re.split(r'(\.|\d+)', self.HOSTER_DOMAIN) if part != '.') + + if self.HOSTER_NAME[0].isdigit(): + self.HOSTER_NAME = 'X' + self.HOSTER_NAME + + account = self.core.accountManager.getAccountPlugin(self.HOSTER_NAME) + + if account and account.canUse(): + self.account = account + + elif self.account: + self.account.HOSTER_DOMAIN = self.HOSTER_DOMAIN + + else: + return + + self.user, data = self.account.selectAccount() + self.req = self.account.getAccountRequest(self.user) + self.premium = self.account.isPremium(self.user) + + + def setup(self): + self.chunkLimit = 1 + self.resumeDownload = self.premium + self.multiDL = True diff --git a/module/plugins/hoster/XHamsterCom.py b/pyload/plugin/hoster/XHamsterCom.py index 92340152f..92340152f 100644 --- a/module/plugins/hoster/XHamsterCom.py +++ b/pyload/plugin/hoster/XHamsterCom.py diff --git a/module/plugins/hoster/XVideosCom.py b/pyload/plugin/hoster/XVideosCom.py index c5e2921cb..c5e2921cb 100644 --- a/module/plugins/hoster/XVideosCom.py +++ b/pyload/plugin/hoster/XVideosCom.py diff --git a/pyload/plugin/hoster/XdadevelopersCom.py b/pyload/plugin/hoster/XdadevelopersCom.py new file mode 100644 index 000000000..386973a94 --- /dev/null +++ b/pyload/plugin/hoster/XdadevelopersCom.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -* +# +# Test links: +# http://forum.xda-developers.com/devdb/project/dl/?id=10885 + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class XdadevelopersCom(SimpleHoster): + __name__ = "XdadevelopersCom" + __type__ = "hoster" + __version__ = "0.03" + + __pattern__ = r'https?://(?:www\.)?forum\.xda-developers\.com/devdb/project/dl/\?id=\d+' + + __description__ = """Xda-developers.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] + + + NAME_PATTERN = r'<label>Filename:</label>\s*<div>\s*(?P<N>.*?)\n' + SIZE_PATTERN = r'<label>Size:</label>\s*<div>\s*(?P<S>[\d.,]+)(?P<U>[\w^_]+)' + OFFLINE_PATTERN = r'</i> Device Filter</h3>' + + + def setup(self): + self.multiDL = True + self.resumeDownload = True + self.chunkLimit = 1 + + + def handleFree(self, pyfile): + self.link = pyfile.url + "&task=get" #@TODO: Revert to `get={'task': "get"}` in 0.4.10 diff --git a/module/plugins/hoster/Xdcc.py b/pyload/plugin/hoster/Xdcc.py index 277b7ad0c..277b7ad0c 100644 --- a/module/plugins/hoster/Xdcc.py +++ b/pyload/plugin/hoster/Xdcc.py diff --git a/pyload/plugin/hoster/YibaishiwuCom.py b/pyload/plugin/hoster/YibaishiwuCom.py new file mode 100644 index 000000000..a53acdaf5 --- /dev/null +++ b/pyload/plugin/hoster/YibaishiwuCom.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.utils import json_loads +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class YibaishiwuCom(SimpleHoster): + __name__ = "YibaishiwuCom" + __type__ = "hoster" + __version__ = "0.14" + + __pattern__ = r'http://(?:www\.)?(?:u\.)?115\.com/file/(?P<ID>\w+)' + + __description__ = """115.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + NAME_PATTERN = r'file_name: \'(?P<N>.+?)\'' + SIZE_PATTERN = r'file_size: \'(?P<S>.+?)\'' + OFFLINE_PATTERN = ur'<h3><i style="color:red;">ååïŒæåç äžååšïŒäžåŠšææçå§ïŒ</i></h3>' + + LINK_FREE_PATTERN = r'(/\?ct=(pickcode|download)[^"\']+)' + + + def handleFree(self, pyfile): + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("LINK_FREE_PATTERN not found")) + + url = m.group(1) + + self.logDebug(('FREEUSER' if m.group(2) == 'download' else 'GUEST') + ' URL', url) + + res = json_loads(self.load("http://115.com" + url, decode=False)) + if "urls" in res: + mirrors = res['urls'] + + elif "data" in res: + mirrors = res['data'] + + else: + mirrors = None + + for mr in mirrors: + try: + url = mr['url'].replace("\\", "") + self.logDebug("Trying URL: " + url) + self.download(url) + break + except Exception: + continue + else: + self.fail(_("No working link found")) diff --git a/module/plugins/hoster/YoupornCom.py b/pyload/plugin/hoster/YoupornCom.py index 75606935d..75606935d 100644 --- a/module/plugins/hoster/YoupornCom.py +++ b/pyload/plugin/hoster/YoupornCom.py diff --git a/module/plugins/hoster/YourfilesTo.py b/pyload/plugin/hoster/YourfilesTo.py index a600d822f..a600d822f 100644 --- a/module/plugins/hoster/YourfilesTo.py +++ b/pyload/plugin/hoster/YourfilesTo.py diff --git a/module/plugins/hoster/YoutubeCom.py b/pyload/plugin/hoster/YoutubeCom.py index bf8785022..bf8785022 100644 --- a/module/plugins/hoster/YoutubeCom.py +++ b/pyload/plugin/hoster/YoutubeCom.py diff --git a/module/plugins/hoster/ZDF.py b/pyload/plugin/hoster/ZDF.py index da6d6448e..da6d6448e 100644 --- a/module/plugins/hoster/ZDF.py +++ b/pyload/plugin/hoster/ZDF.py diff --git a/pyload/plugin/hoster/ZShareNet.py b/pyload/plugin/hoster/ZShareNet.py new file mode 100644 index 000000000..12c65b206 --- /dev/null +++ b/pyload/plugin/hoster/ZShareNet.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.DeadHoster import DeadHoster + + +class ZShareNet(DeadHoster): + __name__ = "ZShareNet" + __type__ = "hoster" + __version__ = "0.21" + + __pattern__ = r'https?://(?:ww[2w]\.)?zshares?\.net/.+' + + __description__ = """ZShare.net hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("espes", ""), + ("Cptn Sandwich", "")] diff --git a/pyload/plugin/hoster/ZeveraCom.py b/pyload/plugin/hoster/ZeveraCom.py new file mode 100644 index 000000000..264a62a7d --- /dev/null +++ b/pyload/plugin/hoster/ZeveraCom.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urljoin + +from pyload.plugin.internal.MultiHoster import MultiHoster + + +class ZeveraCom(MultiHoster): + __name__ = "ZeveraCom" + __type__ = "hoster" + __version__ = "0.28" + + __pattern__ = r'https?://(?:www\.)zevera\.com/(getFiles\.ashx|Members/download\.ashx)\?.*ourl=.+' + + __description__ = """Zevera.com multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + def handlePremium(self, pyfile): + self.link = "https://%s/getFiles.ashx?ourl=%s" % (self.account.HOSTER_DOMAIN, pyfile.url) + + + def checkFile(self): + if self.checkDownload({"error": 'action="ErrorDownload.aspx'}): + self.fail(_("Error response received")) + + return super(ZeveraCom, self).checkFile() diff --git a/pyload/plugin/hoster/ZippyshareCom.py b/pyload/plugin/hoster/ZippyshareCom.py new file mode 100644 index 000000000..0aa59fdaa --- /dev/null +++ b/pyload/plugin/hoster/ZippyshareCom.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.CaptchaService import ReCaptcha +from pyload.plugin.internal.SimpleHoster import SimpleHoster + + +class ZippyshareCom(SimpleHoster): + __name__ = "ZippyshareCom" + __type__ = "hoster" + __version__ = "0.72" + + __pattern__ = r'http://www\d{0,2}\.zippyshare\.com/v(/|iew\.jsp.*key=)(?P<KEY>[\w^_]+)' + + __description__ = """Zippyshare.com hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + COOKIES = [("zippyshare.com", "ziplocale", "en")] + + NAME_PATTERN = r'("\d{6,}/"[ ]*\+.+?"/|<title>Zippyshare.com - )(?P<N>.+?)("|</title>)' + SIZE_PATTERN = r'>Size:.+?">(?P<S>[\d.,]+) (?P<U>[\w^_]+)' + OFFLINE_PATTERN = r'>File does not exist on this server' + + LINK_PREMIUM_PATTERN = r'document.location = \'(.+?)\'' + + + def setup(self): + self.chunkLimit = -1 + self.multiDL = True + self.resumeDownload = True + + + def handleFree(self, pyfile): + recaptcha = ReCaptcha(self) + captcha_key = recaptcha.detect_key() + + if captcha_key: + try: + self.link = re.search(self.LINK_PREMIUM_PATTERN, self.html) + recaptcha.challenge() + + except Exception, e: + self.error(e) + + else: + self.link = '/'.join(("d", self.info['pattern']['KEY'], str(self.get_checksum()), self.pyfile.name)) + + + def get_checksum(self): + try: + n = 2 + b = int(re.search(r'var b = (\d+)', self.html).group(1)) + checksum = int("%d3" % (n + n * 2 + b)) + + except Exception: + self.error(_("Unable to calculate checksum")) + + else: + return checksum diff --git a/module/plugins/internal/__init__.py b/pyload/plugin/hoster/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/plugins/internal/__init__.py +++ b/pyload/plugin/hoster/__init__.py diff --git a/pyload/plugin/internal/BasePlugin.py b/pyload/plugin/internal/BasePlugin.py new file mode 100644 index 000000000..103e0d5cb --- /dev/null +++ b/pyload/plugin/internal/BasePlugin.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- + +import re + +from urllib import unquote +from urlparse import urljoin, urlparse + +from pyload.network.HTTPRequest import BadHeader +from pyload.plugin.internal.SimpleHoster import fileUrl +from pyload.plugin.Hoster import Hoster + + +class BasePlugin(Hoster): + __name__ = "BasePlugin" + __type__ = "hoster" + __version__ = "0.34" + + __pattern__ = r'^unmatchable$' + + __description__ = """Base plugin when any other didnt fit""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + @classmethod + def getInfo(cls, url="", html=""): #@TODO: Move to hoster class in 0.4.10 + url = unquote(url) + url_p = urlparse(url) + return {'name' : (url_p.path.split('/')[-1] + or url_p.query.split('=', 1)[::-1][0].split('&', 1)[0] + or url_p.netloc.split('.', 1)[0]), + 'size' : 0, + 'status': 3 if url else 8, + 'url' : url} + + + def setup(self): + self.chunkLimit = -1 + self.multiDL = True + self.resumeDownload = True + + + def process(self, pyfile): + """main function""" + + pyfile.name = self.getInfo(pyfile.url)['name'] + + if not pyfile.url.startswith("http"): + self.fail(_("No plugin matched")) + + for _i in xrange(5): + try: + link = fileUrl(self, unquote(pyfile.url)) + + if link: + self.download(link, ref=False, disposition=True) + else: + self.fail(_("File not found")) + + except BadHeader, e: + if e.code is 404: + self.offline() + + elif e.code in (401, 403): + self.logDebug("Auth required", "Received HTTP status code: %d" % e.code) + + account = self.core.accountManager.getAccountPlugin('Http') + servers = [x['login'] for x in account.getAllAccounts()] + server = urlparse(pyfile.url).netloc + + if server in servers: + self.logDebug("Logging on to %s" % server) + self.req.addAuth(account.getAccountData(server)['password']) + else: + pwd = self.getPassword() + if ':' in pwd: + self.req.addAuth(pwd) + else: + self.fail(_("Authorization required")) + else: + self.fail(e) + else: + break + else: + self.fail(_("No file downloaded")) #@TODO: Move to hoster class in 0.4.10 + + check = self.checkDownload({'empty file': re.compile(r'\A\Z'), + 'html file' : re.compile(r'\A\s*<!DOCTYPE html'), + 'html error': re.compile(r'\A\s*(<.+>)?\d{3}(\Z|\s+)')}) + if check: + self.fail(check.capitalize()) diff --git a/pyload/plugin/internal/DeadCrypter.py b/pyload/plugin/internal/DeadCrypter.py new file mode 100644 index 000000000..ddeb0431d --- /dev/null +++ b/pyload/plugin/internal/DeadCrypter.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.Crypter import Crypter as _Crypter + + +class DeadCrypter(_Crypter): + __name__ = "DeadCrypter" + __type__ = "crypter" + __version__ = "0.04" + + __pattern__ = r'^unmatchable$' + + __description__ = """Crypter is no longer available""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + @classmethod + def apiInfo(cls, url="", get={}, post={}): + api = super(DeadCrypter, self).apiInfo(url, get, post) + api['status'] = 1 + return api + + + def setup(self): + self.pyfile.error = "Crypter is no longer available" + self.offline() #@TODO: self.offline("Crypter is no longer available") diff --git a/pyload/plugin/internal/DeadHoster.py b/pyload/plugin/internal/DeadHoster.py new file mode 100644 index 000000000..1596943ae --- /dev/null +++ b/pyload/plugin/internal/DeadHoster.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.Hoster import Hoster as _Hoster + + +class DeadHoster(_Hoster): + __name__ = "DeadHoster" + __type__ = "hoster" + __version__ = "0.14" + + __pattern__ = r'^unmatchable$' + + __description__ = """Hoster is no longer available""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + @classmethod + def apiInfo(cls, url="", get={}, post={}): + api = super(DeadHoster, self).apiInfo(url, get, post) + api['status'] = 1 + return api + + + def setup(self): + self.pyfile.error = "Hoster is no longer available" + self.offline() #@TODO: self.offline("Hoster is no longer available") diff --git a/pyload/plugin/internal/MultiHook.py b/pyload/plugin/internal/MultiHook.py new file mode 100644 index 000000000..2beccfcc5 --- /dev/null +++ b/pyload/plugin/internal/MultiHook.py @@ -0,0 +1,308 @@ +# -*- coding: utf-8 -*- + +import re + +from time import sleep + +from pyload.plugin.Hook import Hook +from pyload.utils import decode, remove_chars + + +class MultiHook(Hook): + __name__ = "MultiHook" + __type__ = "hook" + __version__ = "0.37" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), + ("revertfailed" , "bool" , "Revert to standard download if fails", True ), + ("retry" , "int" , "Number of retries before revert" , 10 ), + ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Hook plugin for multi hoster/crypter""" + __license__ = "GPLv3" + __authors__ = [("pyLoad Team", "admin@pyload.org"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + MIN_INTERVAL = 1 * 60 * 60 + + DOMAIN_REPLACEMENTS = [(r'180upload\.com' , "hundredeightyupload.com"), + (r'1fichier\.com' , "onefichier.com" ), + (r'2shared\.com' , "twoshared.com" ), + (r'4shared\.com' , "fourshared.com" ), + (r'bayfiles\.net' , "bayfiles.com" ), + (r'cloudnator\.com' , "shragle.com" ), + (r'dfiles\.eu' , "depositfiles.com" ), + (r'easy-share\.com' , "crocko.com" ), + (r'freakshare\.net' , "freakshare.com" ), + (r'hellshare\.com' , "hellshare.cz" ), + (r'ifile\.it' , "filecloud.io" ), + (r'nowdownload\.\w+', "nowdownload.sx" ), + (r'nowvideo\.\w+' , "nowvideo.sx" ), + (r'putlocker\.com' , "firedrive.com" ), + (r'share-?rapid\.cz', "multishare.cz" ), + (r'ul\.to' , "uploaded.to" ), + (r'uploaded\.net' , "uploaded.to" ), + (r'uploadhero\.co' , "uploadhero.com" ), + (r'zshares\.net' , "zshare.net" ), + (r'(\d+.+)' , "X\1" )] + + + def setup(self): + self.plugins = [] + self.supported = [] + self.new_supported = [] + + self.account = None + self.pluginclass = None + self.pluginmodule = None + self.pluginname = None + self.plugintype = None + + self._initPlugin() + + + def _initPlugin(self): + plugin, type = self.core.pluginManager.findPlugin(self.__name__) + + if not plugin: + self.logWarning("Hook plugin will be deactivated due missing plugin reference") + self.setConfig('activated', False) + else: + self.pluginname = self.__name__ + self.plugintype = type + self.pluginmodule = self.core.pluginManager.loadModule(type, self.__name__) + self.pluginclass = getattr(self.pluginmodule, self.__name__) + + + def _loadAccount(self): + self.account = self.core.accountManager.getAccountPlugin(self.pluginname) + + if self.account and not self.account.canUse(): + self.account = None + + if not self.account and hasattr(self.pluginclass, "LOGIN_ACCOUNT") and self.pluginclass.LOGIN_ACCOUNT: + self.logWarning("Hook plugin will be deactivated due missing account reference") + self.setConfig('activated', False) + + + def activate(self): + self._loadAccount() + + + def getURL(self, *args, **kwargs): #@TODO: Remove in 0.4.10 + """ see HTTPRequest for argument list """ + h = pyreq.getHTTPRequest(timeout=120) + try: + if not 'decode' in kwargs: + kwargs['decode'] = True + rep = h.load(*args, **kwargs) + finally: + h.close() + + return rep + + + def getConfig(self, option, default=''): + """getConfig with default value - sublass may not implements all config options""" + try: + return self.getConf(option) + + except KeyError: + return default + + + def pluginsCached(self): + if self.plugins: + return self.plugins + + for _i in xrange(3): + try: + pluginset = self._pluginSet(self.getHosters() if self.plugintype == "hoster" else self.getCrypters()) + + except Exception, e: + self.logError(e, "Waiting 1 minute and retry") + sleep(60) + + else: + break + else: + return list() + + try: + configmode = self.getConfig("pluginmode", 'all') + if configmode in ("listed", "unlisted"): + pluginlist = self.getConfig("pluginlist", '').replace('|', ',').replace(';', ',').split(',') + configset = self._pluginSet(pluginlist) + + if configmode == "listed": + pluginset &= configset + else: + pluginset -= configset + + except Exception, e: + self.logError(e) + + self.plugins = list(pluginset) + + return self.plugins + + + def _pluginSet(self, plugins): + plugins = set((decode(x).strip().lower() for x in plugins if '.' in x)) + + for rf, rt in self.DOMAIN_REPLACEMENTS: + regex = re.compile(rf) + for p in filter(lambda x: regex.match(x), plugins): + plugins.remove(p) + plugins.add(re.sub(rf, rt, p)) + + plugins.discard('') + + return plugins + + + def getHosters(self): + """Load list of supported hoster + + :return: List of domain names + """ + raise NotImplementedError + + + def getCrypters(self): + """Load list of supported crypters + + :return: List of domain names + """ + raise NotImplementedError + + + def periodical(self): + """reload plugin list periodically""" + self.logInfo(_("Reloading supported %s list") % self.plugintype) + + old_supported = self.supported + + self.supported = [] + self.new_supported = [] + self.plugins = [] + + self.overridePlugins() + + old_supported = [plugin for plugin in old_supported if plugin not in self.supported] + + if old_supported: + self.logDebug("Unload: %s" % ", ".join(old_supported)) + for plugin in old_supported: + self.unloadPlugin(plugin) + + if self.getConfig("reload", True): + self.interval = max(self.getConfig("reloadinterval", 12) * 60 * 60, self.MIN_INTERVAL) + else: + self.core.scheduler.removeJob(self.cb) + self.cb = None + + + def overridePlugins(self): + excludedList = [] + + if self.plugintype == "hoster": + pluginMap = dict((name.lower(), name) for name in self.core.pluginManager.hosterPlugins.iterkeys()) + accountList = [account.type.lower() for account in self.core.api.getAccounts(False) if account.valid and account.premium] + else: + pluginMap = {} + accountList = [name[::-1].replace("Folder"[::-1], "", 1).lower()[::-1] for name in self.core.pluginManager.crypterPlugins.iterkeys()] + + for plugin in self.pluginsCached(): + name = remove_chars(plugin, "-.") + + if name in accountList: + excludedList.append(plugin) + else: + if name in pluginMap: + self.supported.append(pluginMap[name]) + else: + self.new_supported.append(plugin) + + if not self.supported and not self.new_supported: + self.logError(_("No %s loaded") % self.plugintype) + return + + # inject plugin plugin + self.logDebug("Overwritten %ss: %s" % (self.plugintype, ", ".join(sorted(self.supported)))) + + for plugin in self.supported: + hdict = self.core.pluginManager.plugins[self.plugintype][plugin] + hdict['new_module'] = self.pluginmodule + hdict['new_name'] = self.pluginname + + if excludedList: + self.logInfo(_("%ss not overwritten: %s") % (self.plugintype.capitalize(), ", ".join(sorted(excludedList)))) + + if self.new_supported: + plugins = sorted(self.new_supported) + + self.logDebug("New %ss: %s" % (self.plugintype, ", ".join(plugins))) + + # create new regexp + regexp = r'.*(?P<DOMAIN>%s).*' % "|".join([x.replace(".", "\.") for x in plugins]) + if hasattr(self.pluginclass, "__pattern__") and isinstance(self.pluginclass.__pattern__, basestring) and '://' in self.pluginclass.__pattern__: + regexp = r'%s|%s' % (self.pluginclass.__pattern__, regexp) + + self.logDebug("Regexp: %s" % regexp) + + hdict = self.core.pluginManager.plugins[self.plugintype][self.pluginname] + hdict['pattern'] = regexp + hdict['re'] = re.compile(regexp) + + + def unloadPlugin(self, plugin): + hdict = self.core.pluginManager.plugins[self.plugintype][plugin] + if "module" in hdict: + del hdict['module'] + + if "new_module" in hdict: + del hdict['new_module'] + del hdict['new_name'] + + + def deactivate(self): + """Remove override for all plugins. Scheduler job is removed by hookmanager""" + for plugin in self.supported: + self.unloadPlugin(plugin) + + # reset pattern + hdict = self.core.pluginManager.plugins[self.plugintype][self.pluginname] + + hdict['pattern'] = getattr(self.pluginclass, "__pattern__", r'^unmatchable$') + hdict['re'] = re.compile(hdict['pattern']) + + + def downloadFailed(self, pyfile): + """remove plugin override if download fails but not if file is offline/temp.offline""" + if pyfile.status != 8 or not self.getConfig("revertfailed", True): + return + + hdict = self.core.pluginManager.plugins[self.plugintype][pyfile.pluginname] + if "new_name" in hdict and hdict['new_name'] == self.pluginname: + if pyfile.error == "MultiHook": + self.logDebug("Unload MultiHook", pyfile.pluginname, hdict) + self.unloadPlugin(pyfile.pluginname) + pyfile.setStatus("queued") + pyfile.sync() + else: + retries = max(self.getConfig("retry", 10), 0) + wait_time = max(self.getConfig("retryinterval", 1), 0) + + if 0 < retries > pyfile.plugin.retries: + self.logInfo(_("Retrying: %s") % pyfile.name) + pyfile.setCustomStatus("MultiHook", "queued") + pyfile.sync() + + pyfile.plugin.retries += 1 + pyfile.plugin.setWait(wait_time) + pyfile.plugin.wait() diff --git a/pyload/plugin/internal/MultiHoster.py b/pyload/plugin/internal/MultiHoster.py new file mode 100644 index 000000000..ed425ffaa --- /dev/null +++ b/pyload/plugin/internal/MultiHoster.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.internal.SimpleHoster import SimpleHoster, replace_patterns, set_cookies + + +class MultiHoster(SimpleHoster): + __name__ = "MultiHoster" + __type__ = "hoster" + __version__ = "0.37" + + __pattern__ = r'^unmatchable$' + + __description__ = """Multi hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + LOGIN_ACCOUNT = True + + + def setup(self): + self.chunkLimit = 1 + self.multiDL = bool(self.account) + self.resumeDownload = self.premium + + + def prepare(self): + self.info = {} + self.html = "" + self.link = "" #@TODO: Move to hoster class in 0.4.10 + self.directDL = False #@TODO: Move to hoster class in 0.4.10 + + if self.LOGIN_ACCOUNT and not self.account: + self.fail(_("Required account not found")) + + self.req.setOption("timeout", 120) + + if isinstance(self.COOKIES, list): + set_cookies(self.req.cj, self.COOKIES) + + if self.DIRECT_LINK is None: + self.directDL = self.__pattern__ != r'^unmatchable$' and re.match(self.__pattern__, self.pyfile.url) + else: + self.directDL = self.DIRECT_LINK + + self.pyfile.url = replace_patterns(self.pyfile.url, self.URL_REPLACEMENTS) + + + def process(self, pyfile): + self.prepare() + + if self.directDL: + self.checkInfo() + self.logDebug("Looking for direct download link...") + self.handleDirect(pyfile) + + if not self.link and not self.lastDownload: + self.preload() + + self.checkErrors() + self.checkStatus(getinfo=False) + + if self.premium and (not self.CHECK_TRAFFIC or self.checkTrafficLeft()): + self.logDebug("Handled as premium download") + self.handlePremium(pyfile) + + elif not self.LOGIN_ACCOUNT or (not self.CHECK_TRAFFIC or self.checkTrafficLeft()): + self.logDebug("Handled as free download") + self.handleFree(pyfile) + + self.downloadLink(self.link, True) + self.checkFile() + + + def handlePremium(self, pyfile): + return self.handleFree(pyfile) + + + def handleFree(self, pyfile): + if self.premium: + raise NotImplementedError + else: + self.fail(_("Required premium account not found")) diff --git a/pyload/plugin/internal/SimpleCrypter.py b/pyload/plugin/internal/SimpleCrypter.py new file mode 100644 index 000000000..e4b8874f3 --- /dev/null +++ b/pyload/plugin/internal/SimpleCrypter.py @@ -0,0 +1,157 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urljoin, urlparse + +from pyload.plugin.Crypter import Crypter +from pyload.plugin.internal.SimpleHoster import SimpleHoster, replace_patterns, set_cookies +from pyload.utils import fixup + + +class SimpleCrypter(Crypter, SimpleHoster): + __name__ = "SimpleCrypter" + __type__ = "crypter" + __version__ = "0.43" + + __pattern__ = r'^unmatchable$' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), #: Overrides core.config['general']['folder_per_package'] + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Simple decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it"), + ("zoidberg", "zoidberg@mujmail.cz"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + """ + Following patterns should be defined by each crypter: + + LINK_PATTERN: Download link or regex to catch links in group(1) + example: LINK_PATTERN = r'<div class="link"><a href="(.+?)"' + + NAME_PATTERN: (optional) folder name or page title + example: NAME_PATTERN = r'<title>Files of: (?P<N>[^<]+) folder</title>' + + OFFLINE_PATTERN: (optional) Checks if the page is unreachable + example: OFFLINE_PATTERN = r'File (deleted|not found)' + + TEMP_OFFLINE_PATTERN: (optional) Checks if the page is temporarily unreachable + example: TEMP_OFFLINE_PATTERN = r'Server maintainance' + + + You can override the getLinks method if you need a more sophisticated way to extract the links. + + + If the links are splitted on multiple pages you can define the PAGES_PATTERN regex: + + PAGES_PATTERN: (optional) group(1) should be the number of overall pages containing the links + example: PAGES_PATTERN = r'Pages: (\d+)' + + and its loadPage method: + + + def loadPage(self, page_n): + return the html of the page number page_n + """ + + LINK_PATTERN = None + + NAME_REPLACEMENTS = [("&#?\w+;", fixup)] + URL_REPLACEMENTS = [] + + TEXT_ENCODING = False #: Set to True or encoding name if encoding in http header is not correct + COOKIES = True #: or False or list of tuples [(domain, name, value)] + + LOGIN_ACCOUNT = False + LOGIN_PREMIUM = False + + + def prepare(self): + self.pyfile.error = "" #@TODO: Remove in 0.4.10 + + self.info = {} + self.html = "" + self.links = [] #@TODO: Move to hoster class in 0.4.10 + + if self.LOGIN_PREMIUM and not self.premium: + self.fail(_("Required premium account not found")) + + if self.LOGIN_ACCOUNT and not self.account: + self.fail(_("Required account not found")) + + self.req.setOption("timeout", 120) + + if isinstance(self.COOKIES, list): + set_cookies(self.req.cj, self.COOKIES) + + self.pyfile.url = replace_patterns(self.pyfile.url, self.URL_REPLACEMENTS) + + + def decrypt(self, pyfile): + self.prepare() + + self.preload() + self.checkInfo() + + self.links = self.getLinks() + + if hasattr(self, 'PAGES_PATTERN') and hasattr(self, 'loadPage'): + self.handlePages(pyfile) + + self.logDebug("Package has %d links" % len(self.links)) + + if self.links: + self.packages = [(self.info['name'], self.links, self.info['folder'])] + + elif not self.urls and not self.packages: #@TODO: Remove in 0.4.10 + self.fail(_("No link grabbed")) + + + def checkNameSize(self, getinfo=True): + if not self.info or getinfo: + self.logDebug("File info (BEFORE): %s" % self.info) + self.info.update(self.getInfo(self.pyfile.url, self.html)) + self.logDebug("File info (AFTER): %s" % self.info) + + try: + url = self.info['url'].strip() + name = self.info['name'].strip() + if name and name != url: + self.pyfile.name = name + + except Exception: + pass + + try: + folder = self.info['folder'] = self.pyfile.name + + except Exception: + pass + + self.logDebug("File name: %s" % self.pyfile.name, + "File folder: %s" % self.pyfile.name) + + + def getLinks(self): + """ + Returns the links extracted from self.html + You should override this only if it's impossible to extract links using only the LINK_PATTERN. + """ + url_p = urlparse(self.pyfile.url) + baseurl = "%s://%s" % (url_p.scheme, url_p.netloc) + + return [urljoin(baseurl, link) if not urlparse(link).scheme else link \ + for link in re.findall(self.LINK_PATTERN, self.html)] + + + def handlePages(self, pyfile): + try: + pages = int(re.search(self.PAGES_PATTERN, self.html).group(1)) + except Exception: + pages = 1 + + for p in xrange(2, pages + 1): + self.html = self.loadPage(p) + self.links += self.getLinks() diff --git a/pyload/plugin/internal/SimpleDereferer.py b/pyload/plugin/internal/SimpleDereferer.py new file mode 100644 index 000000000..6d323b4b0 --- /dev/null +++ b/pyload/plugin/internal/SimpleDereferer.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- + +import re + +from urllib import unquote + +from pyload.plugin.Crypter import Crypter +from pyload.plugin.internal.SimpleHoster import fileUrl, set_cookies + + +class SimpleDereferer(Crypter): + __name__ = "SimpleDereferer" + __type__ = "crypter" + __version__ = "0.07" + + __pattern__ = r'^unmatchable$' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Simple dereferer plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + """ + Following patterns should be defined by each crypter: + + LINK_PATTERN: Regex to catch the redirect url in group(1) + example: LINK_PATTERN = r'<div class="link"><a href="(.+?)"' + + OFFLINE_PATTERN: (optional) Checks if the page is unreachable + example: OFFLINE_PATTERN = r'File (deleted|not found)' + + TEMP_OFFLINE_PATTERN: (optional) Checks if the page is temporarily unreachable + example: TEMP_OFFLINE_PATTERN = r'Server maintainance' + + + You can override the getLinks method if you need a more sophisticated way to extract the redirect url. + """ + + LINK_PATTERN = None + + TEXT_ENCODING = False + COOKIES = True + + + def decrypt(self, pyfile): + link = fileUrl(self, pyfile.url) + + if not link: + try: + link = unquote(re.match(self.__pattern__, pyfile.url).group('LINK')) + + except Exception: + self.prepare() + self.preload() + self.checkStatus() + + link = self.getLink() + + if link.strip(): + self.urls = [link.strip()] #@TODO: Remove `.strip()` in 0.4.10 + + elif not self.urls and not self.packages: #@TODO: Remove in 0.4.10 + self.fail(_("No link grabbed")) + + + def prepare(self): + self.info = {} + self.html = "" + + self.req.setOption("timeout", 120) + + if isinstance(self.COOKIES, list): + set_cookies(self.req.cj, self.COOKIES) + + + def preload(self): + self.html = self.load(self.pyfile.url, cookies=bool(self.COOKIES), decode=not self.TEXT_ENCODING) + + if isinstance(self.TEXT_ENCODING, basestring): + self.html = unicode(self.html, self.TEXT_ENCODING) + + + def checkStatus(self): + if hasattr(self, "OFFLINE_PATTERN") and re.search(self.OFFLINE_PATTERN, self.html): + self.offline() + + elif hasattr(self, "TEMP_OFFLINE_PATTERN") and re.search(self.TEMP_OFFLINE_PATTERN, self.html): + self.tempOffline() + + + def getLink(self): + try: + return re.search(self.LINK_PATTERN, self.html).group(1) + + except Exception: + pass diff --git a/pyload/plugin/internal/SimpleHoster.py b/pyload/plugin/internal/SimpleHoster.py new file mode 100644 index 000000000..ac7f5aa4d --- /dev/null +++ b/pyload/plugin/internal/SimpleHoster.py @@ -0,0 +1,701 @@ +# -*- coding: utf-8 -*- + +import mimetypes +import os +import re + +from datetime import datetime, timedelta +from inspect import isclass +from time import time +from urllib import unquote +from urlparse import urljoin, urlparse + +from pyload.datatype.File import statusMap as _statusMap +from pyload.network.CookieJar import CookieJar +from pyload.network.HTTPRequest import BadHeader +from pyload.network.RequestFactory import getURL +from pyload.plugin.Hoster import Hoster +from pyload.plugin.Plugin import Fail +from pyload.utils import fixup, fs_encode, parseFileSize + + +#@TODO: Adapt and move to PyFile in 0.4.10 +statusMap = dict((v, k) for k, v in _statusMap.iteritems()) + + +#@TODO: Remove in 0.4.10 and redirect to self.error instead +def _error(self, reason, type): + if not reason and not type: + type = "unknown" + + msg = _("%s error") % type.strip().capitalize() if type else _("Error") + msg += ": %s" % reason.strip() if reason else "" + msg += _(" | Plugin may be out of date") + + raise Fail(msg) + + +#@TODO: Remove in 0.4.10 +def _wait(self, seconds, reconnect): + if seconds: + self.setWait(int(seconds) + 1) + + if reconnect is not None: + self.wantReconnect = reconnect + + super(SimpleHoster, self).wait() + + +def replace_patterns(string, ruleslist): + for r in ruleslist: + rf, rt = r + string = re.sub(rf, rt, string) + return string + + +def set_cookies(cj, cookies): + for cookie in cookies: + if isinstance(cookie, tuple) and len(cookie) == 3: + domain, name, value = cookie + cj.setCookie(domain, name, value) + + +def parseHtmlTagAttrValue(attr_name, tag): + m = re.search(r"%s\s*=\s*([\"']?)((?<=\")[^\"]+|(?<=')[^']+|[^>\s\"'][^>\s]*)\1" % attr_name, tag, re.I) + return m.group(2) if m else None + + +def parseHtmlForm(attr_str, html, input_names={}): + for form in re.finditer(r"(?P<TAG><form[^>]*%s[^>]*>)(?P<CONTENT>.*?)</?(form|body|html)[^>]*>" % attr_str, + html, re.S | re.I): + inputs = {} + action = parseHtmlTagAttrValue("action", form.group('TAG')) + + for inputtag in re.finditer(r'(<(input|textarea)[^>]*>)([^<]*(?=</\2)|)', form.group('CONTENT'), re.S | re.I): + name = parseHtmlTagAttrValue("name", inputtag.group(1)) + if name: + value = parseHtmlTagAttrValue("value", inputtag.group(1)) + if not value: + inputs[name] = inputtag.group(3) or '' + else: + inputs[name] = value + + if input_names: + # check input attributes + for key, val in input_names.iteritems(): + if key in inputs: + if isinstance(val, basestring) and inputs[key] == val: + continue + elif isinstance(val, tuple) and inputs[key] in val: + continue + elif hasattr(val, "search") and re.match(val, inputs[key]): + continue + break #: attibute value does not match + else: + break #: attibute name does not match + else: + return action, inputs #: passed attribute check + else: + # no attribute check + return action, inputs + + return {}, None #: no matching form found + + +#: Deprecated +def parseFileInfo(plugin, url="", html=""): + if hasattr(plugin, "getInfo"): + info = plugin.getInfo(url, html) + res = info['name'], info['size'], info['status'], info['url'] + else: + url = unquote(url) + url_p = urlparse(url) + res = ((url_p.path.split('/')[-1] + or url_p.query.split('=', 1)[::-1][0].split('&', 1)[0] + or url_p.netloc.split('.', 1)[0]), + 0, + 3 if url else 8, + url) + + return res + + +#@TODO: Remove in 0.4.10 +#@NOTE: Every plugin must have own parseInfos classmethod to work with 0.4.10 +# def create_getInfo(plugin): + + # def generator(list): + # for x in list: + # yield x + + # if hasattr(plugin, "parseInfos"): + # fn = lambda urls: generator((info['name'], info['size'], info['status'], info['url']) for info in plugin.parseInfos(urls)) + # else: + # fn = lambda urls: generator(parseFileInfo(url) for url in urls) + + # return fn + + +def timestamp(): + return int(time() * 1000) + + +#@TODO: Move to hoster class in 0.4.10 +def fileUrl(self, url, follow_location=None): + link = "" + redirect = 1 + + if type(follow_location) is int: + redirect = max(follow_location, 1) + else: + redirect = 5 + + for i in xrange(redirect): + try: + self.logDebug("Redirect #%d to: %s" % (i, url)) + header = self.load(url, ref=True, cookies=True, just_header=True, decode=True) + + except Exception: #: Bad bad bad... + req = pyreq.getHTTPRequest() + res = req.load(url, cookies=True, just_header=True, decode=True) + + req.close() + + header = {"code": req.code} + for line in res.splitlines(): + line = line.strip() + if not line or ":" not in line: + continue + + key, none, value = line.partition(":") + key = key.lower().strip() + value = value.strip() + + if key in header: + if type(header[key]) == list: + header[key].append(value) + else: + header[key] = [header[key], value] + else: + header[key] = value + + if 'content-disposition' in header: + link = url + + elif 'location' in header and header['location'].strip(): + location = header['location'] + + if not urlparse(location).scheme: + url_p = urlparse(url) + baseurl = "%s://%s" % (url_p.scheme, url_p.netloc) + location = urljoin(baseurl, location) + + if 'code' in header and header['code'] == 302: + link = location + + if follow_location: + url = location + continue + + else: + extension = os.path.splitext(urlparse(url).path.split('/')[-1])[-1] + + if 'content-type' in header and header['content-type'].strip(): + mimetype = header['content-type'].split(';')[0].strip() + + elif extension: + mimetype = mimetypes.guess_type(extension, False)[0] or "application/octet-stream" + + else: + mimetype = "" + + if mimetype and (link or 'html' not in mimetype): + link = url + else: + link = "" + + break + + else: + try: + self.logError(_("Too many redirects")) + except Exception: + pass + + return link + + +def secondsToMidnight(gmt=0): + now = datetime.utcnow() + timedelta(hours=gmt) + + if now.hour is 0 and now.minute < 10: + midnight = now + else: + midnight = now + timedelta(days=1) + + td = midnight.replace(hour=0, minute=10, second=0, microsecond=0) - now + + if hasattr(td, 'total_seconds'): + res = td.total_seconds() + else: #@NOTE: work-around for python 2.5 and 2.6 missing timedelta.total_seconds + res = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6 + + return int(res) + + +class SimpleHoster(Hoster): + __name__ = "SimpleHoster" + __type__ = "hoster" + __version__ = "1.15" + + __pattern__ = r'^unmatchable$' + + __description__ = """Simple hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), + ("stickell", "l.stickell@yahoo.it"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + """ + Info patterns should be defined by each hoster: + + INFO_PATTERN: (optional) Name and Size of the file + example: INFO_PATTERN = r'(?P<N>file_name) (?P<S>file_size) (?P<U>size_unit)' + or + NAME_PATTERN: (optional) Name that will be set for the file + example: NAME_PATTERN = r'(?P<N>file_name)' + SIZE_PATTERN: (optional) Size that will be checked for the file + example: SIZE_PATTERN = r'(?P<S>file_size) (?P<U>size_unit)' + + HASHSUM_PATTERN: (optional) Hash code and type of the file + example: HASHSUM_PATTERN = r'(?P<H>hash_code) (?P<T>MD5)' + + OFFLINE_PATTERN: (optional) Check if the page is unreachable + example: OFFLINE_PATTERN = r'File (deleted|not found)' + + TEMP_OFFLINE_PATTERN: (optional) Check if the page is temporarily unreachable + example: TEMP_OFFLINE_PATTERN = r'Server (maintenance|maintainance)' + + + Error handling patterns are all optional: + + WAIT_PATTERN: (optional) Detect waiting time + example: WAIT_PATTERN = r'' + + PREMIUM_ONLY_PATTERN: (optional) Check if the file can be downloaded only with a premium account + example: PREMIUM_ONLY_PATTERN = r'Premium account required' + + ERROR_PATTERN: (optional) Detect any error preventing download + example: ERROR_PATTERN = r'' + + + Instead overriding handleFree and handlePremium methods you can define the following patterns for direct download: + + LINK_FREE_PATTERN: (optional) group(1) should be the direct link for free download + example: LINK_FREE_PATTERN = r'<div class="link"><a href="(.+?)"' + + LINK_PREMIUM_PATTERN: (optional) group(1) should be the direct link for premium download + example: LINK_PREMIUM_PATTERN = r'<div class="link"><a href="(.+?)"' + """ + + NAME_REPLACEMENTS = [("&#?\w+;", fixup)] + SIZE_REPLACEMENTS = [] + URL_REPLACEMENTS = [] + + TEXT_ENCODING = False #: Set to True or encoding name if encoding value in http header is not correct + COOKIES = True #: or False or list of tuples [(domain, name, value)] + CHECK_TRAFFIC = False #: Set to True to force checking traffic left for premium account + DIRECT_LINK = None #: Set to True to looking for direct link (as defined in handleDirect method), set to None to do it if self.account is True else False + MULTI_HOSTER = False #: Set to True to leech other hoster link (as defined in handleMulti method) + LOGIN_ACCOUNT = False #: Set to True to require account login + DISPOSITION = True #: Work-around to `filename*=UTF-8` bug; remove in 0.4.10 + + directLink = fileUrl #@TODO: Remove in 0.4.10 + + + @classmethod + def parseInfos(cls, urls): #@TODO: Built-in in 0.4.10 core, then remove from plugins + for url in urls: + url = replace_patterns(url, cls.URL_REPLACEMENTS) + yield cls.getInfo(url) + + + @classmethod + def apiInfo(cls, url="", get={}, post={}): + url = unquote(url) + url_p = urlparse(url) + return {'name' : (url_p.path.split('/')[-1] + or url_p.query.split('=', 1)[::-1][0].split('&', 1)[0] + or url_p.netloc.split('.', 1)[0]), + 'size' : 0, + 'status': 3 if url else 8, + 'url' : url} + + + @classmethod + def getInfo(cls, url="", html=""): + info = cls.apiInfo(url) + online = False if info['status'] != 2 else True + + try: + info['pattern'] = re.match(cls.__pattern__, url).groupdict() #: pattern groups will be saved here + + except Exception: + info['pattern'] = {} + + if not html and not online: + if not url: + info['error'] = "missing url" + info['status'] = 1 + + elif info['status'] is 3 and not fileUrl(None, url): + try: + html = getURL(url, cookies=cls.COOKIES, decode=not cls.TEXT_ENCODING) + + if isinstance(cls.TEXT_ENCODING, basestring): + html = unicode(html, cls.TEXT_ENCODING) + + except BadHeader, e: + info['error'] = "%d: %s" % (e.code, e.content) + + if e.code is 404: + info['status'] = 1 + + elif e.code is 503: + info['status'] = 6 + + if html: + if hasattr(cls, "OFFLINE_PATTERN") and re.search(cls.OFFLINE_PATTERN, html): + info['status'] = 1 + + elif hasattr(cls, "TEMP_OFFLINE_PATTERN") and re.search(cls.TEMP_OFFLINE_PATTERN, html): + info['status'] = 6 + + else: + for pattern in ("INFO_PATTERN", "NAME_PATTERN", "SIZE_PATTERN", "HASHSUM_PATTERN"): + try: + attr = getattr(cls, pattern) + pdict = re.search(attr, html).groupdict() + + if all(True for k in pdict if k not in info['pattern']): + info['pattern'].update(pdict) + + except AttributeError: + continue + + else: + online = True + + if online: + info['status'] = 2 + + if 'N' in info['pattern']: + info['name'] = replace_patterns(unquote(info['pattern']['N'].strip()), + cls.NAME_REPLACEMENTS) + + if 'S' in info['pattern']: + size = replace_patterns(info['pattern']['S'] + info['pattern']['U'] if 'U' in info['pattern'] else info['pattern']['S'], + cls.SIZE_REPLACEMENTS) + info['size'] = parseFileSize(size) + + elif isinstance(info['size'], basestring): + unit = info['units'] if 'units' in info else None + info['size'] = parseFileSize(info['size'], unit) + + if 'H' in info['pattern']: + hashtype = info['pattern']['T'] if 'T' in info['pattern'] else "hash" + info[hashtype] = info['pattern']['H'] + + if not info['pattern']: + info.pop('pattern', None) + + return info + + + def setup(self): + self.resumeDownload = self.multiDL = self.premium + + + def prepare(self): + self.pyfile.error = "" #@TODO: Remove in 0.4.10 + + self.info = {} + self.html = "" + self.link = "" #@TODO: Move to hoster class in 0.4.10 + self.directDL = False #@TODO: Move to hoster class in 0.4.10 + self.multihost = False #@TODO: Move to hoster class in 0.4.10 + + if self.LOGIN_ACCOUNT and not self.account: + self.fail(_("Required account not found")) + + self.req.setOption("timeout", 120) + + if isinstance(self.COOKIES, list): + set_cookies(self.req.cj, self.COOKIES) + + if (self.MULTI_HOSTER + and (self.__pattern__ != self.core.pluginManager.hosterPlugins[self.__name__]['pattern'] + or re.match(self.__pattern__, self.pyfile.url) is None)): + self.multihost = True + return + + if self.DIRECT_LINK is None: + self.directDL = bool(self.account) + else: + self.directDL = self.DIRECT_LINK + + self.pyfile.url = replace_patterns(self.pyfile.url, self.URL_REPLACEMENTS) + + + def preload(self): + self.html = self.load(self.pyfile.url, cookies=bool(self.COOKIES), decode=not self.TEXT_ENCODING) + + if isinstance(self.TEXT_ENCODING, basestring): + self.html = unicode(self.html, self.TEXT_ENCODING) + + + def process(self, pyfile): + self.prepare() + self.checkInfo() + + if self.directDL: + self.logDebug("Looking for direct download link...") + self.handleDirect(pyfile) + + if self.multihost and not self.link and not self.lastDownload: + self.logDebug("Looking for leeched download link...") + self.handleMulti(pyfile) + + if not self.link and not self.lastDownload: + self.MULTI_HOSTER = False + self.retry(1, reason="Multi hoster fails") + + if not self.link and not self.lastDownload: + self.preload() + self.checkInfo() + + if self.premium and (not self.CHECK_TRAFFIC or self.checkTrafficLeft()): + self.logDebug("Handled as premium download") + self.handlePremium(pyfile) + + elif not self.LOGIN_ACCOUNT or (not self.CHECK_TRAFFIC or self.checkTrafficLeft()): + self.logDebug("Handled as free download") + self.handleFree(pyfile) + + self.downloadLink(self.link, self.DISPOSITION) #: Remove `self.DISPOSITION` in 0.4.10 + self.checkFile() + + + def downloadLink(self, link, disposition=True): + if link and isinstance(link, basestring): + self.correctCaptcha() + + if not urlparse(link).scheme: + url_p = urlparse(self.pyfile.url) + baseurl = "%s://%s" % (url_p.scheme, url_p.netloc) + link = urljoin(baseurl, link) + + self.download(link, ref=False, disposition=disposition) + + + def checkFile(self): + if self.cTask and not self.lastDownload: + self.invalidCaptcha() + self.retry(10, reason=_("Wrong captcha")) + + elif not self.lastDownload or not os.path.exists(fs_encode(self.lastDownload)): + self.lastDownload = "" + self.error(self.pyfile.error or _("No file downloaded")) + + else: + rules = {'empty file': re.compile(r'\A\Z'), + 'html file' : re.compile(r'\A\s*<!DOCTYPE html'), + 'html error': re.compile(r'\A\s*(<.+>)?\d{3}(\Z|\s+)')} + + if hasattr(self, 'ERROR_PATTERN'): + rules['error'] = re.compile(self.ERROR_PATTERN) + + check = self.checkDownload(rules) + if check: #@TODO: Move to hoster in 0.4.10 + errmsg = check.strip().capitalize() + if self.lastCheck: + errmsg += " | " + self.lastCheck.group(0).strip() + + self.lastDownload = "" + self.retry(10, 60, errmsg) + + + def checkErrors(self): + if not self.html: + self.logWarning(_("No html code to check")) + return + + if hasattr(self, 'PREMIUM_ONLY_PATTERN') and not self.premium and re.search(self.PREMIUM_ONLY_PATTERN, self.html): + self.fail(_("Link require a premium account to be handled")) + + elif hasattr(self, 'ERROR_PATTERN'): + m = re.search(self.ERROR_PATTERN, self.html) + if m: + errmsg = self.info['error'] = m.group(1) + self.error(errmsg) + + elif hasattr(self, 'WAIT_PATTERN'): + m = re.search(self.WAIT_PATTERN, self.html) + if m: + wait_time = sum(int(v) * {"hr": 3600, "hour": 3600, "min": 60, "sec": 1}[u.lower()] for v, u in + re.findall(r'(\d+)\s*(hr|hour|min|sec)', m.group(0), re.I)) + self.wait(wait_time, wait_time > 300) + return + + self.info.pop('error', None) + + + def checkStatus(self, getinfo=True): + if not self.info or getinfo: + self.logDebug("Update file info...") + self.logDebug("Previous file info: %s" % self.info) + self.info.update(self.getInfo(self.pyfile.url, self.html)) + self.logDebug("Current file info: %s" % self.info) + + try: + status = self.info['status'] + + if status is 1: + self.offline() + + elif status is 6: + self.tempOffline() + + elif status is 8: + self.fail() + + finally: + self.logDebug("File status: %s" % statusMap[status]) + + + def checkNameSize(self, getinfo=True): + if not self.info or getinfo: + self.logDebug("Update file info...") + self.logDebug("Previous file info: %s" % self.info) + self.info.update(self.getInfo(self.pyfile.url, self.html)) + self.logDebug("Current file info: %s" % self.info) + + try: + url = self.info['url'].strip() + name = self.info['name'].strip() + if name and name != url: + self.pyfile.name = name + + except Exception: + pass + + try: + size = self.info['size'] + if size > 0: + self.pyfile.size = size + + except Exception: + pass + + self.logDebug("File name: %s" % self.pyfile.name, + "File size: %s byte" % self.pyfile.size if self.pyfile.size > 0 else "File size: Unknown") + + + def checkInfo(self): + self.checkNameSize() + + if self.html: + self.checkErrors() + self.checkNameSize() + + self.checkStatus(getinfo=False) + + + #: Deprecated + def getFileInfo(self): + self.info = {} + self.checkInfo() + return self.info + + + def handleDirect(self, pyfile): + link = self.directLink(pyfile.url, self.resumeDownload) + + if link: + self.logInfo(_("Direct download link detected")) + + self.link = link + else: + self.logDebug("Direct download link not found") + + + def handleMulti(self, pyfile): #: Multi-hoster handler + pass + + + def handleFree(self, pyfile): + if not hasattr(self, 'LINK_FREE_PATTERN'): + self.logError(_("Free download not implemented")) + + m = re.search(self.LINK_FREE_PATTERN, self.html) + if m is None: + self.error(_("Free download link not found")) + else: + self.link = m.group(1) + + + def handlePremium(self, pyfile): + if not hasattr(self, 'LINK_PREMIUM_PATTERN'): + self.logError(_("Premium download not implemented")) + self.logDebug("Handled as free download") + self.handleFree(pyfile) + + m = re.search(self.LINK_PREMIUM_PATTERN, self.html) + if m is None: + self.error(_("Premium download link not found")) + else: + self.link = m.group(1) + + + def longWait(self, wait_time=None, max_tries=3): + if wait_time and isinstance(wait_time, (int, long, float)): + time_str = "%dh %dm" % divmod(wait_time / 60, 60) + else: + wait_time = 900 + time_str = _("(unknown time)") + max_tries = 100 + + self.logInfo(_("Download limit reached, reconnect or wait %s") % time_str) + + self.wait(wait_time, True) + self.retry(max_tries=max_tries, reason=_("Download limit reached")) + + + def parseHtmlForm(self, attr_str="", input_names={}): + return parseHtmlForm(attr_str, self.html, input_names) + + + def checkTrafficLeft(self): + if not self.account: + return True + + traffic = self.account.getAccountInfo(self.user, True)['trafficleft'] + + if traffic is None: + return False + elif traffic == -1: + return True + else: + size = self.pyfile.size / 1024 + self.logInfo(_("Filesize: %i KiB, Traffic left for user %s: %i KiB") % (size, self.user, traffic)) + return size <= traffic + + + #@TODO: Remove in 0.4.10 + def wait(self, seconds=0, reconnect=None): + return _wait(self, seconds, reconnect) + + + def error(self, reason="", type="parse"): + return _error(self, reason, type) diff --git a/pyload/plugin/internal/UpdateManager.py b/pyload/plugin/internal/UpdateManager.py new file mode 100644 index 000000000..ff692b4ae --- /dev/null +++ b/pyload/plugin/internal/UpdateManager.py @@ -0,0 +1,306 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import re +import sys + +from operator import itemgetter +from os import path, remove, stat + +from pyload.network.RequestFactory import getURL +from pyload.plugin.Addon import Expose, Addon, threaded +from pyload.utils import safe_join + + +class UpdateManager(Addon): + __name__ = "UpdateManager" + __type__ = "addon" + __version__ = "0.43" + + __config__ = [("activated" , "bool" , "Activated" , True ), + ("mode" , "pyLoad + plugins;plugins only", "Check updates for" , "pyLoad + plugins"), + ("interval" , "int" , "Check interval in hours" , 8 ), + ("autorestart" , "bool" , "Automatically restart pyLoad when required" , True ), + ("reloadplugins", "bool" , "Monitor plugins for code changes in debug mode", True ), + ("nodebugupdate", "bool" , "Don't check for updates in debug mode" , False )] + + __description__ = """Check for updates""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + # event_list = ["pluginConfigChanged"] + + SERVER_URL = "http://updatemanager.pyload.org" + VERSION = re.compile(r'__version__.*=.*("|\')([\d.]+)') + MIN_INTERVAL = 3 * 60 * 60 #: 3h minimum check interval (value is in seconds) + + + def pluginConfigChanged(self, plugin, name, value): + if name == "interval": + interval = value * 60 * 60 + if self.MIN_INTERVAL <= interval != self.interval: + self.core.scheduler.removeJob(self.cb) + self.interval = interval + self.initPeriodical() + else: + self.logDebug("Invalid interval value, kept current") + + elif name == "reloadplugins": + if self.cb2: + self.core.scheduler.removeJob(self.cb2) + if value is True and self.core.debug: + self.periodical2() + + + def activate(self): + self.pluginConfigChanged(self.__name__, "interval", self.getConfig("interval")) + x = lambda: self.pluginConfigChanged(self.__name__, "reloadplugins", self.getConfig("reloadplugins")) + self.core.scheduler.addJob(10, x, threaded=False) + + + def deactivate(self): + self.pluginConfigChanged(self.__name__, "reloadplugins", False) + + + def setup(self): + self.cb2 = None + self.interval = 0 + self.updating = False + self.info = {'pyload': False, 'version': None, 'plugins': False} + self.mtimes = {} #: store modification time for each plugin + + + def periodical2(self): + if not self.updating: + self.autoreloadPlugins() + + self.cb2 = self.core.scheduler.addJob(4, self.periodical2, threaded=False) + + + @Expose + def autoreloadPlugins(self): + """ reload and reindex all modified plugins """ + modules = filter( + lambda m: m and (m.__name__.startswith("pyload.plugin.") or + m.__name__.startswith("userplugins.")) and + m.__name__.count(".") >= 2, sys.modules.itervalues() + ) + + reloads = [] + + for m in modules: + root, type, name = m.__name__.rsplit(".", 2) + id = (type, name) + if type in self.core.pluginManager.plugins: + f = m.__file__.replace(".pyc", ".py") + if not path.isfile(f): + continue + + mtime = stat(f).st_mtime + + if id not in self.mtimes: + self.mtimes[id] = mtime + elif self.mtimes[id] < mtime: + reloads.append(id) + self.mtimes[id] = mtime + + return True if self.core.pluginManager.reloadPlugins(reloads) else False + + + def periodical(self): + if self.info['pyload'] or self.getConfig("nodebugupdate") and self.core.debug: + return + + self.updateThread() + + + def server_request(self): + try: + return getURL(self.SERVER_URL, get={'v': self.core.api.getServerVersion()}).splitlines() + except Exception: + self.logWarning(_("Unable to contact server to get updates")) + + + @threaded + def updateThread(self): + self.updating = True + + status = self.update(onlyplugin=self.getConfig("mode") == "plugins only") + + if status is 2 and self.getConfig("autorestart"): + self.core.api.restart() + else: + self.updating = False + + + @Expose + def updatePlugins(self): + """ simple wrapper for calling plugin update quickly """ + return self.update(onlyplugin=True) + + + @Expose + def update(self, onlyplugin=False): + """ check for updates """ + data = self.server_request() + + if not data: + exitcode = 0 + + elif data[0] == "None": + self.logInfo(_("No new pyLoad version available")) + updates = data[1:] + exitcode = self._updatePlugins(updates) + + elif onlyplugin: + exitcode = 0 + + else: + newversion = data[0] + self.logInfo(_("*** New pyLoad Version %s available ***") % newversion) + self.logInfo(_("*** Get it here: https://github.com/pyload/pyload/releases ***")) + exitcode = 3 + self.info['pyload'] = True + self.info['version'] = newversion + + return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required; 3 = No plugins updated, new pyLoad version available + + + def _updatePlugins(self, updates): + """ check for plugin updates """ + + if self.info['plugins']: + return False #: plugins were already updated + + exitcode = 0 + updated = [] + + url = updates[0] + schema = updates[1].split('|') + + if "BLACKLIST" in updates: + blacklist = updates[updates.index('BLACKLIST') + 1:] + updates = updates[2:updates.index('BLACKLIST')] + else: + blacklist = None + updates = updates[2:] + + upgradable = [dict(zip(schema, x.split('|'))) for x in updates] + blacklisted = [(x.split('|')[0], x.split('|')[1].rsplit('.', 1)[0]) for x in blacklist] if blacklist else [] + + if blacklist: + # Protect UpdateManager from self-removing + try: + blacklisted.remove(("internal", "UpdateManager")) + except Exception: + pass + + for t, n in blacklisted: + for idx, plugin in enumerate(upgradable): + if n == plugin['name'] and t == plugin['type']: + upgradable.pop(idx) + break + + for t, n in self.removePlugins(sorted(blacklisted)): + self.logInfo(_("Removed blacklisted plugin [%(type)s] %(name)s") % { + 'type': t, + 'name': n, + }) + + for plugin in sorted(upgradable, key=itemgetter("type", "name")): + filename = plugin['name'] + type = plugin['type'] + version = plugin['version'] + + if filename.endswith(".pyc"): + name = filename[:filename.find("_")] + else: + name = filename.replace(".py", "") + + plugins = getattr(self.core.pluginManager, "%sPlugins" % type) + + oldver = float(plugins[name]['version']) if name in plugins else None + newver = float(version) + + if not oldver: + msg = "New plugin: [%(type)s] %(name)s (v%(newver).2f)" + elif newver > oldver: + msg = "New version of plugin: [%(type)s] %(name)s (v%(oldver).2f -> v%(newver).2f)" + else: + continue + + self.logInfo(_(msg) % {'type' : type, + 'name' : name, + 'oldver': oldver, + 'newver': newver}) + try: + content = getURL(url % plugin) + m = self.VERSION.search(content) + + if m and m.group(2) == version: + with open(safe_join("userplugins", prefix, filename), "wb") as f: + f.write(content) + + updated.append((prefix, name)) + else: + raise Exception, _("Version mismatch") + + except Exception, e: + self.logError(_("Error updating plugin: %s") % filename, str(e)) + + if updated: + reloaded = self.core.pluginManager.reloadPlugins(updated) + if reloaded: + self.logInfo(_("Plugins updated and reloaded")) + exitcode = 1 + else: + self.logInfo(_("*** Plugins have been updated, but need a pyLoad restart to be reloaded ***")) + self.info['plugins'] = True + exitcode = 2 + else: + self.logInfo(_("No plugin updates available")) + + return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required + + + @Expose + def removePlugins(self, type_plugins): + """ delete plugins from disk """ + + if not type_plugins: + return + + self.logDebug("Requested deletion of plugins: %s" % type_plugins) + + removed = [] + + for type, name in type_plugins: + err = False + file = name + ".py" + + for root in ("userplugins", path.join(pypath, "pyload", "plugins")): + + filename = safe_join(root, type, file) + try: + remove(filename) + except Exception, e: + self.logDebug("Error deleting: %s" % path.basename(filename), e) + err = True + + filename += "c" + if path.isfile(filename): + try: + if type == "addon": + self.manager.deactivateAddon(name) + remove(filename) + except Exception, e: + self.logDebug("Error deleting: %s" % path.basename(filename), e) + err = True + + if not err: + id = (type, name) + removed.append(id) + + return removed #: return a list of the plugins successfully removed diff --git a/module/plugins/internal/XFSAccount.py b/pyload/plugin/internal/XFSAccount.py index 2e6b7dc50..2e6b7dc50 100644 --- a/module/plugins/internal/XFSAccount.py +++ b/pyload/plugin/internal/XFSAccount.py diff --git a/pyload/plugin/internal/XFSCrypter.py b/pyload/plugin/internal/XFSCrypter.py new file mode 100644 index 000000000..1a03b69d0 --- /dev/null +++ b/pyload/plugin/internal/XFSCrypter.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- + +from pyload.plugin.internal.SimpleCrypter import SimpleCrypter + + +class XFSCrypter(SimpleCrypter): + __name__ = "XFSCrypter" + __type__ = "crypter" + __version__ = "0.06" + + __pattern__ = r'^unmatchable$' + + __description__ = """XFileSharing decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + HOSTER_DOMAIN = None + + URL_REPLACEMENTS = [(r'&?per_page=\d+', ""), (r'[?/&]+$', ""), (r'(.+/[^?]+)$', r'\1?'), (r'$', r'&per_page=10000')] + + LINK_PATTERN = r'<(?:td|TD).*?>\s*<a href="(.+?)".*?>.+?(?:</a>)?\s*</(?:td|TD)>' + NAME_PATTERN = r'<[tT]itle>.*?\: (?P<N>.+) folder</[tT]itle>' + + OFFLINE_PATTERN = r'>\s*\w+ (Not Found|file (was|has been) removed)' + TEMP_OFFLINE_PATTERN = r'>\s*\w+ server (is in )?(maintenance|maintainance)' + + + def prepare(self): + if not self.HOSTER_DOMAIN: + if self.account: + account = self.account + else: + account_name = (self.__name__ + ".py").replace("Folder.py", "").replace(".py", "") + account = self.pyfile.m.core.accountManager.getAccountPlugin(account_name) + + if account and hasattr(account, "HOSTER_DOMAIN") and account.HOSTER_DOMAIN: + self.HOSTER_DOMAIN = account.HOSTER_DOMAIN + else: + self.fail(_("Missing HOSTER_DOMAIN")) + + if isinstance(self.COOKIES, list): + self.COOKIES.insert((self.HOSTER_DOMAIN, "lang", "english")) + + return super(XFSCrypter, self).prepare() diff --git a/pyload/plugin/internal/XFSHoster.py b/pyload/plugin/internal/XFSHoster.py new file mode 100644 index 000000000..b0a5aff0f --- /dev/null +++ b/pyload/plugin/internal/XFSHoster.py @@ -0,0 +1,326 @@ +# -*- coding: utf-8 -*- + +import re + +from random import random +from time import sleep +from urlparse import urljoin, urlparse + +from pyload.plugin.internal.captcha import ReCaptcha, SolveMedia +from pyload.plugin.internal.SimpleHoster import SimpleHoster, secondsToMidnight +from pyload.utils import html_unescape + + +class XFSHoster(SimpleHoster): + __name__ = "XFSHoster" + __type__ = "hoster" + __version__ = "0.44" + + __pattern__ = r'^unmatchable$' + + __description__ = """XFileSharing hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), + ("stickell", "l.stickell@yahoo.it"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + HOSTER_DOMAIN = None + + TEXT_ENCODING = False + DIRECT_LINK = None + MULTI_HOSTER = True #@NOTE: Should be default to False for safe, but I'm lazy... + + NAME_PATTERN = r'(Filename[ ]*:[ ]*</b>(</td><td nowrap>)?|name="fname"[ ]+value="|<[\w^_]+ class="(file)?name">)\s*(?P<N>.+?)(\s*<|")' + SIZE_PATTERN = r'(Size[ ]*:[ ]*</b>(</td><td>)?|File:.*>|</font>\s*\(|<[\w^_]+ class="size">)\s*(?P<S>[\d.,]+)\s*(?P<U>[\w^_]+)' + + OFFLINE_PATTERN = r'>\s*\w+ (Not Found|file (was|has been) removed)' + TEMP_OFFLINE_PATTERN = r'>\s*\w+ server (is in )?(maintenance|maintainance)' + + WAIT_PATTERN = r'<span id="countdown_str">.*?>(\d+)</span>|id="countdown" value=".*?(\d+).*?"' + PREMIUM_ONLY_PATTERN = r'>This file is available for Premium Users only' + ERROR_PATTERN = r'(?:class=["\']err["\'].*?>|<[Cc]enter><b>|>Error</td>|>\(ERROR:)(?:\s*<.+?>\s*)*(.+?)(?:["\']|<|\))' + + LINK_LEECH_PATTERN = r'<h2>Download Link</h2>\s*<textarea[^>]*>([^<]+)' + LINK_PATTERN = None #: final download url pattern + + CAPTCHA_PATTERN = r'(https?://[^"\']+?/captchas?/[^"\']+)' + CAPTCHA_BLOCK_PATTERN = r'>Enter code.*?<div.*?>(.+?)</div>' + RECAPTCHA_PATTERN = None + SOLVEMEDIA_PATTERN = None + + FORM_PATTERN = None + FORM_INPUTS_MAP = None #: dict passed as input_names to parseHtmlForm + + + def setup(self): + self.chunkLimit = -1 if self.premium else 1 + self.resumeDownload = self.multiDL = self.premium + + + def prepare(self): + """ Initialize important variables """ + if not self.HOSTER_DOMAIN: + if self.account: + account = self.account + else: + account = self.pyfile.m.core.accountManager.getAccountPlugin(self.__name__) + + if account and hasattr(account, "HOSTER_DOMAIN") and account.HOSTER_DOMAIN: + self.HOSTER_DOMAIN = account.HOSTER_DOMAIN + else: + self.fail(_("Missing HOSTER_DOMAIN")) + + if isinstance(self.COOKIES, list): + self.COOKIES.insert((self.HOSTER_DOMAIN, "lang", "english")) + + if not self.LINK_PATTERN: + pattern = r'(https?://(?:www\.)?([^/]*?%s|\d+\.\d+\.\d+\.\d+)(\:\d+)?(/d/|(/files)?/\d+/\w+/).+?)["\'<]' + self.LINK_PATTERN = pattern % self.HOSTER_DOMAIN.replace('.', '\.') + + self.captcha = None + self.errmsg = None + + super(XFSHoster, self).prepare() + + if self.DIRECT_LINK is None: + self.directDL = self.premium + + + def handleFree(self, pyfile): + for i in xrange(1, 6): + self.logDebug("Getting download link: #%d" % i) + + self.checkErrors() + + m = re.search(self.LINK_PATTERN, self.html, re.S) + if m: + break + + data = self.getPostParameters() + + self.html = self.load(self.pyfile.url, post=data, ref=True, decode=True, follow_location=False) + + m = re.search(r'Location\s*:\s*(.+)', self.req.http.header, re.I) + if m and not "op=" in m.group(1): + break + + m = re.search(self.LINK_PATTERN, self.html, re.S) + if m: + break + else: + self.logError(data['op'] if 'op' in data else _("UNKNOWN")) + return "" + + self.link = m.group(1).strip() #@TODO: Remove .strip() in 0.4.10 + + + def handlePremium(self, pyfile): + return self.handleFree(pyfile) + + + def handleMulti(self, pyfile): + if not self.account: + self.fail(_("Only registered or premium users can use url leech feature")) + + #only tested with easybytez.com + self.html = self.load("http://www.%s/" % self.HOSTER_DOMAIN) + + action, inputs = self.parseHtmlForm() + + upload_id = "%012d" % int(random() * 10 ** 12) + action += upload_id + "&js_on=1&utype=prem&upload_type=url" + + inputs['tos'] = '1' + inputs['url_mass'] = pyfile.url + inputs['up1oad_type'] = 'url' + + self.logDebug(action, inputs) + + self.req.setOption("timeout", 600) #: wait for file to upload to easybytez.com + + self.html = self.load(action, post=inputs) + + self.checkErrors() + + action, inputs = self.parseHtmlForm('F1') + if not inputs: + if self.errmsg: + self.retry(reason=self.errmsg) + else: + self.error(_("TEXTAREA F1 not found")) + + self.logDebug(inputs) + + stmsg = inputs['st'] + + if stmsg == 'OK': + self.html = self.load(action, post=inputs) + + elif 'Can not leech file' in stmsg: + self.retry(20, 3 * 60, _("Can not leech file")) + + elif 'today' in stmsg: + self.retry(wait_time=secondsToMidnight(gmt=2), reason=_("You've used all Leech traffic today")) + + else: + self.fail(stmsg) + + #get easybytez.com link for uploaded file + m = re.search(self.LINK_LEECH_PATTERN, self.html) + if m is None: + self.error(_("LINK_LEECH_PATTERN not found")) + + header = self.load(m.group(1), just_header=True, decode=True) + + if 'location' in header: #: Direct download link + self.link = header['location'] + + + def checkErrors(self): + m = re.search(self.ERROR_PATTERN, self.html) + if m is None: + self.errmsg = None + else: + self.errmsg = m.group(1).strip() + + self.logWarning(re.sub(r"<.*?>", " ", self.errmsg)) + + if 'wait' in self.errmsg: + wait_time = sum(int(v) * {"hr": 3600, "hour": 3600, "min": 60, "sec": 1}[u.lower()] for v, u in + re.findall(r'(\d+)\s*(hr|hour|min|sec)', self.errmsg, re.I)) + self.wait(wait_time, True) + + elif 'country' in self.errmsg: + self.fail(_("Downloads are disabled for your country")) + + elif 'captcha' in self.errmsg: + self.invalidCaptcha() + + elif 'premium' in self.errmsg and 'require' in self.errmsg: + self.fail(_("File can be downloaded by premium users only")) + + elif 'limit' in self.errmsg: + if 'days' in self.errmsg: + delay = secondsToMidnight(gmt=2) + retries = 3 + else: + delay = 1 * 60 * 60 + retries = 24 + + self.wantReconnect = True + self.retry(retries, delay, _("Download limit exceeded")) + + elif 'countdown' in self.errmsg or 'Expired' in self.errmsg: + self.retry(reason=_("Link expired")) + + elif 'maintenance' in self.errmsg or 'maintainance' in self.errmsg: + self.tempOffline() + + elif 'up to' in self.errmsg: + self.fail(_("File too large for free download")) + + else: + self.wantReconnect = True + self.retry(wait_time=60, reason=self.errmsg) + + if self.errmsg: + self.info['error'] = self.errmsg + else: + self.info.pop('error', None) + + + def getPostParameters(self): + if self.FORM_PATTERN or self.FORM_INPUTS_MAP: + action, inputs = self.parseHtmlForm(self.FORM_PATTERN or "", self.FORM_INPUTS_MAP or {}) + else: + action, inputs = self.parseHtmlForm(input_names={'op': re.compile(r'^download')}) + + if not inputs: + action, inputs = self.parseHtmlForm('F1') + if not inputs: + if self.errmsg: + self.retry(reason=self.errmsg) + else: + self.error(_("TEXTAREA F1 not found")) + + self.logDebug(inputs) + + if 'op' in inputs: + if "password" in inputs: + password = self.getPassword() + if password: + inputs['password'] = password + else: + self.fail(_("Missing password")) + + if not self.premium: + m = re.search(self.WAIT_PATTERN, self.html) + if m: + wait_time = int(m.group(1)) + self.setWait(wait_time, False) + + self.captcha = self.handleCaptcha(inputs) + + self.wait() + else: + inputs['referer'] = self.pyfile.url + + if self.premium: + inputs['method_premium'] = "Premium Download" + inputs.pop('method_free', None) + else: + inputs['method_free'] = "Free Download" + inputs.pop('method_premium', None) + + return inputs + + + def handleCaptcha(self, inputs): + m = re.search(self.CAPTCHA_PATTERN, self.html) + if m: + captcha_url = m.group(1) + inputs['code'] = self.decryptCaptcha(captcha_url) + return 1 + + m = re.search(self.CAPTCHA_BLOCK_PATTERN, self.html, re.S) + if m: + captcha_div = m.group(1) + numerals = re.findall(r'<span.*?padding-left\s*:\s*(\d+).*?>(\d)</span>', html_unescape(captcha_div)) + + self.logDebug(captcha_div) + + inputs['code'] = "".join(a[1] for a in sorted(numerals, key=lambda num: int(num[0]))) + + self.logDebug("Captcha code: %s" % inputs['code'], numerals) + return 2 + + recaptcha = ReCaptcha(self) + try: + captcha_key = re.search(self.RECAPTCHA_PATTERN, self.html).group(1) + + except Exception: + captcha_key = recaptcha.detect_key() + + else: + self.logDebug("ReCaptcha key: %s" % captcha_key) + + if captcha_key: + inputs['recaptcha_response_field'], inputs['recaptcha_challenge_field'] = recaptcha.challenge(captcha_key) + return 3 + + solvemedia = SolveMedia(self) + try: + captcha_key = re.search(self.SOLVEMEDIA_PATTERN, self.html).group(1) + + except Exception: + captcha_key = solvemedia.detect_key() + + else: + self.logDebug("SolveMedia key: %s" % captcha_key) + + if captcha_key: + inputs['adcopy_response'], inputs['adcopy_challenge'] = solvemedia.challenge(captcha_key) + return 4 + + return 0 diff --git a/module/plugins/ocr/__init__.py b/pyload/plugin/internal/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/plugins/ocr/__init__.py +++ b/pyload/plugin/internal/__init__.py diff --git a/module/plugins/ocr/GigasizeCom.py b/pyload/plugin/ocr/GigasizeCom.py index 6982e6ca9..6982e6ca9 100644 --- a/module/plugins/ocr/GigasizeCom.py +++ b/pyload/plugin/ocr/GigasizeCom.py diff --git a/module/plugins/ocr/LinksaveIn.py b/pyload/plugin/ocr/LinksaveIn.py index 7ced74f4b..7ced74f4b 100644 --- a/module/plugins/ocr/LinksaveIn.py +++ b/pyload/plugin/ocr/LinksaveIn.py diff --git a/module/plugins/ocr/NetloadIn.py b/pyload/plugin/ocr/NetloadIn.py index 8939b5318..8939b5318 100644 --- a/module/plugins/ocr/NetloadIn.py +++ b/pyload/plugin/ocr/NetloadIn.py diff --git a/module/plugins/ocr/ShareonlineBiz.py b/pyload/plugin/ocr/ShareonlineBiz.py index bbc3d1762..bbc3d1762 100644 --- a/module/plugins/ocr/ShareonlineBiz.py +++ b/pyload/plugin/ocr/ShareonlineBiz.py diff --git a/module/remote/socketbackend/__init__.py b/pyload/plugin/ocr/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/remote/socketbackend/__init__.py +++ b/pyload/plugin/ocr/__init__.py diff --git a/module/remote/ClickAndLoadBackend.py b/pyload/remote/ClickAndLoadBackend.py index a73ea7f24..a73ea7f24 100644 --- a/module/remote/ClickAndLoadBackend.py +++ b/pyload/remote/ClickAndLoadBackend.py diff --git a/module/remote/SocketBackend.py b/pyload/remote/SocketBackend.py index a1c885347..a1c885347 100644 --- a/module/remote/SocketBackend.py +++ b/pyload/remote/SocketBackend.py diff --git a/module/remote/ThriftBackend.py b/pyload/remote/ThriftBackend.py index 16917cfc9..16917cfc9 100644 --- a/module/remote/ThriftBackend.py +++ b/pyload/remote/ThriftBackend.py diff --git a/module/remote/__init__.py b/pyload/remote/__init__.py index 60dfa77c7..60dfa77c7 100644 --- a/module/remote/__init__.py +++ b/pyload/remote/__init__.py diff --git a/module/remote/thriftbackend/__init__.py b/pyload/remote/socketbackend/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/remote/thriftbackend/__init__.py +++ b/pyload/remote/socketbackend/__init__.py diff --git a/module/remote/socketbackend/create_ttypes.py b/pyload/remote/socketbackend/create_ttypes.py index 5bfbcafa0..5bfbcafa0 100644 --- a/module/remote/socketbackend/create_ttypes.py +++ b/pyload/remote/socketbackend/create_ttypes.py diff --git a/module/remote/thriftbackend/Processor.py b/pyload/remote/thriftbackend/Processor.py index 683697d1c..683697d1c 100644 --- a/module/remote/thriftbackend/Processor.py +++ b/pyload/remote/thriftbackend/Processor.py diff --git a/module/remote/thriftbackend/Protocol.py b/pyload/remote/thriftbackend/Protocol.py index 417b45834..417b45834 100644 --- a/module/remote/thriftbackend/Protocol.py +++ b/pyload/remote/thriftbackend/Protocol.py diff --git a/module/remote/thriftbackend/Socket.py b/pyload/remote/thriftbackend/Socket.py index f6edc8408..f6edc8408 100644 --- a/module/remote/thriftbackend/Socket.py +++ b/pyload/remote/thriftbackend/Socket.py diff --git a/module/remote/thriftbackend/ThriftClient.py b/pyload/remote/thriftbackend/ThriftClient.py index 7c2a1cb01..7c2a1cb01 100644 --- a/module/remote/thriftbackend/ThriftClient.py +++ b/pyload/remote/thriftbackend/ThriftClient.py diff --git a/module/remote/thriftbackend/ThriftTest.py b/pyload/remote/thriftbackend/ThriftTest.py index c9c0d3cf3..c9c0d3cf3 100644 --- a/module/remote/thriftbackend/ThriftTest.py +++ b/pyload/remote/thriftbackend/ThriftTest.py diff --git a/module/remote/thriftbackend/Transport.py b/pyload/remote/thriftbackend/Transport.py index 7db4ba9d7..7db4ba9d7 100644 --- a/module/remote/thriftbackend/Transport.py +++ b/pyload/remote/thriftbackend/Transport.py diff --git a/module/remote/thriftbackend/thriftgen/__init__.py b/pyload/remote/thriftbackend/__init__.py index 40a96afc6..40a96afc6 100644 --- a/module/remote/thriftbackend/thriftgen/__init__.py +++ b/pyload/remote/thriftbackend/__init__.py diff --git a/module/remote/thriftbackend/pyload.thrift b/pyload/remote/thriftbackend/pyload.thrift index 3aef7af00..3aef7af00 100644 --- a/module/remote/thriftbackend/pyload.thrift +++ b/pyload/remote/thriftbackend/pyload.thrift diff --git a/pyload/remote/thriftbackend/thriftgen/__init__.py b/pyload/remote/thriftbackend/thriftgen/__init__.py new file mode 100644 index 000000000..40a96afc6 --- /dev/null +++ b/pyload/remote/thriftbackend/thriftgen/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/module/remote/thriftbackend/thriftgen/pyload/Pyload-remote b/pyload/remote/thriftbackend/thriftgen/pyload/Pyload-remote index ddc1dd451..ddc1dd451 100644 --- a/module/remote/thriftbackend/thriftgen/pyload/Pyload-remote +++ b/pyload/remote/thriftbackend/thriftgen/pyload/Pyload-remote diff --git a/module/remote/thriftbackend/thriftgen/pyload/Pyload.py b/pyload/remote/thriftbackend/thriftgen/pyload/Pyload.py index e8d2cf9af..e8d2cf9af 100644 --- a/module/remote/thriftbackend/thriftgen/pyload/Pyload.py +++ b/pyload/remote/thriftbackend/thriftgen/pyload/Pyload.py diff --git a/module/remote/thriftbackend/thriftgen/pyload/__init__.py b/pyload/remote/thriftbackend/thriftgen/pyload/__init__.py index 9a0fb88bf..9a0fb88bf 100644 --- a/module/remote/thriftbackend/thriftgen/pyload/__init__.py +++ b/pyload/remote/thriftbackend/thriftgen/pyload/__init__.py diff --git a/module/remote/thriftbackend/thriftgen/pyload/constants.py b/pyload/remote/thriftbackend/thriftgen/pyload/constants.py index 3bdd64cc1..3bdd64cc1 100644 --- a/module/remote/thriftbackend/thriftgen/pyload/constants.py +++ b/pyload/remote/thriftbackend/thriftgen/pyload/constants.py diff --git a/module/remote/thriftbackend/thriftgen/pyload/ttypes.py b/pyload/remote/thriftbackend/thriftgen/pyload/ttypes.py index 67d23161d..67d23161d 100644 --- a/module/remote/thriftbackend/thriftgen/pyload/ttypes.py +++ b/pyload/remote/thriftbackend/thriftgen/pyload/ttypes.py diff --git a/module/utils/__init__.py b/pyload/utils/__init__.py index 330ee622c..330ee622c 100644 --- a/module/utils/__init__.py +++ b/pyload/utils/__init__.py diff --git a/module/utils/packagetools.py b/pyload/utils/packagetools.py index 9dbde9b50..9dbde9b50 100644 --- a/module/utils/packagetools.py +++ b/pyload/utils/packagetools.py diff --git a/module/utils/printer.py b/pyload/utils/printer.py index 5d333e238..5d333e238 100644 --- a/module/utils/printer.py +++ b/pyload/utils/printer.py diff --git a/module/utils/pylgettext.py b/pyload/utils/pylgettext.py index cab631cf4..cab631cf4 100644 --- a/module/utils/pylgettext.py +++ b/pyload/utils/pylgettext.py diff --git a/module/webui/__init__.py b/pyload/webui/__init__.py index 0d2f1ca36..0d2f1ca36 100644 --- a/module/webui/__init__.py +++ b/pyload/webui/__init__.py diff --git a/module/webui/app/__init__.py b/pyload/webui/app/__init__.py index 39d0fadd5..39d0fadd5 100644 --- a/module/webui/app/__init__.py +++ b/pyload/webui/app/__init__.py diff --git a/module/webui/app/api.py b/pyload/webui/app/api.py index 1ee4b1608..1ee4b1608 100644 --- a/module/webui/app/api.py +++ b/pyload/webui/app/api.py diff --git a/module/webui/app/cnl.py b/pyload/webui/app/cnl.py index e00e47f66..e00e47f66 100644 --- a/module/webui/app/cnl.py +++ b/pyload/webui/app/cnl.py diff --git a/module/webui/app/json.py b/pyload/webui/app/json.py index c347c25e3..c347c25e3 100644 --- a/module/webui/app/json.py +++ b/pyload/webui/app/json.py diff --git a/module/webui/app/pyload.py b/pyload/webui/app/pyload.py index 2d1a8eb86..2d1a8eb86 100644 --- a/module/webui/app/pyload.py +++ b/pyload/webui/app/pyload.py diff --git a/module/webui/app/utils.py b/pyload/webui/app/utils.py index fd0e14cfa..fd0e14cfa 100644 --- a/module/webui/app/utils.py +++ b/pyload/webui/app/utils.py diff --git a/module/webui/filters.py b/pyload/webui/filters.py index 527b18446..527b18446 100644 --- a/module/webui/filters.py +++ b/pyload/webui/filters.py diff --git a/module/webui/middlewares.py b/pyload/webui/middlewares.py index 5f56f81ee..5f56f81ee 100644 --- a/module/webui/middlewares.py +++ b/pyload/webui/middlewares.py diff --git a/module/webui/servers/lighttpd_default.conf b/pyload/webui/servers/lighttpd_default.conf index aa199b3f3..aa199b3f3 100644 --- a/module/webui/servers/lighttpd_default.conf +++ b/pyload/webui/servers/lighttpd_default.conf diff --git a/module/webui/servers/nginx_default.conf b/pyload/webui/servers/nginx_default.conf index c1cfcafca..c1cfcafca 100644 --- a/module/webui/servers/nginx_default.conf +++ b/pyload/webui/servers/nginx_default.conf diff --git a/module/webui/themes/Dark/css/MooDialog.css b/pyload/webui/themes/Dark/css/MooDialog.css index 1714e170f..1714e170f 100644 --- a/module/webui/themes/Dark/css/MooDialog.css +++ b/pyload/webui/themes/Dark/css/MooDialog.css diff --git a/module/webui/themes/Dark/css/base.css b/pyload/webui/themes/Dark/css/base.css index f0bae8f24..f0bae8f24 100644 --- a/module/webui/themes/Dark/css/base.css +++ b/pyload/webui/themes/Dark/css/base.css diff --git a/module/webui/themes/Dark/css/log.css b/pyload/webui/themes/Dark/css/log.css index 3362e9381..3362e9381 100644 --- a/module/webui/themes/Dark/css/log.css +++ b/pyload/webui/themes/Dark/css/log.css diff --git a/module/webui/themes/Dark/css/pathchooser.css b/pyload/webui/themes/Dark/css/pathchooser.css index 204812aa1..204812aa1 100644 --- a/module/webui/themes/Dark/css/pathchooser.css +++ b/pyload/webui/themes/Dark/css/pathchooser.css diff --git a/module/webui/themes/Dark/css/window.css b/pyload/webui/themes/Dark/css/window.css index 1bcc58e6c..1bcc58e6c 100644 --- a/module/webui/themes/Dark/css/window.css +++ b/pyload/webui/themes/Dark/css/window.css diff --git a/module/webui/themes/Dark/img/MooDialog/dialog-close.png b/pyload/webui/themes/Dark/img/MooDialog/dialog-close.png Binary files differindex 81ebb88b2..81ebb88b2 100644 --- a/module/webui/themes/Dark/img/MooDialog/dialog-close.png +++ b/pyload/webui/themes/Dark/img/MooDialog/dialog-close.png diff --git a/module/webui/themes/Dark/img/MooDialog/dialog-error.png b/pyload/webui/themes/Dark/img/MooDialog/dialog-error.png Binary files differindex d70328403..d70328403 100644 --- a/module/webui/themes/Dark/img/MooDialog/dialog-error.png +++ b/pyload/webui/themes/Dark/img/MooDialog/dialog-error.png diff --git a/module/webui/themes/Dark/img/MooDialog/dialog-question.png b/pyload/webui/themes/Dark/img/MooDialog/dialog-question.png Binary files differindex b0af3db5b..b0af3db5b 100644 --- a/module/webui/themes/Dark/img/MooDialog/dialog-question.png +++ b/pyload/webui/themes/Dark/img/MooDialog/dialog-question.png diff --git a/module/webui/themes/Dark/img/MooDialog/dialog-warning.png b/pyload/webui/themes/Dark/img/MooDialog/dialog-warning.png Binary files differindex aad64d4be..aad64d4be 100644 --- a/module/webui/themes/Dark/img/MooDialog/dialog-warning.png +++ b/pyload/webui/themes/Dark/img/MooDialog/dialog-warning.png diff --git a/module/webui/themes/Dark/img/button.png b/pyload/webui/themes/Dark/img/button.png Binary files differindex bb408a7d6..bb408a7d6 100644 --- a/module/webui/themes/Dark/img/button.png +++ b/pyload/webui/themes/Dark/img/button.png diff --git a/module/webui/themes/Dark/img/dark-bg.jpg b/pyload/webui/themes/Dark/img/dark-bg.jpg Binary files differindex 637fa6b93..637fa6b93 100644 --- a/module/webui/themes/Dark/img/dark-bg.jpg +++ b/pyload/webui/themes/Dark/img/dark-bg.jpg diff --git a/module/webui/themes/Dark/img/default/add_folder.png b/pyload/webui/themes/Dark/img/default/add_folder.png Binary files differindex 8acbc411b..8acbc411b 100644 --- a/module/webui/themes/Dark/img/default/add_folder.png +++ b/pyload/webui/themes/Dark/img/default/add_folder.png diff --git a/module/webui/themes/Dark/img/default/ajax-loader.gif b/pyload/webui/themes/Dark/img/default/ajax-loader.gif Binary files differindex 2fd8e0737..2fd8e0737 100644 --- a/module/webui/themes/Dark/img/default/ajax-loader.gif +++ b/pyload/webui/themes/Dark/img/default/ajax-loader.gif diff --git a/module/webui/themes/Dark/img/default/arrow_refresh.png b/pyload/webui/themes/Dark/img/default/arrow_refresh.png Binary files differindex 0de26566d..0de26566d 100644 --- a/module/webui/themes/Dark/img/default/arrow_refresh.png +++ b/pyload/webui/themes/Dark/img/default/arrow_refresh.png diff --git a/module/webui/themes/Dark/img/default/arrow_right.png b/pyload/webui/themes/Dark/img/default/arrow_right.png Binary files differindex b1a181923..b1a181923 100644 --- a/module/webui/themes/Dark/img/default/arrow_right.png +++ b/pyload/webui/themes/Dark/img/default/arrow_right.png diff --git a/module/webui/themes/Dark/img/default/big_button.gif b/pyload/webui/themes/Dark/img/default/big_button.gif Binary files differindex 7680490ea..7680490ea 100644 --- a/module/webui/themes/Dark/img/default/big_button.gif +++ b/pyload/webui/themes/Dark/img/default/big_button.gif diff --git a/module/webui/themes/Dark/img/default/big_button_over.gif b/pyload/webui/themes/Dark/img/default/big_button_over.gif Binary files differindex 2e3ee10d2..2e3ee10d2 100644 --- a/module/webui/themes/Dark/img/default/big_button_over.gif +++ b/pyload/webui/themes/Dark/img/default/big_button_over.gif diff --git a/module/webui/themes/Dark/img/default/body.png b/pyload/webui/themes/Dark/img/default/body.png Binary files differindex 7ff1043e0..7ff1043e0 100644 --- a/module/webui/themes/Dark/img/default/body.png +++ b/pyload/webui/themes/Dark/img/default/body.png diff --git a/module/webui/themes/Dark/img/default/closebtn.gif b/pyload/webui/themes/Dark/img/default/closebtn.gif Binary files differindex 3e27e6030..3e27e6030 100644 --- a/module/webui/themes/Dark/img/default/closebtn.gif +++ b/pyload/webui/themes/Dark/img/default/closebtn.gif diff --git a/module/webui/themes/Dark/img/default/cog.png b/pyload/webui/themes/Dark/img/default/cog.png Binary files differindex 67de2c6cc..67de2c6cc 100644 --- a/module/webui/themes/Dark/img/default/cog.png +++ b/pyload/webui/themes/Dark/img/default/cog.png diff --git a/module/webui/themes/Dark/img/default/control_add.png b/pyload/webui/themes/Dark/img/default/control_add.png Binary files differindex d39886893..d39886893 100644 --- a/module/webui/themes/Dark/img/default/control_add.png +++ b/pyload/webui/themes/Dark/img/default/control_add.png diff --git a/module/webui/themes/Dark/img/default/control_add_blue.png b/pyload/webui/themes/Dark/img/default/control_add_blue.png Binary files differindex d11b7f41d..d11b7f41d 100644 --- a/module/webui/themes/Dark/img/default/control_add_blue.png +++ b/pyload/webui/themes/Dark/img/default/control_add_blue.png diff --git a/module/webui/themes/Dark/img/default/control_cancel.png b/pyload/webui/themes/Dark/img/default/control_cancel.png Binary files differindex 7b9bc3fba..7b9bc3fba 100644 --- a/module/webui/themes/Dark/img/default/control_cancel.png +++ b/pyload/webui/themes/Dark/img/default/control_cancel.png diff --git a/module/webui/themes/Dark/img/default/control_cancel_blue.png b/pyload/webui/themes/Dark/img/default/control_cancel_blue.png Binary files differindex 0c5c96ce3..0c5c96ce3 100644 --- a/module/webui/themes/Dark/img/default/control_cancel_blue.png +++ b/pyload/webui/themes/Dark/img/default/control_cancel_blue.png diff --git a/module/webui/themes/Dark/img/default/control_pause.png b/pyload/webui/themes/Dark/img/default/control_pause.png Binary files differindex 2d9ce9c4e..2d9ce9c4e 100644 --- a/module/webui/themes/Dark/img/default/control_pause.png +++ b/pyload/webui/themes/Dark/img/default/control_pause.png diff --git a/module/webui/themes/Dark/img/default/control_pause_blue.png b/pyload/webui/themes/Dark/img/default/control_pause_blue.png Binary files differindex ec61099b0..ec61099b0 100644 --- a/module/webui/themes/Dark/img/default/control_pause_blue.png +++ b/pyload/webui/themes/Dark/img/default/control_pause_blue.png diff --git a/module/webui/themes/Dark/img/default/control_play.png b/pyload/webui/themes/Dark/img/default/control_play.png Binary files differindex 0846555d0..0846555d0 100644 --- a/module/webui/themes/Dark/img/default/control_play.png +++ b/pyload/webui/themes/Dark/img/default/control_play.png diff --git a/module/webui/themes/Dark/img/default/control_play_blue.png b/pyload/webui/themes/Dark/img/default/control_play_blue.png Binary files differindex f8c8ec683..f8c8ec683 100644 --- a/module/webui/themes/Dark/img/default/control_play_blue.png +++ b/pyload/webui/themes/Dark/img/default/control_play_blue.png diff --git a/module/webui/themes/Dark/img/default/control_stop.png b/pyload/webui/themes/Dark/img/default/control_stop.png Binary files differindex 893bb60e5..893bb60e5 100644 --- a/module/webui/themes/Dark/img/default/control_stop.png +++ b/pyload/webui/themes/Dark/img/default/control_stop.png diff --git a/module/webui/themes/Dark/img/default/control_stop_blue.png b/pyload/webui/themes/Dark/img/default/control_stop_blue.png Binary files differindex e6f75d232..e6f75d232 100644 --- a/module/webui/themes/Dark/img/default/control_stop_blue.png +++ b/pyload/webui/themes/Dark/img/default/control_stop_blue.png diff --git a/module/webui/themes/Dark/img/default/delete.png b/pyload/webui/themes/Dark/img/default/delete.png Binary files differindex 08f249365..08f249365 100644 --- a/module/webui/themes/Dark/img/default/delete.png +++ b/pyload/webui/themes/Dark/img/default/delete.png diff --git a/module/webui/themes/Dark/img/default/drag_corner.gif b/pyload/webui/themes/Dark/img/default/drag_corner.gif Binary files differindex befb1adf1..befb1adf1 100644 --- a/module/webui/themes/Dark/img/default/drag_corner.gif +++ b/pyload/webui/themes/Dark/img/default/drag_corner.gif diff --git a/module/webui/themes/Dark/img/default/error.png b/pyload/webui/themes/Dark/img/default/error.png Binary files differindex c37bd062e..c37bd062e 100644 --- a/module/webui/themes/Dark/img/default/error.png +++ b/pyload/webui/themes/Dark/img/default/error.png diff --git a/module/webui/themes/Dark/img/default/folder.png b/pyload/webui/themes/Dark/img/default/folder.png Binary files differindex 784e8fa48..784e8fa48 100644 --- a/module/webui/themes/Dark/img/default/folder.png +++ b/pyload/webui/themes/Dark/img/default/folder.png diff --git a/module/webui/themes/Dark/img/default/full.png b/pyload/webui/themes/Dark/img/default/full.png Binary files differindex fea52af76..fea52af76 100644 --- a/module/webui/themes/Dark/img/default/full.png +++ b/pyload/webui/themes/Dark/img/default/full.png diff --git a/module/webui/themes/Dark/img/default/head-login.png b/pyload/webui/themes/Dark/img/default/head-login.png Binary files differindex b59b7cbbf..b59b7cbbf 100644 --- a/module/webui/themes/Dark/img/default/head-login.png +++ b/pyload/webui/themes/Dark/img/default/head-login.png diff --git a/module/webui/themes/Dark/img/default/head-menu-collector.png b/pyload/webui/themes/Dark/img/default/head-menu-collector.png Binary files differindex 861be40bc..861be40bc 100644 --- a/module/webui/themes/Dark/img/default/head-menu-collector.png +++ b/pyload/webui/themes/Dark/img/default/head-menu-collector.png diff --git a/module/webui/themes/Dark/img/default/head-menu-config.png b/pyload/webui/themes/Dark/img/default/head-menu-config.png Binary files differindex bbf43d4f3..bbf43d4f3 100644 --- a/module/webui/themes/Dark/img/default/head-menu-config.png +++ b/pyload/webui/themes/Dark/img/default/head-menu-config.png diff --git a/module/webui/themes/Dark/img/default/head-menu-development.png b/pyload/webui/themes/Dark/img/default/head-menu-development.png Binary files differindex fad150fe1..fad150fe1 100644 --- a/module/webui/themes/Dark/img/default/head-menu-development.png +++ b/pyload/webui/themes/Dark/img/default/head-menu-development.png diff --git a/module/webui/themes/Dark/img/default/head-menu-download.png b/pyload/webui/themes/Dark/img/default/head-menu-download.png Binary files differindex 98c5da9db..98c5da9db 100644 --- a/module/webui/themes/Dark/img/default/head-menu-download.png +++ b/pyload/webui/themes/Dark/img/default/head-menu-download.png diff --git a/module/webui/themes/Dark/img/default/head-menu-home.png b/pyload/webui/themes/Dark/img/default/head-menu-home.png Binary files differindex 9d62109aa..9d62109aa 100644 --- a/module/webui/themes/Dark/img/default/head-menu-home.png +++ b/pyload/webui/themes/Dark/img/default/head-menu-home.png diff --git a/module/webui/themes/Dark/img/default/head-menu-index.png b/pyload/webui/themes/Dark/img/default/head-menu-index.png Binary files differindex 44d631064..44d631064 100644 --- a/module/webui/themes/Dark/img/default/head-menu-index.png +++ b/pyload/webui/themes/Dark/img/default/head-menu-index.png diff --git a/module/webui/themes/Dark/img/default/head-menu-news.png b/pyload/webui/themes/Dark/img/default/head-menu-news.png Binary files differindex 43950ebc9..43950ebc9 100644 --- a/module/webui/themes/Dark/img/default/head-menu-news.png +++ b/pyload/webui/themes/Dark/img/default/head-menu-news.png diff --git a/module/webui/themes/Dark/img/default/head-menu-queue.png b/pyload/webui/themes/Dark/img/default/head-menu-queue.png Binary files differindex be98793ce..be98793ce 100644 --- a/module/webui/themes/Dark/img/default/head-menu-queue.png +++ b/pyload/webui/themes/Dark/img/default/head-menu-queue.png diff --git a/module/webui/themes/Dark/img/default/head-menu-recent.png b/pyload/webui/themes/Dark/img/default/head-menu-recent.png Binary files differindex fc9b0497f..fc9b0497f 100644 --- a/module/webui/themes/Dark/img/default/head-menu-recent.png +++ b/pyload/webui/themes/Dark/img/default/head-menu-recent.png diff --git a/module/webui/themes/Dark/img/default/head-menu-wiki.png b/pyload/webui/themes/Dark/img/default/head-menu-wiki.png Binary files differindex 07cf0102d..07cf0102d 100644 --- a/module/webui/themes/Dark/img/default/head-menu-wiki.png +++ b/pyload/webui/themes/Dark/img/default/head-menu-wiki.png diff --git a/module/webui/themes/Dark/img/default/head-search-noshadow.png b/pyload/webui/themes/Dark/img/default/head-search-noshadow.png Binary files differindex aafdae015..aafdae015 100644 --- a/module/webui/themes/Dark/img/default/head-search-noshadow.png +++ b/pyload/webui/themes/Dark/img/default/head-search-noshadow.png diff --git a/module/webui/themes/Dark/img/default/head_bg1.png b/pyload/webui/themes/Dark/img/default/head_bg1.png Binary files differindex f2848c3cc..f2848c3cc 100644 --- a/module/webui/themes/Dark/img/default/head_bg1.png +++ b/pyload/webui/themes/Dark/img/default/head_bg1.png diff --git a/module/webui/themes/Dark/img/default/images.png b/pyload/webui/themes/Dark/img/default/images.png Binary files differindex 184860d1e..184860d1e 100644 --- a/module/webui/themes/Dark/img/default/images.png +++ b/pyload/webui/themes/Dark/img/default/images.png diff --git a/module/webui/themes/Dark/img/default/notice.png b/pyload/webui/themes/Dark/img/default/notice.png Binary files differindex 12cd1aef9..12cd1aef9 100644 --- a/module/webui/themes/Dark/img/default/notice.png +++ b/pyload/webui/themes/Dark/img/default/notice.png diff --git a/module/webui/themes/Dark/img/default/package_go.png b/pyload/webui/themes/Dark/img/default/package_go.png Binary files differindex aace63ad6..aace63ad6 100644 --- a/module/webui/themes/Dark/img/default/package_go.png +++ b/pyload/webui/themes/Dark/img/default/package_go.png diff --git a/module/webui/themes/Dark/img/default/page-tools-backlinks.png b/pyload/webui/themes/Dark/img/default/page-tools-backlinks.png Binary files differindex 3eb6a9ce3..3eb6a9ce3 100644 --- a/module/webui/themes/Dark/img/default/page-tools-backlinks.png +++ b/pyload/webui/themes/Dark/img/default/page-tools-backlinks.png diff --git a/module/webui/themes/Dark/img/default/page-tools-edit.png b/pyload/webui/themes/Dark/img/default/page-tools-edit.png Binary files differindex 188e1c12b..188e1c12b 100644 --- a/module/webui/themes/Dark/img/default/page-tools-edit.png +++ b/pyload/webui/themes/Dark/img/default/page-tools-edit.png diff --git a/module/webui/themes/Dark/img/default/page-tools-revisions.png b/pyload/webui/themes/Dark/img/default/page-tools-revisions.png Binary files differindex 5c3b8587f..5c3b8587f 100644 --- a/module/webui/themes/Dark/img/default/page-tools-revisions.png +++ b/pyload/webui/themes/Dark/img/default/page-tools-revisions.png diff --git a/module/webui/themes/Dark/img/default/parseUri.png b/pyload/webui/themes/Dark/img/default/parseUri.png Binary files differindex 937bded9d..937bded9d 100644 --- a/module/webui/themes/Dark/img/default/parseUri.png +++ b/pyload/webui/themes/Dark/img/default/parseUri.png diff --git a/module/webui/themes/Dark/img/default/pencil.png b/pyload/webui/themes/Dark/img/default/pencil.png Binary files differindex 0bfecd50e..0bfecd50e 100644 --- a/module/webui/themes/Dark/img/default/pencil.png +++ b/pyload/webui/themes/Dark/img/default/pencil.png diff --git a/module/webui/themes/Dark/img/default/reconnect.png b/pyload/webui/themes/Dark/img/default/reconnect.png Binary files differindex 49b269145..49b269145 100644 --- a/module/webui/themes/Dark/img/default/reconnect.png +++ b/pyload/webui/themes/Dark/img/default/reconnect.png diff --git a/module/webui/themes/Dark/img/default/status_None.png b/pyload/webui/themes/Dark/img/default/status_None.png Binary files differindex 293b13f77..293b13f77 100644 --- a/module/webui/themes/Dark/img/default/status_None.png +++ b/pyload/webui/themes/Dark/img/default/status_None.png diff --git a/module/webui/themes/Dark/img/default/status_downloading.png b/pyload/webui/themes/Dark/img/default/status_downloading.png Binary files differindex fb4ebc850..fb4ebc850 100644 --- a/module/webui/themes/Dark/img/default/status_downloading.png +++ b/pyload/webui/themes/Dark/img/default/status_downloading.png diff --git a/module/webui/themes/Dark/img/default/status_failed.png b/pyload/webui/themes/Dark/img/default/status_failed.png Binary files differindex c37bd062e..c37bd062e 100644 --- a/module/webui/themes/Dark/img/default/status_failed.png +++ b/pyload/webui/themes/Dark/img/default/status_failed.png diff --git a/module/webui/themes/Dark/img/default/status_finished.png b/pyload/webui/themes/Dark/img/default/status_finished.png Binary files differindex 89c8129a4..89c8129a4 100644 --- a/module/webui/themes/Dark/img/default/status_finished.png +++ b/pyload/webui/themes/Dark/img/default/status_finished.png diff --git a/module/webui/themes/Dark/img/default/status_offline.png b/pyload/webui/themes/Dark/img/default/status_offline.png Binary files differindex 0cfd58596..0cfd58596 100644 --- a/module/webui/themes/Dark/img/default/status_offline.png +++ b/pyload/webui/themes/Dark/img/default/status_offline.png diff --git a/module/webui/themes/Dark/img/default/status_proc.png b/pyload/webui/themes/Dark/img/default/status_proc.png Binary files differindex 67de2c6cc..67de2c6cc 100644 --- a/module/webui/themes/Dark/img/default/status_proc.png +++ b/pyload/webui/themes/Dark/img/default/status_proc.png diff --git a/module/webui/themes/Dark/img/default/status_queue.png b/pyload/webui/themes/Dark/img/default/status_queue.png Binary files differindex 293b13f77..293b13f77 100644 --- a/module/webui/themes/Dark/img/default/status_queue.png +++ b/pyload/webui/themes/Dark/img/default/status_queue.png diff --git a/module/webui/themes/Dark/img/default/status_waiting.png b/pyload/webui/themes/Dark/img/default/status_waiting.png Binary files differindex 2842cc338..2842cc338 100644 --- a/module/webui/themes/Dark/img/default/status_waiting.png +++ b/pyload/webui/themes/Dark/img/default/status_waiting.png diff --git a/module/webui/themes/Dark/img/default/success.png b/pyload/webui/themes/Dark/img/default/success.png Binary files differindex 89c8129a4..89c8129a4 100644 --- a/module/webui/themes/Dark/img/default/success.png +++ b/pyload/webui/themes/Dark/img/default/success.png diff --git a/module/webui/themes/Dark/img/default/tabs-border-bottom.png b/pyload/webui/themes/Dark/img/default/tabs-border-bottom.png Binary files differindex 02440f428..02440f428 100644 --- a/module/webui/themes/Dark/img/default/tabs-border-bottom.png +++ b/pyload/webui/themes/Dark/img/default/tabs-border-bottom.png diff --git a/module/webui/themes/Dark/img/default/user-actions-logout.png b/pyload/webui/themes/Dark/img/default/user-actions-logout.png Binary files differindex 0010931e2..0010931e2 100644 --- a/module/webui/themes/Dark/img/default/user-actions-logout.png +++ b/pyload/webui/themes/Dark/img/default/user-actions-logout.png diff --git a/module/webui/themes/Dark/img/default/user-actions-profile.png b/pyload/webui/themes/Dark/img/default/user-actions-profile.png Binary files differindex 46573fff6..46573fff6 100644 --- a/module/webui/themes/Dark/img/default/user-actions-profile.png +++ b/pyload/webui/themes/Dark/img/default/user-actions-profile.png diff --git a/module/webui/themes/Dark/img/default/user-info.png b/pyload/webui/themes/Dark/img/default/user-info.png Binary files differindex 6e643100f..6e643100f 100644 --- a/module/webui/themes/Dark/img/default/user-info.png +++ b/pyload/webui/themes/Dark/img/default/user-info.png diff --git a/module/webui/themes/Dark/img/pyload-logo.png b/pyload/webui/themes/Dark/img/pyload-logo.png Binary files differindex e878afee5..e878afee5 100644 --- a/module/webui/themes/Dark/img/pyload-logo.png +++ b/pyload/webui/themes/Dark/img/pyload-logo.png diff --git a/module/webui/themes/Dark/img/tab-background.png b/pyload/webui/themes/Dark/img/tab-background.png Binary files differindex ee96b8407..ee96b8407 100644 --- a/module/webui/themes/Dark/img/tab-background.png +++ b/pyload/webui/themes/Dark/img/tab-background.png diff --git a/module/webui/themes/Dark/js/render/admin.coffee b/pyload/webui/themes/Dark/js/render/admin.coffee index 5afbcbb66..5afbcbb66 100644 --- a/module/webui/themes/Dark/js/render/admin.coffee +++ b/pyload/webui/themes/Dark/js/render/admin.coffee diff --git a/module/webui/themes/Dark/js/render/admin.min.js b/pyload/webui/themes/Dark/js/render/admin.min.js index 94a5e494d..94a5e494d 100644 --- a/module/webui/themes/Dark/js/render/admin.min.js +++ b/pyload/webui/themes/Dark/js/render/admin.min.js diff --git a/module/webui/themes/Dark/js/render/base.coffee b/pyload/webui/themes/Dark/js/render/base.coffee index 07b8bfb6f..07b8bfb6f 100644 --- a/module/webui/themes/Dark/js/render/base.coffee +++ b/pyload/webui/themes/Dark/js/render/base.coffee diff --git a/module/webui/themes/Dark/js/render/base.min.js b/pyload/webui/themes/Dark/js/render/base.min.js index 1ba1d73f9..1ba1d73f9 100644 --- a/module/webui/themes/Dark/js/render/base.min.js +++ b/pyload/webui/themes/Dark/js/render/base.min.js diff --git a/module/webui/themes/Dark/js/render/package.js b/pyload/webui/themes/Dark/js/render/package.js index 659a8e6fc..659a8e6fc 100644 --- a/module/webui/themes/Dark/js/render/package.js +++ b/pyload/webui/themes/Dark/js/render/package.js diff --git a/module/webui/themes/Dark/js/render/settings.coffee b/pyload/webui/themes/Dark/js/render/settings.coffee index d522741b9..d522741b9 100644 --- a/module/webui/themes/Dark/js/render/settings.coffee +++ b/pyload/webui/themes/Dark/js/render/settings.coffee diff --git a/module/webui/themes/Dark/js/render/settings.min.js b/pyload/webui/themes/Dark/js/render/settings.min.js index 41d1cb25a..41d1cb25a 100644 --- a/module/webui/themes/Dark/js/render/settings.min.js +++ b/pyload/webui/themes/Dark/js/render/settings.min.js diff --git a/module/webui/themes/Dark/js/static/MooDialog.js b/pyload/webui/themes/Dark/js/static/MooDialog.js index 45a52496f..45a52496f 100644 --- a/module/webui/themes/Dark/js/static/MooDialog.js +++ b/pyload/webui/themes/Dark/js/static/MooDialog.js diff --git a/module/webui/themes/Dark/js/static/MooDialog.min.js b/pyload/webui/themes/Dark/js/static/MooDialog.min.js index 90b3ae100..90b3ae100 100644 --- a/module/webui/themes/Dark/js/static/MooDialog.min.js +++ b/pyload/webui/themes/Dark/js/static/MooDialog.min.js diff --git a/module/webui/themes/Dark/js/static/MooDropMenu.js b/pyload/webui/themes/Dark/js/static/MooDropMenu.js index ac0fa1874..ac0fa1874 100644 --- a/module/webui/themes/Dark/js/static/MooDropMenu.js +++ b/pyload/webui/themes/Dark/js/static/MooDropMenu.js diff --git a/module/webui/themes/Dark/js/static/MooDropMenu.min.js b/pyload/webui/themes/Dark/js/static/MooDropMenu.min.js index 552ae247a..552ae247a 100644 --- a/module/webui/themes/Dark/js/static/MooDropMenu.min.js +++ b/pyload/webui/themes/Dark/js/static/MooDropMenu.min.js diff --git a/module/webui/themes/Dark/js/static/mootools-core.js b/pyload/webui/themes/Dark/js/static/mootools-core.js index db83850fd..db83850fd 100644 --- a/module/webui/themes/Dark/js/static/mootools-core.js +++ b/pyload/webui/themes/Dark/js/static/mootools-core.js diff --git a/module/webui/themes/Dark/js/static/mootools-core.min.js b/pyload/webui/themes/Dark/js/static/mootools-core.min.js index 354f94196..354f94196 100644 --- a/module/webui/themes/Dark/js/static/mootools-core.min.js +++ b/pyload/webui/themes/Dark/js/static/mootools-core.min.js diff --git a/module/webui/themes/Dark/js/static/mootools-more.js b/pyload/webui/themes/Dark/js/static/mootools-more.js index c7f4a1a0e..c7f4a1a0e 100644 --- a/module/webui/themes/Dark/js/static/mootools-more.js +++ b/pyload/webui/themes/Dark/js/static/mootools-more.js diff --git a/module/webui/themes/Dark/js/static/mootools-more.min.js b/pyload/webui/themes/Dark/js/static/mootools-more.min.js index ce03a60fd..ce03a60fd 100644 --- a/module/webui/themes/Dark/js/static/mootools-more.min.js +++ b/pyload/webui/themes/Dark/js/static/mootools-more.min.js diff --git a/module/webui/themes/Dark/js/static/purr.js b/pyload/webui/themes/Dark/js/static/purr.js index 9cbc503d9..9cbc503d9 100644 --- a/module/webui/themes/Dark/js/static/purr.js +++ b/pyload/webui/themes/Dark/js/static/purr.js diff --git a/module/webui/themes/Dark/js/static/purr.min.js b/pyload/webui/themes/Dark/js/static/purr.min.js index bf70e357d..bf70e357d 100644 --- a/module/webui/themes/Dark/js/static/purr.min.js +++ b/pyload/webui/themes/Dark/js/static/purr.min.js diff --git a/module/webui/themes/Dark/js/static/tinytab.js b/pyload/webui/themes/Dark/js/static/tinytab.js index de50279fc..de50279fc 100644 --- a/module/webui/themes/Dark/js/static/tinytab.js +++ b/pyload/webui/themes/Dark/js/static/tinytab.js diff --git a/module/webui/themes/Dark/js/static/tinytab.min.js b/pyload/webui/themes/Dark/js/static/tinytab.min.js index 2f4fa0436..2f4fa0436 100644 --- a/module/webui/themes/Dark/js/static/tinytab.min.js +++ b/pyload/webui/themes/Dark/js/static/tinytab.min.js diff --git a/module/webui/themes/Dark/tml/admin.html b/pyload/webui/themes/Dark/tml/admin.html index 3a88ffc7a..3a88ffc7a 100644 --- a/module/webui/themes/Dark/tml/admin.html +++ b/pyload/webui/themes/Dark/tml/admin.html diff --git a/module/webui/themes/Dark/tml/base.html b/pyload/webui/themes/Dark/tml/base.html index bebb0600d..bebb0600d 100644 --- a/module/webui/themes/Dark/tml/base.html +++ b/pyload/webui/themes/Dark/tml/base.html diff --git a/module/webui/themes/Dark/tml/captcha.html b/pyload/webui/themes/Dark/tml/captcha.html index 731d97d11..731d97d11 100644 --- a/module/webui/themes/Dark/tml/captcha.html +++ b/pyload/webui/themes/Dark/tml/captcha.html diff --git a/module/webui/themes/Dark/tml/downloads.html b/pyload/webui/themes/Dark/tml/downloads.html index c6ff7a243..c6ff7a243 100644 --- a/module/webui/themes/Dark/tml/downloads.html +++ b/pyload/webui/themes/Dark/tml/downloads.html diff --git a/module/webui/themes/Dark/tml/folder.html b/pyload/webui/themes/Dark/tml/folder.html index b57338d5e..b57338d5e 100644 --- a/module/webui/themes/Dark/tml/folder.html +++ b/pyload/webui/themes/Dark/tml/folder.html diff --git a/module/webui/themes/Dark/tml/home.html b/pyload/webui/themes/Dark/tml/home.html index 9131c640e..9131c640e 100644 --- a/module/webui/themes/Dark/tml/home.html +++ b/pyload/webui/themes/Dark/tml/home.html diff --git a/module/webui/themes/Dark/tml/info.html b/pyload/webui/themes/Dark/tml/info.html index 1c0a35e9f..1c0a35e9f 100644 --- a/module/webui/themes/Dark/tml/info.html +++ b/pyload/webui/themes/Dark/tml/info.html diff --git a/module/webui/themes/Dark/tml/login.html b/pyload/webui/themes/Dark/tml/login.html index dcb3a18b8..dcb3a18b8 100644 --- a/module/webui/themes/Dark/tml/login.html +++ b/pyload/webui/themes/Dark/tml/login.html diff --git a/module/webui/themes/Dark/tml/logout.html b/pyload/webui/themes/Dark/tml/logout.html index 08adfcf6c..08adfcf6c 100644 --- a/module/webui/themes/Dark/tml/logout.html +++ b/pyload/webui/themes/Dark/tml/logout.html diff --git a/module/webui/themes/Dark/tml/logs.html b/pyload/webui/themes/Dark/tml/logs.html index e7fead2df..e7fead2df 100644 --- a/module/webui/themes/Dark/tml/logs.html +++ b/pyload/webui/themes/Dark/tml/logs.html diff --git a/module/webui/themes/Dark/tml/pathchooser.html b/pyload/webui/themes/Dark/tml/pathchooser.html index 288af8bfa..288af8bfa 100644 --- a/module/webui/themes/Dark/tml/pathchooser.html +++ b/pyload/webui/themes/Dark/tml/pathchooser.html diff --git a/module/webui/themes/Dark/tml/queue.html b/pyload/webui/themes/Dark/tml/queue.html index 1a61e2638..1a61e2638 100644 --- a/module/webui/themes/Dark/tml/queue.html +++ b/pyload/webui/themes/Dark/tml/queue.html diff --git a/module/webui/themes/Dark/tml/settings.html b/pyload/webui/themes/Dark/tml/settings.html index cf0fe1745..cf0fe1745 100644 --- a/module/webui/themes/Dark/tml/settings.html +++ b/pyload/webui/themes/Dark/tml/settings.html diff --git a/module/webui/themes/Dark/tml/settings_item.html b/pyload/webui/themes/Dark/tml/settings_item.html index e417e564c..e417e564c 100644 --- a/module/webui/themes/Dark/tml/settings_item.html +++ b/pyload/webui/themes/Dark/tml/settings_item.html diff --git a/module/webui/themes/Dark/tml/window.html b/pyload/webui/themes/Dark/tml/window.html index a518a7b95..a518a7b95 100644 --- a/module/webui/themes/Dark/tml/window.html +++ b/pyload/webui/themes/Dark/tml/window.html diff --git a/module/webui/themes/Default/css/MooDialog.css b/pyload/webui/themes/Default/css/MooDialog.css index 1e2ae68aa..1e2ae68aa 100644 --- a/module/webui/themes/Default/css/MooDialog.css +++ b/pyload/webui/themes/Default/css/MooDialog.css diff --git a/module/webui/themes/Default/css/base.css b/pyload/webui/themes/Default/css/base.css index f5078bfbb..f5078bfbb 100644 --- a/module/webui/themes/Default/css/base.css +++ b/pyload/webui/themes/Default/css/base.css diff --git a/module/webui/themes/Default/css/log.css b/pyload/webui/themes/Default/css/log.css index 33e67397d..33e67397d 100644 --- a/module/webui/themes/Default/css/log.css +++ b/pyload/webui/themes/Default/css/log.css diff --git a/module/webui/themes/Default/css/pathchooser.css b/pyload/webui/themes/Default/css/pathchooser.css index 204812aa1..204812aa1 100644 --- a/module/webui/themes/Default/css/pathchooser.css +++ b/pyload/webui/themes/Default/css/pathchooser.css diff --git a/module/webui/themes/Default/css/window.css b/pyload/webui/themes/Default/css/window.css index b469b4259..b469b4259 100644 --- a/module/webui/themes/Default/css/window.css +++ b/pyload/webui/themes/Default/css/window.css diff --git a/module/webui/themes/Default/img/MooDialog/dialog-close.png b/pyload/webui/themes/Default/img/MooDialog/dialog-close.png Binary files differindex 81ebb88b2..81ebb88b2 100644 --- a/module/webui/themes/Default/img/MooDialog/dialog-close.png +++ b/pyload/webui/themes/Default/img/MooDialog/dialog-close.png diff --git a/module/webui/themes/Default/img/MooDialog/dialog-error.png b/pyload/webui/themes/Default/img/MooDialog/dialog-error.png Binary files differindex d70328403..d70328403 100644 --- a/module/webui/themes/Default/img/MooDialog/dialog-error.png +++ b/pyload/webui/themes/Default/img/MooDialog/dialog-error.png diff --git a/module/webui/themes/Default/img/MooDialog/dialog-question.png b/pyload/webui/themes/Default/img/MooDialog/dialog-question.png Binary files differindex b0af3db5b..b0af3db5b 100644 --- a/module/webui/themes/Default/img/MooDialog/dialog-question.png +++ b/pyload/webui/themes/Default/img/MooDialog/dialog-question.png diff --git a/module/webui/themes/Default/img/MooDialog/dialog-warning.png b/pyload/webui/themes/Default/img/MooDialog/dialog-warning.png Binary files differindex aad64d4be..aad64d4be 100644 --- a/module/webui/themes/Default/img/MooDialog/dialog-warning.png +++ b/pyload/webui/themes/Default/img/MooDialog/dialog-warning.png diff --git a/module/webui/themes/Default/img/add_folder.png b/pyload/webui/themes/Default/img/add_folder.png Binary files differindex 8acbc411b..8acbc411b 100644 --- a/module/webui/themes/Default/img/add_folder.png +++ b/pyload/webui/themes/Default/img/add_folder.png diff --git a/module/webui/themes/Default/img/ajax-loader.gif b/pyload/webui/themes/Default/img/ajax-loader.gif Binary files differindex 2fd8e0737..2fd8e0737 100644 --- a/module/webui/themes/Default/img/ajax-loader.gif +++ b/pyload/webui/themes/Default/img/ajax-loader.gif diff --git a/module/webui/themes/Default/img/arrow_refresh.png b/pyload/webui/themes/Default/img/arrow_refresh.png Binary files differindex 0de26566d..0de26566d 100644 --- a/module/webui/themes/Default/img/arrow_refresh.png +++ b/pyload/webui/themes/Default/img/arrow_refresh.png diff --git a/module/webui/themes/Default/img/arrow_right.png b/pyload/webui/themes/Default/img/arrow_right.png Binary files differindex b1a181923..b1a181923 100644 --- a/module/webui/themes/Default/img/arrow_right.png +++ b/pyload/webui/themes/Default/img/arrow_right.png diff --git a/module/webui/themes/Default/img/big_button.gif b/pyload/webui/themes/Default/img/big_button.gif Binary files differindex 7680490ea..7680490ea 100644 --- a/module/webui/themes/Default/img/big_button.gif +++ b/pyload/webui/themes/Default/img/big_button.gif diff --git a/module/webui/themes/Default/img/big_button_over.gif b/pyload/webui/themes/Default/img/big_button_over.gif Binary files differindex 2e3ee10d2..2e3ee10d2 100644 --- a/module/webui/themes/Default/img/big_button_over.gif +++ b/pyload/webui/themes/Default/img/big_button_over.gif diff --git a/module/webui/themes/Default/img/body.png b/pyload/webui/themes/Default/img/body.png Binary files differindex 7ff1043e0..7ff1043e0 100644 --- a/module/webui/themes/Default/img/body.png +++ b/pyload/webui/themes/Default/img/body.png diff --git a/module/webui/themes/Default/img/button.png b/pyload/webui/themes/Default/img/button.png Binary files differindex 890160614..890160614 100644 --- a/module/webui/themes/Default/img/button.png +++ b/pyload/webui/themes/Default/img/button.png diff --git a/module/webui/themes/Default/img/closebtn.gif b/pyload/webui/themes/Default/img/closebtn.gif Binary files differindex 3e27e6030..3e27e6030 100644 --- a/module/webui/themes/Default/img/closebtn.gif +++ b/pyload/webui/themes/Default/img/closebtn.gif diff --git a/module/webui/themes/Default/img/cog.png b/pyload/webui/themes/Default/img/cog.png Binary files differindex 67de2c6cc..67de2c6cc 100644 --- a/module/webui/themes/Default/img/cog.png +++ b/pyload/webui/themes/Default/img/cog.png diff --git a/module/webui/themes/Default/img/control_add.png b/pyload/webui/themes/Default/img/control_add.png Binary files differindex d39886893..d39886893 100644 --- a/module/webui/themes/Default/img/control_add.png +++ b/pyload/webui/themes/Default/img/control_add.png diff --git a/module/webui/themes/Default/img/control_add_blue.png b/pyload/webui/themes/Default/img/control_add_blue.png Binary files differindex d11b7f41d..d11b7f41d 100644 --- a/module/webui/themes/Default/img/control_add_blue.png +++ b/pyload/webui/themes/Default/img/control_add_blue.png diff --git a/module/webui/themes/Default/img/control_cancel.png b/pyload/webui/themes/Default/img/control_cancel.png Binary files differindex 7b9bc3fba..7b9bc3fba 100644 --- a/module/webui/themes/Default/img/control_cancel.png +++ b/pyload/webui/themes/Default/img/control_cancel.png diff --git a/module/webui/themes/Default/img/control_cancel_blue.png b/pyload/webui/themes/Default/img/control_cancel_blue.png Binary files differindex 0c5c96ce3..0c5c96ce3 100644 --- a/module/webui/themes/Default/img/control_cancel_blue.png +++ b/pyload/webui/themes/Default/img/control_cancel_blue.png diff --git a/module/webui/themes/Default/img/control_pause.png b/pyload/webui/themes/Default/img/control_pause.png Binary files differindex 2d9ce9c4e..2d9ce9c4e 100644 --- a/module/webui/themes/Default/img/control_pause.png +++ b/pyload/webui/themes/Default/img/control_pause.png diff --git a/module/webui/themes/Default/img/control_pause_blue.png b/pyload/webui/themes/Default/img/control_pause_blue.png Binary files differindex ec61099b0..ec61099b0 100644 --- a/module/webui/themes/Default/img/control_pause_blue.png +++ b/pyload/webui/themes/Default/img/control_pause_blue.png diff --git a/module/webui/themes/Default/img/control_play.png b/pyload/webui/themes/Default/img/control_play.png Binary files differindex 0846555d0..0846555d0 100644 --- a/module/webui/themes/Default/img/control_play.png +++ b/pyload/webui/themes/Default/img/control_play.png diff --git a/module/webui/themes/Default/img/control_play_blue.png b/pyload/webui/themes/Default/img/control_play_blue.png Binary files differindex f8c8ec683..f8c8ec683 100644 --- a/module/webui/themes/Default/img/control_play_blue.png +++ b/pyload/webui/themes/Default/img/control_play_blue.png diff --git a/module/webui/themes/Default/img/control_stop.png b/pyload/webui/themes/Default/img/control_stop.png Binary files differindex 893bb60e5..893bb60e5 100644 --- a/module/webui/themes/Default/img/control_stop.png +++ b/pyload/webui/themes/Default/img/control_stop.png diff --git a/module/webui/themes/Default/img/control_stop_blue.png b/pyload/webui/themes/Default/img/control_stop_blue.png Binary files differindex e6f75d232..e6f75d232 100644 --- a/module/webui/themes/Default/img/control_stop_blue.png +++ b/pyload/webui/themes/Default/img/control_stop_blue.png diff --git a/module/webui/themes/Default/img/delete.png b/pyload/webui/themes/Default/img/delete.png Binary files differindex 08f249365..08f249365 100644 --- a/module/webui/themes/Default/img/delete.png +++ b/pyload/webui/themes/Default/img/delete.png diff --git a/module/webui/themes/Default/img/drag_corner.gif b/pyload/webui/themes/Default/img/drag_corner.gif Binary files differindex befb1adf1..befb1adf1 100644 --- a/module/webui/themes/Default/img/drag_corner.gif +++ b/pyload/webui/themes/Default/img/drag_corner.gif diff --git a/module/webui/themes/Default/img/error.png b/pyload/webui/themes/Default/img/error.png Binary files differindex c37bd062e..c37bd062e 100644 --- a/module/webui/themes/Default/img/error.png +++ b/pyload/webui/themes/Default/img/error.png diff --git a/module/webui/themes/Default/img/folder.png b/pyload/webui/themes/Default/img/folder.png Binary files differindex 784e8fa48..784e8fa48 100644 --- a/module/webui/themes/Default/img/folder.png +++ b/pyload/webui/themes/Default/img/folder.png diff --git a/module/webui/themes/Default/img/full.png b/pyload/webui/themes/Default/img/full.png Binary files differindex fea52af76..fea52af76 100644 --- a/module/webui/themes/Default/img/full.png +++ b/pyload/webui/themes/Default/img/full.png diff --git a/module/webui/themes/Default/img/head-login.png b/pyload/webui/themes/Default/img/head-login.png Binary files differindex b59b7cbbf..b59b7cbbf 100644 --- a/module/webui/themes/Default/img/head-login.png +++ b/pyload/webui/themes/Default/img/head-login.png diff --git a/module/webui/themes/Default/img/head-menu-collector.png b/pyload/webui/themes/Default/img/head-menu-collector.png Binary files differindex 861be40bc..861be40bc 100644 --- a/module/webui/themes/Default/img/head-menu-collector.png +++ b/pyload/webui/themes/Default/img/head-menu-collector.png diff --git a/module/webui/themes/Default/img/head-menu-config.png b/pyload/webui/themes/Default/img/head-menu-config.png Binary files differindex bbf43d4f3..bbf43d4f3 100644 --- a/module/webui/themes/Default/img/head-menu-config.png +++ b/pyload/webui/themes/Default/img/head-menu-config.png diff --git a/module/webui/themes/Default/img/head-menu-development.png b/pyload/webui/themes/Default/img/head-menu-development.png Binary files differindex fad150fe1..fad150fe1 100644 --- a/module/webui/themes/Default/img/head-menu-development.png +++ b/pyload/webui/themes/Default/img/head-menu-development.png diff --git a/module/webui/themes/Default/img/head-menu-download.png b/pyload/webui/themes/Default/img/head-menu-download.png Binary files differindex 98c5da9db..98c5da9db 100644 --- a/module/webui/themes/Default/img/head-menu-download.png +++ b/pyload/webui/themes/Default/img/head-menu-download.png diff --git a/module/webui/themes/Default/img/head-menu-home.png b/pyload/webui/themes/Default/img/head-menu-home.png Binary files differindex 9d62109aa..9d62109aa 100644 --- a/module/webui/themes/Default/img/head-menu-home.png +++ b/pyload/webui/themes/Default/img/head-menu-home.png diff --git a/module/webui/themes/Default/img/head-menu-index.png b/pyload/webui/themes/Default/img/head-menu-index.png Binary files differindex 44d631064..44d631064 100644 --- a/module/webui/themes/Default/img/head-menu-index.png +++ b/pyload/webui/themes/Default/img/head-menu-index.png diff --git a/module/webui/themes/Default/img/head-menu-news.png b/pyload/webui/themes/Default/img/head-menu-news.png Binary files differindex 43950ebc9..43950ebc9 100644 --- a/module/webui/themes/Default/img/head-menu-news.png +++ b/pyload/webui/themes/Default/img/head-menu-news.png diff --git a/module/webui/themes/Default/img/head-menu-queue.png b/pyload/webui/themes/Default/img/head-menu-queue.png Binary files differindex be98793ce..be98793ce 100644 --- a/module/webui/themes/Default/img/head-menu-queue.png +++ b/pyload/webui/themes/Default/img/head-menu-queue.png diff --git a/module/webui/themes/Default/img/head-menu-recent.png b/pyload/webui/themes/Default/img/head-menu-recent.png Binary files differindex fc9b0497f..fc9b0497f 100644 --- a/module/webui/themes/Default/img/head-menu-recent.png +++ b/pyload/webui/themes/Default/img/head-menu-recent.png diff --git a/module/webui/themes/Default/img/head-menu-wiki.png b/pyload/webui/themes/Default/img/head-menu-wiki.png Binary files differindex 07cf0102d..07cf0102d 100644 --- a/module/webui/themes/Default/img/head-menu-wiki.png +++ b/pyload/webui/themes/Default/img/head-menu-wiki.png diff --git a/module/webui/themes/Default/img/head-search-noshadow.png b/pyload/webui/themes/Default/img/head-search-noshadow.png Binary files differindex aafdae015..aafdae015 100644 --- a/module/webui/themes/Default/img/head-search-noshadow.png +++ b/pyload/webui/themes/Default/img/head-search-noshadow.png diff --git a/module/webui/themes/Default/img/head_bg1.png b/pyload/webui/themes/Default/img/head_bg1.png Binary files differindex f2848c3cc..f2848c3cc 100644 --- a/module/webui/themes/Default/img/head_bg1.png +++ b/pyload/webui/themes/Default/img/head_bg1.png diff --git a/module/webui/themes/Default/img/images.png b/pyload/webui/themes/Default/img/images.png Binary files differindex 184860d1e..184860d1e 100644 --- a/module/webui/themes/Default/img/images.png +++ b/pyload/webui/themes/Default/img/images.png diff --git a/module/webui/themes/Default/img/notice.png b/pyload/webui/themes/Default/img/notice.png Binary files differindex 12cd1aef9..12cd1aef9 100644 --- a/module/webui/themes/Default/img/notice.png +++ b/pyload/webui/themes/Default/img/notice.png diff --git a/module/webui/themes/Default/img/package_go.png b/pyload/webui/themes/Default/img/package_go.png Binary files differindex aace63ad6..aace63ad6 100644 --- a/module/webui/themes/Default/img/package_go.png +++ b/pyload/webui/themes/Default/img/package_go.png diff --git a/module/webui/themes/Default/img/page-tools-backlinks.png b/pyload/webui/themes/Default/img/page-tools-backlinks.png Binary files differindex 3eb6a9ce3..3eb6a9ce3 100644 --- a/module/webui/themes/Default/img/page-tools-backlinks.png +++ b/pyload/webui/themes/Default/img/page-tools-backlinks.png diff --git a/module/webui/themes/Default/img/page-tools-edit.png b/pyload/webui/themes/Default/img/page-tools-edit.png Binary files differindex 188e1c12b..188e1c12b 100644 --- a/module/webui/themes/Default/img/page-tools-edit.png +++ b/pyload/webui/themes/Default/img/page-tools-edit.png diff --git a/module/webui/themes/Default/img/page-tools-revisions.png b/pyload/webui/themes/Default/img/page-tools-revisions.png Binary files differindex 5c3b8587f..5c3b8587f 100644 --- a/module/webui/themes/Default/img/page-tools-revisions.png +++ b/pyload/webui/themes/Default/img/page-tools-revisions.png diff --git a/module/webui/themes/Default/img/parseUri.png b/pyload/webui/themes/Default/img/parseUri.png Binary files differindex 937bded9d..937bded9d 100644 --- a/module/webui/themes/Default/img/parseUri.png +++ b/pyload/webui/themes/Default/img/parseUri.png diff --git a/module/webui/themes/Default/img/pencil.png b/pyload/webui/themes/Default/img/pencil.png Binary files differindex 0bfecd50e..0bfecd50e 100644 --- a/module/webui/themes/Default/img/pencil.png +++ b/pyload/webui/themes/Default/img/pencil.png diff --git a/module/webui/themes/Default/img/pyload-logo.png b/pyload/webui/themes/Default/img/pyload-logo.png Binary files differindex 2443cd8b1..2443cd8b1 100644 --- a/module/webui/themes/Default/img/pyload-logo.png +++ b/pyload/webui/themes/Default/img/pyload-logo.png diff --git a/module/webui/themes/Default/img/reconnect.png b/pyload/webui/themes/Default/img/reconnect.png Binary files differindex 49b269145..49b269145 100644 --- a/module/webui/themes/Default/img/reconnect.png +++ b/pyload/webui/themes/Default/img/reconnect.png diff --git a/module/webui/themes/Default/img/status_None.png b/pyload/webui/themes/Default/img/status_None.png Binary files differindex 293b13f77..293b13f77 100644 --- a/module/webui/themes/Default/img/status_None.png +++ b/pyload/webui/themes/Default/img/status_None.png diff --git a/module/webui/themes/Default/img/status_downloading.png b/pyload/webui/themes/Default/img/status_downloading.png Binary files differindex fb4ebc850..fb4ebc850 100644 --- a/module/webui/themes/Default/img/status_downloading.png +++ b/pyload/webui/themes/Default/img/status_downloading.png diff --git a/module/webui/themes/Default/img/status_failed.png b/pyload/webui/themes/Default/img/status_failed.png Binary files differindex c37bd062e..c37bd062e 100644 --- a/module/webui/themes/Default/img/status_failed.png +++ b/pyload/webui/themes/Default/img/status_failed.png diff --git a/module/webui/themes/Default/img/status_finished.png b/pyload/webui/themes/Default/img/status_finished.png Binary files differindex 89c8129a4..89c8129a4 100644 --- a/module/webui/themes/Default/img/status_finished.png +++ b/pyload/webui/themes/Default/img/status_finished.png diff --git a/module/webui/themes/Default/img/status_offline.png b/pyload/webui/themes/Default/img/status_offline.png Binary files differindex 0cfd58596..0cfd58596 100644 --- a/module/webui/themes/Default/img/status_offline.png +++ b/pyload/webui/themes/Default/img/status_offline.png diff --git a/module/webui/themes/Default/img/status_proc.png b/pyload/webui/themes/Default/img/status_proc.png Binary files differindex 67de2c6cc..67de2c6cc 100644 --- a/module/webui/themes/Default/img/status_proc.png +++ b/pyload/webui/themes/Default/img/status_proc.png diff --git a/module/webui/themes/Default/img/status_queue.png b/pyload/webui/themes/Default/img/status_queue.png Binary files differindex 293b13f77..293b13f77 100644 --- a/module/webui/themes/Default/img/status_queue.png +++ b/pyload/webui/themes/Default/img/status_queue.png diff --git a/module/webui/themes/Default/img/status_waiting.png b/pyload/webui/themes/Default/img/status_waiting.png Binary files differindex 2842cc338..2842cc338 100644 --- a/module/webui/themes/Default/img/status_waiting.png +++ b/pyload/webui/themes/Default/img/status_waiting.png diff --git a/module/webui/themes/Default/img/success.png b/pyload/webui/themes/Default/img/success.png Binary files differindex 89c8129a4..89c8129a4 100644 --- a/module/webui/themes/Default/img/success.png +++ b/pyload/webui/themes/Default/img/success.png diff --git a/module/webui/themes/Default/img/tab-background.png b/pyload/webui/themes/Default/img/tab-background.png Binary files differindex 29a5d1991..29a5d1991 100644 --- a/module/webui/themes/Default/img/tab-background.png +++ b/pyload/webui/themes/Default/img/tab-background.png diff --git a/module/webui/themes/Default/img/tabs-border-bottom.png b/pyload/webui/themes/Default/img/tabs-border-bottom.png Binary files differindex 02440f428..02440f428 100644 --- a/module/webui/themes/Default/img/tabs-border-bottom.png +++ b/pyload/webui/themes/Default/img/tabs-border-bottom.png diff --git a/module/webui/themes/Default/img/user-actions-logout.png b/pyload/webui/themes/Default/img/user-actions-logout.png Binary files differindex 0010931e2..0010931e2 100644 --- a/module/webui/themes/Default/img/user-actions-logout.png +++ b/pyload/webui/themes/Default/img/user-actions-logout.png diff --git a/module/webui/themes/Default/img/user-actions-profile.png b/pyload/webui/themes/Default/img/user-actions-profile.png Binary files differindex 46573fff6..46573fff6 100644 --- a/module/webui/themes/Default/img/user-actions-profile.png +++ b/pyload/webui/themes/Default/img/user-actions-profile.png diff --git a/module/webui/themes/Default/img/user-info.png b/pyload/webui/themes/Default/img/user-info.png Binary files differindex 6e643100f..6e643100f 100644 --- a/module/webui/themes/Default/img/user-info.png +++ b/pyload/webui/themes/Default/img/user-info.png diff --git a/module/webui/themes/Default/js/render/admin.coffee b/pyload/webui/themes/Default/js/render/admin.coffee index 5afbcbb66..5afbcbb66 100644 --- a/module/webui/themes/Default/js/render/admin.coffee +++ b/pyload/webui/themes/Default/js/render/admin.coffee diff --git a/module/webui/themes/Default/js/render/admin.min.js b/pyload/webui/themes/Default/js/render/admin.min.js index 94a5e494d..94a5e494d 100644 --- a/module/webui/themes/Default/js/render/admin.min.js +++ b/pyload/webui/themes/Default/js/render/admin.min.js diff --git a/module/webui/themes/Default/js/render/base.coffee b/pyload/webui/themes/Default/js/render/base.coffee index 07b8bfb6f..07b8bfb6f 100644 --- a/module/webui/themes/Default/js/render/base.coffee +++ b/pyload/webui/themes/Default/js/render/base.coffee diff --git a/module/webui/themes/Default/js/render/base.min.js b/pyload/webui/themes/Default/js/render/base.min.js index 1ba1d73f9..1ba1d73f9 100644 --- a/module/webui/themes/Default/js/render/base.min.js +++ b/pyload/webui/themes/Default/js/render/base.min.js diff --git a/module/webui/themes/Default/js/render/package.js b/pyload/webui/themes/Default/js/render/package.js index 659a8e6fc..659a8e6fc 100644 --- a/module/webui/themes/Default/js/render/package.js +++ b/pyload/webui/themes/Default/js/render/package.js diff --git a/module/webui/themes/Default/js/render/settings.coffee b/pyload/webui/themes/Default/js/render/settings.coffee index d522741b9..d522741b9 100644 --- a/module/webui/themes/Default/js/render/settings.coffee +++ b/pyload/webui/themes/Default/js/render/settings.coffee diff --git a/module/webui/themes/Default/js/render/settings.min.js b/pyload/webui/themes/Default/js/render/settings.min.js index 41d1cb25a..41d1cb25a 100644 --- a/module/webui/themes/Default/js/render/settings.min.js +++ b/pyload/webui/themes/Default/js/render/settings.min.js diff --git a/module/webui/themes/Default/js/static/MooDialog.js b/pyload/webui/themes/Default/js/static/MooDialog.js index 45a52496f..45a52496f 100644 --- a/module/webui/themes/Default/js/static/MooDialog.js +++ b/pyload/webui/themes/Default/js/static/MooDialog.js diff --git a/module/webui/themes/Default/js/static/MooDialog.min.js b/pyload/webui/themes/Default/js/static/MooDialog.min.js index 90b3ae100..90b3ae100 100644 --- a/module/webui/themes/Default/js/static/MooDialog.min.js +++ b/pyload/webui/themes/Default/js/static/MooDialog.min.js diff --git a/module/webui/themes/Default/js/static/MooDropMenu.js b/pyload/webui/themes/Default/js/static/MooDropMenu.js index ac0fa1874..ac0fa1874 100644 --- a/module/webui/themes/Default/js/static/MooDropMenu.js +++ b/pyload/webui/themes/Default/js/static/MooDropMenu.js diff --git a/module/webui/themes/Default/js/static/MooDropMenu.min.js b/pyload/webui/themes/Default/js/static/MooDropMenu.min.js index 552ae247a..552ae247a 100644 --- a/module/webui/themes/Default/js/static/MooDropMenu.min.js +++ b/pyload/webui/themes/Default/js/static/MooDropMenu.min.js diff --git a/module/webui/themes/Default/js/static/mootools-core.js b/pyload/webui/themes/Default/js/static/mootools-core.js index db83850fd..db83850fd 100644 --- a/module/webui/themes/Default/js/static/mootools-core.js +++ b/pyload/webui/themes/Default/js/static/mootools-core.js diff --git a/module/webui/themes/Default/js/static/mootools-core.min.js b/pyload/webui/themes/Default/js/static/mootools-core.min.js index 354f94196..354f94196 100644 --- a/module/webui/themes/Default/js/static/mootools-core.min.js +++ b/pyload/webui/themes/Default/js/static/mootools-core.min.js diff --git a/module/webui/themes/Default/js/static/mootools-more.js b/pyload/webui/themes/Default/js/static/mootools-more.js index c7f4a1a0e..c7f4a1a0e 100644 --- a/module/webui/themes/Default/js/static/mootools-more.js +++ b/pyload/webui/themes/Default/js/static/mootools-more.js diff --git a/module/webui/themes/Default/js/static/mootools-more.min.js b/pyload/webui/themes/Default/js/static/mootools-more.min.js index ce03a60fd..ce03a60fd 100644 --- a/module/webui/themes/Default/js/static/mootools-more.min.js +++ b/pyload/webui/themes/Default/js/static/mootools-more.min.js diff --git a/module/webui/themes/Default/js/static/purr.js b/pyload/webui/themes/Default/js/static/purr.js index 9cbc503d9..9cbc503d9 100644 --- a/module/webui/themes/Default/js/static/purr.js +++ b/pyload/webui/themes/Default/js/static/purr.js diff --git a/module/webui/themes/Default/js/static/purr.min.js b/pyload/webui/themes/Default/js/static/purr.min.js index bf70e357d..bf70e357d 100644 --- a/module/webui/themes/Default/js/static/purr.min.js +++ b/pyload/webui/themes/Default/js/static/purr.min.js diff --git a/module/webui/themes/Default/js/static/tinytab.js b/pyload/webui/themes/Default/js/static/tinytab.js index de50279fc..de50279fc 100644 --- a/module/webui/themes/Default/js/static/tinytab.js +++ b/pyload/webui/themes/Default/js/static/tinytab.js diff --git a/module/webui/themes/Default/js/static/tinytab.min.js b/pyload/webui/themes/Default/js/static/tinytab.min.js index 2f4fa0436..2f4fa0436 100644 --- a/module/webui/themes/Default/js/static/tinytab.min.js +++ b/pyload/webui/themes/Default/js/static/tinytab.min.js diff --git a/module/webui/themes/Default/tml/admin.html b/pyload/webui/themes/Default/tml/admin.html index 0b7301fc8..0b7301fc8 100644 --- a/module/webui/themes/Default/tml/admin.html +++ b/pyload/webui/themes/Default/tml/admin.html diff --git a/module/webui/themes/Default/tml/base.html b/pyload/webui/themes/Default/tml/base.html index aac70a394..aac70a394 100644 --- a/module/webui/themes/Default/tml/base.html +++ b/pyload/webui/themes/Default/tml/base.html diff --git a/module/webui/themes/Default/tml/captcha.html b/pyload/webui/themes/Default/tml/captcha.html index 3bfa6cbcf..3bfa6cbcf 100644 --- a/module/webui/themes/Default/tml/captcha.html +++ b/pyload/webui/themes/Default/tml/captcha.html diff --git a/module/webui/themes/Default/tml/downloads.html b/pyload/webui/themes/Default/tml/downloads.html index fe0f4f1bc..fe0f4f1bc 100644 --- a/module/webui/themes/Default/tml/downloads.html +++ b/pyload/webui/themes/Default/tml/downloads.html diff --git a/module/webui/themes/Default/tml/filemanager.html b/pyload/webui/themes/Default/tml/filemanager.html index c2ac5df9d..c2ac5df9d 100644 --- a/module/webui/themes/Default/tml/filemanager.html +++ b/pyload/webui/themes/Default/tml/filemanager.html diff --git a/module/webui/themes/Default/tml/folder.html b/pyload/webui/themes/Default/tml/folder.html index 54dd72bb9..54dd72bb9 100644 --- a/module/webui/themes/Default/tml/folder.html +++ b/pyload/webui/themes/Default/tml/folder.html diff --git a/module/webui/themes/Default/tml/home.html b/pyload/webui/themes/Default/tml/home.html index 09daae596..09daae596 100644 --- a/module/webui/themes/Default/tml/home.html +++ b/pyload/webui/themes/Default/tml/home.html diff --git a/module/webui/themes/Default/tml/info.html b/pyload/webui/themes/Default/tml/info.html index a5fc3c3f7..a5fc3c3f7 100644 --- a/module/webui/themes/Default/tml/info.html +++ b/pyload/webui/themes/Default/tml/info.html diff --git a/module/webui/themes/Default/tml/login.html b/pyload/webui/themes/Default/tml/login.html index 538ce792d..538ce792d 100644 --- a/module/webui/themes/Default/tml/login.html +++ b/pyload/webui/themes/Default/tml/login.html diff --git a/module/webui/themes/Default/tml/logout.html b/pyload/webui/themes/Default/tml/logout.html index 19d673e7c..19d673e7c 100644 --- a/module/webui/themes/Default/tml/logout.html +++ b/pyload/webui/themes/Default/tml/logout.html diff --git a/module/webui/themes/Default/tml/logs.html b/pyload/webui/themes/Default/tml/logs.html index ccf992d04..ccf992d04 100644 --- a/module/webui/themes/Default/tml/logs.html +++ b/pyload/webui/themes/Default/tml/logs.html diff --git a/module/webui/themes/Default/tml/pathchooser.html b/pyload/webui/themes/Default/tml/pathchooser.html index 5cf08a6e2..5cf08a6e2 100644 --- a/module/webui/themes/Default/tml/pathchooser.html +++ b/pyload/webui/themes/Default/tml/pathchooser.html diff --git a/module/webui/themes/Default/tml/queue.html b/pyload/webui/themes/Default/tml/queue.html index 0fa9580e0..0fa9580e0 100644 --- a/module/webui/themes/Default/tml/queue.html +++ b/pyload/webui/themes/Default/tml/queue.html diff --git a/module/webui/themes/Default/tml/settings.html b/pyload/webui/themes/Default/tml/settings.html index 9205f011b..9205f011b 100644 --- a/module/webui/themes/Default/tml/settings.html +++ b/pyload/webui/themes/Default/tml/settings.html diff --git a/module/webui/themes/Default/tml/settings_item.html b/pyload/webui/themes/Default/tml/settings_item.html index 6642d34b4..6642d34b4 100644 --- a/module/webui/themes/Default/tml/settings_item.html +++ b/pyload/webui/themes/Default/tml/settings_item.html diff --git a/module/webui/themes/Default/tml/window.html b/pyload/webui/themes/Default/tml/window.html index 800874af0..800874af0 100644 --- a/module/webui/themes/Default/tml/window.html +++ b/pyload/webui/themes/Default/tml/window.html diff --git a/module/webui/themes/Flat/css/MooDialog.css b/pyload/webui/themes/Flat/css/MooDialog.css index 7d6e38ece..7d6e38ece 100644 --- a/module/webui/themes/Flat/css/MooDialog.css +++ b/pyload/webui/themes/Flat/css/MooDialog.css diff --git a/module/webui/themes/Flat/css/base.css b/pyload/webui/themes/Flat/css/base.css index fd73d0a19..fd73d0a19 100644 --- a/module/webui/themes/Flat/css/base.css +++ b/pyload/webui/themes/Flat/css/base.css diff --git a/module/webui/themes/Flat/css/log.css b/pyload/webui/themes/Flat/css/log.css index c2f21b506..c2f21b506 100644 --- a/module/webui/themes/Flat/css/log.css +++ b/pyload/webui/themes/Flat/css/log.css diff --git a/module/webui/themes/Flat/css/pathchooser.css b/pyload/webui/themes/Flat/css/pathchooser.css index 204812aa1..204812aa1 100644 --- a/module/webui/themes/Flat/css/pathchooser.css +++ b/pyload/webui/themes/Flat/css/pathchooser.css diff --git a/module/webui/themes/Flat/css/window.css b/pyload/webui/themes/Flat/css/window.css index 40c1aadca..40c1aadca 100644 --- a/module/webui/themes/Flat/css/window.css +++ b/pyload/webui/themes/Flat/css/window.css diff --git a/module/webui/themes/Flat/img/MooDialog/dialog-close.png b/pyload/webui/themes/Flat/img/MooDialog/dialog-close.png Binary files differindex 81ebb88b2..81ebb88b2 100644 --- a/module/webui/themes/Flat/img/MooDialog/dialog-close.png +++ b/pyload/webui/themes/Flat/img/MooDialog/dialog-close.png diff --git a/module/webui/themes/Flat/img/MooDialog/dialog-error.png b/pyload/webui/themes/Flat/img/MooDialog/dialog-error.png Binary files differindex d70328403..d70328403 100644 --- a/module/webui/themes/Flat/img/MooDialog/dialog-error.png +++ b/pyload/webui/themes/Flat/img/MooDialog/dialog-error.png diff --git a/module/webui/themes/Flat/img/MooDialog/dialog-question.png b/pyload/webui/themes/Flat/img/MooDialog/dialog-question.png Binary files differindex b0af3db5b..b0af3db5b 100644 --- a/module/webui/themes/Flat/img/MooDialog/dialog-question.png +++ b/pyload/webui/themes/Flat/img/MooDialog/dialog-question.png diff --git a/module/webui/themes/Flat/img/MooDialog/dialog-warning.png b/pyload/webui/themes/Flat/img/MooDialog/dialog-warning.png Binary files differindex aad64d4be..aad64d4be 100644 --- a/module/webui/themes/Flat/img/MooDialog/dialog-warning.png +++ b/pyload/webui/themes/Flat/img/MooDialog/dialog-warning.png diff --git a/module/webui/themes/Flat/img/arrow_refresh.png b/pyload/webui/themes/Flat/img/arrow_refresh.png Binary files differindex b1b6fa4dc..b1b6fa4dc 100644 --- a/module/webui/themes/Flat/img/arrow_refresh.png +++ b/pyload/webui/themes/Flat/img/arrow_refresh.png diff --git a/module/webui/themes/Flat/img/arrow_right.png b/pyload/webui/themes/Flat/img/arrow_right.png Binary files differindex 68f379fc7..68f379fc7 100644 --- a/module/webui/themes/Flat/img/arrow_right.png +++ b/pyload/webui/themes/Flat/img/arrow_right.png diff --git a/module/webui/themes/Flat/img/button.png b/pyload/webui/themes/Flat/img/button.png Binary files differindex bb408a7d6..bb408a7d6 100644 --- a/module/webui/themes/Flat/img/button.png +++ b/pyload/webui/themes/Flat/img/button.png diff --git a/module/webui/themes/Flat/img/cog.png b/pyload/webui/themes/Flat/img/cog.png Binary files differindex 833f779ac..833f779ac 100644 --- a/module/webui/themes/Flat/img/cog.png +++ b/pyload/webui/themes/Flat/img/cog.png diff --git a/module/webui/themes/Flat/img/control_add.png b/pyload/webui/themes/Flat/img/control_add.png Binary files differindex e3f29fab2..e3f29fab2 100644 --- a/module/webui/themes/Flat/img/control_add.png +++ b/pyload/webui/themes/Flat/img/control_add.png diff --git a/module/webui/themes/Flat/img/control_add_blue.png b/pyload/webui/themes/Flat/img/control_add_blue.png Binary files differindex e3f29fab2..e3f29fab2 100644 --- a/module/webui/themes/Flat/img/control_add_blue.png +++ b/pyload/webui/themes/Flat/img/control_add_blue.png diff --git a/module/webui/themes/Flat/img/control_cancel.png b/pyload/webui/themes/Flat/img/control_cancel.png Binary files differindex 07c9cad30..07c9cad30 100644 --- a/module/webui/themes/Flat/img/control_cancel.png +++ b/pyload/webui/themes/Flat/img/control_cancel.png diff --git a/module/webui/themes/Flat/img/control_cancel_blue.png b/pyload/webui/themes/Flat/img/control_cancel_blue.png Binary files differindex 07c9cad30..07c9cad30 100644 --- a/module/webui/themes/Flat/img/control_cancel_blue.png +++ b/pyload/webui/themes/Flat/img/control_cancel_blue.png diff --git a/module/webui/themes/Flat/img/control_pause.png b/pyload/webui/themes/Flat/img/control_pause.png Binary files differindex 24e3705fa..24e3705fa 100644 --- a/module/webui/themes/Flat/img/control_pause.png +++ b/pyload/webui/themes/Flat/img/control_pause.png diff --git a/module/webui/themes/Flat/img/control_pause_blue.png b/pyload/webui/themes/Flat/img/control_pause_blue.png Binary files differindex 24e3705fa..24e3705fa 100644 --- a/module/webui/themes/Flat/img/control_pause_blue.png +++ b/pyload/webui/themes/Flat/img/control_pause_blue.png diff --git a/module/webui/themes/Flat/img/control_play.png b/pyload/webui/themes/Flat/img/control_play.png Binary files differindex 15ced1e21..15ced1e21 100644 --- a/module/webui/themes/Flat/img/control_play.png +++ b/pyload/webui/themes/Flat/img/control_play.png diff --git a/module/webui/themes/Flat/img/control_play_blue.png b/pyload/webui/themes/Flat/img/control_play_blue.png Binary files differindex 15ced1e21..15ced1e21 100644 --- a/module/webui/themes/Flat/img/control_play_blue.png +++ b/pyload/webui/themes/Flat/img/control_play_blue.png diff --git a/module/webui/themes/Flat/img/control_stop.png b/pyload/webui/themes/Flat/img/control_stop.png Binary files differindex 71215ef67..71215ef67 100644 --- a/module/webui/themes/Flat/img/control_stop.png +++ b/pyload/webui/themes/Flat/img/control_stop.png diff --git a/module/webui/themes/Flat/img/control_stop_blue.png b/pyload/webui/themes/Flat/img/control_stop_blue.png Binary files differindex 71215ef67..71215ef67 100644 --- a/module/webui/themes/Flat/img/control_stop_blue.png +++ b/pyload/webui/themes/Flat/img/control_stop_blue.png diff --git a/module/webui/themes/Flat/img/default/add_folder.png b/pyload/webui/themes/Flat/img/default/add_folder.png Binary files differindex 8acbc411b..8acbc411b 100644 --- a/module/webui/themes/Flat/img/default/add_folder.png +++ b/pyload/webui/themes/Flat/img/default/add_folder.png diff --git a/module/webui/themes/Flat/img/default/ajax-loader.gif b/pyload/webui/themes/Flat/img/default/ajax-loader.gif Binary files differindex 2fd8e0737..2fd8e0737 100644 --- a/module/webui/themes/Flat/img/default/ajax-loader.gif +++ b/pyload/webui/themes/Flat/img/default/ajax-loader.gif diff --git a/module/webui/themes/Flat/img/default/big_button.gif b/pyload/webui/themes/Flat/img/default/big_button.gif Binary files differindex 7680490ea..7680490ea 100644 --- a/module/webui/themes/Flat/img/default/big_button.gif +++ b/pyload/webui/themes/Flat/img/default/big_button.gif diff --git a/module/webui/themes/Flat/img/default/big_button_over.gif b/pyload/webui/themes/Flat/img/default/big_button_over.gif Binary files differindex 2e3ee10d2..2e3ee10d2 100644 --- a/module/webui/themes/Flat/img/default/big_button_over.gif +++ b/pyload/webui/themes/Flat/img/default/big_button_over.gif diff --git a/module/webui/themes/Flat/img/default/body.png b/pyload/webui/themes/Flat/img/default/body.png Binary files differindex 7ff1043e0..7ff1043e0 100644 --- a/module/webui/themes/Flat/img/default/body.png +++ b/pyload/webui/themes/Flat/img/default/body.png diff --git a/module/webui/themes/Flat/img/default/closebtn.gif b/pyload/webui/themes/Flat/img/default/closebtn.gif Binary files differindex 3e27e6030..3e27e6030 100644 --- a/module/webui/themes/Flat/img/default/closebtn.gif +++ b/pyload/webui/themes/Flat/img/default/closebtn.gif diff --git a/module/webui/themes/Flat/img/default/drag_corner.gif b/pyload/webui/themes/Flat/img/default/drag_corner.gif Binary files differindex befb1adf1..befb1adf1 100644 --- a/module/webui/themes/Flat/img/default/drag_corner.gif +++ b/pyload/webui/themes/Flat/img/default/drag_corner.gif diff --git a/module/webui/themes/Flat/img/default/full.png b/pyload/webui/themes/Flat/img/default/full.png Binary files differindex fea52af76..fea52af76 100644 --- a/module/webui/themes/Flat/img/default/full.png +++ b/pyload/webui/themes/Flat/img/default/full.png diff --git a/module/webui/themes/Flat/img/default/head-menu-recent.png b/pyload/webui/themes/Flat/img/default/head-menu-recent.png Binary files differindex fc9b0497f..fc9b0497f 100644 --- a/module/webui/themes/Flat/img/default/head-menu-recent.png +++ b/pyload/webui/themes/Flat/img/default/head-menu-recent.png diff --git a/module/webui/themes/Flat/img/default/head_bg1.png b/pyload/webui/themes/Flat/img/default/head_bg1.png Binary files differindex f2848c3cc..f2848c3cc 100644 --- a/module/webui/themes/Flat/img/default/head_bg1.png +++ b/pyload/webui/themes/Flat/img/default/head_bg1.png diff --git a/module/webui/themes/Flat/img/default/images.png b/pyload/webui/themes/Flat/img/default/images.png Binary files differindex 184860d1e..184860d1e 100644 --- a/module/webui/themes/Flat/img/default/images.png +++ b/pyload/webui/themes/Flat/img/default/images.png diff --git a/module/webui/themes/Flat/img/default/parseUri.png b/pyload/webui/themes/Flat/img/default/parseUri.png Binary files differindex 937bded9d..937bded9d 100644 --- a/module/webui/themes/Flat/img/default/parseUri.png +++ b/pyload/webui/themes/Flat/img/default/parseUri.png diff --git a/module/webui/themes/Flat/img/default/pyload-logo.png b/pyload/webui/themes/Flat/img/default/pyload-logo.png Binary files differindex 2443cd8b1..2443cd8b1 100644 --- a/module/webui/themes/Flat/img/default/pyload-logo.png +++ b/pyload/webui/themes/Flat/img/default/pyload-logo.png diff --git a/module/webui/themes/Flat/img/default/tab-background.png b/pyload/webui/themes/Flat/img/default/tab-background.png Binary files differindex 29a5d1991..29a5d1991 100644 --- a/module/webui/themes/Flat/img/default/tab-background.png +++ b/pyload/webui/themes/Flat/img/default/tab-background.png diff --git a/module/webui/themes/Flat/img/default/tabs-border-bottom.png b/pyload/webui/themes/Flat/img/default/tabs-border-bottom.png Binary files differindex 02440f428..02440f428 100644 --- a/module/webui/themes/Flat/img/default/tabs-border-bottom.png +++ b/pyload/webui/themes/Flat/img/default/tabs-border-bottom.png diff --git a/module/webui/themes/Flat/img/delete.png b/pyload/webui/themes/Flat/img/delete.png Binary files differindex 4539cff12..4539cff12 100644 --- a/module/webui/themes/Flat/img/delete.png +++ b/pyload/webui/themes/Flat/img/delete.png diff --git a/module/webui/themes/Flat/img/error.png b/pyload/webui/themes/Flat/img/error.png Binary files differindex 6c565c99c..6c565c99c 100644 --- a/module/webui/themes/Flat/img/error.png +++ b/pyload/webui/themes/Flat/img/error.png diff --git a/module/webui/themes/Flat/img/folder.png b/pyload/webui/themes/Flat/img/folder.png Binary files differindex 0b067dd3c..0b067dd3c 100644 --- a/module/webui/themes/Flat/img/folder.png +++ b/pyload/webui/themes/Flat/img/folder.png diff --git a/module/webui/themes/Flat/img/head-login.png b/pyload/webui/themes/Flat/img/head-login.png Binary files differindex 6b57515bc..6b57515bc 100644 --- a/module/webui/themes/Flat/img/head-login.png +++ b/pyload/webui/themes/Flat/img/head-login.png diff --git a/module/webui/themes/Flat/img/head-menu-collector.png b/pyload/webui/themes/Flat/img/head-menu-collector.png Binary files differindex bbcbe6406..bbcbe6406 100644 --- a/module/webui/themes/Flat/img/head-menu-collector.png +++ b/pyload/webui/themes/Flat/img/head-menu-collector.png diff --git a/module/webui/themes/Flat/img/head-menu-config.png b/pyload/webui/themes/Flat/img/head-menu-config.png Binary files differindex 93e8f83ac..93e8f83ac 100644 --- a/module/webui/themes/Flat/img/head-menu-config.png +++ b/pyload/webui/themes/Flat/img/head-menu-config.png diff --git a/module/webui/themes/Flat/img/head-menu-development.png b/pyload/webui/themes/Flat/img/head-menu-development.png Binary files differindex 33d8b062f..33d8b062f 100644 --- a/module/webui/themes/Flat/img/head-menu-development.png +++ b/pyload/webui/themes/Flat/img/head-menu-development.png diff --git a/module/webui/themes/Flat/img/head-menu-download.png b/pyload/webui/themes/Flat/img/head-menu-download.png Binary files differindex 3691deebc..3691deebc 100644 --- a/module/webui/themes/Flat/img/head-menu-download.png +++ b/pyload/webui/themes/Flat/img/head-menu-download.png diff --git a/module/webui/themes/Flat/img/head-menu-home.png b/pyload/webui/themes/Flat/img/head-menu-home.png Binary files differindex b77bef5eb..b77bef5eb 100644 --- a/module/webui/themes/Flat/img/head-menu-home.png +++ b/pyload/webui/themes/Flat/img/head-menu-home.png diff --git a/module/webui/themes/Flat/img/head-menu-index.png b/pyload/webui/themes/Flat/img/head-menu-index.png Binary files differindex 8bc6e9604..8bc6e9604 100644 --- a/module/webui/themes/Flat/img/head-menu-index.png +++ b/pyload/webui/themes/Flat/img/head-menu-index.png diff --git a/module/webui/themes/Flat/img/head-menu-news.png b/pyload/webui/themes/Flat/img/head-menu-news.png Binary files differindex 44e79a9a9..44e79a9a9 100644 --- a/module/webui/themes/Flat/img/head-menu-news.png +++ b/pyload/webui/themes/Flat/img/head-menu-news.png diff --git a/module/webui/themes/Flat/img/head-menu-queue.png b/pyload/webui/themes/Flat/img/head-menu-queue.png Binary files differindex e4fa41ad8..e4fa41ad8 100644 --- a/module/webui/themes/Flat/img/head-menu-queue.png +++ b/pyload/webui/themes/Flat/img/head-menu-queue.png diff --git a/module/webui/themes/Flat/img/head-menu-wiki.png b/pyload/webui/themes/Flat/img/head-menu-wiki.png Binary files differindex 61b0e54ea..61b0e54ea 100644 --- a/module/webui/themes/Flat/img/head-menu-wiki.png +++ b/pyload/webui/themes/Flat/img/head-menu-wiki.png diff --git a/module/webui/themes/Flat/img/head-search-noshadow.png b/pyload/webui/themes/Flat/img/head-search-noshadow.png Binary files differindex 16d39bd06..16d39bd06 100644 --- a/module/webui/themes/Flat/img/head-search-noshadow.png +++ b/pyload/webui/themes/Flat/img/head-search-noshadow.png diff --git a/module/webui/themes/Flat/img/notice.png b/pyload/webui/themes/Flat/img/notice.png Binary files differindex a52b067cb..a52b067cb 100644 --- a/module/webui/themes/Flat/img/notice.png +++ b/pyload/webui/themes/Flat/img/notice.png diff --git a/module/webui/themes/Flat/img/package_go.png b/pyload/webui/themes/Flat/img/package_go.png Binary files differindex 80b2c42ee..80b2c42ee 100644 --- a/module/webui/themes/Flat/img/package_go.png +++ b/pyload/webui/themes/Flat/img/package_go.png diff --git a/module/webui/themes/Flat/img/page-tools-backlinks.png b/pyload/webui/themes/Flat/img/page-tools-backlinks.png Binary files differindex fb8f55b38..fb8f55b38 100644 --- a/module/webui/themes/Flat/img/page-tools-backlinks.png +++ b/pyload/webui/themes/Flat/img/page-tools-backlinks.png diff --git a/module/webui/themes/Flat/img/page-tools-edit.png b/pyload/webui/themes/Flat/img/page-tools-edit.png Binary files differindex 67177cf89..67177cf89 100644 --- a/module/webui/themes/Flat/img/page-tools-edit.png +++ b/pyload/webui/themes/Flat/img/page-tools-edit.png diff --git a/module/webui/themes/Flat/img/page-tools-revisions.png b/pyload/webui/themes/Flat/img/page-tools-revisions.png Binary files differindex 088fe0087..088fe0087 100644 --- a/module/webui/themes/Flat/img/page-tools-revisions.png +++ b/pyload/webui/themes/Flat/img/page-tools-revisions.png diff --git a/module/webui/themes/Flat/img/pencil.png b/pyload/webui/themes/Flat/img/pencil.png Binary files differindex e39c93cd8..e39c93cd8 100644 --- a/module/webui/themes/Flat/img/pencil.png +++ b/pyload/webui/themes/Flat/img/pencil.png diff --git a/module/webui/themes/Flat/img/reconnect.png b/pyload/webui/themes/Flat/img/reconnect.png Binary files differindex cd35c9325..cd35c9325 100644 --- a/module/webui/themes/Flat/img/reconnect.png +++ b/pyload/webui/themes/Flat/img/reconnect.png diff --git a/module/webui/themes/Flat/img/status_None.png b/pyload/webui/themes/Flat/img/status_None.png Binary files differindex 1400d3eb3..1400d3eb3 100644 --- a/module/webui/themes/Flat/img/status_None.png +++ b/pyload/webui/themes/Flat/img/status_None.png diff --git a/module/webui/themes/Flat/img/status_downloading.png b/pyload/webui/themes/Flat/img/status_downloading.png Binary files differindex db8ad8cd6..db8ad8cd6 100644 --- a/module/webui/themes/Flat/img/status_downloading.png +++ b/pyload/webui/themes/Flat/img/status_downloading.png diff --git a/module/webui/themes/Flat/img/status_failed.png b/pyload/webui/themes/Flat/img/status_failed.png Binary files differindex 6c565c99c..6c565c99c 100644 --- a/module/webui/themes/Flat/img/status_failed.png +++ b/pyload/webui/themes/Flat/img/status_failed.png diff --git a/module/webui/themes/Flat/img/status_finished.png b/pyload/webui/themes/Flat/img/status_finished.png Binary files differindex 2c4aca40d..2c4aca40d 100644 --- a/module/webui/themes/Flat/img/status_finished.png +++ b/pyload/webui/themes/Flat/img/status_finished.png diff --git a/module/webui/themes/Flat/img/status_offline.png b/pyload/webui/themes/Flat/img/status_offline.png Binary files differindex 6c565c99c..6c565c99c 100644 --- a/module/webui/themes/Flat/img/status_offline.png +++ b/pyload/webui/themes/Flat/img/status_offline.png diff --git a/module/webui/themes/Flat/img/status_proc.png b/pyload/webui/themes/Flat/img/status_proc.png Binary files differindex 833f779ac..833f779ac 100644 --- a/module/webui/themes/Flat/img/status_proc.png +++ b/pyload/webui/themes/Flat/img/status_proc.png diff --git a/module/webui/themes/Flat/img/status_queue.png b/pyload/webui/themes/Flat/img/status_queue.png Binary files differindex 1400d3eb3..1400d3eb3 100644 --- a/module/webui/themes/Flat/img/status_queue.png +++ b/pyload/webui/themes/Flat/img/status_queue.png diff --git a/module/webui/themes/Flat/img/status_waiting.png b/pyload/webui/themes/Flat/img/status_waiting.png Binary files differindex fd038175e..fd038175e 100644 --- a/module/webui/themes/Flat/img/status_waiting.png +++ b/pyload/webui/themes/Flat/img/status_waiting.png diff --git a/module/webui/themes/Flat/img/success.png b/pyload/webui/themes/Flat/img/success.png Binary files differindex 2c4aca40d..2c4aca40d 100644 --- a/module/webui/themes/Flat/img/success.png +++ b/pyload/webui/themes/Flat/img/success.png diff --git a/module/webui/themes/Flat/img/user-actions-logout.png b/pyload/webui/themes/Flat/img/user-actions-logout.png Binary files differindex d4ef360e8..d4ef360e8 100644 --- a/module/webui/themes/Flat/img/user-actions-logout.png +++ b/pyload/webui/themes/Flat/img/user-actions-logout.png diff --git a/module/webui/themes/Flat/img/user-actions-profile.png b/pyload/webui/themes/Flat/img/user-actions-profile.png Binary files differindex 9ec410b13..9ec410b13 100644 --- a/module/webui/themes/Flat/img/user-actions-profile.png +++ b/pyload/webui/themes/Flat/img/user-actions-profile.png diff --git a/module/webui/themes/Flat/img/user-info.png b/pyload/webui/themes/Flat/img/user-info.png Binary files differindex 345ed52e4..345ed52e4 100644 --- a/module/webui/themes/Flat/img/user-info.png +++ b/pyload/webui/themes/Flat/img/user-info.png diff --git a/module/webui/themes/Flat/js/render/admin.coffee b/pyload/webui/themes/Flat/js/render/admin.coffee index 5afbcbb66..5afbcbb66 100644 --- a/module/webui/themes/Flat/js/render/admin.coffee +++ b/pyload/webui/themes/Flat/js/render/admin.coffee diff --git a/module/webui/themes/Flat/js/render/admin.min.js b/pyload/webui/themes/Flat/js/render/admin.min.js index 94a5e494d..94a5e494d 100644 --- a/module/webui/themes/Flat/js/render/admin.min.js +++ b/pyload/webui/themes/Flat/js/render/admin.min.js diff --git a/module/webui/themes/Flat/js/render/base.coffee b/pyload/webui/themes/Flat/js/render/base.coffee index 07b8bfb6f..07b8bfb6f 100644 --- a/module/webui/themes/Flat/js/render/base.coffee +++ b/pyload/webui/themes/Flat/js/render/base.coffee diff --git a/module/webui/themes/Flat/js/render/base.min.js b/pyload/webui/themes/Flat/js/render/base.min.js index 1ba1d73f9..1ba1d73f9 100644 --- a/module/webui/themes/Flat/js/render/base.min.js +++ b/pyload/webui/themes/Flat/js/render/base.min.js diff --git a/module/webui/themes/Flat/js/render/filemanager.js b/pyload/webui/themes/Flat/js/render/filemanager.js index ab9b8b492..ab9b8b492 100644 --- a/module/webui/themes/Flat/js/render/filemanager.js +++ b/pyload/webui/themes/Flat/js/render/filemanager.js diff --git a/module/webui/themes/Flat/js/render/package.js b/pyload/webui/themes/Flat/js/render/package.js index 659a8e6fc..659a8e6fc 100644 --- a/module/webui/themes/Flat/js/render/package.js +++ b/pyload/webui/themes/Flat/js/render/package.js diff --git a/module/webui/themes/Flat/js/render/settings.coffee b/pyload/webui/themes/Flat/js/render/settings.coffee index d522741b9..d522741b9 100644 --- a/module/webui/themes/Flat/js/render/settings.coffee +++ b/pyload/webui/themes/Flat/js/render/settings.coffee diff --git a/module/webui/themes/Flat/js/render/settings.min.js b/pyload/webui/themes/Flat/js/render/settings.min.js index 41d1cb25a..41d1cb25a 100644 --- a/module/webui/themes/Flat/js/render/settings.min.js +++ b/pyload/webui/themes/Flat/js/render/settings.min.js diff --git a/module/webui/themes/Flat/js/static/MooDialog.js b/pyload/webui/themes/Flat/js/static/MooDialog.js index 45a52496f..45a52496f 100644 --- a/module/webui/themes/Flat/js/static/MooDialog.js +++ b/pyload/webui/themes/Flat/js/static/MooDialog.js diff --git a/module/webui/themes/Flat/js/static/MooDialog.min.js b/pyload/webui/themes/Flat/js/static/MooDialog.min.js index 90b3ae100..90b3ae100 100644 --- a/module/webui/themes/Flat/js/static/MooDialog.min.js +++ b/pyload/webui/themes/Flat/js/static/MooDialog.min.js diff --git a/module/webui/themes/Flat/js/static/MooDropMenu.js b/pyload/webui/themes/Flat/js/static/MooDropMenu.js index ac0fa1874..ac0fa1874 100644 --- a/module/webui/themes/Flat/js/static/MooDropMenu.js +++ b/pyload/webui/themes/Flat/js/static/MooDropMenu.js diff --git a/module/webui/themes/Flat/js/static/MooDropMenu.min.js b/pyload/webui/themes/Flat/js/static/MooDropMenu.min.js index 552ae247a..552ae247a 100644 --- a/module/webui/themes/Flat/js/static/MooDropMenu.min.js +++ b/pyload/webui/themes/Flat/js/static/MooDropMenu.min.js diff --git a/module/webui/themes/Flat/js/static/mootools-core.js b/pyload/webui/themes/Flat/js/static/mootools-core.js index db83850fd..db83850fd 100644 --- a/module/webui/themes/Flat/js/static/mootools-core.js +++ b/pyload/webui/themes/Flat/js/static/mootools-core.js diff --git a/module/webui/themes/Flat/js/static/mootools-core.min.js b/pyload/webui/themes/Flat/js/static/mootools-core.min.js index 354f94196..354f94196 100644 --- a/module/webui/themes/Flat/js/static/mootools-core.min.js +++ b/pyload/webui/themes/Flat/js/static/mootools-core.min.js diff --git a/module/webui/themes/Flat/js/static/mootools-more.js b/pyload/webui/themes/Flat/js/static/mootools-more.js index c7f4a1a0e..c7f4a1a0e 100644 --- a/module/webui/themes/Flat/js/static/mootools-more.js +++ b/pyload/webui/themes/Flat/js/static/mootools-more.js diff --git a/module/webui/themes/Flat/js/static/mootools-more.min.js b/pyload/webui/themes/Flat/js/static/mootools-more.min.js index ce03a60fd..ce03a60fd 100644 --- a/module/webui/themes/Flat/js/static/mootools-more.min.js +++ b/pyload/webui/themes/Flat/js/static/mootools-more.min.js diff --git a/module/webui/themes/Flat/js/static/purr.js b/pyload/webui/themes/Flat/js/static/purr.js index 9cbc503d9..9cbc503d9 100644 --- a/module/webui/themes/Flat/js/static/purr.js +++ b/pyload/webui/themes/Flat/js/static/purr.js diff --git a/module/webui/themes/Flat/js/static/purr.min.js b/pyload/webui/themes/Flat/js/static/purr.min.js index bf70e357d..bf70e357d 100644 --- a/module/webui/themes/Flat/js/static/purr.min.js +++ b/pyload/webui/themes/Flat/js/static/purr.min.js diff --git a/module/webui/themes/Flat/js/static/tinytab.js b/pyload/webui/themes/Flat/js/static/tinytab.js index de50279fc..de50279fc 100644 --- a/module/webui/themes/Flat/js/static/tinytab.js +++ b/pyload/webui/themes/Flat/js/static/tinytab.js diff --git a/module/webui/themes/Flat/js/static/tinytab.min.js b/pyload/webui/themes/Flat/js/static/tinytab.min.js index 2f4fa0436..2f4fa0436 100644 --- a/module/webui/themes/Flat/js/static/tinytab.min.js +++ b/pyload/webui/themes/Flat/js/static/tinytab.min.js diff --git a/module/webui/themes/Flat/tml/admin.html b/pyload/webui/themes/Flat/tml/admin.html index eb87666ff..eb87666ff 100644 --- a/module/webui/themes/Flat/tml/admin.html +++ b/pyload/webui/themes/Flat/tml/admin.html diff --git a/module/webui/themes/Flat/tml/base.html b/pyload/webui/themes/Flat/tml/base.html index 4473ee5e2..4473ee5e2 100644 --- a/module/webui/themes/Flat/tml/base.html +++ b/pyload/webui/themes/Flat/tml/base.html diff --git a/module/webui/themes/Flat/tml/captcha.html b/pyload/webui/themes/Flat/tml/captcha.html index 731d97d11..731d97d11 100644 --- a/module/webui/themes/Flat/tml/captcha.html +++ b/pyload/webui/themes/Flat/tml/captcha.html diff --git a/module/webui/themes/Flat/tml/downloads.html b/pyload/webui/themes/Flat/tml/downloads.html index 4b9ae7baf..4b9ae7baf 100644 --- a/module/webui/themes/Flat/tml/downloads.html +++ b/pyload/webui/themes/Flat/tml/downloads.html diff --git a/module/webui/themes/Flat/tml/filemanager.html b/pyload/webui/themes/Flat/tml/filemanager.html index 4dbbd288c..4dbbd288c 100644 --- a/module/webui/themes/Flat/tml/filemanager.html +++ b/pyload/webui/themes/Flat/tml/filemanager.html diff --git a/module/webui/themes/Flat/tml/folder.html b/pyload/webui/themes/Flat/tml/folder.html index a0d1dcec9..a0d1dcec9 100644 --- a/module/webui/themes/Flat/tml/folder.html +++ b/pyload/webui/themes/Flat/tml/folder.html diff --git a/module/webui/themes/Flat/tml/home.html b/pyload/webui/themes/Flat/tml/home.html index ec7f4aae2..ec7f4aae2 100644 --- a/module/webui/themes/Flat/tml/home.html +++ b/pyload/webui/themes/Flat/tml/home.html diff --git a/module/webui/themes/Flat/tml/info.html b/pyload/webui/themes/Flat/tml/info.html index a650afc5a..a650afc5a 100644 --- a/module/webui/themes/Flat/tml/info.html +++ b/pyload/webui/themes/Flat/tml/info.html diff --git a/module/webui/themes/Flat/tml/login.html b/pyload/webui/themes/Flat/tml/login.html index 64ed28426..64ed28426 100644 --- a/module/webui/themes/Flat/tml/login.html +++ b/pyload/webui/themes/Flat/tml/login.html diff --git a/module/webui/themes/Flat/tml/logout.html b/pyload/webui/themes/Flat/tml/logout.html index f91b16914..f91b16914 100644 --- a/module/webui/themes/Flat/tml/logout.html +++ b/pyload/webui/themes/Flat/tml/logout.html diff --git a/module/webui/themes/Flat/tml/logs.html b/pyload/webui/themes/Flat/tml/logs.html index eada9ad3f..eada9ad3f 100644 --- a/module/webui/themes/Flat/tml/logs.html +++ b/pyload/webui/themes/Flat/tml/logs.html diff --git a/module/webui/themes/Flat/tml/pathchooser.html b/pyload/webui/themes/Flat/tml/pathchooser.html index 5ad1fd6d7..5ad1fd6d7 100644 --- a/module/webui/themes/Flat/tml/pathchooser.html +++ b/pyload/webui/themes/Flat/tml/pathchooser.html diff --git a/module/webui/themes/Flat/tml/queue.html b/pyload/webui/themes/Flat/tml/queue.html index 80e6c864c..80e6c864c 100644 --- a/module/webui/themes/Flat/tml/queue.html +++ b/pyload/webui/themes/Flat/tml/queue.html diff --git a/module/webui/themes/Flat/tml/settings.html b/pyload/webui/themes/Flat/tml/settings.html index 8a8e54b0f..8a8e54b0f 100644 --- a/module/webui/themes/Flat/tml/settings.html +++ b/pyload/webui/themes/Flat/tml/settings.html diff --git a/module/webui/themes/Flat/tml/settings_item.html b/pyload/webui/themes/Flat/tml/settings_item.html index 813383343..813383343 100644 --- a/module/webui/themes/Flat/tml/settings_item.html +++ b/pyload/webui/themes/Flat/tml/settings_item.html diff --git a/module/webui/themes/Flat/tml/window.html b/pyload/webui/themes/Flat/tml/window.html index ea5d65e46..ea5d65e46 100644 --- a/module/webui/themes/Flat/tml/window.html +++ b/pyload/webui/themes/Flat/tml/window.html |